@ -36,6 +36,7 @@
# include "util/log_buffer.h"
# include "util/mutexlock.h"
# include "util/string_util.h"
# include "util/sync_point.h"
# include "util/testharness.h"
# include "util/testutil.h"
@ -43,6 +44,17 @@ namespace rocksdb {
static const int kDelayMicros = 100000 ;
std : : unique_ptr < char , void ( & ) ( void * ) > NewAligned ( const size_t size ,
const char ch ) {
char * ptr = nullptr ;
if ( posix_memalign ( reinterpret_cast < void * * > ( & ptr ) , 4 * 1024 , size ) ! = 0 ) {
return std : : unique_ptr < char , void ( & ) ( void * ) > ( nullptr , free ) ;
}
std : : unique_ptr < char , void ( & ) ( void * ) > uptr ( ptr , free ) ;
memset ( uptr . get ( ) , ch , size ) ;
return uptr ;
}
class EnvPosixTest : public testing : : Test {
private :
port : : Mutex mu_ ;
@ -553,108 +565,119 @@ class IoctlFriendlyTmpdir {
// Only works in linux platforms
TEST_F ( EnvPosixTest , RandomAccessUniqueID ) {
// Create file.
const EnvOptions soptions ;
IoctlFriendlyTmpdir ift ;
std : : string fname = ift . name ( ) + " /testfile " ;
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
unique_ptr < RandomAccessFile > file ;
// Get Unique ID
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
size_t id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
std : : string unique_id1 ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id1 ) ) ;
// Get Unique ID again
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
std : : string unique_id2 ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id2 ) ) ;
// Get Unique ID again after waiting some time.
env_ - > SleepForMicroseconds ( 1000000 ) ;
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
std : : string unique_id3 ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id3 ) ) ;
// Check IDs are the same.
ASSERT_EQ ( unique_id1 , unique_id2 ) ;
ASSERT_EQ ( unique_id2 , unique_id3 ) ;
// Delete the file
env_ - > DeleteFile ( fname ) ;
for ( bool directio : { true , false } ) {
// Create file.
EnvOptions soptions ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
IoctlFriendlyTmpdir ift ;
std : : string fname = ift . name ( ) + " /testfile " ;
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
unique_ptr < RandomAccessFile > file ;
// Get Unique ID
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
size_t id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
std : : string unique_id1 ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id1 ) ) ;
// Get Unique ID again
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
std : : string unique_id2 ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id2 ) ) ;
// Get Unique ID again after waiting some time.
env_ - > SleepForMicroseconds ( 1000000 ) ;
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
std : : string unique_id3 ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id3 ) ) ;
// Check IDs are the same.
ASSERT_EQ ( unique_id1 , unique_id2 ) ;
ASSERT_EQ ( unique_id2 , unique_id3 ) ;
// Delete the file
env_ - > DeleteFile ( fname ) ;
}
}
// only works in linux platforms
# ifdef ROCKSDB_FALLOCATE_PRESENT
TEST_F ( EnvPosixTest , AllocateTest ) {
IoctlFriendlyTmpdir ift ;
std : : string fname = ift . name ( ) + " /preallocate_testfile " ;
// Try fallocate in a file to see whether the target file system supports it.
// Skip the test if fallocate is not supported.
std : : string fname_test_fallocate = ift . name ( ) + " /preallocate_testfile_2 " ;
int fd = - 1 ;
do {
fd = open ( fname_test_fallocate . c_str ( ) , O_CREAT | O_RDWR | O_TRUNC , 0644 ) ;
} while ( fd < 0 & & errno = = EINTR ) ;
ASSERT_GT ( fd , 0 ) ;
for ( bool directio : { true , false } ) {
IoctlFriendlyTmpdir ift ;
std : : string fname = ift . name ( ) + " /preallocate_testfile " ;
// Try fallocate in a file to see whether the target file system supports
// it.
// Skip the test if fallocate is not supported.
std : : string fname_test_fallocate = ift . name ( ) + " /preallocate_testfile_2 " ;
int fd = - 1 ;
do {
fd = open ( fname_test_fallocate . c_str ( ) , O_CREAT | O_RDWR | O_TRUNC , 0644 ) ;
} while ( fd < 0 & & errno = = EINTR ) ;
ASSERT_GT ( fd , 0 ) ;
int alloc_status = fallocate ( fd , 0 , 0 , 1 ) ;
int err_number = 0 ;
if ( alloc_status ! = 0 ) {
err_number = errno ;
fprintf ( stderr , " Warning: fallocate() fails, %s \n " , strerror ( err_number ) ) ;
}
close ( fd ) ;
ASSERT_OK ( env_ - > DeleteFile ( fname_test_fallocate ) ) ;
if ( alloc_status ! = 0 & & err_number = = EOPNOTSUPP ) {
// The filesystem containing the file does not support fallocate
return ;
}
int alloc_status = fallocate ( fd , 0 , 0 , 1 ) ;
EnvOptions soptions ;
soptions . use_mmap_writes = false ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
int err_number = 0 ;
if ( alloc_status ! = 0 ) {
err_number = errno ;
fprintf ( stderr , " Warning: fallocate() fails, %s \n " , strerror ( err_number ) ) ;
}
close ( fd ) ;
ASSERT_OK ( env_ - > DeleteFile ( fname_test_fallocate ) ) ;
if ( alloc_status ! = 0 & & err_number = = EOPNOTSUPP ) {
// The filesystem containing the file does not support fallocate
return ;
// allocate 100 MB
size_t kPreallocateSize = 100 * 1024 * 1024 ;
size_t kBlockSize = 512 ;
size_t kPageSize = 4096 ;
size_t kDataSize = 1024 * 1024 ;
auto data_ptr = NewAligned ( kDataSize , ' A ' ) ;
Slice data ( data_ptr . get ( ) , kDataSize ) ;
wfile - > SetPreallocationBlockSize ( kPreallocateSize ) ;
wfile - > PrepareWrite ( wfile - > GetFileSize ( ) , kDataSize ) ;
ASSERT_OK ( wfile - > Append ( data ) ) ;
ASSERT_OK ( wfile - > Flush ( ) ) ;
struct stat f_stat ;
ASSERT_EQ ( stat ( fname . c_str ( ) , & f_stat ) , 0 ) ;
ASSERT_EQ ( ( unsigned int ) kDataSize , f_stat . st_size ) ;
// verify that blocks are preallocated
// Note here that we don't check the exact number of blocks preallocated --
// we only require that number of allocated blocks is at least what we
// expect.
// It looks like some FS give us more blocks that we asked for. That's fine.
// It might be worth investigating further.
ASSERT_LE ( ( unsigned int ) ( kPreallocateSize / kBlockSize ) , f_stat . st_blocks ) ;
// close the file, should deallocate the blocks
wfile . reset ( ) ;
stat ( fname . c_str ( ) , & f_stat ) ;
ASSERT_EQ ( ( unsigned int ) kDataSize , f_stat . st_size ) ;
// verify that preallocated blocks were deallocated on file close
// Because the FS might give us more blocks, we add a full page to the size
// and expect the number of blocks to be less or equal to that.
ASSERT_GE ( ( f_stat . st_size + kPageSize + kBlockSize - 1 ) / kBlockSize ,
( unsigned int ) f_stat . st_blocks ) ;
}
EnvOptions soptions ;
soptions . use_mmap_writes = false ;
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
// allocate 100 MB
size_t kPreallocateSize = 100 * 1024 * 1024 ;
size_t kBlockSize = 512 ;
size_t kPageSize = 4096 ;
std : : string data ( 1024 * 1024 , ' a ' ) ;
wfile - > SetPreallocationBlockSize ( kPreallocateSize ) ;
wfile - > PrepareWrite ( wfile - > GetFileSize ( ) , data . size ( ) ) ;
ASSERT_OK ( wfile - > Append ( Slice ( data ) ) ) ;
ASSERT_OK ( wfile - > Flush ( ) ) ;
struct stat f_stat ;
stat ( fname . c_str ( ) , & f_stat ) ;
ASSERT_EQ ( ( unsigned int ) data . size ( ) , f_stat . st_size ) ;
// verify that blocks are preallocated
// Note here that we don't check the exact number of blocks preallocated --
// we only require that number of allocated blocks is at least what we expect.
// It looks like some FS give us more blocks that we asked for. That's fine.
// It might be worth investigating further.
ASSERT_LE ( ( unsigned int ) ( kPreallocateSize / kBlockSize ) , f_stat . st_blocks ) ;
// close the file, should deallocate the blocks
wfile . reset ( ) ;
stat ( fname . c_str ( ) , & f_stat ) ;
ASSERT_EQ ( ( unsigned int ) data . size ( ) , f_stat . st_size ) ;
// verify that preallocated blocks were deallocated on file close
// Because the FS might give us more blocks, we add a full page to the size
// and expect the number of blocks to be less or equal to that.
ASSERT_GE ( ( f_stat . st_size + kPageSize + kBlockSize - 1 ) / kBlockSize , ( unsigned int ) f_stat . st_blocks ) ;
}
# endif // ROCKSDB_FALLOCATE_PRESENT
@ -675,119 +698,159 @@ bool HasPrefix(const std::unordered_set<std::string>& ss) {
// Only works in linux platforms
TEST_F ( EnvPosixTest , RandomAccessUniqueIDConcurrent ) {
// Check whether a bunch of concurrently existing files have unique IDs.
const EnvOptions soptions ;
for ( bool directio : { true , false } ) {
// Check whether a bunch of concurrently existing files have unique IDs.
EnvOptions soptions ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
// Create the files
IoctlFriendlyTmpdir ift ;
std : : vector < std : : string > fnames ;
for ( int i = 0 ; i < 1000 ; + + i ) {
fnames . push_back ( ift . name ( ) + " / " + " testfile " + ToString ( i ) ) ;
// Create file.
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fnames [ i ] , & wfile , soptions ) ) ;
}
// Create the files
IoctlFriendlyTmpdir ift ;
std : : vector < std : : string > fnames ;
for ( int i = 0 ; i < 1000 ; + + i ) {
fnames . push_back ( ift . name ( ) + " / " + " testfile " + ToString ( i ) ) ;
// Collect and check whether the IDs are unique.
std : : unordered_set < std : : string > ids ;
for ( const std : : string fname : fnames ) {
unique_ptr < RandomAccessFile > file ;
std : : string unique_id ;
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
size_t id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
unique_id = std : : string ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id ) ) ;
// Create file.
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fnames [ i ] , & wfile , soptions ) ) ;
}
ASSERT_TRUE ( ids . count ( unique_id ) = = 0 ) ;
ids . insert ( unique_id ) ;
}
// Collect and check whether the IDs are unique.
std : : unordered_set < std : : string > ids ;
for ( const std : : string fname : fnames ) {
unique_ptr < RandomAccessFile > file ;
std : : string unique_id ;
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
size_t id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
unique_id = std : : string ( temp_id , id_size ) ;
ASSERT_TRUE ( IsUniqueIDValid ( unique_id ) ) ;
// Delete the files
for ( const std : : string fname : fnames ) {
ASSERT_OK ( env_ - > DeleteFile ( fname ) ) ;
}
ASSERT_TRUE ( ids . count ( unique_id ) = = 0 ) ;
ids . insert ( unique_id ) ;
ASSERT_TRUE ( ! HasPrefix ( ids ) ) ;
}
}
// Delete the files
for ( const std : : string fname : fnames ) {
ASSERT_OK ( env_ - > DeleteFile ( fname ) ) ;
}
// Only works in linux platforms
TEST_F ( EnvPosixTest , RandomAccessUniqueIDDeletes ) {
for ( bool directio : { true , false } ) {
EnvOptions soptions ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
IoctlFriendlyTmpdir ift ;
std : : string fname = ift . name ( ) + " / " + " testfile " ;
// Check that after file is deleted we don't get same ID again in a new
// file.
std : : unordered_set < std : : string > ids ;
for ( int i = 0 ; i < 1000 ; + + i ) {
// Create file.
{
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
}
// Get Unique ID
std : : string unique_id ;
{
unique_ptr < RandomAccessFile > file ;
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
size_t id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
unique_id = std : : string ( temp_id , id_size ) ;
}
ASSERT_TRUE ( IsUniqueIDValid ( unique_id ) ) ;
ASSERT_TRUE ( ids . count ( unique_id ) = = 0 ) ;
ids . insert ( unique_id ) ;
// Delete the file
ASSERT_OK ( env_ - > DeleteFile ( fname ) ) ;
}
ASSERT_TRUE ( ! HasPrefix ( ids ) ) ;
ASSERT_TRUE ( ! HasPrefix ( ids ) ) ;
}
}
// Only works in linux platforms
TEST_F ( EnvPosixTest , RandomAccessUniqueIDDeletes ) {
const EnvOptions soptions ;
TEST_P ( EnvPosixTestWithParam , InvalidateCache ) {
rocksdb : : SyncPoint : : GetInstance ( ) - > EnableProcessing ( ) ;
for ( bool directio : { true , false } ) {
EnvOptions soptions ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
std : : string fname = test : : TmpDir ( env_ ) + " / " + " testfile " ;
IoctlFriendlyTmpdir ift ;
std : : string fname = ift . name ( ) + " / " + " testfile " ;
const size_t kSectorSize = 512 ;
auto data = NewAligned ( kSectorSize , ' A ' ) ;
Slice slice ( data . get ( ) , kSectorSize ) ;
// Check that after file is deleted we don't get same ID again in a new file.
std : : unordered_set < std : : string > ids ;
for ( int i = 0 ; i < 1000 ; + + i ) {
// Create file.
{
unique_ptr < WritableFile > wfile ;
if ( soptions . use_direct_writes ) {
rocksdb : : SyncPoint : : GetInstance ( ) - > SetCallBack (
" NewWritableFile:O_DIRECT " , [ & ] ( void * arg ) {
int * val = static_cast < int * > ( arg ) ;
* val & = ~ O_DIRECT ;
} ) ;
}
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
ASSERT_OK ( wfile . get ( ) - > Append ( slice ) ) ;
ASSERT_OK ( wfile . get ( ) - > InvalidateCache ( 0 , 0 ) ) ;
ASSERT_OK ( wfile . get ( ) - > Close ( ) ) ;
}
// Get Unique ID
std : : string unique_id ;
// Random Read
{
unique_ptr < RandomAccessFile > file ;
char scratch [ kSectorSize ] ;
Slice result ;
if ( soptions . use_direct_reads ) {
rocksdb : : SyncPoint : : GetInstance ( ) - > SetCallBack (
" NewRandomAccessFile:O_DIRECT " , [ & ] ( void * arg ) {
int * val = static_cast < int * > ( arg ) ;
* val & = ~ O_DIRECT ;
} ) ;
}
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
size_t id_size = file - > GetUniqueId ( temp_id , MAX_ID_SIZE ) ;
ASSERT_TRUE ( id_size > 0 ) ;
unique_id = std : : string ( temp_id , id_size ) ;
ASSERT_OK ( file . get ( ) - > Read ( 0 , kSectorSize , & result , scratch ) ) ;
ASSERT_EQ ( memcmp ( scratch , data . get ( ) , kSectorSize ) , 0 ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 11 ) ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 0 ) ) ;
}
ASSERT_TRUE ( IsUniqueIDValid ( unique_id ) ) ;
ASSERT_TRUE ( ids . count ( unique_id ) = = 0 ) ;
ids . insert ( unique_id ) ;
// Sequential Read
{
unique_ptr < SequentialFile > file ;
char scratch [ kSectorSize ] ;
Slice result ;
if ( soptions . use_direct_reads ) {
rocksdb : : SyncPoint : : GetInstance ( ) - > SetCallBack (
" NewSequentialFile:O_DIRECT " , [ & ] ( void * arg ) {
int * val = static_cast < int * > ( arg ) ;
* val & = ~ O_DIRECT ;
} ) ;
}
ASSERT_OK ( env_ - > NewSequentialFile ( fname , & file , soptions ) ) ;
ASSERT_OK ( file . get ( ) - > Read ( kSectorSize , & result , scratch ) ) ;
ASSERT_EQ ( memcmp ( scratch , data . get ( ) , kSectorSize ) , 0 ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 11 ) ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 0 ) ) ;
}
// Delete the file
ASSERT_OK ( env_ - > DeleteFile ( fname ) ) ;
}
ASSERT_TRUE ( ! HasPrefix ( ids ) ) ;
}
// Only works in linux platforms
TEST_P ( EnvPosixTestWithParam , InvalidateCache ) {
const EnvOptions soptions ;
std : : string fname = test : : TmpDir ( env_ ) + " / " + " testfile " ;
// Create file.
{
unique_ptr < WritableFile > wfile ;
ASSERT_OK ( env_ - > NewWritableFile ( fname , & wfile , soptions ) ) ;
ASSERT_OK ( wfile . get ( ) - > Append ( Slice ( " Hello world " ) ) ) ;
ASSERT_OK ( wfile . get ( ) - > InvalidateCache ( 0 , 0 ) ) ;
ASSERT_OK ( wfile . get ( ) - > Close ( ) ) ;
}
// Random Read
{
unique_ptr < RandomAccessFile > file ;
char scratch [ 100 ] ;
Slice result ;
ASSERT_OK ( env_ - > NewRandomAccessFile ( fname , & file , soptions ) ) ;
ASSERT_OK ( file . get ( ) - > Read ( 0 , 11 , & result , scratch ) ) ;
ASSERT_EQ ( memcmp ( scratch , " Hello world " , 11 ) , 0 ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 11 ) ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 0 ) ) ;
}
// Sequential Read
{
unique_ptr < SequentialFile > file ;
char scratch [ 100 ] ;
Slice result ;
ASSERT_OK ( env_ - > NewSequentialFile ( fname , & file , soptions ) ) ;
ASSERT_OK ( file . get ( ) - > Read ( 11 , & result , scratch ) ) ;
ASSERT_EQ ( memcmp ( scratch , " Hello world " , 11 ) , 0 ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 11 ) ) ;
ASSERT_OK ( file . get ( ) - > InvalidateCache ( 0 , 0 ) ) ;
}
// Delete the file
ASSERT_OK ( env_ - > DeleteFile ( fname ) ) ;
rocksdb : : SyncPoint : : GetInstance ( ) - > ClearTrace ( ) ;
}
# endif // not TRAVIS
# endif // OS_LINUX
@ -909,73 +972,109 @@ TEST_P(EnvPosixTestWithParam, LogBufferMaxSizeTest) {
}
TEST_P ( EnvPosixTestWithParam , Preallocation ) {
const std : : string src = test : : TmpDir ( env_ ) + " / " + " testfile " ;
unique_ptr < WritableFile > srcfile ;
const EnvOptions soptions ;
ASSERT_OK ( env_ - > NewWritableFile ( src , & srcfile , soptions ) ) ;
srcfile - > SetPreallocationBlockSize ( 1024 * 1024 ) ;
// No writes should mean no preallocation
size_t block_size , last_allocated_block ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 0UL ) ;
// Small write should preallocate one block
std : : string str = " test " ;
srcfile - > PrepareWrite ( srcfile - > GetFileSize ( ) , str . size ( ) ) ;
srcfile - > Append ( str ) ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 1UL ) ;
// Write an entire preallocation block, make sure we increased by two.
std : : string buf ( block_size , ' ' ) ;
srcfile - > PrepareWrite ( srcfile - > GetFileSize ( ) , buf . size ( ) ) ;
srcfile - > Append ( buf ) ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 2UL ) ;
// Write five more blocks at once, ensure we're where we need to be.
buf = std : : string ( block_size * 5 , ' ' ) ;
srcfile - > PrepareWrite ( srcfile - > GetFileSize ( ) , buf . size ( ) ) ;
srcfile - > Append ( buf ) ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 7UL ) ;
rocksdb : : SyncPoint : : GetInstance ( ) - > EnableProcessing ( ) ;
for ( bool directio : { true , false } ) {
const std : : string src = test : : TmpDir ( env_ ) + " / " + " testfile " ;
unique_ptr < WritableFile > srcfile ;
EnvOptions soptions ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
if ( soptions . use_direct_writes ) {
rocksdb : : SyncPoint : : GetInstance ( ) - > SetCallBack (
" NewWritableFile:O_DIRECT " , [ & ] ( void * arg ) {
int * val = static_cast < int * > ( arg ) ;
* val & = ~ O_DIRECT ;
} ) ;
}
ASSERT_OK ( env_ - > NewWritableFile ( src , & srcfile , soptions ) ) ;
srcfile - > SetPreallocationBlockSize ( 1024 * 1024 ) ;
// No writes should mean no preallocation
size_t block_size , last_allocated_block ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 0UL ) ;
// Small write should preallocate one block
size_t kStrSize = 512 ;
auto data = NewAligned ( kStrSize , ' A ' ) ;
Slice str ( data . get ( ) , kStrSize ) ;
srcfile - > PrepareWrite ( srcfile - > GetFileSize ( ) , kStrSize ) ;
srcfile - > Append ( str ) ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 1UL ) ;
// Write an entire preallocation block, make sure we increased by two.
{
auto buf_ptr = NewAligned ( block_size , ' ' ) ;
Slice buf ( buf_ptr . get ( ) , block_size ) ;
srcfile - > PrepareWrite ( srcfile - > GetFileSize ( ) , block_size ) ;
srcfile - > Append ( buf ) ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 2UL ) ;
}
// Write five more blocks at once, ensure we're where we need to be.
{
auto buf_ptr = NewAligned ( block_size * 5 , ' ' ) ;
Slice buf = Slice ( buf_ptr . get ( ) , block_size * 5 ) ;
srcfile - > PrepareWrite ( srcfile - > GetFileSize ( ) , buf . size ( ) ) ;
srcfile - > Append ( buf ) ;
srcfile - > GetPreallocationStatus ( & block_size , & last_allocated_block ) ;
ASSERT_EQ ( last_allocated_block , 7UL ) ;
}
}
rocksdb : : SyncPoint : : GetInstance ( ) - > ClearTrace ( ) ;
}
// Test that the two ways to get children file attributes (in bulk or
// individually) behave consistently.
TEST_P ( EnvPosixTestWithParam , ConsistentChildrenAttributes ) {
const EnvOptions soptions ;
const int kNumChildren = 10 ;
std : : string data ;
for ( int i = 0 ; i < kNumChildren ; + + i ) {
std : : ostringstream oss ;
oss < < test : : TmpDir ( env_ ) < < " /testfile_ " < < i ;
const std : : string path = oss . str ( ) ;
unique_ptr < WritableFile > file ;
ASSERT_OK ( env_ - > NewWritableFile ( path , & file , soptions ) ) ;
file - > Append ( data ) ;
data . append ( " test " ) ;
}
rocksdb : : SyncPoint : : GetInstance ( ) - > EnableProcessing ( ) ;
for ( bool directio : { true , false } ) {
EnvOptions soptions ;
soptions . use_direct_reads = soptions . use_direct_writes = directio ;
const int kNumChildren = 10 ;
std : : string data ;
for ( int i = 0 ; i < kNumChildren ; + + i ) {
std : : ostringstream oss ;
oss < < test : : TmpDir ( env_ ) < < " /testfile_ " < < i ;
const std : : string path = oss . str ( ) ;
unique_ptr < WritableFile > file ;
if ( soptions . use_direct_writes ) {
rocksdb : : SyncPoint : : GetInstance ( ) - > SetCallBack (
" NewWritableFile:O_DIRECT " , [ & ] ( void * arg ) {
int * val = static_cast < int * > ( arg ) ;
* val & = ~ O_DIRECT ;
} ) ;
}
std : : vector < Env : : FileAttributes > file_attrs ;
ASSERT_OK ( env_ - > GetChildrenFileAttributes ( test : : TmpDir ( env_ ) , & file_attrs ) ) ;
for ( int i = 0 ; i < kNumChildren ; + + i ) {
std : : ostringstream oss ;
oss < < " testfile_ " < < i ;
const std : : string name = oss . str ( ) ;
const std : : string path = test : : TmpDir ( env_ ) + " / " + name ;
auto file_attrs_iter = std : : find_if (
file_attrs . begin ( ) , file_attrs . end ( ) ,
[ & name ] ( const Env : : FileAttributes & fm ) { return fm . name = = name ; } ) ;
ASSERT_TRUE ( file_attrs_iter ! = file_attrs . end ( ) ) ;
uint64_t size ;
ASSERT_OK ( env_ - > GetFileSize ( path , & size ) ) ;
ASSERT_EQ ( size , 4 * i ) ;
ASSERT_EQ ( size , file_attrs_iter - > size_bytes ) ;
ASSERT_OK ( env_ - > NewWritableFile ( path , & file , soptions ) ) ;
auto buf_ptr = NewAligned ( data . size ( ) , ' T ' ) ;
Slice buf ( buf_ptr . get ( ) , data . size ( ) ) ;
file - > Append ( buf ) ;
data . append ( std : : string ( 512 , ' T ' ) ) ;
}
std : : vector < Env : : FileAttributes > file_attrs ;
ASSERT_OK ( env_ - > GetChildrenFileAttributes ( test : : TmpDir ( env_ ) , & file_attrs ) ) ;
for ( int i = 0 ; i < kNumChildren ; + + i ) {
std : : ostringstream oss ;
oss < < " testfile_ " < < i ;
const std : : string name = oss . str ( ) ;
const std : : string path = test : : TmpDir ( env_ ) + " / " + name ;
auto file_attrs_iter = std : : find_if (
file_attrs . begin ( ) , file_attrs . end ( ) ,
[ & name ] ( const Env : : FileAttributes & fm ) { return fm . name = = name ; } ) ;
ASSERT_TRUE ( file_attrs_iter ! = file_attrs . end ( ) ) ;
uint64_t size ;
ASSERT_OK ( env_ - > GetFileSize ( path , & size ) ) ;
ASSERT_EQ ( size , 512 * i ) ;
ASSERT_EQ ( size , file_attrs_iter - > size_bytes ) ;
}
}
rocksdb : : SyncPoint : : GetInstance ( ) - > ClearTrace ( ) ;
}
// Test that all WritableFileWrapper forwards all calls to WritableFile.