1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
#include <gtest/gtest.h>
#include <blockstore/implementations/compressing/CompressingBlockStore.h>
#include <blockstore/implementations/compressing/compressors/RunLengthEncoding.h>
#include <blockstore/implementations/inmemory/InMemoryBlockStore2.h>
#include <blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h>
#include <cpp-utils/data/DataFixture.h>
#include <cpp-utils/data/Data.h>
#include "blobstore/implementations/onblocks/BlobOnBlocks.h"
#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h"
#include <cstddef>
using namespace blobstore;
using namespace blobstore::onblocks;
using cpputils::unique_ref;
using cpputils::make_unique_ref;
using cpputils::DataFixture;
using cpputils::Data;
using blockstore::inmemory::InMemoryBlockStore2;
using blockstore::lowtohighlevel::LowToHighLevelBlockStore;
using blockstore::compressing::CompressingBlockStore;
using blockstore::compressing::RunLengthEncoding;
// Test cases, ensuring that big blobs (>4G) work (i.e. testing that we don't use any 32bit variables for blob size, etc.)
class BigBlobsTest : public ::testing::Test {
public:
static constexpr size_t BLOCKSIZE = 32 * 1024;
static constexpr uint64_t SMALL_BLOB_SIZE = UINT64_C(1024)*1024*1024*3.95; // 3.95 GB (<4GB)
static constexpr uint64_t LARGE_BLOB_SIZE = UINT64_C(1024)*1024*1024*4.05; // 4.05 GB (>4GB)
static constexpr uint64_t max_uint_32 = std::numeric_limits<uint32_t>::max();
static_assert(SMALL_BLOB_SIZE < max_uint_32, "LARGE_BLOB_SIZE should need 64bit or the test case is mute");
static_assert(LARGE_BLOB_SIZE > max_uint_32, "LARGE_BLOB_SIZE should need 64bit or the test case is mute");
unique_ref<BlobStore> blobStore = make_unique_ref<BlobStoreOnBlocks>(make_unique_ref<CompressingBlockStore<RunLengthEncoding>>(make_unique_ref<LowToHighLevelBlockStore>(make_unique_ref<InMemoryBlockStore2>())), BLOCKSIZE);
unique_ref<Blob> blob = blobStore->create();
};
constexpr size_t BigBlobsTest::BLOCKSIZE;
constexpr uint64_t BigBlobsTest::SMALL_BLOB_SIZE;
constexpr uint64_t BigBlobsTest::LARGE_BLOB_SIZE;
TEST_F(BigBlobsTest, Resize) {
//These operations are in one test case and not in many small ones, because it takes quite long to create a >4GB blob.
//Resize to >4GB
blob->resize(LARGE_BLOB_SIZE);
EXPECT_EQ(LARGE_BLOB_SIZE, blob->size());
//Grow while >4GB
blob->resize(LARGE_BLOB_SIZE + 1024);
EXPECT_EQ(LARGE_BLOB_SIZE + 1024, blob->size());
//Shrink while >4GB
blob->resize(LARGE_BLOB_SIZE);
EXPECT_EQ(LARGE_BLOB_SIZE, blob->size());
//Shrink to <4GB
blob->resize(SMALL_BLOB_SIZE);
EXPECT_EQ(SMALL_BLOB_SIZE, blob->size());
//Grow to >4GB
blob->resize(LARGE_BLOB_SIZE);
EXPECT_EQ(LARGE_BLOB_SIZE, blob->size());
//Flush >4GB blob
blob->flush();
//Destruct >4GB blob
auto blockId = blob->blockId();
cpputils::destruct(std::move(blob));
//Load >4GB blob
blob = blobStore->load(blockId).value();
//Remove >4GB blob
blobStore->remove(std::move(blob));
}
TEST_F(BigBlobsTest, GrowByWriting_Crossing4GBBorder) {
Data fixture = DataFixture::generate(2*(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE));
blob->write(fixture.data(), SMALL_BLOB_SIZE, fixture.size());
EXPECT_EQ(LARGE_BLOB_SIZE+(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE), blob->size());
Data loaded(fixture.size());
blob->read(loaded.data(), SMALL_BLOB_SIZE, loaded.size());
EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size()));
}
TEST_F(BigBlobsTest, GrowByWriting_Outside4GBBorder_StartingSizeZero) {
Data fixture = DataFixture::generate(1024);
blob->write(fixture.data(), LARGE_BLOB_SIZE, fixture.size());
EXPECT_EQ(LARGE_BLOB_SIZE+1024, blob->size());
Data loaded(fixture.size());
blob->read(loaded.data(), LARGE_BLOB_SIZE, loaded.size());
EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size()));
}
TEST_F(BigBlobsTest, GrowByWriting_Outside4GBBorder_StartingSizeOutside4GBBorder) {
blob->resize(LARGE_BLOB_SIZE);
Data fixture = DataFixture::generate(1024);
blob->write(fixture.data(), LARGE_BLOB_SIZE+1024, fixture.size());
EXPECT_EQ(LARGE_BLOB_SIZE+2048, blob->size());
Data loaded(fixture.size());
blob->read(loaded.data(), LARGE_BLOB_SIZE+1024, loaded.size());
EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size()));
}
TEST_F(BigBlobsTest, ReadWriteAfterGrown_Crossing4GBBorder) {
blob->resize(LARGE_BLOB_SIZE+(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE)+1024);
Data fixture = DataFixture::generate(2*(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE));
blob->write(fixture.data(), SMALL_BLOB_SIZE, fixture.size());
EXPECT_EQ(LARGE_BLOB_SIZE+(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE)+1024, blob->size());
Data loaded(fixture.size());
blob->read(loaded.data(), SMALL_BLOB_SIZE, loaded.size());
EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size()));
}
TEST_F(BigBlobsTest, ReadWriteAfterGrown_Outside4GBBorder) {
blob->resize(LARGE_BLOB_SIZE+2048);
Data fixture = DataFixture::generate(1024);
blob->write(fixture.data(), LARGE_BLOB_SIZE, fixture.size());
EXPECT_EQ(LARGE_BLOB_SIZE+2048, blob->size());
Data loaded(fixture.size());
blob->read(loaded.data(), LARGE_BLOB_SIZE, loaded.size());
EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size()));
}
//TODO Test Blob::readAll (only on 64bit systems)
|