Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Harden ledger state invariance: move LCL header, HAS and Soroban config to read-only BucketList snapshot #4597

Closed
wants to merge 8 commits into from
29 changes: 18 additions & 11 deletions src/bucket/BucketListSnapshotBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ namespace stellar
{
template <class BucketT>
BucketListSnapshot<BucketT>::BucketListSnapshot(
BucketListBase<BucketT> const& bl, LedgerHeader header)
: mHeader(std::move(header))
BucketListBase<BucketT> const& bl, LastClosedLedger lastClosed)
: mLastClosedLedger(std::move(lastClosed))
{
releaseAssert(threadIsMain());

Expand All @@ -31,7 +31,7 @@ BucketListSnapshot<BucketT>::BucketListSnapshot(
template <class BucketT>
BucketListSnapshot<BucketT>::BucketListSnapshot(
BucketListSnapshot<BucketT> const& snapshot)
: mLevels(snapshot.mLevels), mHeader(snapshot.mHeader)
: mLevels(snapshot.mLevels), mLastClosedLedger(snapshot.mLastClosedLedger)
{
}

Expand All @@ -46,18 +46,25 @@ template <class BucketT>
uint32_t
BucketListSnapshot<BucketT>::getLedgerSeq() const
{
return mHeader.ledgerSeq;
return mLastClosedLedger.lhhe.header.ledgerSeq;
}

template <class BucketT>
LedgerHeader const&
SearchableBucketListSnapshotBase<BucketT>::getLedgerHeader()
SearchableBucketListSnapshotBase<BucketT>::getLedgerHeader() const
{
releaseAssert(mSnapshot);
mSnapshotManager.maybeUpdateSnapshot(mSnapshot, mHistoricalSnapshots);
return mSnapshot->getLedgerHeader();
}

template <class BucketT>
LastClosedLedger const&
SearchableBucketListSnapshotBase<BucketT>::getLastClosedLedger() const
{
releaseAssert(mSnapshot);
return mSnapshot->getLastClosedLedger();
}

template <class BucketT>
void
SearchableBucketListSnapshotBase<BucketT>::loopAllBuckets(
Expand Down Expand Up @@ -85,7 +92,7 @@ SearchableBucketListSnapshotBase<BucketT>::loopAllBuckets(

template <class BucketT>
std::shared_ptr<typename BucketT::LoadT>
SearchableBucketListSnapshotBase<BucketT>::load(LedgerKey const& k)
SearchableBucketListSnapshotBase<BucketT>::load(LedgerKey const& k) const
{
ZoneScoped;

Expand All @@ -108,7 +115,6 @@ SearchableBucketListSnapshotBase<BucketT>::load(LedgerKey const& k)
}
};

mSnapshotManager.maybeUpdateSnapshot(mSnapshot, mHistoricalSnapshots);
if (threadIsMain())
{
mSnapshotManager.startPointLoadTimer();
Expand All @@ -127,7 +133,8 @@ SearchableBucketListSnapshotBase<BucketT>::load(LedgerKey const& k)
template <class BucketT>
std::optional<std::vector<typename BucketT::LoadT>>
SearchableBucketListSnapshotBase<BucketT>::loadKeysFromLedger(
std::set<LedgerKey, LedgerEntryIdCmp> const& inKeys, uint32_t ledgerSeq)
std::set<LedgerKey, LedgerEntryIdCmp> const& inKeys,
uint32_t ledgerSeq) const
{
return loadKeysInternal(inKeys, /*lkMeter=*/nullptr, ledgerSeq);
}
Expand All @@ -142,9 +149,9 @@ BucketLevelSnapshot<BucketT>::BucketLevelSnapshot(
template <class BucketT>
SearchableBucketListSnapshotBase<BucketT>::SearchableBucketListSnapshotBase(
BucketSnapshotManager const& snapshotManager)
: mSnapshotManager(snapshotManager), mHistoricalSnapshots()
: mSnapshotManager(snapshotManager)
, mHistoricalSnapshots()
{

mSnapshotManager.maybeUpdateSnapshot(mSnapshot, mHistoricalSnapshots);
}

Expand Down
87 changes: 79 additions & 8 deletions src/bucket/BucketListSnapshotBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "bucket/BucketUtils.h"
#include "bucket/HotArchiveBucket.h"
#include "bucket/LiveBucket.h"
#include "history/HistoryArchive.h"
#include "ledger/NetworkConfig.h"

namespace medida
{
Expand All @@ -34,8 +36,70 @@ template <class BucketT> struct BucketLevelSnapshot
BucketLevelSnapshot(BucketLevel<BucketT> const& level);
};

// Complete state of last closed ledger: ledger header, soroban network config,
// bucketlist
struct LastClosedLedger
{
std::optional<SorobanNetworkConfig> sorobanNetworkConfig;
LedgerHeaderHistoryEntry lhhe;
HistoryArchiveState has;
LastClosedLedger() = default;
explicit LastClosedLedger(
LedgerHeaderHistoryEntry const& lhhe, HistoryArchiveState const& has,
std::optional<SorobanNetworkConfig> const& sorobanNetworkConfig)
: sorobanNetworkConfig(sorobanNetworkConfig), lhhe(lhhe), has(has)
{
}
// Add getters
uint32_t
getProtocolVersion() const
{
return lhhe.header.ledgerVersion;
}
uint32_t
getLastTxFee() const
{
return lhhe.header.baseFee;
}
uint32_t
getLastReserve() const
{
return lhhe.header.baseReserve;
}
uint32_t
getMaxTxSetSize() const
{
return lhhe.header.maxTxSetSize;
}
uint32_t
getLastMaxTxSetSizeOps() const
{
auto n = getMaxTxSetSize();
return protocolVersionStartsFrom(getProtocolVersion(),
ProtocolVersion::V_11)
? n
: (n * MAX_OPS_PER_TX);
}
uint32_t
getLedgerSeq() const
{
return lhhe.header.ledgerSeq;
}
LedgerHeaderHistoryEntry const&
getLedgerHeaderHistoryEntry() const
{
return lhhe;
}
std::optional<SorobanNetworkConfig> const&
getSorobanNetworkConfig() const
{
return sorobanNetworkConfig;
}
};

template <class BucketT> class BucketListSnapshot : public NonMovable
{

BUCKET_TYPE_ASSERT(BucketT);
using BucketSnapshotT =
std::conditional_t<std::is_same_v<BucketT, LiveBucket>,
Expand All @@ -44,11 +108,12 @@ template <class BucketT> class BucketListSnapshot : public NonMovable
private:
std::vector<BucketLevelSnapshot<BucketT>> mLevels;

// LedgerHeader associated with this ledger state snapshot
LedgerHeader const mHeader;
// Last closed ledger associated with this snapshot
LastClosedLedger const mLastClosedLedger;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we switch this to std::shared_ptr<LastClosedLedger const> const? We're making a lot of copies of this struct and it's not trivial in size.


public:
BucketListSnapshot(BucketListBase<BucketT> const& bl, LedgerHeader hhe);
BucketListSnapshot(BucketListBase<BucketT> const& bl,
LastClosedLedger lastClosed);

// Only allow copies via constructor
BucketListSnapshot(BucketListSnapshot const& snapshot);
Expand All @@ -59,7 +124,12 @@ template <class BucketT> class BucketListSnapshot : public NonMovable
LedgerHeader const&
getLedgerHeader() const
{
return mHeader;
return mLastClosedLedger.lhhe.header;
}
LastClosedLedger const&
getLastClosedLedger() const
{
return mLastClosedLedger;
}
};

Expand Down Expand Up @@ -102,7 +172,7 @@ class SearchableBucketListSnapshotBase : public NonMovableOrCopyable
std::optional<std::vector<typename BucketT::LoadT>>
loadKeysInternal(std::set<LedgerKey, LedgerEntryIdCmp> const& inKeys,
LedgerKeyMeter* lkMeter,
std::optional<uint32_t> ledgerSeq);
std::optional<uint32_t> ledgerSeq) const;

public:
uint32_t
Expand All @@ -111,7 +181,8 @@ class SearchableBucketListSnapshotBase : public NonMovableOrCopyable
return mSnapshot->getLedgerSeq();
}

LedgerHeader const& getLedgerHeader();
LedgerHeader const& getLedgerHeader() const;
LastClosedLedger const& getLastClosedLedger() const;

// Loads inKeys from the specified historical snapshot. Returns
// load_result_vec if the snapshot for the given ledger is
Expand All @@ -121,8 +192,8 @@ class SearchableBucketListSnapshotBase : public NonMovableOrCopyable
// in the BucketList is N - 1.
std::optional<std::vector<typename BucketT::LoadT>>
loadKeysFromLedger(std::set<LedgerKey, LedgerEntryIdCmp> const& inKeys,
uint32_t ledgerSeq);
uint32_t ledgerSeq) const;

std::shared_ptr<typename BucketT::LoadT> load(LedgerKey const& k);
std::shared_ptr<typename BucketT::LoadT> load(LedgerKey const& k) const;
};
}
23 changes: 4 additions & 19 deletions src/bucket/BucketManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ BucketManager::initialize()
mHotArchiveBucketList = std::make_unique<HotArchiveBucketList>();
mSnapshotManager = std::make_unique<BucketSnapshotManager>(
mApp,
std::make_unique<BucketListSnapshot<LiveBucket>>(*mLiveBucketList,
LedgerHeader()),
std::make_unique<BucketListSnapshot<LiveBucket>>(
*mLiveBucketList, LastClosedLedger()),
std::make_unique<BucketListSnapshot<HotArchiveBucket>>(
*mHotArchiveBucketList, LedgerHeader()),
*mHotArchiveBucketList, LastClosedLedger()),
mConfig.QUERY_SNAPSHOT_LEDGERS);
}

Expand Down Expand Up @@ -1054,8 +1054,7 @@ BucketManager::startBackgroundEvictionScan(uint32_t ledgerSeq)
releaseAssert(!mEvictionFuture.valid());
releaseAssert(mEvictionStatistics);

auto searchableBL =
mSnapshotManager->copySearchableLiveBucketListSnapshot();
auto searchableBL = mSnapshotManager->copySearchableLiveBucketListSnapshot();
auto const& cfg = mApp.getLedgerManager().getSorobanNetworkConfig();
auto const& sas = cfg.stateArchivalSettings();

Expand Down Expand Up @@ -1580,20 +1579,6 @@ BucketManager::getConfig() const
return mConfig;
}

std::shared_ptr<SearchableLiveBucketListSnapshot>
BucketManager::getSearchableLiveBucketListSnapshot()
{
// Any other threads must maintain their own snapshot
releaseAssert(threadIsMain());
if (!mSearchableBucketListSnapshot)
{
mSearchableBucketListSnapshot =
mSnapshotManager->copySearchableLiveBucketListSnapshot();
}

return mSearchableBucketListSnapshot;
}

void
BucketManager::reportBucketEntryCountMetrics()
{
Expand Down
6 changes: 0 additions & 6 deletions src/bucket/BucketManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ class BucketManager : NonMovableOrCopyable
std::unique_ptr<TmpDir> mWorkDir;
BucketMapT<LiveBucket> mSharedLiveBuckets;
BucketMapT<HotArchiveBucket> mSharedHotArchiveBuckets;
std::shared_ptr<SearchableLiveBucketListSnapshot>
mSearchableBucketListSnapshot{};

// Lock for managing raw Bucket files or the bucket directory. This lock is
// only required for file access, but is not required for logical changes to
Expand Down Expand Up @@ -381,10 +379,6 @@ class BucketManager : NonMovableOrCopyable

Config const& getConfig() const;

// Get bucketlist snapshot
std::shared_ptr<SearchableLiveBucketListSnapshot>
getSearchableLiveBucketListSnapshot();

void reportBucketEntryCountMetrics();
};

Expand Down
2 changes: 1 addition & 1 deletion src/bucket/BucketSnapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Loop
LiveBucketSnapshot::scanForEviction(
EvictionIterator& iter, uint32_t& bytesToScan, uint32_t ledgerSeq,
std::list<EvictionResultEntry>& evictableKeys,
SearchableLiveBucketListSnapshot& bl) const
SearchableLiveBucketListSnapshot const& bl) const
{
ZoneScoped;
if (isEmpty() || protocolVersionIsBefore(mBucket->getBucketVersion(),
Expand Down
2 changes: 1 addition & 1 deletion src/bucket/BucketSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class LiveBucketSnapshot : public BucketSnapshotBase<LiveBucket>
Loop scanForEviction(EvictionIterator& iter, uint32_t& bytesToScan,
uint32_t ledgerSeq,
std::list<EvictionResultEntry>& evictableKeys,
SearchableLiveBucketListSnapshot& bl) const;
SearchableLiveBucketListSnapshot const& bl) const;
};

class HotArchiveBucketSnapshot : public BucketSnapshotBase<HotArchiveBucket>
Expand Down
Loading
Loading