diff options
| author | zousar <[email protected]> | 2025-06-24 16:26:29 -0600 |
|---|---|---|
| committer | zousar <[email protected]> | 2025-06-24 16:26:29 -0600 |
| commit | bb298631ba35a323827dda0b8cd6158e276b5f61 (patch) | |
| tree | 7ba8db91c44ce83f2c518f80f80ab14910eefa6f /src/zenstore/blockstore.cpp | |
| parent | Change to PutResult structure (diff) | |
| parent | 5.6.14 (diff) | |
| download | zen-bb298631ba35a323827dda0b8cd6158e276b5f61.tar.xz zen-bb298631ba35a323827dda0b8cd6158e276b5f61.zip | |
Merge branch 'main' into zs/put-overwrite-policy
Diffstat (limited to 'src/zenstore/blockstore.cpp')
| -rw-r--r-- | src/zenstore/blockstore.cpp | 256 |
1 files changed, 193 insertions, 63 deletions
diff --git a/src/zenstore/blockstore.cpp b/src/zenstore/blockstore.cpp index e976c061d..7b56c64bd 100644 --- a/src/zenstore/blockstore.cpp +++ b/src/zenstore/blockstore.cpp @@ -70,7 +70,7 @@ BlockStoreFile::Open() return false; } ZEN_WARN("Failed to open cas block '{}', reason: '{}', retries left: {}.", m_Path, Ec.message(), RetriesLeft); - Sleep(100 - (3 - RetriesLeft) * 100); // Total 600 ms + Sleep(100 + (3 - RetriesLeft) * 100); // Total 600 ms RetriesLeft--; return true; }); @@ -85,7 +85,7 @@ BlockStoreFile::Create(uint64_t InitialSize) ZEN_TRACE_CPU("BlockStoreFile::Create"); auto ParentPath = m_Path.parent_path(); - if (!std::filesystem::is_directory(ParentPath)) + if (!IsDir(ParentPath)) { CreateDirectories(ParentPath); } @@ -153,14 +153,28 @@ void BlockStoreFile::Write(const void* Data, uint64_t Size, uint64_t FileOffset) { ZEN_TRACE_CPU("BlockStoreFile::Write"); +#if ZEN_BUILD_DEBUG + if (uint64_t CachedFileSize = m_CachedFileSize.load(); CachedFileSize > 0) + { + ZEN_ASSERT(FileOffset + Size <= CachedFileSize); + } +#endif // ZEN_BUILD_DEBUG m_File.Write(Data, Size, FileOffset); } void -BlockStoreFile::Flush() +BlockStoreFile::Flush(uint64_t FinalSize) { ZEN_TRACE_CPU("BlockStoreFile::Flush"); m_File.Flush(); + if (FinalSize != (uint64_t)-1) + { + uint64_t ExpectedSize = 0; + if (!m_CachedFileSize.compare_exchange_weak(ExpectedSize, FinalSize)) + { + ZEN_ASSERT(m_CachedFileSize.load() == FinalSize); + } + } } BasicFile& @@ -215,7 +229,7 @@ IsMetaDataValid(const std::filesystem::path& BlockPath, const std::filesystem::p } if (MetaWriteTime < BlockWriteTime) { - std::filesystem::remove(MetaPath, Ec); + RemoveFile(MetaPath, Ec); return false; } return true; @@ -239,7 +253,7 @@ BlockStoreFile::MetaSize() const if (IsMetaDataValid(m_Path, MetaPath)) { std::error_code DummyEc; - if (uint64_t Size = std::filesystem::file_size(MetaPath, DummyEc); !DummyEc) + if (uint64_t Size = FileSizeFromPath(MetaPath, DummyEc); !DummyEc) { return Size; } @@ -252,7 +266,7 @@ BlockStoreFile::RemoveMeta() { std::filesystem::path MetaPath = GetMetaPath(); std::error_code DummyEc; - std::filesystem::remove(MetaPath, DummyEc); + RemoveFile(MetaPath, DummyEc); } std::filesystem::path @@ -272,6 +286,14 @@ BlockStore::BlockStore() BlockStore::~BlockStore() { + try + { + Close(); + } + catch (const std::exception& Ex) + { + ZEN_ERROR("~BlockStore() failed with: ", Ex.what()); + } } void @@ -291,8 +313,9 @@ BlockStore::Initialize(const std::filesystem::path& BlocksBasePath, uint64_t Max m_MaxBlockSize = MaxBlockSize; m_MaxBlockCount = MaxBlockCount; - if (std::filesystem::is_directory(m_BlocksBasePath)) + if (IsDir(m_BlocksBasePath)) { + std::vector<std::filesystem::path> EmptyBlockFiles; uint32_t NextBlockIndex = 0; std::vector<std::filesystem::path> FoldersToScan; FoldersToScan.push_back(m_BlocksBasePath); @@ -320,6 +343,12 @@ BlockStore::Initialize(const std::filesystem::path& BlocksBasePath, uint64_t Max { continue; } + if (Entry.file_size() == 0) + { + EmptyBlockFiles.push_back(Path); + continue; + } + Ref<BlockStoreFile> BlockFile{new BlockStoreFile(Path)}; BlockFile->Open(); m_TotalSize.fetch_add(BlockFile->TotalSize(), std::memory_order::relaxed); @@ -333,6 +362,17 @@ BlockStore::Initialize(const std::filesystem::path& BlocksBasePath, uint64_t Max } ++FolderOffset; } + + for (const std::filesystem::path& EmptyBlockFile : EmptyBlockFiles) + { + std::error_code Ec; + RemoveFile(EmptyBlockFile, Ec); + if (Ec) + { + ZEN_WARN("Unable to remove empty block file {}. Reason: {}", EmptyBlockFile, Ec.message()); + } + } + m_WriteBlockIndex.store(NextBlockIndex, std::memory_order_release); } else @@ -341,7 +381,7 @@ BlockStore::Initialize(const std::filesystem::path& BlocksBasePath, uint64_t Max } } -void +BlockStore::BlockIndexSet BlockStore::SyncExistingBlocksOnDisk(const BlockIndexSet& KnownBlocks) { ZEN_MEMSCOPE(GetBlocksTag()); @@ -349,8 +389,8 @@ BlockStore::SyncExistingBlocksOnDisk(const BlockIndexSet& KnownBlocks) RwLock::ExclusiveLockScope InsertLock(m_InsertLock); - tsl::robin_set<uint32_t> MissingBlocks; - tsl::robin_set<uint32_t> DeleteBlocks; + BlockIndexSet MissingBlocks; + BlockIndexSet DeleteBlocks; DeleteBlocks.reserve(m_ChunkBlocks.size()); for (auto It : m_ChunkBlocks) { @@ -369,13 +409,6 @@ BlockStore::SyncExistingBlocksOnDisk(const BlockIndexSet& KnownBlocks) MissingBlocks.insert(BlockIndex); } } - for (std::uint32_t BlockIndex : MissingBlocks) - { - std::filesystem::path BlockPath = GetBlockPath(m_BlocksBasePath, BlockIndex); - Ref<BlockStoreFile> NewBlockFile(new BlockStoreFile(BlockPath)); - NewBlockFile->Create(0); - m_ChunkBlocks[BlockIndex] = NewBlockFile; - } for (std::uint32_t BlockIndex : DeleteBlocks) { std::filesystem::path BlockPath = GetBlockPath(m_BlocksBasePath, BlockIndex); @@ -386,6 +419,7 @@ BlockStore::SyncExistingBlocksOnDisk(const BlockIndexSet& KnownBlocks) } m_ChunkBlocks.erase(BlockIndex); } + return MissingBlocks; } BlockStore::BlockEntryCountMap @@ -500,7 +534,7 @@ BlockStore::GetFreeBlockIndex(uint32_t ProbeIndex, RwLock::ExclusiveLockScope&, { OutBlockPath = GetBlockPath(m_BlocksBasePath, ProbeIndex); std::error_code Ec; - bool Exists = std::filesystem::exists(OutBlockPath, Ec); + bool Exists = IsFile(OutBlockPath, Ec); if (Ec) { ZEN_WARN("Failed to probe existence of file '{}' when trying to allocate a new block. Reason: '{}'", @@ -540,7 +574,7 @@ BlockStore::WriteChunk(const void* Data, uint64_t Size, uint32_t Alignment, cons { if (m_WriteBlock) { - m_WriteBlock->Flush(); + m_WriteBlock->Flush(m_CurrentInsertOffset); m_WriteBlock = nullptr; } @@ -578,7 +612,7 @@ BlockStore::WriteChunk(const void* Data, uint64_t Size, uint32_t Alignment, cons } void -BlockStore::WriteChunks(std::span<IoBuffer> Datas, uint32_t Alignment, const WriteChunksCallback& Callback) +BlockStore::WriteChunks(std::span<const IoBuffer> Datas, uint32_t Alignment, const WriteChunksCallback& Callback) { ZEN_MEMSCOPE(GetBlocksTag()); ZEN_TRACE_CPU("BlockStore::WriteChunks"); @@ -674,6 +708,27 @@ BlockStore::WriteChunks(std::span<IoBuffer> Datas, uint32_t Alignment, const Wri } } +bool +BlockStore::HasChunk(const BlockStoreLocation& Location) const +{ + ZEN_TRACE_CPU("BlockStore::TryGetChunk"); + RwLock::SharedLockScope InsertLock(m_InsertLock); + if (auto BlockIt = m_ChunkBlocks.find(Location.BlockIndex); BlockIt != m_ChunkBlocks.end()) + { + if (const Ref<BlockStoreFile>& Block = BlockIt->second; Block) + { + InsertLock.ReleaseNow(); + + const uint64_t BlockSize = Block->FileSize(); + if (Location.Offset + Location.Size <= BlockSize) + { + return true; + } + } + } + return false; +} + IoBuffer BlockStore::TryGetChunk(const BlockStoreLocation& Location) const { @@ -706,7 +761,7 @@ BlockStore::Flush(bool ForceNewBlock) { if (m_WriteBlock) { - m_WriteBlock->Flush(); + m_WriteBlock->Flush(m_CurrentInsertOffset); } m_WriteBlock = nullptr; m_CurrentInsertOffset = 0; @@ -735,6 +790,8 @@ BlockStore::IterateBlock(std::span<const BlockStoreLocation> ChunkLocations, return true; } + ZEN_ASSERT(ChunkLocations.size() >= InChunkIndexes.size()); + if (LargeSizeLimit == 0) { LargeSizeLimit = DefaultIterateSmallChunkWindowSize; @@ -746,7 +803,10 @@ BlockStore::IterateBlock(std::span<const BlockStoreLocation> ChunkLocations, IterateSmallChunkWindowSize = Min((LargeSizeLimit + IterateSmallChunkMaxGapSize) * ChunkLocations.size(), IterateSmallChunkWindowSize); - uint32_t BlockIndex = ChunkLocations[InChunkIndexes[0]].BlockIndex; + const size_t FirstLocationIndex = InChunkIndexes[0]; + ZEN_ASSERT(FirstLocationIndex < ChunkLocations.size()); + + const uint32_t BlockIndex = ChunkLocations[FirstLocationIndex].BlockIndex; std::vector<size_t> ChunkIndexes(InChunkIndexes.begin(), InChunkIndexes.end()); std::sort(ChunkIndexes.begin(), ChunkIndexes.end(), [&](size_t IndexA, size_t IndexB) -> bool { return ChunkLocations[IndexA].Offset < ChunkLocations[IndexB].Offset; @@ -756,8 +816,9 @@ BlockStore::IterateBlock(std::span<const BlockStoreLocation> ChunkLocations, IterateSmallChunkWindowSize, IterateSmallChunkMaxGapSize, &ChunkLocations](uint64_t BlockFileSize, std::span<const size_t> ChunkIndexes, size_t StartIndexOffset) -> size_t { - size_t ChunkCount = 0; - size_t StartIndex = ChunkIndexes[StartIndexOffset]; + size_t ChunkCount = 0; + size_t StartIndex = ChunkIndexes[StartIndexOffset]; + ZEN_ASSERT(StartIndex < ChunkLocations.size()); const BlockStoreLocation& StartLocation = ChunkLocations[StartIndex]; uint64_t StartOffset = StartLocation.Offset; uint64_t LastEnd = StartOffset + StartLocation.Size; @@ -810,22 +871,26 @@ BlockStore::IterateBlock(std::span<const BlockStoreLocation> ChunkLocations, ZEN_ASSERT(BlockFile); InsertLock.ReleaseNow(); + const size_t BlockSize = BlockFile->FileSize(); + IoBuffer ReadBuffer; void* BufferBase = nullptr; size_t LocationIndexOffset = 0; while (LocationIndexOffset < ChunkIndexes.size()) { - size_t ChunkIndex = ChunkIndexes[LocationIndexOffset]; + size_t ChunkIndex = ChunkIndexes[LocationIndexOffset]; + ZEN_ASSERT(ChunkIndex < ChunkLocations.size()); const BlockStoreLocation& FirstLocation = ChunkLocations[ChunkIndex]; + ZEN_ASSERT(FirstLocation.BlockIndex == BlockIndex); - const size_t BlockSize = BlockFile->FileSize(); const size_t RangeCount = GetNextRange(BlockSize, ChunkIndexes, LocationIndexOffset); if (RangeCount > 1) { - size_t LastChunkIndex = ChunkIndexes[LocationIndexOffset + RangeCount - 1]; - const BlockStoreLocation& LastLocation = ChunkLocations[LastChunkIndex]; - uint64_t Size = LastLocation.Offset + LastLocation.Size - FirstLocation.Offset; + size_t LastChunkIndex = ChunkIndexes[LocationIndexOffset + RangeCount - 1]; + ZEN_ASSERT(LastChunkIndex < ChunkLocations.size()); + const BlockStoreLocation& LastLocation = ChunkLocations[LastChunkIndex]; + uint64_t Size = LastLocation.Offset + LastLocation.Size - FirstLocation.Offset; if (ReadBuffer.GetSize() < Size) { ReadBuffer = IoBuffer(Min(Size * 2, IterateSmallChunkWindowSize)); @@ -834,8 +899,9 @@ BlockStore::IterateBlock(std::span<const BlockStoreLocation> ChunkLocations, BlockFile->Read(BufferBase, Size, FirstLocation.Offset); for (size_t RangeIndex = 0; RangeIndex < RangeCount; ++RangeIndex) { - size_t NextChunkIndex = ChunkIndexes[LocationIndexOffset + RangeIndex]; - const BlockStoreLocation& ChunkLocation = ChunkLocations[NextChunkIndex]; + size_t NextChunkIndex = ChunkIndexes[LocationIndexOffset + RangeIndex]; + ZEN_ASSERT(NextChunkIndex < ChunkLocations.size()); + const BlockStoreLocation& ChunkLocation = ChunkLocations[NextChunkIndex]; if (ChunkLocation.Size == 0 || ((ChunkLocation.Offset + ChunkLocation.Size) > BlockSize)) { ZEN_LOG_SCOPE("chunk [{},{}] out of bounds (block #{} file size = {})", @@ -958,6 +1024,7 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, uint32_t NewBlockIndex = 0; MovedChunksArray MovedChunks; + ChunkIndexArray ScrubbedChunks; uint64_t AddedSize = 0; uint64_t RemovedSize = 0; @@ -986,14 +1053,16 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, auto ReportChanges = [&]() -> bool { bool Continue = true; - if (!MovedChunks.empty() || RemovedSize > 0) + if (!MovedChunks.empty() || !ScrubbedChunks.empty() || RemovedSize > 0) { - Continue = ChangeCallback(MovedChunks, RemovedSize > AddedSize ? RemovedSize - AddedSize : 0); + Continue = ChangeCallback(MovedChunks, ScrubbedChunks, RemovedSize > AddedSize ? RemovedSize - AddedSize : 0); DeletedSize += RemovedSize; + m_TotalSize.fetch_add(AddedSize); RemovedSize = 0; AddedSize = 0; MovedCount += MovedChunks.size(); MovedChunks.clear(); + ScrubbedChunks.clear(); } return Continue; }; @@ -1022,6 +1091,7 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, LogPrefix, m_BlocksBasePath, BlockIndex); + ScrubbedChunks.insert(ScrubbedChunks.end(), KeepChunkIndexes.begin(), KeepChunkIndexes.end()); return true; } if (!It->second) @@ -1030,6 +1100,7 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, LogPrefix, m_BlocksBasePath, BlockIndex); + ScrubbedChunks.insert(ScrubbedChunks.end(), KeepChunkIndexes.begin(), KeepChunkIndexes.end()); return true; } OldBlockFile = It->second; @@ -1051,11 +1122,10 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, std::sort(SortedChunkIndexes.begin(), SortedChunkIndexes.end(), [&ChunkLocations](size_t Lhs, size_t Rhs) { return ChunkLocations[Lhs].Offset < ChunkLocations[Rhs].Offset; }); - BasicFileBuffer SourceFileBuffer(OldBlockFile->GetBasicFile(), Min(65536u, OldBlockSize)); + BasicFileBuffer SourceFileBuffer(OldBlockFile->GetBasicFile(), Min(256u * 1024u, OldBlockSize)); - uint64_t WrittenBytesToBlock = 0; - uint64_t MovedFromBlock = 0; - std::vector<uint8_t> Chunk; + uint64_t MovedFromBlock = 0; + std::vector<uint8_t> ChunkBuffer; for (const size_t& ChunkIndex : SortedChunkIndexes) { const BlockStoreLocation ChunkLocation = ChunkLocations[ChunkIndex]; @@ -1070,19 +1140,29 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, ChunkLocation.Size, OldBlockFile->GetPath(), OldBlockSize); + ScrubbedChunks.push_back(ChunkIndex); continue; } - Chunk.resize(ChunkLocation.Size); - SourceFileBuffer.Read(Chunk.data(), Chunk.size(), ChunkLocation.Offset); + MemoryView ChunkView = SourceFileBuffer.MakeView(ChunkLocation.Size, ChunkLocation.Offset); + if (ChunkView.GetSize() != ChunkLocation.Size) + { + ChunkBuffer.resize(ChunkLocation.Size); + SourceFileBuffer.Read(ChunkBuffer.data(), ChunkLocation.Size, ChunkLocation.Offset); + ChunkView = MemoryView(ChunkBuffer.data(), ChunkLocation.Size); + } - if ((WriteOffset + Chunk.size()) > m_MaxBlockSize) + if ((WriteOffset + ChunkView.GetSize()) > m_MaxBlockSize) { - TargetFileBuffer.reset(); + if (TargetFileBuffer) + { + TargetFileBuffer->Flush(); + TargetFileBuffer.reset(); + } if (NewBlockFile) { ZEN_ASSERT_SLOW(NewBlockFile->IsOpen()); - NewBlockFile->Flush(); + NewBlockFile->Flush(WriteOffset); uint64_t NewBlockSize = NewBlockFile->FileSize(); MovedSize += NewBlockSize; NewBlockFile = nullptr; @@ -1161,22 +1241,23 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, NiceBytes(Space.Free + ReclaimedSpace)); } NewBlockFile->Create(m_MaxBlockSize); - NewBlockIndex = NextBlockIndex; - WriteOffset = 0; - AddedSize += WrittenBytesToBlock; - WrittenBytesToBlock = 0; - TargetFileBuffer = std::make_unique<BasicFileWriter>(NewBlockFile->GetBasicFile(), Min(65536u, m_MaxBlockSize)); + NewBlockIndex = NextBlockIndex; + WriteOffset = 0; + TargetFileBuffer = std::make_unique<BasicFileWriter>(NewBlockFile->GetBasicFile(), Min(256u * 1024u, m_MaxBlockSize)); } - TargetFileBuffer->Write(Chunk.data(), ChunkLocation.Size, WriteOffset); + const uint64_t OldWriteOffset = WriteOffset; + WriteOffset = TargetFileBuffer->AlignTo(PayloadAlignment); + + TargetFileBuffer->Write(ChunkView.GetData(), ChunkLocation.Size, WriteOffset); MovedChunks.push_back( {ChunkIndex, {.BlockIndex = NewBlockIndex, .Offset = gsl::narrow<uint32_t>(WriteOffset), .Size = ChunkLocation.Size}}); - WrittenBytesToBlock = WriteOffset + ChunkLocation.Size; + WriteOffset += ChunkLocation.Size; MovedFromBlock += RoundUp(ChunkLocation.Offset + ChunkLocation.Size, PayloadAlignment) - ChunkLocation.Offset; - WriteOffset = RoundUp(WriteOffset + ChunkLocation.Size, PayloadAlignment); + uint64_t WrittenBytes = WriteOffset - OldWriteOffset; + AddedSize += WrittenBytes; } - AddedSize += WrittenBytesToBlock; ZEN_INFO("{}moved {} chunks ({}) from '{}' to new block, freeing {}", LogPrefix, KeepChunkIndexes.size(), @@ -1209,10 +1290,16 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, return true; }); + if (TargetFileBuffer) + { + TargetFileBuffer->Flush(); + TargetFileBuffer.reset(); + } + if (NewBlockFile) { ZEN_ASSERT_SLOW(NewBlockFile->IsOpen()); - NewBlockFile->Flush(); + NewBlockFile->Flush(WriteOffset); uint64_t NewBlockSize = NewBlockFile->FileSize(); MovedSize += NewBlockSize; NewBlockFile = nullptr; @@ -1343,6 +1430,8 @@ TEST_CASE("blockstore.blockfile") CHECK(std::string(Boop) == "boop"); File1.Flush(); CHECK(File1.FileSize() == 10); + File1.Flush(10); + CHECK(File1.FileSize() == 10); } { BlockStoreFile File1(RootDirectory / "1"); @@ -1375,14 +1464,14 @@ TEST_CASE("blockstore.blockfile") BoopChunk = File1.GetChunk(5, 5); } - CHECK(std::filesystem::exists(RootDirectory / "1")); + CHECK(IsFile(RootDirectory / "1")); const char* Data = static_cast<const char*>(DataChunk.GetData()); CHECK(std::string(Data) == "data"); const char* Boop = static_cast<const char*>(BoopChunk.GetData()); CHECK(std::string(Boop) == "boop"); } - CHECK(std::filesystem::exists(RootDirectory / "1")); + CHECK(IsFile(RootDirectory / "1")); { IoBuffer DataChunk; @@ -1401,7 +1490,7 @@ TEST_CASE("blockstore.blockfile") const char* Boop = static_cast<const char*>(BoopChunk.GetData()); CHECK(std::string(Boop) == "boop"); } - CHECK(!std::filesystem::exists(RootDirectory / "1")); + CHECK(!IsFile(RootDirectory / "1")); } namespace blockstore::impl { @@ -1800,7 +1889,7 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray&, uint64_t) { + [&](const BlockStore::MovedChunksArray&, const BlockStore::ChunkIndexArray&, uint64_t) { CHECK(false); return true; }, @@ -1825,9 +1914,10 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray& Moved, uint64_t Removed) { + [&](const BlockStore::MovedChunksArray& Moved, const BlockStore::ChunkIndexArray& Scrubbed, uint64_t Removed) { RemovedSize += Removed; CHECK(Moved.empty()); + CHECK(Scrubbed.empty()); return true; }, []() { return 0; }); @@ -1850,9 +1940,10 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray& Moved, uint64_t Removed) { + [&](const BlockStore::MovedChunksArray& Moved, const BlockStore::ChunkIndexArray& Scrubbed, uint64_t Removed) { RemovedSize += Removed; CHECK(Moved.empty()); + CHECK(Scrubbed.empty()); return true; }, []() { return 0; }); @@ -1860,7 +1951,7 @@ TEST_CASE("blockstore.compact.blocks") CHECK_LE(Store.TotalSize(), 1088); CHECK_GT(Store.TotalSize(), 0); } - SUBCASE("keep everthing") + SUBCASE("keep everything") { Store.Flush(true); @@ -1873,7 +1964,7 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray&, uint64_t) { + [&](const BlockStore::MovedChunksArray&, const BlockStore::ChunkIndexArray&, uint64_t) { CHECK(false); return true; }, @@ -1904,8 +1995,9 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray& Moved, uint64_t Removed) { + [&](const BlockStore::MovedChunksArray& Moved, const BlockStore::ChunkIndexArray& Scrubbed, uint64_t Removed) { CHECK(Moved.empty()); + CHECK(Scrubbed.empty()); RemovedSize += Removed; return true; }, @@ -1939,7 +2031,8 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray& Moved, uint64_t Removed) { + [&](const BlockStore::MovedChunksArray& Moved, const BlockStore::ChunkIndexArray& Scrubbed, uint64_t Removed) { + CHECK(Scrubbed.empty()); for (const auto& Move : Moved) { const BlockStoreLocation& OldLocation = State.GetLocation(Move.first); @@ -2016,7 +2109,8 @@ TEST_CASE("blockstore.compact.blocks") Store.CompactBlocks( State, Alignment, - [&](const BlockStore::MovedChunksArray& Moved, uint64_t Removed) { + [&](const BlockStore::MovedChunksArray& Moved, const BlockStore::ChunkIndexArray& Scrubbed, uint64_t Removed) { + CHECK(Scrubbed.empty()); for (const auto& Move : Moved) { const BlockStoreLocation& OldLocation = State.GetLocation(Move.first); @@ -2051,6 +2145,42 @@ TEST_CASE("blockstore.compact.blocks") } CHECK_LT(Store.TotalSize(), PreSize); } + SUBCASE("scrub") + { + Store.Flush(true); + + BlockStoreCompactState State; + for (const BlockStoreLocation& Location : ChunkLocations) + { + State.IncludeBlock(Location.BlockIndex); + CHECK(State.AddKeepLocation(Location)); + } + State.IncludeBlock(0); + State.IncludeBlock(999); + std::vector<size_t> ExpectedScrubbedIndexes; + ExpectedScrubbedIndexes.push_back(ChunkLocations.size() + 0); + State.AddKeepLocation(BlockStoreLocation{.BlockIndex = 0, .Offset = 2000, .Size = 322}); + ExpectedScrubbedIndexes.push_back(ChunkLocations.size() + 1); + State.AddKeepLocation(BlockStoreLocation{.BlockIndex = 0, .Offset = 10, .Size = 3220}); + ExpectedScrubbedIndexes.push_back(ChunkLocations.size() + 2); + State.AddKeepLocation(BlockStoreLocation{.BlockIndex = 999, .Offset = 2, .Size = 40}); + + std::vector<size_t> ScrubbedIndexes; + + Store.CompactBlocks( + State, + Alignment, + [&](const BlockStore::MovedChunksArray&, const BlockStore::ChunkIndexArray& ScrubbedArray, uint64_t) { + ScrubbedIndexes.insert(ScrubbedIndexes.end(), ScrubbedArray.begin(), ScrubbedArray.end()); + return true; + }, + []() { + CHECK(false); + return 0; + }); + std::sort(ScrubbedIndexes.begin(), ScrubbedIndexes.end()); + CHECK_EQ(ExpectedScrubbedIndexes, ScrubbedIndexes); + } } #endif |