Skip to content

Commit 9ff6133

Browse files
authored
Hot archive tx apply (#4603)
# Description Resolves #4584 This PR adds support for the Hot Archive to TX apply. Specifically, `InvokeHostFunctionOp` will check both the live BucketList and Hot Archive BucketList for archived entries. The `RestoreFootprintOp` can now restore entries from both the live BucketList and Hot Archive. Additionally, restore meta has also changed for p23. The `LEDGER_ENTRY_RESTORED` type has been added for the restore op. When an entry is restored. both the `LedgerEntry` of the restored data and the corresponding `TTL` entry are emitted as `LEDGER_ENTRY_RESTORED LedgerEntryChangeType`. If the entry has not yet been evicted (such that the entry and it's TTL still exist in the live BucketList), the preexisting TTL value will be emitted as `LEDGER_ENTRY_STATE`. If the entry has been evicted such that the TTL value has been previously deleted, only a single change type of `LEDGER_ENTRY_RESTORED` will be emitted for the new value. For the data being restored, `LEDGER_ENTRY_STATE` is never emitted. Rebased on #4585. # Checklist - [x] Reviewed the [contributing](https://github.com/stellar/stellar-core/blob/master/CONTRIBUTING.md#submitting-changes) document - [x] Rebased on top of master (no merge commits) - [x] Ran `clang-format` v8.0.0 (via `make format` or the Visual Studio extension) - [x] Compiles - [x] 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 8539c45 + c7e470a commit 9ff6133

29 files changed

+879
-77
lines changed

src/bucket/BucketManager.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
#include "bucket/BucketSnapshotManager.h"
1010
#include "bucket/BucketUtils.h"
1111
#include "bucket/HotArchiveBucket.h"
12+
#include "bucket/HotArchiveBucketList.h"
1213
#include "bucket/LiveBucket.h"
13-
#include "bucket/SearchableBucketList.h"
14+
#include "bucket/LiveBucketList.h"
1415
#include "crypto/BLAKE2.h"
1516
#include "crypto/Hex.h"
1617
#include "history/HistoryManager.h"

src/bucket/BucketManager.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#pragma once
22

33
#include "bucket/BucketMergeMap.h"
4-
#include "bucket/HotArchiveBucketList.h"
5-
#include "bucket/LiveBucketList.h"
64
#include "main/Config.h"
75
#include "util/types.h"
86
#include "xdr/Stellar-ledger.h"
97

8+
#include <filesystem>
109
#include <map>
1110
#include <memory>
1211
#include <mutex>
@@ -32,6 +31,9 @@ class AbstractLedgerTxn;
3231
class Application;
3332
class Bucket;
3433
class LiveBucketList;
34+
class HotArchiveBucketList;
35+
class BucketBase;
36+
class BucketIndex;
3537
class BucketSnapshotManager;
3638
class SearchableLiveBucketListSnapshot;
3739
struct BucketEntryCounters;
@@ -395,7 +397,6 @@ class BucketManager : NonMovableOrCopyable
395397
scheduleVerifyReferencedBucketsWork(HistoryArchiveState const& has);
396398

397399
Config const& getConfig() const;
398-
399400
void reportBucketEntryCountMetrics();
400401
};
401402

src/bucket/FutureBucket.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// else.
88
#include "util/asio.h" // IWYU pragma: keep
99

10+
#include "bucket/BucketListBase.h"
1011
#include "bucket/BucketManager.h"
1112
#include "bucket/FutureBucket.h"
1213
#include "bucket/HotArchiveBucket.h"

src/bucket/SearchableBucketList.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "bucket/SearchableBucketList.h"
66
#include "bucket/BucketInputIterator.h"
77
#include "bucket/BucketListSnapshotBase.h"
8+
#include "bucket/LiveBucketList.h"
89
#include "util/GlobalChecks.h"
910

1011
#include <medida/timer.h>

src/bucket/test/BucketTestUtils.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,27 @@ LedgerManagerForBucketTests::transferLedgerEntriesToBucketList(
235235
ltxEvictions, lh.ledgerSeq, keys, initialLedgerVers,
236236
mApp.getLedgerManager()
237237
.getSorobanNetworkConfigForApply());
238-
239238
if (protocolVersionStartsFrom(
240239
initialLedgerVers,
241240
BucketBase::
242241
FIRST_PROTOCOL_SUPPORTING_PERSISTENT_EVICTION))
243242
{
243+
std::vector<LedgerKey> restoredKeys;
244+
auto restoredKeysMap = ltx.getRestoredHotArchiveKeys();
245+
for (auto const& key : restoredKeysMap)
246+
{
247+
// Hot Archive does not track TTLs
248+
if (key.type() == CONTRACT_DATA ||
249+
key.type() == CONTRACT_CODE)
250+
{
251+
restoredKeys.emplace_back(key);
252+
}
253+
}
244254
mApp.getBucketManager().addHotArchiveBatch(
245-
mApp, lh, evictedState.archivedEntries, {}, {});
255+
mApp, lh, evictedState.archivedEntries, restoredKeys,
256+
{});
246257
}
258+
247259
if (ledgerCloseMeta)
248260
{
249261
ledgerCloseMeta->populateEvictedEntries(evictedState);

src/catchup/IndexBucketsWork.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "IndexBucketsWork.h"
66
#include "bucket/BucketIndex.h"
77
#include "bucket/BucketManager.h"
8+
#include "bucket/LiveBucket.h"
89
#include "util/Fs.h"
910
#include "util/Logging.h"
1011
#include "util/UnorderedSet.h"

src/ledger/LedgerManagerImpl.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "ledger/LedgerManagerImpl.h"
66
#include "bucket/BucketManager.h"
7+
#include "bucket/HotArchiveBucketList.h"
78
#include "bucket/LiveBucketList.h"
89
#include "catchup/AssumeStateWork.h"
910
#include "crypto/Hex.h"
@@ -44,6 +45,7 @@
4445

4546
#include <fmt/format.h>
4647

48+
#include "xdr/Stellar-ledger-entries.h"
4749
#include "xdr/Stellar-ledger.h"
4850
#include "xdr/Stellar-transaction.h"
4951
#include "xdrpp/types.h"
@@ -1790,8 +1792,19 @@ LedgerManagerImpl::transferLedgerEntriesToBucketList(
17901792
initialLedgerVers,
17911793
BucketBase::FIRST_PROTOCOL_SUPPORTING_PERSISTENT_EVICTION))
17921794
{
1795+
std::vector<LedgerKey> restoredKeys;
1796+
auto const& restoredKeyMap = ltx.getRestoredHotArchiveKeys();
1797+
for (auto const& key : restoredKeyMap)
1798+
{
1799+
// TTL keys are not recorded in the hot archive BucketList
1800+
if (key.type() == CONTRACT_DATA ||
1801+
key.type() == CONTRACT_CODE)
1802+
{
1803+
restoredKeys.push_back(key);
1804+
}
1805+
}
17931806
mApp.getBucketManager().addHotArchiveBatch(
1794-
mApp, lh, evictedState.archivedEntries, {}, {});
1807+
mApp, lh, evictedState.archivedEntries, restoredKeys, {});
17951808
}
17961809

17971810
if (ledgerCloseMeta)

src/ledger/LedgerTxn.cpp

+140-5
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
#include "main/Application.h"
1717
#include "transactions/TransactionUtils.h"
1818
#include "util/GlobalChecks.h"
19+
#include "util/UnorderedSet.h"
1920
#include "util/types.h"
2021
#include "xdr/Stellar-ledger-entries.h"
2122
#include <Tracy.hpp>
2223
#include <soci.h>
2324

2425
#include <algorithm>
26+
#include <stdexcept>
2527

2628
namespace stellar
2729
{
@@ -501,14 +503,16 @@ LedgerTxn::Impl::commit() noexcept
501503
maybeUpdateLastModifiedThenInvokeThenSeal([&](EntryMap const& entries) {
502504
// getEntryIterator has the strong exception safety guarantee
503505
// commitChild has the strong exception safety guarantee
504-
mParent.commitChild(getEntryIterator(entries), mConsistency);
506+
mParent.commitChild(getEntryIterator(entries), mRestoredKeys,
507+
mConsistency);
505508
});
506509
}
507510

508511
void
509-
LedgerTxn::commitChild(EntryIterator iter, LedgerTxnConsistency cons) noexcept
512+
LedgerTxn::commitChild(EntryIterator iter, RestoredKeys const& restoredKeys,
513+
LedgerTxnConsistency cons) noexcept
510514
{
511-
getImpl()->commitChild(std::move(iter), cons);
515+
getImpl()->commitChild(std::move(iter), restoredKeys, cons);
512516
}
513517

514518
static LedgerTxnConsistency
@@ -527,6 +531,7 @@ joinConsistencyLevels(LedgerTxnConsistency c1, LedgerTxnConsistency c2)
527531

528532
void
529533
LedgerTxn::Impl::commitChild(EntryIterator iter,
534+
RestoredKeys const& restoredKeys,
530535
LedgerTxnConsistency cons) noexcept
531536
{
532537
// Assignment of xdrpp objects does not have the strong exception safety
@@ -632,6 +637,24 @@ LedgerTxn::Impl::commitChild(EntryIterator iter,
632637
printErrorAndAbort("unknown fatal error during commit to LedgerTxn");
633638
}
634639

640+
for (auto const& key : restoredKeys.hotArchive)
641+
{
642+
auto [_, inserted] = mRestoredKeys.hotArchive.emplace(key);
643+
if (!inserted)
644+
{
645+
printErrorAndAbort("restored hot archive entry already exists");
646+
}
647+
}
648+
649+
for (auto const& key : restoredKeys.liveBucketList)
650+
{
651+
auto [_, inserted] = mRestoredKeys.liveBucketList.emplace(key);
652+
if (!inserted)
653+
{
654+
printErrorAndAbort("restored live BucketList entry already exists");
655+
}
656+
}
657+
635658
// std::unique_ptr<...>::swap does not throw
636659
mHeader.swap(childHeader);
637660
mChild = nullptr;
@@ -802,6 +825,91 @@ LedgerTxn::Impl::erase(InternalLedgerKey const& key)
802825
}
803826
}
804827

828+
void
829+
LedgerTxn::restoreFromHotArchive(LedgerEntry const& entry, uint32_t ttl)
830+
{
831+
getImpl()->restoreFromHotArchive(*this, entry, ttl);
832+
}
833+
834+
void
835+
LedgerTxn::Impl::restoreFromHotArchive(LedgerTxn& self,
836+
LedgerEntry const& entry, uint32_t ttl)
837+
{
838+
throwIfSealed();
839+
throwIfChild();
840+
841+
if (!isPersistentEntry(entry.data))
842+
{
843+
throw std::runtime_error("Key type not supported in Hot Archive");
844+
}
845+
auto ttlKey = getTTLKey(entry);
846+
847+
// Restore entry by creating it on the live BucketList
848+
create(self, entry);
849+
850+
// Also create the corresponding TTL entry
851+
LedgerEntry ttlEntry;
852+
ttlEntry.data.type(TTL);
853+
ttlEntry.data.ttl().liveUntilLedgerSeq = ttl;
854+
ttlEntry.data.ttl().keyHash = ttlKey.ttl().keyHash;
855+
create(self, ttlEntry);
856+
857+
// Mark the keys as restored
858+
auto addKey = [this](LedgerKey const& key) {
859+
auto [_, inserted] = mRestoredKeys.hotArchive.insert(key);
860+
if (!inserted)
861+
{
862+
throw std::runtime_error("Key already removed from hot archive");
863+
}
864+
};
865+
addKey(LedgerEntryKey(entry));
866+
addKey(ttlKey);
867+
}
868+
869+
void
870+
LedgerTxn::restoreFromLiveBucketList(LedgerKey const& key, uint32_t ttl)
871+
{
872+
getImpl()->restoreFromLiveBucketList(*this, key, ttl);
873+
}
874+
875+
void
876+
LedgerTxn::Impl::restoreFromLiveBucketList(LedgerTxn& self,
877+
LedgerKey const& key, uint32_t ttl)
878+
{
879+
throwIfSealed();
880+
throwIfChild();
881+
882+
if (!isPersistentEntry(key))
883+
{
884+
throw std::runtime_error("Key type not supported for restoration");
885+
}
886+
887+
auto ttlKey = getTTLKey(key);
888+
889+
// Note: key should have already been loaded via loadWithoutRecord by
890+
// caller, so this read should already be in the cache.
891+
auto ttlLtxe = load(self, ttlKey);
892+
if (!ttlLtxe)
893+
{
894+
throw std::runtime_error("Entry restored from live BucketList but does "
895+
"not exist in the live BucketList.");
896+
}
897+
898+
ttlLtxe.current().data.ttl().liveUntilLedgerSeq = ttl;
899+
900+
// Mark the keys as restored
901+
auto addKey = [this](LedgerKey const& key) {
902+
auto [_, inserted] = mRestoredKeys.liveBucketList.insert(key);
903+
if (!inserted)
904+
{
905+
throw std::runtime_error(
906+
"Key already restored from Live BucketList");
907+
}
908+
};
909+
addKey(key);
910+
addKey(ttlKey);
911+
}
912+
805913
void
806914
LedgerTxn::eraseWithoutLoading(InternalLedgerKey const& key)
807915
{
@@ -1470,6 +1578,30 @@ LedgerTxn::Impl::getAllEntries(std::vector<LedgerEntry>& initEntries,
14701578
deadEntries.swap(resDead);
14711579
}
14721580

1581+
UnorderedSet<LedgerKey> const&
1582+
LedgerTxn::getRestoredHotArchiveKeys() const
1583+
{
1584+
return getImpl()->getRestoredHotArchiveKeys();
1585+
}
1586+
1587+
UnorderedSet<LedgerKey> const&
1588+
LedgerTxn::Impl::getRestoredHotArchiveKeys() const
1589+
{
1590+
return mRestoredKeys.hotArchive;
1591+
}
1592+
1593+
UnorderedSet<LedgerKey> const&
1594+
LedgerTxn::getRestoredLiveBucketListKeys() const
1595+
{
1596+
return getImpl()->getRestoredLiveBucketListKeys();
1597+
}
1598+
1599+
UnorderedSet<LedgerKey> const&
1600+
LedgerTxn::Impl::getRestoredLiveBucketListKeys() const
1601+
{
1602+
return mRestoredKeys.liveBucketList;
1603+
}
1604+
14731605
LedgerKeySet
14741606
LedgerTxn::getAllTTLKeysWithoutSealing() const
14751607
{
@@ -1957,6 +2089,8 @@ LedgerTxn::Impl::rollback() noexcept
19572089
}
19582090

19592091
mEntry.clear();
2092+
mRestoredKeys.hotArchive.clear();
2093+
mRestoredKeys.liveBucketList.clear();
19602094
mMultiOrderBook.clear();
19612095
mActive.clear();
19622096
mActiveHeader.reset();
@@ -2559,10 +2693,10 @@ LedgerTxnRoot::Impl::throwIfChild() const
25592693
}
25602694

25612695
void
2562-
LedgerTxnRoot::commitChild(EntryIterator iter,
2696+
LedgerTxnRoot::commitChild(EntryIterator iter, RestoredKeys const& restoredKeys,
25632697
LedgerTxnConsistency cons) noexcept
25642698
{
2565-
mImpl->commitChild(std::move(iter), cons);
2699+
mImpl->commitChild(std::move(iter), restoredKeys, cons);
25662700
}
25672701

25682702
static void
@@ -2619,6 +2753,7 @@ LedgerTxnRoot::Impl::bulkApply(BulkLedgerEntryChangeAccumulator& bleca,
26192753

26202754
void
26212755
LedgerTxnRoot::Impl::commitChild(EntryIterator iter,
2756+
RestoredKeys const& restoredHotArchiveKeys,
26222757
LedgerTxnConsistency cons) noexcept
26232758
{
26242759
ZoneScoped;

0 commit comments

Comments
 (0)