Skip to content

Commit d6f2546

Browse files
authored
Parallelize in-memory state update with bucket list operations. (stellar#5284)
# Description 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 there is no need for synchronization. # Checklist - [ ] Reviewed the [contributing](https://github.com/stellar/stellar-core/blob/master/CONTRIBUTING.md#submitting-changes) document - [ ] Rebased on top of master (no merge commits) - [ ] Ran `clang-format` v8.0.0 (via `make format` or the Visual Studio extension) - [ ] Compiles - [ ] Ran all tests - [ ] If change impacts performance, include supporting evidence per the [performance document](https://github.com/stellar/stellar-core/blob/master/performance-eval/performance-eval.md)
2 parents 6e768de + 5c9ace9 commit d6f2546

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);
@@ -2988,25 +2990,29 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
29882990
// `ledgerApplied` protects this call with a mutex
29892991
std::vector<LedgerEntry> initEntries, liveEntries;
29902992
std::vector<LedgerKey> deadEntries;
2993+
2994+
EvictedStateVectors evictedState;
2995+
std::vector<LedgerKey> restoredHotArchiveKeys;
2996+
std::future<void> hotArchiveBatchFuture;
2997+
29912998
// Any V20 features must be behind initialLedgerVers check, see comment
29922999
// in LedgerManagerImpl::ledgerApplied
29933000
if (protocolVersionStartsFrom(initialLedgerVers, SOROBAN_PROTOCOL_VERSION))
29943001
{
3002+
bool hotArchiveBatchedAdded = false;
3003+
29953004
// In `getAllTTLKeysWithoutSealing` it is important not to seal ltx,
29963005
// because it is still being modified by the eviction flow.
29973006
// `getAllTTLKeysWithoutSealing` must be called at the right time
29983007
// _after_ all operations have been applied, but _before_ evictions.
29993008
auto sorobanConfig = SorobanNetworkConfig::loadFromLedger(ltx);
3000-
auto evictedState =
3001-
mApp.getBucketManager().resolveBackgroundEvictionScan(
3002-
lclApplyView, ltx, ltx.getAllKeysWithoutSealing());
3009+
evictedState = mApp.getBucketManager().resolveBackgroundEvictionScan(
3010+
lclApplyView, ltx, ltx.getAllKeysWithoutSealing());
30033011

30043012
if (protocolVersionStartsFrom(
30053013
initialLedgerVers,
30063014
LiveBucket::FIRST_PROTOCOL_SUPPORTING_PERSISTENT_EVICTION))
30073015
{
3008-
std::vector<LedgerKey> restoredHotArchiveKeys;
3009-
30103016
auto const& restoredHotArchiveKeyMap =
30113017
ltx.getRestoredHotArchiveKeys();
30123018
for (auto const& [key, entry] : restoredHotArchiveKeyMap)
@@ -3033,12 +3039,10 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30333039
p23_hot_archive_bug::addHotArchiveBatchWithP23HotArchiveFix(
30343040
ltx, mApp, lclApplyView, lh, evictedState.archivedEntries,
30353041
restoredHotArchiveKeys);
3042+
hotArchiveBatchedAdded = true;
30363043
}
30373044
else
30383045
{
3039-
mApp.getBucketManager().addHotArchiveBatch(
3040-
mApp, lh, evictedState.archivedEntries,
3041-
restoredHotArchiveKeys);
30423046
// Validate evicted entries against Protocol 23 corruption
30433047
// data if configured
30443048
if (mApp.getProtocol23CorruptionDataVerifier())
@@ -3050,6 +3054,12 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30503054
}
30513055
}
30523056
}
3057+
else
3058+
{
3059+
// There is no hot archive support yet, so just mark the batch as
3060+
// already 'added' to avoid trying to add it later.
3061+
hotArchiveBatchedAdded = true;
3062+
}
30533063

30543064
if (ledgerCloseMeta)
30553065
{
@@ -3066,6 +3076,19 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30663076
// important to maintain as a protocol implementation detail.
30673077
SorobanNetworkConfig::maybeSnapshotSorobanStateSize(
30683078
lh.ledgerSeq, mApplyState.getSorobanInMemoryStateSize(), ltx, mApp);
3079+
3080+
if (!hotArchiveBatchedAdded)
3081+
{
3082+
hotArchiveBatchFuture =
3083+
std::async(std::launch::async,
3084+
[this, lh, evictedState = std::move(evictedState),
3085+
restoredHotArchiveKeys =
3086+
std::move(restoredHotArchiveKeys)]() mutable {
3087+
mApp.getBucketManager().addHotArchiveBatch(
3088+
mApp, lh, evictedState.archivedEntries,
3089+
restoredHotArchiveKeys);
3090+
});
3091+
}
30693092
}
30703093
std::optional<SorobanNetworkConfig> finalSorobanConfig;
30713094
// NB: We're looking for the most up-to-date config at this point, so we
@@ -3078,12 +3101,27 @@ LedgerManagerImpl::finalizeLedgerTxnChanges(
30783101
}
30793102
// NB: getAllEntries seals the ltx.
30803103
ltx.getAllEntries(initEntries, liveEntries, deadEntries);
3104+
3105+
// Launch async task to update in-memory Soroban state. This is independent
3106+
// from both addHotArchiveBatch and addLiveBatch, so all can run in
3107+
// parallel.
3108+
auto inMemoryStateUpdateFuture = std::async(
3109+
std::launch::async, [this, &initEntries, &liveEntries, &deadEntries, lh,
3110+
&finalSorobanConfig]() {
3111+
mApplyState.updateInMemorySorobanState(
3112+
initEntries, liveEntries, deadEntries, lh, finalSorobanConfig);
3113+
});
3114+
30813115
mApplyState.addAnyContractsToModuleCache(lh.ledgerVersion, initEntries);
30823116
mApplyState.addAnyContractsToModuleCache(lh.ledgerVersion, liveEntries);
30833117
mApp.getBucketManager().addLiveBatch(mApp, lh, initEntries, liveEntries,
30843118
deadEntries);
3085-
mApplyState.updateInMemorySorobanState(initEntries, liveEntries,
3086-
deadEntries, lh, finalSorobanConfig);
3119+
// Wait for all async operations to complete before returning.
3120+
if (hotArchiveBatchFuture.valid())
3121+
{
3122+
hotArchiveBatchFuture.get();
3123+
}
3124+
inMemoryStateUpdateFuture.get();
30873125
return finalSorobanConfig;
30883126
}
30893127

0 commit comments

Comments
 (0)