diff --git a/cloud/blockstore/libs/storage/partition/part_cleanup_logic.cpp b/cloud/blockstore/libs/storage/partition/part_cleanup_logic.cpp index d439b8f27f3..8a71d80964b 100644 --- a/cloud/blockstore/libs/storage/partition/part_cleanup_logic.cpp +++ b/cloud/blockstore/libs/storage/partition/part_cleanup_logic.cpp @@ -96,8 +96,13 @@ TVerifyBlocksMetaResult VerifyMixedBlocksMeta( struct TVisitor final: public IMixedBlocksIndexVisitor { + TPartialBlobId OriginalBlobId; TVector LeakedBlocks; + TVisitor(TPartialBlobId originalBlobId) + : OriginalBlobId(originalBlobId) + {} + bool VisitBlock( ui32 blockIndex, ui64 commitId, @@ -105,17 +110,20 @@ TVerifyBlocksMetaResult VerifyMixedBlocksMeta( ui16 blobOffset, ui8 compactionRangeCount) override { - Y_UNUSED(blobId); Y_UNUSED(blobOffset); Y_UNUSED(compactionRangeCount); + if (blobId != OriginalBlobId) { + return true; + } + LeakedBlocks.emplace_back(blockIndex, commitId, false); return true; } }; - TVisitor visitor; + TVisitor visitor{originalBlobId}; bool ready = db.FindMixedBlocks(visitor, missedBlocks); if (!ready) { return {.Ready = false}; @@ -302,7 +310,8 @@ void ExecuteCleanupTransaction( } } else { // each block has its own commitId - Y_ABORT_UNLESS(mixedBlocks.BlocksSize() == mixedBlocks.CommitIdsSize()); + Y_ABORT_UNLESS( + mixedBlocks.BlocksSize() == mixedBlocks.CommitIdsSize()); for (size_t j = 0; j < mixedBlocks.BlocksSize(); ++j) { ui32 blockIndex = mixedBlocks.GetBlocks(j); ui64 commitId = mixedBlocks.GetCommitIds(j); @@ -342,8 +351,8 @@ void ExecuteCleanupTransaction( ++mergedBlobsCount; if (!IsDeletionMarker(item.BlobId)) { - // Mins for block counts are needed due to some inconsistencies caused by - // NBS-1422 + // Mins for block counts are needed due to some inconsistencies + // caused by NBS-1422 ui64 delta = blockRange.Size() - mergedBlocks.GetSkipped(); state.DecrementMergedBlocksCount( Min(delta, state.GetMergedBlocksCount())); @@ -351,7 +360,7 @@ void ExecuteCleanupTransaction( } LOG_DEBUG( - *actorSystem, + *actorSystem, TBlockStoreComponents::PARTITION, "%s Delete blob: %s", logTitle.GetWithTime().c_str(), diff --git a/cloud/blockstore/libs/storage/partition/part_cleanup_logic_ut.cpp b/cloud/blockstore/libs/storage/partition/part_cleanup_logic_ut.cpp index 2fa1aa14b07..a471993fe68 100644 --- a/cloud/blockstore/libs/storage/partition/part_cleanup_logic_ut.cpp +++ b/cloud/blockstore/libs/storage/partition/part_cleanup_logic_ut.cpp @@ -512,6 +512,38 @@ Y_UNIT_TEST_SUITE(TVerifyRecreatedBlobMetaTest) }); } + Y_UNIT_TEST(ShouldRejectLeakedBlocksInRecreatedMixedMetaOnlyIfBlobIdMatches) + { + TTestExecutor executor; + executor.WriteTx([](TPartitionDatabase db) { db.InitSchema(); }); + + TPartialBlobId blobId; + executor.WriteTx( + [&](TPartitionDatabase db) + { + blobId = executor.MakeBlobId(1); + + auto anotherBlobId = executor.MakeBlobId(1); + db.WriteMixedBlock({anotherBlobId, 1, 0, 0, 0}); + }); + + const auto blobMeta = MakeMixedBlobMeta({0}, {1}); + const auto recreatedBlobMeta = MakeMixedBlobMeta({}, {}); + + executor.ReadTx( + [&](TPartitionDatabase db) + { + const auto result = VerifyRecreatedBlobMeta( + db, + blobId, + blobMeta, + recreatedBlobMeta); + + UNIT_ASSERT(result.Ready); + UNIT_ASSERT(!HasError(result.Error)); + }); + } + Y_UNIT_TEST(ShouldRejectExtraBlocksInRecreatedMixedMeta) { TTestExecutor executor;