rippled
Loading...
Searching...
No Matches
SkipListAcquire.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2020 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/ledger/InboundLedger.h>
21#include <xrpld/app/ledger/LedgerReplayer.h>
22#include <xrpld/app/ledger/detail/SkipListAcquire.h>
23#include <xrpld/app/main/Application.h>
24#include <xrpld/core/JobQueue.h>
25#include <xrpld/overlay/PeerSet.h>
26
27namespace ripple {
28
30 Application& app,
31 InboundLedgers& inboundLedgers,
32 uint256 const& ledgerHash,
35 app,
36 ledgerHash,
37 LedgerReplayParameters::SUB_TASK_TIMEOUT,
39 "SkipListAcquire",
41 app.journal("LedgerReplaySkipList"))
42 , inboundLedgers_(inboundLedgers)
43 , peerSet_(std::move(peerSet))
44{
45 JLOG(journal_.trace()) << "Create " << hash_;
46}
47
49{
50 JLOG(journal_.trace()) << "Destroy " << hash_;
51}
52
53void
55{
57 if (!isDone())
58 {
59 trigger(numPeers, sl);
60 setTimer(sl);
61 }
62}
63
64void
66{
67 if (auto const l = app_.getLedgerMaster().getLedgerByHash(hash_); l)
68 {
69 JLOG(journal_.trace()) << "existing ledger " << hash_;
70 retrieveSkipList(l, sl);
71 return;
72 }
73
74 if (!fallBack_)
75 {
76 peerSet_->addPeers(
77 limit,
78 [this](auto peer) {
79 return peer->supportsFeature(ProtocolFeature::LedgerReplay) &&
80 peer->hasLedger(hash_, 0);
81 },
82 [this](auto peer) {
83 if (peer->supportsFeature(ProtocolFeature::LedgerReplay))
84 {
85 JLOG(journal_.trace())
86 << "Add a peer " << peer->id() << " for " << hash_;
87 protocol::TMProofPathRequest request;
88 request.set_ledgerhash(hash_.data(), hash_.size());
89 request.set_key(
90 keylet::skip().key.data(), keylet::skip().key.size());
91 request.set_type(
92 protocol::TMLedgerMapType::lmACCOUNT_STATE);
93 peerSet_->sendRequest(request, peer);
94 }
95 else
96 {
97 JLOG(journal_.trace()) << "Add a no feature peer "
98 << peer->id() << " for " << hash_;
99 if (++noFeaturePeerCount_ >=
101 {
102 JLOG(journal_.debug()) << "Fall back for " << hash_;
105 fallBack_ = true;
106 }
107 }
108 });
109 }
110
111 if (fallBack_)
113}
114
115void
117{
118 JLOG(journal_.trace()) << "mTimeouts=" << timeouts_ << " for " << hash_;
120 {
121 failed_ = true;
122 JLOG(journal_.debug()) << "too many timeouts " << hash_;
123 notify(sl);
124 }
125 else
126 {
127 trigger(1, sl);
128 }
129}
130
133{
134 return shared_from_this();
135}
136
137void
139 std::uint32_t ledgerSeq,
140 boost::intrusive_ptr<SHAMapItem const> const& item)
141{
142 XRPL_ASSERT(
143 ledgerSeq != 0 && item,
144 "ripple::SkipListAcquire::processData : valid inputs");
146 if (isDone())
147 return;
148
149 JLOG(journal_.trace()) << "got data for " << hash_;
150 try
151 {
152 if (auto sle =
153 std::make_shared<SLE>(SerialIter{item->slice()}, item->key());
154 sle)
155 {
156 if (auto const& skipList = sle->getFieldV256(sfHashes).value();
157 !skipList.empty())
158 onSkipListAcquired(skipList, ledgerSeq, sl);
159 return;
160 }
161 }
162 catch (...)
163 {
164 }
165
166 failed_ = true;
167 JLOG(journal_.error()) << "failed to retrieve Skip list from verified data "
168 << hash_;
169 notify(sl);
170}
171
172void
174{
176 dataReadyCallbacks_.emplace_back(std::move(cb));
177 if (isDone())
178 {
179 JLOG(journal_.debug())
180 << "task added to a finished SkipListAcquire " << hash_;
181 notify(sl);
182 }
183}
184
187{
189 return data_;
190}
191
192void
194 std::shared_ptr<Ledger const> const& ledger,
195 ScopedLockType& sl)
196{
197 if (auto const hashIndex = ledger->read(keylet::skip());
198 hashIndex && hashIndex->isFieldPresent(sfHashes))
199 {
200 auto const& slist = hashIndex->getFieldV256(sfHashes).value();
201 if (!slist.empty())
202 {
203 onSkipListAcquired(slist, ledger->seq(), sl);
204 return;
205 }
206 }
207
208 failed_ = true;
209 JLOG(journal_.error()) << "failed to retrieve Skip list from a ledger "
210 << hash_;
211 notify(sl);
212}
213
214void
216 std::vector<uint256> const& skipList,
217 std::uint32_t ledgerSeq,
218 ScopedLockType& sl)
219{
220 complete_ = true;
221 data_ = std::make_shared<SkipListData>(ledgerSeq, skipList);
222 JLOG(journal_.debug()) << "Skip list acquired " << hash_;
223 notify(sl);
224}
225
226void
228{
229 XRPL_ASSERT(isDone(), "ripple::SkipListAcquire::notify : is done");
232 auto const good = !failed_;
233 sl.unlock();
234
235 for (auto& cb : toCall)
236 {
237 cb(good, hash_);
238 }
239
240 sl.lock();
241}
242
243} // namespace ripple
Stream error() const
Definition: Journal.h:335
Stream debug() const
Definition: Journal.h:317
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
virtual LedgerMaster & getLedgerMaster()=0
Manages the lifetime of inbound ledgers.
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
void init(int numPeers)
Start the SkipListAcquire task.
void addDataCallback(OnSkipListDataCB &&cb)
Add a callback that will be called when the skipList is ready or failed.
InboundLedgers & inboundLedgers_
std::shared_ptr< SkipListData const > getData() const
SkipListAcquire(Application &app, InboundLedgers &inboundLedgers, uint256 const &ledgerHash, std::unique_ptr< PeerSet > peerSet)
Constructor.
std::weak_ptr< TimeoutCounter > pmDowncast() override
Return a weak pointer to this.
void onTimer(bool progress, ScopedLockType &peerSetLock) override
Hook called from invokeOnTimer().
void notify(ScopedLockType &sl)
Call the OnSkipListDataCB callbacks.
void retrieveSkipList(std::shared_ptr< Ledger const > const &ledger, ScopedLockType &sl)
Retrieve the skip list from the ledger.
void trigger(std::size_t limit, ScopedLockType &sl)
Trigger another round.
std::shared_ptr< SkipListData const > data_
void processData(std::uint32_t ledgerSeq, boost::intrusive_ptr< SHAMapItem const > const &item)
Process the data extracted from a peer's reply.
void onSkipListAcquired(std::vector< uint256 > const &skipList, std::uint32_t ledgerSeq, ScopedLockType &sl)
Process the skip list.
std::vector< OnSkipListDataCB > dataReadyCallbacks_
std::unique_ptr< PeerSet > peerSet_
std::uint32_t noFeaturePeerCount_
This class is an "active" object.
void setTimer(ScopedLockType &)
Schedule a call to queueJob() after mTimerInterval.
std::chrono::milliseconds timerInterval_
The minimum time to wait between calls to execute().
beast::Journal journal_
uint256 const hash_
The hash of the object (in practice, always a ledger) we are trying to fetch.
std::recursive_mutex mtx_
pointer data()
Definition: base_uint.h:124
static constexpr std::size_t size()
Definition: base_uint.h:525
T lock(T... args)
auto constexpr SUB_TASK_FALLBACK_TIMEOUT
std::uint32_t constexpr MAX_QUEUED_TASKS
std::uint32_t constexpr SUB_TASK_MAX_TIMEOUTS
auto constexpr MAX_NO_FEATURE_PEER_COUNT
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition: Indexes.cpp:172
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ jtREPLAY_TASK
Definition: Job.h:61
uint256 key
Definition: Keylet.h:40
T swap(T... args)
T unlock(T... args)