rippled
Loading...
Searching...
No Matches
LedgerReplayTask.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/InboundLedgers.h>
21#include <xrpld/app/ledger/LedgerReplayTask.h>
22#include <xrpld/app/ledger/LedgerReplayer.h>
23#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
24#include <xrpld/app/ledger/detail/SkipListAcquire.h>
25#include <xrpld/core/JobQueue.h>
26
27namespace ripple {
28
31 uint256 const& finishLedgerHash,
32 std::uint32_t totalNumLedgers)
33 : reason_(r), finishHash_(finishLedgerHash), totalLedgers_(totalNumLedgers)
34{
35 XRPL_ASSERT(
36 finishLedgerHash.isNonZero() && totalNumLedgers > 0,
37 "ripple::LedgerReplayTask::TaskParameter::TaskParameter : valid "
38 "inputs");
39}
40
41bool
43 uint256 const& hash,
44 std::uint32_t seq,
45 std::vector<uint256> const& sList)
46{
47 if (finishHash_ != hash || sList.size() + 1 < totalLedgers_ || full_)
48 return false;
49
50 finishSeq_ = seq;
51 skipList_ = sList;
52 skipList_.emplace_back(finishHash_);
53 startHash_ = skipList_[skipList_.size() - totalLedgers_];
54 XRPL_ASSERT(
55 startHash_.isNonZero(),
56 "ripple::LedgerReplayTask::TaskParameter::update : nonzero start hash");
57 startSeq_ = finishSeq_ - totalLedgers_ + 1;
58 full_ = true;
59 return true;
60}
61
62bool
64 TaskParameter const& existingTask) const
65{
66 if (reason_ == existingTask.reason_)
67 {
68 if (finishHash_ == existingTask.finishHash_ &&
69 totalLedgers_ <= existingTask.totalLedgers_)
70 {
71 return true;
72 }
73
74 if (existingTask.full_)
75 {
76 auto const& exList = existingTask.skipList_;
77 if (auto i = std::find(exList.begin(), exList.end(), finishHash_);
78 i != exList.end())
79 {
80 return existingTask.totalLedgers_ >=
81 totalLedgers_ + (exList.end() - i) - 1;
82 }
83 }
84 }
85
86 return false;
87}
88
90 Application& app,
91 InboundLedgers& inboundLedgers,
92 LedgerReplayer& replayer,
93 std::shared_ptr<SkipListAcquire>& skipListAcquirer,
94 TaskParameter&& parameter)
96 app,
97 parameter.finishHash_,
98 LedgerReplayParameters::TASK_TIMEOUT,
100 "LedgerReplayTask",
102 app.journal("LedgerReplayTask"))
103 , inboundLedgers_(inboundLedgers)
104 , replayer_(replayer)
105 , parameter_(parameter)
106 , maxTimeouts_(std::max(
108 parameter.totalLedgers_ *
110 , skipListAcquirer_(skipListAcquirer)
111{
112 JLOG(journal_.trace()) << "Create " << hash_;
113}
114
116{
117 JLOG(journal_.trace()) << "Destroy " << hash_;
118}
119
120void
122{
123 JLOG(journal_.debug()) << "Task start " << hash_;
124
126 skipListAcquirer_->addDataCallback([wptr](bool good, uint256 const& hash) {
127 if (auto sptr = wptr.lock(); sptr)
128 {
129 if (!good)
130 {
131 sptr->cancel();
132 }
133 else
134 {
135 auto const skipListData = sptr->skipListAcquirer_->getData();
136 sptr->updateSkipList(
137 hash, skipListData->ledgerSeq, skipListData->skipList);
138 }
139 }
140 });
141
142 ScopedLockType sl(mtx_);
143 if (!isDone())
144 {
145 trigger(sl);
146 setTimer(sl);
147 }
148}
149
150void
151LedgerReplayTask::trigger(ScopedLockType& sl)
152{
153 JLOG(journal_.trace()) << "trigger " << hash_;
154 if (!parameter_.full_)
155 return;
156
157 if (!parent_)
158 {
159 parent_ = app_.getLedgerMaster().getLedgerByHash(parameter_.startHash_);
160 if (!parent_)
161 {
162 parent_ = inboundLedgers_.acquire(
163 parameter_.startHash_,
164 parameter_.startSeq_,
165 InboundLedger::Reason::GENERIC);
166 }
167 if (parent_)
168 {
169 JLOG(journal_.trace())
170 << "Got start ledger " << parameter_.startHash_ << " for task "
171 << hash_;
172 }
173 }
174
175 tryAdvance(sl);
176}
177
178void
179LedgerReplayTask::deltaReady(uint256 const& deltaHash)
180{
181 JLOG(journal_.trace()) << "Delta " << deltaHash << " ready for task "
182 << hash_;
183 ScopedLockType sl(mtx_);
184 if (!isDone())
185 tryAdvance(sl);
186}
187
188void
189LedgerReplayTask::tryAdvance(ScopedLockType& sl)
190{
191 JLOG(journal_.trace()) << "tryAdvance task " << hash_
192 << (parameter_.full_ ? ", full parameter"
193 : ", waiting to fill parameter")
194 << ", deltaIndex=" << deltaToBuild_
195 << ", totalDeltas=" << deltas_.size() << ", parent "
196 << (parent_ ? parent_->info().hash : uint256());
197
198 bool shouldTry = parent_ && parameter_.full_ &&
199 parameter_.totalLedgers_ - 1 == deltas_.size();
200 if (!shouldTry)
201 return;
202
203 try
204 {
205 for (; deltaToBuild_ < deltas_.size(); ++deltaToBuild_)
206 {
207 auto& delta = deltas_[deltaToBuild_];
208 XRPL_ASSERT(
209 parent_->seq() + 1 == delta->ledgerSeq_,
210 "ripple::LedgerReplayTask::tryAdvance : consecutive sequence");
211 if (auto l = delta->tryBuild(parent_); l)
212 {
213 JLOG(journal_.debug())
214 << "Task " << hash_ << " got ledger " << l->info().hash
215 << " deltaIndex=" << deltaToBuild_
216 << " totalDeltas=" << deltas_.size();
217 parent_ = l;
218 }
219 else
220 return;
221 }
222
223 complete_ = true;
224 JLOG(journal_.info()) << "Completed " << hash_;
225 }
226 catch (std::runtime_error const&)
227 {
228 failed_ = true;
229 }
230}
231
232void
233LedgerReplayTask::updateSkipList(
234 uint256 const& hash,
235 std::uint32_t seq,
236 std::vector<uint256> const& sList)
237{
238 {
239 ScopedLockType sl(mtx_);
240 if (isDone())
241 return;
242 if (!parameter_.update(hash, seq, sList))
243 {
244 JLOG(journal_.error()) << "Parameter update failed " << hash_;
245 failed_ = true;
246 return;
247 }
248 }
249
250 replayer_.createDeltas(shared_from_this());
251 ScopedLockType sl(mtx_);
252 if (!isDone())
253 trigger(sl);
254}
255
256void
257LedgerReplayTask::onTimer(bool progress, ScopedLockType& sl)
258{
259 JLOG(journal_.trace()) << "mTimeouts=" << timeouts_ << " for " << hash_;
260 if (timeouts_ > maxTimeouts_)
261 {
262 failed_ = true;
263 JLOG(journal_.debug())
264 << "LedgerReplayTask Failed, too many timeouts " << hash_;
265 }
266 else
267 {
268 trigger(sl);
269 }
270}
271
273LedgerReplayTask::pmDowncast()
274{
275 return shared_from_this();
276}
277
278void
279LedgerReplayTask::addDelta(std::shared_ptr<LedgerDeltaAcquire> const& delta)
280{
281 std::weak_ptr<LedgerReplayTask> wptr = shared_from_this();
282 delta->addDataCallback(
283 parameter_.reason_, [wptr](bool good, uint256 const& hash) {
284 if (auto sptr = wptr.lock(); sptr)
285 {
286 if (!good)
287 sptr->cancel();
288 else
289 sptr->deltaReady(hash);
290 }
291 });
292
293 ScopedLockType sl(mtx_);
294 if (!isDone())
295 {
296 JLOG(journal_.trace())
297 << "addDelta task " << hash_ << " deltaIndex=" << deltaToBuild_
298 << " totalDeltas=" << deltas_.size();
299 XRPL_ASSERT(
300 deltas_.empty() ||
301 deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_,
302 "ripple::LedgerReplayTask::addDelta : no deltas or consecutive "
303 "sequence", );
304 deltas_.push_back(delta);
305 }
306}
307
308bool
309LedgerReplayTask::finished() const
310{
311 ScopedLockType sl(mtx_);
312 return isDone();
313}
314
315} // namespace ripple
Stream debug() const
Definition: Journal.h:317
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
Manages the lifetime of inbound ledgers.
TaskParameter(InboundLedger::Reason r, uint256 const &finishLedgerHash, std::uint32_t totalNumLedgers)
constructor
bool update(uint256 const &hash, std::uint32_t seq, std::vector< uint256 > const &sList)
fill all the fields that was not filled during construction
bool canMergeInto(TaskParameter const &existingTask) const
check if this task can be merged into an existing task
void init()
Start the task.
std::shared_ptr< SkipListAcquire > skipListAcquirer_
LedgerReplayTask(Application &app, InboundLedgers &inboundLedgers, LedgerReplayer &replayer, std::shared_ptr< SkipListAcquire > &skipListAcquirer, TaskParameter &&parameter)
Constructor.
Manages the lifetime of ledger replay tasks.
This class is an "active" object.
beast::Journal journal_
uint256 const hash_
The hash of the object (in practice, always a ledger) we are trying to fetch.
bool isNonZero() const
Definition: base_uint.h:544
T emplace_back(T... args)
T find(T... args)
T lock(T... args)
T max(T... args)
std::uint32_t constexpr TASK_MAX_TIMEOUTS_MINIMUM
std::uint32_t constexpr MAX_QUEUED_TASKS
std::uint32_t constexpr TASK_MAX_TIMEOUTS_MULTIPLIER
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ jtREPLAY_TASK
Definition: Job.h:61
T size(T... args)