2015-12-11 00:18:17 +01:00
|
|
|
#include <gtest/gtest.h>
|
2016-02-11 15:19:58 +01:00
|
|
|
#include <blockstore/implementations/compressing/CompressingBlockStore.h>
|
|
|
|
#include <blockstore/implementations/compressing/compressors/RunLengthEncoding.h>
|
2017-07-21 04:32:42 +02:00
|
|
|
#include <blockstore/implementations/inmemory/InMemoryBlockStore2.h>
|
|
|
|
#include <blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h>
|
2016-02-11 15:19:58 +01:00
|
|
|
#include <cpp-utils/data/DataFixture.h>
|
|
|
|
#include <cpp-utils/data/Data.h>
|
2023-07-08 23:48:59 +02:00
|
|
|
|
2016-02-11 15:19:58 +01:00
|
|
|
#include "blobstore/implementations/onblocks/BlobOnBlocks.h"
|
2023-07-08 23:48:59 +02:00
|
|
|
#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h"
|
|
|
|
#include <cstddef>
|
2015-12-11 00:18:17 +01:00
|
|
|
|
|
|
|
using namespace blobstore;
|
|
|
|
using namespace blobstore::onblocks;
|
|
|
|
using cpputils::unique_ref;
|
|
|
|
using cpputils::make_unique_ref;
|
|
|
|
using cpputils::DataFixture;
|
|
|
|
using cpputils::Data;
|
2017-07-21 04:32:42 +02:00
|
|
|
using blockstore::inmemory::InMemoryBlockStore2;
|
|
|
|
using blockstore::lowtohighlevel::LowToHighLevelBlockStore;
|
2015-12-14 17:18:12 +01:00
|
|
|
using blockstore::compressing::CompressingBlockStore;
|
|
|
|
using blockstore::compressing::RunLengthEncoding;
|
2015-12-11 00:18:17 +01:00
|
|
|
|
|
|
|
// 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;
|
2018-05-04 06:32:21 +02:00
|
|
|
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)
|
2015-12-11 00:18:17 +01:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2017-07-21 04:32:42 +02:00
|
|
|
unique_ref<BlobStore> blobStore = make_unique_ref<BlobStoreOnBlocks>(make_unique_ref<CompressingBlockStore<RunLengthEncoding>>(make_unique_ref<LowToHighLevelBlockStore>(make_unique_ref<InMemoryBlockStore2>())), BLOCKSIZE);
|
2015-12-11 00:18:17 +01:00
|
|
|
unique_ref<Blob> blob = blobStore->create();
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr size_t BigBlobsTest::BLOCKSIZE;
|
2015-12-13 13:30:05 +01:00
|
|
|
constexpr uint64_t BigBlobsTest::SMALL_BLOB_SIZE;
|
|
|
|
constexpr uint64_t BigBlobsTest::LARGE_BLOB_SIZE;
|
2015-12-11 00:18:17 +01:00
|
|
|
|
2015-12-14 18:19:40 +01:00
|
|
|
TEST_F(BigBlobsTest, Resize) {
|
2015-12-11 00:18:17 +01:00
|
|
|
//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
|
2017-09-17 03:07:27 +02:00
|
|
|
auto blockId = blob->blockId();
|
2015-12-11 00:18:17 +01:00
|
|
|
cpputils::destruct(std::move(blob));
|
|
|
|
|
|
|
|
//Load >4GB blob
|
2017-09-17 03:07:27 +02:00
|
|
|
blob = blobStore->load(blockId).value();
|
2015-12-11 00:18:17 +01:00
|
|
|
|
|
|
|
//Remove >4GB blob
|
|
|
|
blobStore->remove(std::move(blob));
|
|
|
|
}
|
|
|
|
|
2015-12-14 18:19:40 +01:00
|
|
|
TEST_F(BigBlobsTest, GrowByWriting_Crossing4GBBorder) {
|
2015-12-11 00:18:17 +01:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2015-12-14 18:19:40 +01:00
|
|
|
TEST_F(BigBlobsTest, GrowByWriting_Outside4GBBorder_StartingSizeZero) {
|
2015-12-11 00:18:17 +01:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2015-12-14 18:19:40 +01:00
|
|
|
TEST_F(BigBlobsTest, GrowByWriting_Outside4GBBorder_StartingSizeOutside4GBBorder) {
|
2015-12-11 00:18:17 +01:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2015-12-14 18:19:40 +01:00
|
|
|
TEST_F(BigBlobsTest, ReadWriteAfterGrown_Crossing4GBBorder) {
|
2015-12-11 00:18:17 +01:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
2015-12-14 18:19:40 +01:00
|
|
|
TEST_F(BigBlobsTest, ReadWriteAfterGrown_Outside4GBBorder) {
|
2015-12-11 00:18:17 +01:00
|
|
|
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)
|