xrpld
Loading...
Searching...
No Matches
SkipListAcquire.cpp
1#include <xrpld/app/ledger/detail/SkipListAcquire.h>
2
3#include <xrpld/app/ledger/InboundLedger.h>
4#include <xrpld/app/ledger/InboundLedgers.h>
5#include <xrpld/app/ledger/LedgerMaster.h>
6#include <xrpld/app/ledger/LedgerReplayer.h>
7#include <xrpld/app/ledger/detail/TimeoutCounter.h>
8#include <xrpld/app/main/Application.h>
9#include <xrpld/overlay/Peer.h>
10#include <xrpld/overlay/PeerSet.h>
11
12#include <xrpl/basics/Log.h>
13#include <xrpl/basics/base_uint.h>
14#include <xrpl/beast/utility/instrumentation.h>
15#include <xrpl/core/Job.h>
16#include <xrpl/protocol/Indexes.h>
17#include <xrpl/protocol/SField.h>
18#include <xrpl/shamap/SHAMapItem.h>
19
20#include <boost/smart_ptr/intrusive_ptr.hpp>
21
22#include <xrpl.pb.h>
23
24#include <cstddef>
25#include <cstdint>
26#include <memory>
27#include <utility>
28#include <vector>
29
30namespace xrpl {
31
33 Application& app,
34 InboundLedgers& inboundLedgers,
35 uint256 const& ledgerHash,
38 app,
39 ledgerHash,
40 ledger_replay_parameters::kSubTaskTimeout,
41 {.jobType = JtReplayTask,
42 .jobName = "SkipListAcq",
44 app.getJournal("LedgerReplaySkipList"))
45 , inboundLedgers_(inboundLedgers)
46 , peerSet_(std::move(peerSet))
47{
48 JLOG(journal_.trace()) << "Create " << hash_;
49}
50
52{
53 JLOG(journal_.trace()) << "Destroy " << hash_;
54}
55
56void
58{
60 if (!isDone())
61 {
62 trigger(numPeers, sl);
63 setTimer(sl);
64 }
65}
66
67void
69{
70 if (auto const l = app_.getLedgerMaster().getLedgerByHash(hash_); l)
71 {
72 JLOG(journal_.trace()) << "existing ledger " << hash_;
73 retrieveSkipList(l, sl);
74 return;
75 }
76
77 if (!fallBack_)
78 {
79 peerSet_->addPeers(
80 limit,
81 [this](auto peer) {
82 return peer->supportsFeature(ProtocolFeature::LedgerReplay) &&
83 peer->hasLedger(hash_, 0);
84 },
85 [this](auto peer) {
86 if (peer->supportsFeature(ProtocolFeature::LedgerReplay))
87 {
88 JLOG(journal_.trace()) << "Add a peer " << peer->id() << " for " << hash_;
89 protocol::TMProofPathRequest request;
90 request.set_ledgerhash(hash_.data(), hash_.size());
91 request.set_key(keylet::skip().key.data(), keylet::skip().key.size());
92 request.set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
93 peerSet_->sendRequest(request, peer);
94 }
95 else
96 {
97 JLOG(journal_.trace())
98 << "Add a no feature peer " << peer->id() << " for " << hash_;
100 {
101 JLOG(journal_.debug()) << "Fall back for " << hash_;
103 fallBack_ = true;
104 }
105 }
106 });
107 }
108
109 if (fallBack_)
111}
112
113void
115{
116 JLOG(journal_.trace()) << "timeouts_=" << timeouts_ << " for " << hash_;
118 {
119 failed_ = true;
120 JLOG(journal_.debug()) << "too many timeouts " << hash_;
121 notify(sl);
122 }
123 else
124 {
125 trigger(1, sl);
126 }
127}
128
134
135void
137 std::uint32_t ledgerSeq,
138 boost::intrusive_ptr<SHAMapItem const> const& item)
139{
140 XRPL_ASSERT(ledgerSeq != 0 && item, "xrpl::SkipListAcquire::processData : valid inputs");
142 if (isDone())
143 return;
144
145 JLOG(journal_.trace()) << "got data for " << hash_;
146 try
147 {
148 if (auto sle = std::make_shared<SLE>(SerialIter{item->slice()}, item->key()); sle)
149 {
150 if (auto const& skipList = sle->getFieldV256(sfHashes).value(); !skipList.empty())
151 onSkipListAcquired(skipList, ledgerSeq, sl);
152 return;
153 }
154 }
155 catch (...) // NOLINT(bugprone-empty-catch)
156 {
157 }
158
159 failed_ = true;
160 JLOG(journal_.error()) << "failed to retrieve Skip list from verified data " << hash_;
161 notify(sl);
162}
163
164void
166{
168 dataReadyCallbacks_.emplace_back(std::move(cb));
169 if (isDone())
170 {
171 JLOG(journal_.debug()) << "task added to a finished SkipListAcquire " << hash_;
172 notify(sl);
173 }
174}
175
178{
179 ScopedLockType const sl(mtx_);
180 return data_;
181}
182
183void
185{
186 if (auto const hashIndex = ledger->read(keylet::skip());
187 hashIndex && hashIndex->isFieldPresent(sfHashes))
188 {
189 auto const& slist = hashIndex->getFieldV256(sfHashes).value();
190 if (!slist.empty())
191 {
192 onSkipListAcquired(slist, ledger->seq(), sl);
193 return;
194 }
195 }
196
197 failed_ = true;
198 JLOG(journal_.error()) << "failed to retrieve Skip list from a ledger " << hash_;
199 notify(sl);
200}
201
202void
204 std::vector<uint256> const& skipList,
205 std::uint32_t ledgerSeq,
206 ScopedLockType& sl)
207{
208 complete_ = true;
209 data_ = std::make_shared<SkipListData>(ledgerSeq, skipList);
210 JLOG(journal_.debug()) << "Skip list acquired " << hash_;
211 notify(sl);
212}
213
214void
216{
217 XRPL_ASSERT(isDone(), "xrpl::SkipListAcquire::notify : is done");
220 auto const good = !failed_;
221 sl.unlock();
222
223 for (auto& cb : toCall)
224 {
225 cb(good, hash_);
226 }
227
228 sl.lock();
229}
230
231} // namespace xrpl
Manages the lifetime of inbound ledgers.
void addDataCallback(OnSkipListDataCB &&cb)
Add a callback that will be called when the skipList is ready or failed.
std::uint32_t noFeaturePeerCount_
std::weak_ptr< TimeoutCounter > pmDowncast() override
Return a weak pointer to this.
std::unique_ptr< PeerSet > peerSet_
std::shared_ptr< SkipListData const > data_
void trigger(std::size_t limit, ScopedLockType &sl)
Trigger another round.
void notify(ScopedLockType &sl)
Call the OnSkipListDataCB callbacks.
std::vector< OnSkipListDataCB > dataReadyCallbacks_
std::shared_ptr< SkipListData const > getData() const
void onTimer(bool progress, ScopedLockType &peerSetLock) override
Hook called from invokeOnTimer().
InboundLedgers & inboundLedgers_
std::function< void(bool successful, uint256 const &hash)> OnSkipListDataCB
A callback used to notify that the SkipList is ready or failed.
void onSkipListAcquired(std::vector< uint256 > const &skipList, std::uint32_t ledgerSeq, ScopedLockType &sl)
Process the skip list.
void retrieveSkipList(std::shared_ptr< Ledger const > const &ledger, ScopedLockType &sl)
Retrieve the skip list from the ledger.
void processData(std::uint32_t ledgerSeq, boost::intrusive_ptr< SHAMapItem const > const &item)
Process the data extracted from a peer's reply.
SkipListAcquire(Application &app, InboundLedgers &inboundLedgers, uint256 const &ledgerHash, std::unique_ptr< PeerSet > peerSet)
Constructor.
void init(int numPeers)
Start the SkipListAcquire task.
TimeoutCounter(Application &app, uint256 const &targetHash, std::chrono::milliseconds timeoutInterval, QueueJobParameter &&jobParameter, beast::Journal journal)
std::recursive_mutex mtx_
std::unique_lock< std::recursive_mutex > ScopedLockType
uint256 const hash_
The hash of the object (in practice, always a ledger) we are trying to fetch.
beast::Journal journal_
void setTimer(ScopedLockType &)
Schedule a call to queueJob() after timerInterval_.
std::chrono::milliseconds timerInterval_
The minimum time to wait between calls to execute().
T lock(T... args)
T make_shared(T... args)
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:210
constexpr std::uint32_t kSubTaskMaxTimeouts
constexpr std::uint32_t kMaxQueuedTasks
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ JtReplayTask
Definition Job.h:47
BaseUInt< 256 > uint256
Definition base_uint.h:580
T swap(T... args)
T unlock(T... args)