Skip to content

Commit 5c9ace9

Browse files
committed
Parallelize in-memory state update with bucket list operations.
During ledger close, run addHotArchiveBatch, addLiveBatch and updateInMemorySorobanState concurrently. They modify independent data structures and so need no synchronization.
1 parent 1c8439f commit 5c9ace9

2 files changed

Lines changed: 50 additions & 12 deletions

File tree

Builds/VisualStudio/build_rust.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ setlocal EnableDelayedExpansion
3333

3434
rem -- range to use for stable host envs
3535
set MIN_P=21
36-
set MAX_P=26
36+
set MAX_P=27
3737
rem -- version of the latest WIP protocol
3838
set LATEST_P=27
3939
rem -- source host used to build the latest protocol. When this differs from

src/ledger/LedgerManagerImpl.cpp

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676

7777
#include "LedgerManagerImpl.h"
7878
#include <chrono>
79+
#include <future>
7980
#include <memory>
8081
#include <optional>
8182
#include <regex>
@@ -318,7 +319,8 @@ LedgerManagerImpl::ApplyState::updateInMemorySorobanState(
318319
std::vector<LedgerKey> const& deadEntries, LedgerHeader const& lh,
319320
std::optional<SorobanNetworkConfig const> const& sorobanConfig)
320321
{
321-
assertWritablePhase();
322+
releaseAssert(mPhase == Phase::SETTING_UP_STATE ||
323+
mPhase == Phase::COMMITTING);
322324
mInMemorySorobanState.updateState(initEntries, liveEntries, deadEntries, lh,
323325
sorobanConfig,
324326
getMetrics().mSorobanMetrics);
@@ -2986,25 +2988,29 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
29862988
// `ledgerApplied` protects this call with a mutex
29872989
std::vector<LedgerEntry> initEntries, liveEntries;
29882990
std::vector<LedgerKey> deadEntries;
2991+
2992+
EvictedStateVectors evictedState;
2993+
std::vector<LedgerKey> restoredHotArchiveKeys;
2994+
std::future<void> hotArchiveBatchFuture;
2995+
29892996
// Any V20 features must be behind initialLedgerVers check, see comment
29902997
// in LedgerManagerImpl::ledgerApplied
29912998
if (protocolVersionStartsFrom(initialLedgerVers, SOROBAN_PROTOCOL_VERSION))
29922999
{
3000+
bool hotArchiveBatchedAdded = false;
3001+
29933002
// In `getAllTTLKeysWithoutSealing` it is important not to seal ltx,
29943003
// because it is still being modified by the eviction flow.
29953004
// `getAllTTLKeysWithoutSealing` must be called at the right time
29963005
// _after_ all operations have been applied, but _before_ evictions.
29973006
auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(ltx);
2998-
auto evictedState =
2999-
mApp.getBucketManager().resolveBackgroundEvictionScan(
3000-
lclApplyView, ltx, ltx.getAllKeysWithoutSealing());
3007+
evictedState = mApp.getBucketManager().resolveBackgroundEvictionScan(
3008+
lclApplyView, ltx, ltx.getAllKeysWithoutSealing());
30013009

30023010
if (protocolVersionStartsFrom(
30033011
initialLedgerVers,
30043012
LiveBucket::FIRST_PROTOCOL_SUPPORTING_PERSISTENT_EVICTION))
30053013
{
3006-
std::vector<LedgerKey> restoredHotArchiveKeys;
3007-
30083014
auto const& restoredHotArchiveKeyMap =
30093015
ltx.getRestoredHotArchiveKeys();
30103016
for (auto const& [key, entry] : restoredHotArchiveKeyMap)
@@ -3031,12 +3037,10 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30313037
p23_hot_archive_bug::addHotArchiveBatchWithP23HotArchiveFix(
30323038
ltx, mApp, lclApplyView, lh, evictedState.archivedEntries,
30333039
restoredHotArchiveKeys);
3040+
hotArchiveBatchedAdded = true;
30343041
}
30353042
else
30363043
{
3037-
mApp.getBucketManager().addHotArchiveBatch(
3038-
mApp, lh, evictedState.archivedEntries,
3039-
restoredHotArchiveKeys);
30403044
// Validate evicted entries against Protocol 23 corruption
30413045
// data if configured
30423046
if (mApp.getProtocol23CorruptionDataVerifier())
@@ -3048,6 +3052,12 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30483052
}
30493053
}
30503054
}
3055+
else
3056+
{
3057+
// There is no hot archive support yet, so just mark the batch as
3058+
// already 'added' to avoid trying to add it later.
3059+
hotArchiveBatchedAdded = true;
3060+
}
30513061

30523062
if (ledgerCloseMeta)
30533063
{
@@ -3064,6 +3074,19 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30643074
// important to maintain as a protocol implementation detail.
30653075
SorobanNetworkConfig::maybeSnapshotSorobanStateSize(
30663076
lh.ledgerSeq, mApplyState.getSorobanInMemoryStateSize(), ltx, mApp);
3077+
3078+
if (!hotArchiveBatchedAdded)
3079+
{
3080+
hotArchiveBatchFuture =
3081+
std::async(std::launch::async,
3082+
[this, lh, evictedState = std::move(evictedState),
3083+
restoredHotArchiveKeys =
3084+
std::move(restoredHotArchiveKeys)]() mutable {
3085+
mApp.getBucketManager().addHotArchiveBatch(
3086+
mApp, lh, evictedState.archivedEntries,
3087+
restoredHotArchiveKeys);
3088+
});
3089+
}
30673090
}
30683091
std::optional<SorobanNetworkConfig> finalSorobanConfig;
30693092
// NB: We're looking for the most up-to-date config at this point, so we
@@ -3076,12 +3099,27 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30763099
}
30773100
// NB: getAllEntries seals the ltx.
30783101
ltx.getAllEntries(initEntries, liveEntries, deadEntries);
3102+
3103+
// Launch async task to update in-memory Soroban state. This is independent
3104+
// from both addHotArchiveBatch and addLiveBatch, so all can run in
3105+
// parallel.
3106+
auto inMemoryStateUpdateFuture = std::async(
3107+
std::launch::async, [this, &initEntries, &liveEntries, &deadEntries, lh,
3108+
&finalSorobanConfig]() {
3109+
mApplyState.updateInMemorySorobanState(
3110+
initEntries, liveEntries, deadEntries, lh, finalSorobanConfig);
3111+
});
3112+
30793113
mApplyState.addAnyContractsToModuleCache(lh.ledgerVersion, initEntries);
30803114
mApplyState.addAnyContractsToModuleCache(lh.ledgerVersion, liveEntries);
30813115
mApp.getBucketManager().addLiveBatch(mApp, lh, initEntries, liveEntries,
30823116
deadEntries);
3083-
mApplyState.updateInMemorySorobanState(initEntries, liveEntries,
3084-
deadEntries, lh, finalSorobanConfig);
3117+
// Wait for all async operations to complete before returning.
3118+
if (hotArchiveBatchFuture.valid())
3119+
{
3120+
hotArchiveBatchFuture.get();
3121+
}
3122+
inMemoryStateUpdateFuture.get();
30853123
return finalSorobanConfig;
30863124
}
30873125

0 commit comments

Comments
 (0)