@@ -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+
391408LedgerHeader
392409LedgerManager::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
601634void
@@ -979,7 +1012,9 @@ void
9791012LedgerManagerImpl::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
18671922void
0 commit comments