Skip to content

Commit 9b3ce7b

Browse files
committed
Avoid redundant eviction disk reads in p23
1 parent 9ec1c10 commit 9b3ce7b

File tree

3 files changed

+149
-2
lines changed

3 files changed

+149
-2
lines changed

src/bucket/BucketSnapshot.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,11 @@ LiveBucketSnapshot::scanForEviction(
314314
// for persistent entries, we need to make sure we evict the
315315
// newest version of the entry, since it will be persisted in
316316
// the hot archive. So we add persistent entries to our DB
317-
// lookup to find the newest version.
318-
if (isPersistentEntry(le.data))
317+
// lookup to find the newest version. Note that there was a
318+
// bug in protocol 23 where this check was not performed.
319+
if (isPersistentEntry(le.data) &&
320+
protocolVersionStartsFrom(ledgerVers,
321+
ProtocolVersion::V_24))
319322
{
320323
keysToSearch.emplace(LedgerEntryKey(le));
321324
}

src/bucket/SearchableBucketList.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ SearchableLiveBucketListSnapshot::scanForEviction(
5151
auto startIter = evictionIter;
5252
auto scanSize = sas.evictionScanSize;
5353

54+
// exit scan early if there's nothing to scan. We still need to call
55+
// `updateStartingEvictionIterator` before exiting early in case the
56+
// underlying bucket has changed, since even when scanning is disabled, it's
57+
// important to maintain a valid iterator.
58+
if (scanSize == 0)
59+
{
60+
return result;
61+
}
62+
5463
for (;;)
5564
{
5665
auto const& b = getBucketFromIter(evictionIter);

src/transactions/test/InvokeHostFunctionTests.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7501,6 +7501,141 @@ TEST_CASE_VERSIONS("do not evict outdated keys", "[archival][soroban]")
75017501
});
75027502
}
75037503

7504+
TEST_CASE("disable eviction scan", "[archival][soroban]")
7505+
{
7506+
// This test verifies that when the eviction scan size is set to 0,
7507+
// no entries are evicted and the eviction iterator does not advance.
7508+
auto cfg = getTestConfig(0);
7509+
cfg.TESTING_SOROBAN_HIGH_LIMIT_OVERRIDE = true;
7510+
cfg.TESTING_MINIMUM_PERSISTENT_ENTRY_LIFETIME = 10;
7511+
cfg.OVERRIDE_EVICTION_PARAMS_FOR_TESTING = true;
7512+
cfg.TESTING_STARTING_EVICTION_SCAN_LEVEL = 1;
7513+
cfg.TESTING_MAX_ENTRIES_TO_ARCHIVE = 1;
7514+
7515+
SorobanTest test(cfg, false);
7516+
ContractStorageTestClient client(test);
7517+
auto& snapshotManager =
7518+
test.getApp().getBucketManager().getBucketSnapshotManager();
7519+
7520+
// WASM and instance should not expire
7521+
test.invokeExtendOp(client.getContract().getKeys(), 10'000);
7522+
7523+
// We'll create two evictable entries, one persistent and one temporary.
7524+
auto persistentKey = client.getContract().getDataKey(
7525+
makeSymbolSCVal("persistent_key"), ContractDataDurability::PERSISTENT);
7526+
client.put("persistent_key", ContractDataDurability::PERSISTENT, 123);
7527+
7528+
auto firstEvictionLedger =
7529+
test.getLCLSeq() +
7530+
MinimumSorobanNetworkConfig::MINIMUM_PERSISTENT_ENTRY_LIFETIME;
7531+
7532+
auto temporaryKey = client.getContract().getDataKey(
7533+
makeSymbolSCVal("temporary_key"), ContractDataDurability::TEMPORARY);
7534+
client.put("temporary_key", ContractDataDurability::TEMPORARY, 456);
7535+
7536+
// modifySorobanNetworkConfig will close 4 ledgers before the upgrade will
7537+
// take affect, so close enough ledgers here such that the persistent entry
7538+
// would be evicted on the ledger immediately following the upgrade.
7539+
for (auto ledgerSeq = test.getLCLSeq() + 1;
7540+
ledgerSeq < firstEvictionLedger - 4; ++ledgerSeq)
7541+
{
7542+
closeLedgerOn(test.getApp(), ledgerSeq, 2, 1, 2016);
7543+
}
7544+
7545+
// Disable eviction scan by setting evictionScanSize to 0
7546+
modifySorobanNetworkConfig(test.getApp(), [](SorobanNetworkConfig& cfg) {
7547+
cfg.mStateArchivalSettings.evictionScanSize = 0;
7548+
});
7549+
7550+
// Capture the eviction iterator after disabling eviction scan
7551+
auto initialIterator = test.getNetworkCfg().evictionIterator();
7552+
7553+
// Close ledgers well beyond when the entries would have been evicted.
7554+
auto closeLedgersUntil = test.getLCLSeq() + 20;
7555+
for (auto ledgerSeq = test.getLCLSeq() + 1; ledgerSeq <= closeLedgersUntil;
7556+
++ledgerSeq)
7557+
{
7558+
closeLedgerOn(test.getApp(), ledgerSeq, 2, 1, 2016);
7559+
7560+
// Verify iterator has not changed
7561+
REQUIRE(initialIterator == test.getNetworkCfg().evictionIterator());
7562+
}
7563+
7564+
auto liveBL = snapshotManager.copySearchableLiveBucketListSnapshot();
7565+
auto hotArchive =
7566+
snapshotManager.copySearchableHotArchiveBucketListSnapshot();
7567+
7568+
auto assertTemp = [&](bool isLive) {
7569+
liveBL = snapshotManager.copySearchableLiveBucketListSnapshot();
7570+
hotArchive =
7571+
snapshotManager.copySearchableHotArchiveBucketListSnapshot();
7572+
auto tempLiveLoad = liveBL->load(temporaryKey);
7573+
REQUIRE(static_cast<bool>(tempLiveLoad) == isLive);
7574+
7575+
// Temp entries are never archived
7576+
REQUIRE(!hotArchive->load(temporaryKey));
7577+
};
7578+
7579+
auto assertPersistent = [&](bool isLive) {
7580+
liveBL = snapshotManager.copySearchableLiveBucketListSnapshot();
7581+
hotArchive =
7582+
snapshotManager.copySearchableHotArchiveBucketListSnapshot();
7583+
7584+
auto persistentLiveLoad = liveBL->load(persistentKey);
7585+
REQUIRE(static_cast<bool>(persistentLiveLoad) == isLive);
7586+
7587+
auto hotArchiveLoad = hotArchive->load(persistentKey);
7588+
REQUIRE(static_cast<bool>(hotArchiveLoad) != isLive);
7589+
};
7590+
7591+
// Verify entries are not evicted
7592+
assertPersistent(true);
7593+
assertTemp(true);
7594+
7595+
// Now, re-enable eviction. maxEntriesToArchive = 1 limits archiving to
7596+
// one entry per ledger. Note that the first eviction will actually occur on
7597+
// the upgrade ledger itself.
7598+
modifySorobanNetworkConfig(test.getApp(), [](SorobanNetworkConfig& cfg) {
7599+
cfg.mStateArchivalSettings.evictionScanSize = 10000;
7600+
cfg.mStateArchivalSettings.maxEntriesToArchive = 1;
7601+
});
7602+
7603+
auto iteratorAfterUpgrade = test.getNetworkCfg().evictionIterator();
7604+
7605+
// Iterator should have advanced from initial position during the upgrade
7606+
// ledger.
7607+
REQUIRE(!(initialIterator == iteratorAfterUpgrade));
7608+
initialIterator = iteratorAfterUpgrade;
7609+
7610+
// Check that exactly one entry has been evicted
7611+
liveBL = snapshotManager.copySearchableLiveBucketListSnapshot();
7612+
hotArchive = snapshotManager.copySearchableHotArchiveBucketListSnapshot();
7613+
7614+
auto persistentLiveLoad = liveBL->load(persistentKey);
7615+
if (persistentLiveLoad)
7616+
{
7617+
// If perstent entry is live, assert that the temp entry is evicted.
7618+
assertPersistent(true);
7619+
assertTemp(false);
7620+
}
7621+
else
7622+
{
7623+
// If perstent entry is evicted, assert that the temp entry is live.
7624+
assertPersistent(false);
7625+
assertTemp(true);
7626+
}
7627+
7628+
// Close one more ledger to evict the last remaining entry.
7629+
closeLedgerOn(test.getApp(), test.getLCLSeq() + 1, 2, 1, 2016);
7630+
7631+
// check that the iterator has advanced
7632+
REQUIRE(!(initialIterator == test.getNetworkCfg().evictionIterator()));
7633+
7634+
// Verify both entries have been evicted
7635+
assertPersistent(false);
7636+
assertTemp(false);
7637+
}
7638+
75047639
TEST_CASE("Module cache cost with restore gaps", "[tx][soroban][modulecache]")
75057640
{
75067641
VirtualClock clock;

0 commit comments

Comments
 (0)