Skip to content

Commit 9ed2f84

Browse files
committed
Populate Soroban in-memory state in a background thread
1 parent e42dcc3 commit 9ed2f84

File tree

7 files changed

+105
-18
lines changed

7 files changed

+105
-18
lines changed

src/bucket/BucketSnapshot.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,11 @@ LiveBucketSnapshot::scanForEntriesOfType(
363363
return Loop::INCOMPLETE;
364364
}
365365

366-
auto& stream = getStream();
366+
// We open up a stream locally here because otherwise, we might race with
367+
// other methods accessing the stream while populating in memory soroban
368+
// state
369+
XDRInputFileStream stream;
370+
stream.open(mBucket->getFilename().string());
367371
stream.seek(range->first);
368372

369373
BucketEntry be;

src/catchup/ApplyLedgerWork.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ BasicWork::State
2323
ApplyLedgerWork::onRun()
2424
{
2525
ZoneScoped;
26+
if (mApp.getLedgerManager().isBooting())
27+
{
28+
mApp.postOnBackgroundThread(
29+
[this] {
30+
mApp.getLedgerManager().waitForBoot();
31+
wakeUp();
32+
},
33+
"Wait for LedgerManager to finish booting");
34+
return BasicWork::State::WORK_WAITING;
35+
}
2636
mApp.getLedgerManager().applyLedger(mLedgerCloseData,
2737
/* externalize */ false);
2838
return BasicWork::State::WORK_SUCCESS;

src/catchup/LedgerApplyManagerImpl.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,11 @@ LedgerApplyManagerImpl::processLedger(LedgerCloseData const& ledgerData,
153153
// 2. LedgerApplyManager received ledger that should be immediately applied
154154
// by LedgerManager: check if we have any sequential ledgers. If so, attempt
155155
// to apply mSyncingLedgers and possibly get back in sync
156-
if (!mCatchupWork && lastReceivedLedgerSeq == *mLastQueuedToApply + 1)
156+
if (((!mCatchupWork && lastReceivedLedgerSeq == *mLastQueuedToApply + 1) ||
157+
mTMP_TODO) &&
158+
!mApp.getLedgerManager().isBooting())
157159
{
160+
mTMP_TODO = false;
158161
tryApplySyncingLedgers();
159162
return ProcessLedgerResult::PROCESSED_ALL_LEDGERS_SEQUENTIALLY;
160163
}
@@ -173,6 +176,13 @@ LedgerApplyManagerImpl::processLedger(LedgerCloseData const& ledgerData,
173176
"Close of ledger {} buffered. mSyncingLedgers has {} ledgers",
174177
ledgerData.getLedgerSeq(), mSyncingLedgers.size());
175178

179+
if (mApp.getLedgerManager().isBooting())
180+
{
181+
mTMP_TODO = true;
182+
return ProcessLedgerResult::WAIT_TO_APPLY_BUFFERED_OR_CATCHUP;
183+
}
184+
mTMP_TODO = false;
185+
176186
// First: if CatchupWork has started, just buffer and return early.
177187
if (mCatchupWork)
178188
{
@@ -513,7 +523,7 @@ LedgerApplyManagerImpl::tryApplySyncingLedgers()
513523
// If we have too many ledgers queued to apply, just stop scheduling
514524
// more and let the node gracefully go into catchup.
515525
releaseAssert(mLastQueuedToApply >= lcl);
516-
if (nextToApply - lcl >= MAX_EXTERNALIZE_LEDGER_APPLY_DRIFT)
526+
if (nextToApply - lcl >= MAX_EXTERNALIZE_LEDGER_APPLY_DRIFT && false)
517527
{
518528
CLOG_INFO(History,
519529
"Next ledger to apply is {}, but LCL {} is too far "

src/catchup/LedgerApplyManagerImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class LedgerApplyManagerImpl : public LedgerApplyManager
2929

3030
Application& mApp;
3131
std::shared_ptr<CatchupWork> mCatchupWork;
32+
bool mTMP_TODO{false};
3233

3334
// key is ledgerSeq
3435
// mSyncingLedgers has the following invariants:

src/ledger/LedgerManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ class LedgerManager
198198
virtual void beginApply() = 0;
199199
virtual State getState() const = 0;
200200
virtual std::string getStateHuman() const = 0;
201+
virtual bool isBooting() const = 0;
202+
virtual void waitForBoot() = 0;
201203

202204
bool
203205
isSynced() const

src/ledger/LedgerManagerImpl.cpp

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,23 @@ LedgerManagerImpl::getStateHuman() const
388388
return std::string(stateStrings[getState()]);
389389
}
390390

391+
bool
392+
LedgerManagerImpl::isBooting() const
393+
{
394+
std::lock_guard guard{mBootingLock};
395+
return mIsBooting;
396+
}
397+
398+
void
399+
LedgerManagerImpl::waitForBoot()
400+
{
401+
std::unique_lock<std::mutex> lk{mBootingLock};
402+
if (mIsBooting)
403+
{
404+
mBootingCV.wait(lk, [this] { return !mIsBooting; });
405+
}
406+
}
407+
391408
LedgerHeader
392409
LedgerManager::genesisLedger()
393410
{
@@ -526,7 +543,6 @@ LedgerManagerImpl::loadLastKnownLedgerInternal(bool skipBuildingFullState)
526543

527544
// Step 2. Restore LedgerHeader from DB based on the ledger hash derived
528545
// earlier, or verify we're at genesis if in no-history mode
529-
std::optional<LedgerHeader> latestLedgerHeader;
530546
auto currentLedger =
531547
LedgerHeaderUtils::loadByHash(getDatabase(), lastLedgerHash);
532548
if (!currentLedger)
@@ -543,9 +559,7 @@ LedgerManagerImpl::loadLastKnownLedgerInternal(bool skipBuildingFullState)
543559
CLOG_INFO(Ledger, "Loaded LCL header from database: {}",
544560
ledgerAbbrev(*currentLedger));
545561
setLedgerTxnHeader(*currentLedger, mApp);
546-
latestLedgerHeader = *currentLedger;
547-
548-
releaseAssert(latestLedgerHeader.has_value());
562+
LedgerHeader latestLedgerHeader = *currentLedger;
549563

550564
auto missing = mApp.getBucketManager().checkForMissingBucketsFiles(has);
551565
auto pubmissing =
@@ -562,12 +576,12 @@ LedgerManagerImpl::loadLastKnownLedgerInternal(bool skipBuildingFullState)
562576
// (standalone offline commands, in-memory setup) do not need to
563577
// spin up expensive merge processes.
564578
auto assumeStateWork = mApp.getWorkScheduler().executeWork<AssumeStateWork>(
565-
has, latestLedgerHeader->ledgerVersion,
579+
has, latestLedgerHeader.ledgerVersion,
566580
/* restartMerges */ !skipBuildingFullState);
567581
if (assumeStateWork->getState() == BasicWork::State::WORK_SUCCESS)
568582
{
569583
CLOG_INFO(Ledger, "Assumed bucket-state for LCL: {}",
570-
ledgerAbbrev(*latestLedgerHeader));
584+
ledgerAbbrev(latestLedgerHeader));
571585
}
572586
else
573587
{
@@ -577,12 +591,12 @@ LedgerManagerImpl::loadLastKnownLedgerInternal(bool skipBuildingFullState)
577591

578592
// Step 4. Restore LedgerManager's LCL state
579593
advanceLastClosedLedgerState(
580-
advanceBucketListSnapshotAndMakeLedgerState(*latestLedgerHeader, has));
594+
advanceBucketListSnapshotAndMakeLedgerState(latestLedgerHeader, has));
581595

582596
// Maybe truncate checkpoint files if we're restarting after a crash
583597
// in applyLedger (in which case any modifications to the ledger state have
584598
// been rolled back)
585-
mApp.getHistoryManager().restoreCheckpoint(latestLedgerHeader->ledgerSeq);
599+
mApp.getHistoryManager().restoreCheckpoint(latestLedgerHeader.ledgerSeq);
586600

587601
// Prime module cache with LCL state, not apply-state. This is acceptable
588602
// here because we just started and there is no apply-state yet and no apply
@@ -591,11 +605,30 @@ LedgerManagerImpl::loadLastKnownLedgerInternal(bool skipBuildingFullState)
591605
if (!skipBuildingFullState)
592606
{
593607
mApplyState.compileAllContractsInLedger(
594-
snapshot, latestLedgerHeader->ledgerVersion);
595-
mApplyState.populateInMemorySorobanState(
596-
snapshot, latestLedgerHeader->ledgerVersion);
608+
snapshot, latestLedgerHeader.ledgerVersion);
609+
mBootingLock.lock();
610+
mIsBooting = true;
611+
mBootingLock.unlock();
612+
mApp.postOnBackgroundThread(
613+
[=] {
614+
mApplyState.populateInMemorySorobanState(
615+
snapshot, latestLedgerHeader.ledgerVersion);
616+
mApp.postOnMainThread(
617+
[=] {
618+
mBootingLock.lock();
619+
mIsBooting = false;
620+
mBootingLock.unlock();
621+
mBootingCV.notify_all();
622+
mApplyState.markEndOfSetupPhase();
623+
},
624+
"Finish populating in-memory Soroban state");
625+
},
626+
"Populate in-memory Soroban state");
627+
}
628+
else
629+
{
630+
mApplyState.markEndOfSetupPhase();
597631
}
598-
mApplyState.markEndOfSetupPhase();
599632
}
600633

601634
void
@@ -979,7 +1012,9 @@ void
9791012
LedgerManagerImpl::ApplyState::populateInMemorySorobanState(
9801013
SearchableSnapshotConstPtr snap, uint32_t ledgerVersion)
9811014
{
982-
assertSetupPhase();
1015+
// We don't use assertSetupPhase() because we don't expect the thread
1016+
// invariant to hold
1017+
releaseAssert(mPhase == Phase::SETTING_UP_STATE);
9831018
mInMemorySorobanState.initializeStateFromSnapshot(snap, ledgerVersion);
9841019
}
9851020

@@ -1859,9 +1894,29 @@ LedgerManagerImpl::setLastClosedLedger(
18591894
// a snapshot _from_ the LCL state.
18601895
auto const& snapshot = mLastClosedLedgerState->getBucketSnapshot();
18611896
mApplyState.compileAllContractsInLedger(snapshot, ledgerVersion);
1862-
mApplyState.populateInMemorySorobanState(snapshot, ledgerVersion);
1897+
mBootingLock.lock();
1898+
mIsBooting = true;
1899+
mBootingLock.unlock();
1900+
mApp.postOnBackgroundThread(
1901+
[=] {
1902+
mApplyState.populateInMemorySorobanState(snapshot,
1903+
ledgerVersion);
1904+
mApp.postOnMainThread(
1905+
[=] {
1906+
mBootingLock.lock();
1907+
mIsBooting = false;
1908+
mBootingLock.unlock();
1909+
mBootingCV.notify_all();
1910+
mApplyState.markEndOfSetupPhase();
1911+
},
1912+
"Finish populating in-memory Soroban state");
1913+
},
1914+
"Populate in-memory Soroban state");
1915+
}
1916+
else
1917+
{
1918+
mApplyState.markEndOfSetupPhase();
18631919
}
1864-
mApplyState.markEndOfSetupPhase();
18651920
}
18661921

18671922
void

src/ledger/LedgerManagerImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,9 @@ class LedgerManagerImpl : public LedgerManager
409409
Config const& config);
410410

411411
State mState;
412+
bool mIsBooting{false};
413+
std::condition_variable mBootingCV;
414+
std::mutex mutable mBootingLock;
412415

413416
#ifdef BUILD_TESTS
414417
std::vector<TransactionMetaFrame> mLastLedgerTxMeta;
@@ -479,6 +482,8 @@ class LedgerManagerImpl : public LedgerManager
479482
void beginApply() override;
480483
State getState() const override;
481484
std::string getStateHuman() const override;
485+
bool isBooting() const override;
486+
void waitForBoot() override;
482487

483488
void valueExternalized(LedgerCloseData const& ledgerData,
484489
bool isLatestSlot) override;

0 commit comments

Comments
 (0)