Skip to content

Commit 994087f

Browse files
committed
Live to initentry conversion in lowest level live bucket merge
1 parent 21ce88b commit 994087f

5 files changed

+105
-0
lines changed

src/bucket/BucketOutputIterator.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,30 @@ BucketOutputIterator<BucketT>::put(typename BucketT::EntryT const& e)
157157
mBuf = std::make_unique<typename BucketT::EntryT>();
158158
}
159159

160+
// If BucketT is a live bucket, and this is the lowest level of the
161+
// bucketlist, we also want to convert each LIVEENTRY to an INITENTRY.
162+
// This is because each level of the bucket list contains only one entry
163+
// per key, and per CAP-0020, INITENTRY implies that no entry with
164+
// the same ledger key exists in an older bucket. Therefore, all entries
165+
// of type LIVEENTRY in the lowest level should be of type INITENTRY.
166+
if constexpr (std::is_same_v<BucketT, LiveBucket>)
167+
{
168+
if (!mKeepTombstoneEntries /* lowest level */ &&
169+
e.type() == LIVEENTRY &&
170+
protocolVersionStartsFrom(
171+
mMeta.ledgerVersion,
172+
LiveBucket::
173+
FIRST_PROTOCOL_CONVERTING_BOTTOM_LEVEL_LIVE_TO_INIT))
174+
{
175+
++mMergeCounters.mOutputIteratorLiveToInitRewrites;
176+
++mMergeCounters.mOutputIteratorBufferUpdates;
177+
auto eCopy = e;
178+
eCopy.type(INITENTRY);
179+
*mBuf = eCopy;
180+
return;
181+
}
182+
}
183+
160184
// In any case, replace *mBuf with e.
161185
++mMergeCounters.mOutputIteratorBufferUpdates;
162186
*mBuf = e;

src/bucket/BucketUtils.h

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct MergeCounters
6464
uint64_t mOutputIteratorTombstoneElisions{0};
6565
uint64_t mOutputIteratorBufferUpdates{0};
6666
uint64_t mOutputIteratorActualWrites{0};
67+
uint64_t mOutputIteratorLiveToInitRewrites{0};
6768
MergeCounters& operator+=(MergeCounters const& delta);
6869
bool operator==(MergeCounters const& other) const;
6970
};

src/bucket/LiveBucket.h

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class LiveBucket : public BucketBase,
7373
ProtocolVersion::V_11;
7474
static constexpr ProtocolVersion FIRST_PROTOCOL_SHADOWS_REMOVED =
7575
ProtocolVersion::V_12;
76+
static constexpr ProtocolVersion
77+
FIRST_PROTOCOL_CONVERTING_BOTTOM_LEVEL_LIVE_TO_INIT =
78+
ProtocolVersion::V_23;
7679

7780
static void checkProtocolLegality(BucketEntry const& entry,
7881
uint32_t protocolVersion);

src/bucket/test/BucketListTests.cpp

+73
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,79 @@ TEST_CASE_VERSIONS("hot archive bucket tombstones expire at bottom level",
454454
});
455455
}
456456

457+
TEST_CASE_VERSIONS(
458+
"live bucket entries converted to init enties at bottom level",
459+
"[bucket][bucketlist]")
460+
{
461+
VirtualClock clock;
462+
Config const& cfg = getTestConfig();
463+
464+
for_versions_with_differing_bucket_logic(cfg, [&](Config const& cfg) {
465+
Application::pointer app = createTestApplication(clock, cfg);
466+
LiveBucketList bl;
467+
BucketManager& bm = app->getBucketManager();
468+
auto& mergeTimer = bm.getMergeTimer();
469+
CLOG_INFO(Bucket, "Establishing random bucketlist");
470+
for (uint32_t i = 0; i < LiveBucketList::kNumLevels; ++i)
471+
{
472+
auto& level = bl.getLevel(i);
473+
level.setCurr(LiveBucket::fresh(
474+
bm, getAppLedgerVersion(app), {}, // No init entries.
475+
LedgerTestUtils::generateValidUniqueLedgerEntries(8),
476+
LedgerTestUtils::generateValidLedgerEntryKeysWithExclusions(
477+
{CONFIG_SETTING}, 5),
478+
/*countMergeEvents=*/true, clock.getIOContext(),
479+
/*doFsync=*/true));
480+
level.setSnap(LiveBucket::fresh(
481+
bm, getAppLedgerVersion(app), {},
482+
LedgerTestUtils::generateValidUniqueLedgerEntries(8),
483+
LedgerTestUtils::generateValidLedgerEntryKeysWithExclusions(
484+
{CONFIG_SETTING}, 5),
485+
/*countMergeEvents=*/true, clock.getIOContext(),
486+
/*doFsync=*/true));
487+
}
488+
489+
auto countNonBottomLevelEntries = [&] {
490+
auto size = 0;
491+
for (uint32_t i = 0; i < LiveBucketList::kNumLevels - 1; ++i)
492+
{
493+
auto& level = bl.getLevel(i);
494+
size += countEntries(level.getCurr());
495+
size += countEntries(level.getSnap());
496+
}
497+
return size;
498+
};
499+
500+
auto ledger = 1;
501+
// Close ledgers until all entries have merged into the bottom level
502+
// bucket
503+
while (countNonBottomLevelEntries() != 0)
504+
{
505+
bl.addBatch(*app, ledger, getAppLedgerVersion(app), {}, {}, {});
506+
++ledger;
507+
}
508+
509+
auto bottomCurr = bl.getLevel(LiveBucketList::kNumLevels - 1).getCurr();
510+
EntryCounts<LiveBucket> e(bottomCurr);
511+
512+
if (protocolVersionStartsFrom(
513+
cfg.LEDGER_PROTOCOL_VERSION,
514+
LiveBucket::
515+
FIRST_PROTOCOL_CONVERTING_BOTTOM_LEVEL_LIVE_TO_INIT))
516+
{
517+
// Assert that init entries are converted to live entries
518+
// at the lowest level.
519+
REQUIRE(e.nLive == 0);
520+
REQUIRE(e.nInitOrArchived != 0);
521+
}
522+
else
523+
{
524+
REQUIRE(e.nLive != 0);
525+
REQUIRE(e.nInitOrArchived == 0);
526+
}
527+
});
528+
}
529+
457530
TEST_CASE_VERSIONS("live bucket tombstones expire at bottom level",
458531
"[bucket][bucketlist][tombstones]")
459532
{

src/bucket/test/BucketManagerTests.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,8 @@ class StopAndRestartBucketMergesTest
760760
mMergeCounters.mDeadEntryShadowElisions);
761761
CLOG_INFO(Bucket, "OutputIteratorTombstoneElisions: {}",
762762
mMergeCounters.mOutputIteratorTombstoneElisions);
763+
CLOG_INFO(Bucket, "OutputIteratorLiveToInitConversions: {}",
764+
mMergeCounters.mOutputIteratorLiveToInitRewrites);
763765
CLOG_INFO(Bucket, "OutputIteratorBufferUpdates: {}",
764766
mMergeCounters.mOutputIteratorBufferUpdates);
765767
CLOG_INFO(Bucket, "OutputIteratorActualWrites: {}",
@@ -915,6 +917,8 @@ class StopAndRestartBucketMergesTest
915917

916918
CHECK(mMergeCounters.mOutputIteratorTombstoneElisions ==
917919
other.mMergeCounters.mOutputIteratorTombstoneElisions);
920+
CHECK(mMergeCounters.mOutputIteratorLiveToInitRewrites ==
921+
other.mMergeCounters.mOutputIteratorLiveToInitRewrites);
918922
CHECK(mMergeCounters.mOutputIteratorBufferUpdates ==
919923
other.mMergeCounters.mOutputIteratorBufferUpdates);
920924
CHECK(mMergeCounters.mOutputIteratorActualWrites ==

0 commit comments

Comments
 (0)