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/overlay/PeerSet.h>
25
26namespace ripple {
27
29 Application& app,
30 InboundLedgers& inboundLedgers,
31 uint256 const& ledgerHash,
34 app,
35 ledgerHash,
36 LedgerReplayParameters::SUB_TASK_TIMEOUT,
38 "SkipListAcquire",
40 app.journal("LedgerReplaySkipList"))
41 , inboundLedgers_(inboundLedgers)
42 , peerSet_(std::move(peerSet))
43{
44 JLOG(journal_.trace()) << "Create " << hash_;
45}
46
48{
49 JLOG(journal_.trace()) << "Destroy " << hash_;
50}
51
52void
54{
56 if (!isDone())
57 {
58 trigger(numPeers, sl);
59 setTimer(sl);
60 }
61}
62
63void
65{
66 if (auto const l = app_.getLedgerMaster().getLedgerByHash(hash_); l)
67 {
68 JLOG(journal_.trace()) << "existing ledger " << hash_;
69 retrieveSkipList(l, sl);
70 return;
71 }
72
73 if (!fallBack_)
74 {
75 peerSet_->addPeers(
76 limit,
77 [this](auto peer) {
78 return peer->supportsFeature(ProtocolFeature::LedgerReplay) &&
79 peer->hasLedger(hash_, 0);
80 },
81 [this](auto peer) {
82 if (peer->supportsFeature(ProtocolFeature::LedgerReplay))
83 {
84 JLOG(journal_.trace())
85 << "Add a peer " << peer->id() << " for " << hash_;
86 protocol::TMProofPathRequest request;
87 request.set_ledgerhash(hash_.data(), hash_.size());
88 request.set_key(
89 keylet::skip().key.data(), keylet::skip().key.size());
90 request.set_type(
91 protocol::TMLedgerMapType::lmACCOUNT_STATE);
92 peerSet_->sendRequest(request, peer);
93 }
94 else
95 {
96 JLOG(journal_.trace()) << "Add a no feature peer "
97 << peer->id() << " for " << hash_;
98 if (++noFeaturePeerCount_ >=
100 {
101 JLOG(journal_.debug()) << "Fall back for " << hash_;
104 fallBack_ = true;
105 }
106 }
107 });
108 }
109
110 if (fallBack_)
112}
113
114void
116{
117 JLOG(journal_.trace()) << "mTimeouts=" << timeouts_ << " for " << hash_;
119 {
120 failed_ = true;
121 JLOG(journal_.debug()) << "too many timeouts " << hash_;
122 notify(sl);
123 }
124 else
125 {
126 trigger(1, sl);
127 }
128}
129
132{
133 return shared_from_this();
134}
135
136void
138 std::uint32_t ledgerSeq,
139 boost::intrusive_ptr<SHAMapItem const> const& item)
140{
141 XRPL_ASSERT(
142 ledgerSeq != 0 && item,
143 "ripple::SkipListAcquire::processData : valid inputs");
145 if (isDone())
146 return;
147
148 JLOG(journal_.trace()) << "got data for " << hash_;
149 try
150 {
151 if (auto sle =
152 std::make_shared<SLE>(SerialIter{item->slice()}, item->key());
153 sle)
154 {
155 if (auto const& skipList = sle->getFieldV256(sfHashes).value();
156 !skipList.empty())
157 onSkipListAcquired(skipList, ledgerSeq, sl);
158 return;
159 }
160 }
161 catch (...)
162 {
163 }
164
165 failed_ = true;
166 JLOG(journal_.error()) << "failed to retrieve Skip list from verified data "
167 << hash_;
168 notify(sl);
169}
170
171void
173{
175 dataReadyCallbacks_.emplace_back(std::move(cb));
176 if (isDone())
177 {
178 JLOG(journal_.debug())
179 << "task added to a finished SkipListAcquire " << hash_;
180 notify(sl);
181 }
182}
183
186{
188 return data_;
189}
190
191void
193 std::shared_ptr<Ledger const> const& ledger,
194 ScopedLockType& sl)
195{
196 if (auto const hashIndex = ledger->read(keylet::skip());
197 hashIndex && hashIndex->isFieldPresent(sfHashes))
198 {
199 auto const& slist = hashIndex->getFieldV256(sfHashes).value();
200 if (!slist.empty())
201 {
202 onSkipListAcquired(slist, ledger->seq(), sl);
203 return;
204 }
205 }
206
207 failed_ = true;
208 JLOG(journal_.error()) << "failed to retrieve Skip list from a ledger "
209 << hash_;
210 notify(sl);
211}
212
213void
215 std::vector<uint256> const& skipList,
216 std::uint32_t ledgerSeq,
217 ScopedLockType& sl)
218{
219 complete_ = true;
220 data_ = std::make_shared<SkipListData>(ledgerSeq, skipList);
221 JLOG(journal_.debug()) << "Skip list acquired " << hash_;
222 notify(sl);
223}
224
225void
227{
228 XRPL_ASSERT(isDone(), "ripple::SkipListAcquire::notify : is done");
231 auto const good = !failed_;
232 sl.unlock();
233
234 for (auto& cb : toCall)
235 {
236 cb(good, hash_);
237 }
238
239 sl.lock();
240}
241
242} // namespace ripple
Stream error() const
Definition: Journal.h:346
Stream debug() const
Definition: Journal.h:328
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
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:125
static constexpr std::size_t size()
Definition: base_uint.h:526
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:189
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)