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

Initialize Soroban live state cache on startup #4663

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/bucket/BucketSnapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,44 @@ LiveBucketSnapshot::scanForEviction(
return Loop::INCOMPLETE;
}

Loop
LiveBucketSnapshot::scanForSorobanEntries(
std::function<Loop(BucketEntry const&)> callback) const
{
ZoneScoped;
if (isEmpty())
{
return Loop::INCOMPLETE;
}

auto range = mBucket->getSorobanRange();
if (!range)
{
return Loop::INCOMPLETE;
}

// Open new stream to not interfere with TTL lookups during the scan
XDRInputFileStream stream{};
stream.open(mBucket->getFilename());
stream.seek(range->first);

BucketEntry be;
while (stream.pos() < range->second && stream.readOne(be))
{
if (((be.type() == LIVEENTRY || be.type() == INITENTRY) &&
isSorobanEntry(be.liveEntry().data)) ||
(be.type() == DEADENTRY && isSorobanEntry(be.deadEntry())))
{
if (callback(be) == Loop::COMPLETE)
{
return Loop::COMPLETE;
}
}
}

return Loop::INCOMPLETE;
}

template <class BucketT>
XDRInputFileStream&
BucketSnapshotBase<BucketT>::getStream() const
Expand Down
3 changes: 3 additions & 0 deletions src/bucket/BucketSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class LiveBucketSnapshot : public BucketSnapshotBase<LiveBucket>
std::list<EvictionResultEntry>& evictableKeys,
SearchableLiveBucketListSnapshot const& bl,
uint32_t ledgerVers) const;

Loop scanForSorobanEntries(
std::function<Loop(BucketEntry const&)> callback) const;
};

class HotArchiveBucketSnapshot : public BucketSnapshotBase<HotArchiveBucket>
Expand Down
32 changes: 32 additions & 0 deletions src/bucket/InMemoryIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "bucket/BucketManager.h"
#include "bucket/LedgerCmp.h"
#include "bucket/LiveBucket.h"
#include "ledger/LedgerTypeUtils.h"
#include "util/XDRStream.h"
#include "util/types.h"
#include "xdr/Stellar-ledger-entries.h"
Expand Down Expand Up @@ -60,6 +61,8 @@ InMemoryIndex::InMemoryIndex(BucketManager const& bm,
std::streamoff lastOffset = 0;
std::optional<std::streamoff> firstOffer;
std::optional<std::streamoff> lastOffer;
std::optional<std::streamoff> firstSoroban;
std::optional<std::streamoff> lastSoroban;

while (in && in.readOne(be, hasher))
{
Expand Down Expand Up @@ -109,6 +112,16 @@ InMemoryIndex::InMemoryIndex(BucketManager const& bm,
lastOffer = lastOffset;
}

// populate sorobanRange
if (!firstSoroban && isSorobanEntry(lk))
{
firstSoroban = lastOffset;
}
if (!lastSoroban && lk.type() > CONTRACT_CODE)
{
lastSoroban = lastOffset;
}

lastOffset = in.pos();
}

Expand All @@ -130,5 +143,24 @@ InMemoryIndex::InMemoryIndex(BucketManager const& bm,
{
mOfferRange = std::nullopt;
}

if (firstSoroban)
{
if (lastSoroban)
{
mSorobanRange = {*firstSoroban, *lastSoroban};
}
// If we didn't see any entries after our last data/code entry, then the
// upper bound is EOF
else
{
mSorobanRange = {*firstSoroban,
std::numeric_limits<std::streamoff>::max()};
}
}
else
{
mSorobanRange = std::nullopt;
}
}
}
9 changes: 9 additions & 0 deletions src/bucket/InMemoryIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class InMemoryIndex
BucketEntryCounters mCounters{};
std::optional<std::pair<std::streamoff, std::streamoff>> mOfferRange;

// Range of data/code entries in the Bucket
std::optional<std::pair<std::streamoff, std::streamoff>> mSorobanRange;

public:
using IterT = InMemoryBucketState::IterT;

Expand Down Expand Up @@ -105,6 +108,12 @@ class InMemoryIndex
return mOfferRange;
}

std::optional<std::pair<std::streamoff, std::streamoff>>
getSorobanRange() const
{
return mSorobanRange;
}

#ifdef BUILD_TESTS
bool
operator==(InMemoryIndex const& in) const
Expand Down
6 changes: 6 additions & 0 deletions src/bucket/LiveBucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,12 @@ LiveBucket::getOfferRange() const
return getIndex().getOfferRange();
}

std::optional<std::pair<std::streamoff, std::streamoff>>
LiveBucket::getSorobanRange() const
{
return getIndex().getSorobanRange();
}

std::vector<BucketEntry>
LiveBucket::convertToBucketEntry(bool useInit,
std::vector<LedgerEntry> const& initEntries,
Expand Down
6 changes: 6 additions & 0 deletions src/bucket/LiveBucket.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ class LiveBucket : public BucketBase<LiveBucket, LiveBucketIndex>,
std::optional<std::pair<std::streamoff, std::streamoff>>
getOfferRange() const;

// Returns [lowerBound, upperBound) of file offsets for all soroban entries
// (CONTRACT_DATA and CONTRACT_CODE) in the bucket, or std::nullopt if no
// soroban entries exist
std::optional<std::pair<std::streamoff, std::streamoff>>
getSorobanRange() const;

// Create a fresh bucket from given vectors of init (created) and live
// (updated) LedgerEntries, and dead LedgerEntryKeys. The bucket will
// be sorted, hashed, and adopted in the provided BucketManager.
Expand Down
24 changes: 24 additions & 0 deletions src/bucket/LiveBucketIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,30 @@ LiveBucketIndex::getOfferRange() const
return mInMemoryIndex->getOfferRange();
}

std::optional<std::pair<std::streamoff, std::streamoff>>
LiveBucketIndex::getSorobanRange() const
{
if (mDiskIndex)
{
// LedgerKey ordering in the bucket is CONTRACT_DATA, CONTRACT_CODE,
// so for the range we need the smallest CONTRACT_DATA entry and the
// largest CONTRACT_CODE entry.
LedgerKey lowerBound(CONTRACT_DATA);
lowerBound.contractData().contract.type(SC_ADDRESS_TYPE_ACCOUNT);
lowerBound.contractData().contract.accountId().ed25519().fill(
std::numeric_limits<uint8_t>::min());

LedgerKey upperBound(CONTRACT_CODE);
upperBound.contractCode().hash.fill(
std::numeric_limits<uint8_t>::max());

return mDiskIndex->getOffsetBounds(lowerBound, upperBound);
}

releaseAssertOrThrow(mInMemoryIndex);
return mInMemoryIndex->getSorobanRange();
}

uint32_t
LiveBucketIndex::getPageSize() const
{
Expand Down
3 changes: 3 additions & 0 deletions src/bucket/LiveBucketIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ class LiveBucketIndex : public NonMovableOrCopyable
std::optional<std::pair<std::streamoff, std::streamoff>>
getOfferRange() const;

std::optional<std::pair<std::streamoff, std::streamoff>>
getSorobanRange() const;

void maybeAddToCache(std::shared_ptr<BucketEntry const> const& entry) const;

BucketEntryCounters const& getBucketEntryCounters() const;
Expand Down
10 changes: 10 additions & 0 deletions src/bucket/SearchableBucketList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ SearchableLiveBucketListSnapshot::scanForEviction(
return result;
}

void
SearchableLiveBucketListSnapshot::scanForSorobanEntries(
std::function<Loop(BucketEntry const&)> callback) const
{
releaseAssert(mSnapshot);
auto f = [&](auto const& b) { return b.scanForSorobanEntries(callback); };

loopAllBuckets(f, *mSnapshot);
}

// This query has two steps:
// 1. For each bucket, determine what PoolIDs contain the target asset via the
// assetToPoolID index
Expand Down
5 changes: 5 additions & 0 deletions src/bucket/SearchableBucketList.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class SearchableLiveBucketListSnapshot
std::shared_ptr<EvictionStatistics> stats,
StateArchivalSettings const& sas, uint32_t ledgerVers) const;

// Calls callback on each CONTRACT_CODE and CONTRACT_DATA entry in
// BucketList
void scanForSorobanEntries(
std::function<Loop(BucketEntry const&)> callback) const;

friend SearchableSnapshotConstPtr
BucketSnapshotManager::copySearchableLiveBucketListSnapshot() const;
};
Expand Down
Loading
Loading