2015-03-06 16:39:40 +01:00
# include "testutils/BlobStoreTest.h"
# include <messmer/blockstore/utils/Data.h>
2015-03-06 16:54:49 +01:00
# include "../../testutils/DataBlockFixture.h"
2015-03-06 20:40:23 +01:00
# include "../../../implementations/onblocks/datanodestore/DataNodeView.h"
2015-03-06 16:39:40 +01:00
using std : : unique_ptr ;
2015-03-06 20:40:23 +01:00
using : : testing : : WithParamInterface ;
using : : testing : : Values ;
2015-03-06 16:39:40 +01:00
using namespace blobstore ;
2015-03-06 20:40:23 +01:00
using blobstore : : onblocks : : datanodestore : : DataNodeLayout ;
2015-03-06 16:39:40 +01:00
using blockstore : : Key ;
using blockstore : : Data ;
class BlobReadWriteTest : public BlobStoreTest {
public :
2015-03-06 16:54:49 +01:00
static constexpr uint32_t LARGE_SIZE = 10 * 1024 * 1024 ;
2015-03-06 20:40:23 +01:00
static constexpr DataNodeLayout LAYOUT = DataNodeLayout ( BLOCKSIZE_BYTES ) ;
2015-03-06 16:54:49 +01:00
BlobReadWriteTest ( )
: randomData ( LARGE_SIZE ) ,
blob ( blobStore - > create ( ) ) {
}
Data readBlob ( const Blob & blob ) {
Data data ( blob . size ( ) ) ;
blob . read ( data . data ( ) , 0 , data . size ( ) ) ;
return data ;
}
2015-03-06 20:40:23 +01:00
template < class DataClass >
void EXPECT_DATA_READS_AS ( const DataClass & expected , const Blob & actual , uint64_t offset , uint64_t size ) {
Data read ( size ) ;
actual . read ( read . data ( ) , offset , size ) ;
EXPECT_EQ ( 0 , std : : memcmp ( expected . data ( ) , read . data ( ) , size ) ) ;
}
2015-03-06 16:54:49 +01:00
DataBlockFixture randomData ;
unique_ptr < Blob > blob ;
2015-03-06 16:39:40 +01:00
} ;
2015-03-06 16:54:49 +01:00
constexpr uint32_t BlobReadWriteTest : : LARGE_SIZE ;
2015-03-06 20:40:23 +01:00
constexpr DataNodeLayout BlobReadWriteTest : : LAYOUT ;
2015-03-06 16:54:49 +01:00
TEST_F ( BlobReadWriteTest , WritingImmediatelyFlushes_SmallSize ) {
blob - > resize ( 5 ) ;
blob - > write ( randomData . data ( ) , 0 , 5 ) ;
auto loaded = blobStore - > load ( blob - > key ( ) ) ;
2015-03-06 20:40:23 +01:00
EXPECT_DATA_READS_AS ( randomData , * loaded , 0 , 5 ) ;
2015-03-06 16:54:49 +01:00
}
TEST_F ( BlobReadWriteTest , WritingImmediatelyFlushes_LargeSize ) {
blob - > resize ( LARGE_SIZE ) ;
blob - > write ( randomData . data ( ) , 0 , LARGE_SIZE ) ;
auto loaded = blobStore - > load ( blob - > key ( ) ) ;
2015-03-06 20:40:23 +01:00
EXPECT_DATA_READS_AS ( randomData , * loaded , 0 , LARGE_SIZE ) ;
}
struct DataRange {
DataRange ( size_t blobsize_ , off_t offset_ , size_t count_ ) : blobsize ( blobsize_ ) , offset ( offset_ ) , count ( count_ ) { }
size_t blobsize ;
off_t offset ;
size_t count ;
} ;
class BlobReadWriteDataTest : public BlobReadWriteTest , public WithParamInterface < DataRange > {
public :
DataBlockFixture foregroundData ;
DataBlockFixture backgroundData ;
BlobReadWriteDataTest ( )
: foregroundData ( GetParam ( ) . count ) ,
backgroundData ( GetParam ( ) . blobsize ) {
}
template < class DataClass >
void EXPECT_DATA_READS_AS_OUTSIDE_OF ( const DataClass & expected , const Blob & blob , off_t start , size_t count ) {
Data begin ( start ) ;
Data end ( GetParam ( ) . blobsize - count - start ) ;
std : : memcpy ( begin . data ( ) , expected . data ( ) , start ) ;
std : : memcpy ( end . data ( ) , ( uint8_t * ) expected . data ( ) + start + count , end . size ( ) ) ;
EXPECT_DATA_READS_AS ( begin , blob , 0 , start ) ;
EXPECT_DATA_READS_AS ( end , blob , start + count , end . size ( ) ) ;
}
void EXPECT_DATA_IS_ZEROES_OUTSIDE_OF ( const Blob & blob , off_t start , size_t count ) {
Data ZEROES ( GetParam ( ) . blobsize ) ;
ZEROES . FillWithZeroes ( ) ;
EXPECT_DATA_READS_AS_OUTSIDE_OF ( ZEROES , blob , start , count ) ;
}
} ;
INSTANTIATE_TEST_CASE_P ( BlobReadWriteDataTest , BlobReadWriteDataTest , Values (
//Blob with only one leaf
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) , 0 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) ) , // full size leaf, access beginning to end
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) , 100 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 200 ) , // full size leaf, access middle to middle
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) , 0 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 ) , // full size leaf, access beginning to middle
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) , 100 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 ) , // full size leaf, access middle to end
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 , 0 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 ) , // non-full size leaf, access beginning to end
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 , 100 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 300 ) , // non-full size leaf, access middle to middle
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 , 0 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 200 ) , // non-full size leaf, access beginning to middle
DataRange ( BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 100 , 100 , BlobReadWriteDataTest : : LAYOUT . maxBytesPerLeaf ( ) - 200 ) , // non-full size leaf, access middle to end
//Larger blob
2015-03-06 21:18:22 +01:00
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , 0 , BlobReadWriteDataTest : : LARGE_SIZE ) , // access beginning to end
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , 100 , BlobReadWriteDataTest : : LARGE_SIZE - 200 ) , // access middle first leaf to middle last leaf
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , 0 , BlobReadWriteDataTest : : LARGE_SIZE - 100 ) , // access beginning to middle last leaf
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , 100 , BlobReadWriteDataTest : : LARGE_SIZE - 100 ) , // access middle first leaf to end
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , BlobReadWriteDataTest : : LARGE_SIZE * 1 / 3 , BlobReadWriteDataTest : : LARGE_SIZE * 1 / 3 ) , // access middle to middle
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , 0 , BlobReadWriteDataTest : : LARGE_SIZE * 2 / 3 ) , // access beginning to middle
DataRange ( BlobReadWriteDataTest : : LARGE_SIZE , BlobReadWriteDataTest : : LARGE_SIZE * 1 / 3 , BlobReadWriteDataTest : : LARGE_SIZE * 2 / 3 ) // access middle to end
2015-03-06 20:40:23 +01:00
) ) ;
TEST_P ( BlobReadWriteDataTest , WriteAndReadImmediately ) {
blob - > resize ( GetParam ( ) . blobsize ) ;
blob - > write ( this - > foregroundData . data ( ) , GetParam ( ) . offset , GetParam ( ) . count ) ;
EXPECT_DATA_READS_AS ( this - > foregroundData , * blob , GetParam ( ) . offset , GetParam ( ) . count ) ;
EXPECT_DATA_IS_ZEROES_OUTSIDE_OF ( * blob , GetParam ( ) . offset , GetParam ( ) . count ) ;
}
TEST_P ( BlobReadWriteDataTest , WriteAndReadAfterLoading ) {
blob - > resize ( GetParam ( ) . blobsize ) ;
blob - > write ( this - > foregroundData . data ( ) , GetParam ( ) . offset , GetParam ( ) . count ) ;
auto loaded = blobStore - > load ( blob - > key ( ) ) ;
EXPECT_DATA_READS_AS ( this - > foregroundData , * loaded , GetParam ( ) . offset , GetParam ( ) . count ) ;
EXPECT_DATA_IS_ZEROES_OUTSIDE_OF ( * loaded , GetParam ( ) . offset , GetParam ( ) . count ) ;
}
TEST_P ( BlobReadWriteDataTest , OverwriteAndRead ) {
blob - > resize ( GetParam ( ) . blobsize ) ;
blob - > write ( this - > backgroundData . data ( ) , 0 , GetParam ( ) . blobsize ) ;
blob - > write ( this - > foregroundData . data ( ) , GetParam ( ) . offset , GetParam ( ) . count ) ;
EXPECT_DATA_READS_AS ( this - > foregroundData , * blob , GetParam ( ) . offset , GetParam ( ) . count ) ;
EXPECT_DATA_READS_AS_OUTSIDE_OF ( this - > backgroundData , * blob , GetParam ( ) . offset , GetParam ( ) . count ) ;
2015-03-06 16:54:49 +01:00
}
2015-03-06 20:40:23 +01:00
TEST_P ( BlobReadWriteDataTest , WriteWholeAndReadPart ) {
blob - > resize ( GetParam ( ) . blobsize ) ;
blob - > write ( this - > backgroundData . data ( ) , 0 , GetParam ( ) . blobsize ) ;
Data read ( GetParam ( ) . count ) ;
blob - > read ( read . data ( ) , GetParam ( ) . offset , GetParam ( ) . count ) ;
EXPECT_EQ ( 0 , std : : memcmp ( read . data ( ) , this - > backgroundData . data ( ) + GetParam ( ) . offset , GetParam ( ) . count ) ) ;
}
TEST_P ( BlobReadWriteDataTest , WritePartAndReadWhole ) {
blob - > resize ( GetParam ( ) . blobsize ) ;
blob - > write ( this - > backgroundData . data ( ) , 0 , GetParam ( ) . blobsize ) ;
blob - > write ( this - > foregroundData . data ( ) , GetParam ( ) . offset , GetParam ( ) . count ) ;
Data read = readBlob ( * blob ) ;
EXPECT_EQ ( 0 , std : : memcmp ( read . data ( ) , this - > backgroundData . data ( ) , GetParam ( ) . offset ) ) ;
EXPECT_EQ ( 0 , std : : memcmp ( ( uint8_t * ) read . data ( ) + GetParam ( ) . offset , this - > foregroundData . data ( ) , GetParam ( ) . count ) ) ;
EXPECT_EQ ( 0 , std : : memcmp ( ( uint8_t * ) read . data ( ) + GetParam ( ) . offset + GetParam ( ) . count , ( uint8_t * ) this - > backgroundData . data ( ) + GetParam ( ) . offset + GetParam ( ) . count , GetParam ( ) . blobsize - GetParam ( ) . count - GetParam ( ) . offset ) ) ;
}