xrpld
Loading...
Searching...
No Matches
LedgerReplayTask.cpp
1#include <xrpld/app/ledger/LedgerReplayTask.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/LedgerDeltaAcquire.h>
8#include <xrpld/app/ledger/detail/SkipListAcquire.h>
9#include <xrpld/app/ledger/detail/TimeoutCounter.h>
10#include <xrpld/app/main/Application.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
17#include <algorithm>
18#include <cstdint>
19#include <memory>
20#include <stdexcept>
21#include <vector>
22
23namespace xrpl {
24
27 uint256 const& finishLedgerHash,
28 std::uint32_t totalNumLedgers)
29 : reason(r), finishHash(finishLedgerHash), totalLedgers(totalNumLedgers)
30{
31 XRPL_ASSERT(
32 finishLedgerHash.isNonZero() && totalNumLedgers > 0,
33 "xrpl::LedgerReplayTask::TaskParameter::TaskParameter : valid "
34 "inputs");
35}
36
37bool
39 uint256 const& hash,
40 std::uint32_t seq,
41 std::vector<uint256> const& sList)
42{
43 if (finishHash != hash || sList.size() + 1 < totalLedgers || full)
44 return false;
45
46 finishSeq = seq;
47 skipList = sList;
48 skipList.emplace_back(finishHash);
50 XRPL_ASSERT(
51 startHash.isNonZero(),
52 "xrpl::LedgerReplayTask::TaskParameter::update : nonzero start hash");
54 full = true;
55 return true;
56}
57
58bool
60{
61 if (reason == existingTask.reason)
62 {
63 if (finishHash == existingTask.finishHash && totalLedgers <= existingTask.totalLedgers)
64 {
65 return true;
66 }
67
68 if (existingTask.full)
69 {
70 auto const& exList = existingTask.skipList;
71 if (auto i = std::ranges::find(exList, finishHash); i != exList.end())
72 {
73 return existingTask.totalLedgers >= totalLedgers + (exList.end() - i) - 1;
74 }
75 }
76 }
77
78 return false;
79}
80
82 Application& app,
83 InboundLedgers& inboundLedgers,
84 LedgerReplayer& replayer,
85 std::shared_ptr<SkipListAcquire>& skipListAcquirer,
86 TaskParameter const& parameter)
88 app,
89 parameter.finishHash,
90 ledger_replay_parameters::kTaskTimeout,
91 {.jobType = JtReplayTask,
92 .jobName = "LedReplTask",
94 app.getJournal("LedgerReplayTask"))
95 , inboundLedgers_(inboundLedgers)
96 , replayer_(replayer)
97 , parameter_(parameter)
98 , maxTimeouts_(
102 , skipListAcquirer_(skipListAcquirer)
103{
104 JLOG(journal_.trace()) << "Create " << hash_;
105}
106
108{
109 JLOG(journal_.trace()) << "Destroy " << hash_;
110}
111
112void
114{
115 JLOG(journal_.debug()) << "Task start " << hash_;
116
118 skipListAcquirer_->addDataCallback([wptr](bool good, uint256 const& hash) {
119 if (auto sptr = wptr.lock(); sptr)
120 {
121 if (!good)
122 {
123 sptr->cancel();
124 }
125 else
126 {
127 auto const skipListData = sptr->skipListAcquirer_->getData();
128 sptr->updateSkipList(hash, skipListData->ledgerSeq, skipListData->skipList);
129 }
130 }
131 });
132
134 if (!isDone())
135 {
136 trigger(sl);
137 setTimer(sl);
138 }
139}
140
141void
143{
144 JLOG(journal_.trace()) << "trigger " << hash_;
145 if (!parameter_.full)
146 return;
147
148 if (!parent_)
149 {
150 parent_ = app_.getLedgerMaster().getLedgerByHash(parameter_.startHash);
151 if (!parent_)
152 {
153 parent_ = inboundLedgers_.acquire(
155 }
156 if (parent_)
157 {
158 JLOG(journal_.trace())
159 << "Got start ledger " << parameter_.startHash << " for task " << hash_;
160 }
161 }
162
163 tryAdvance(sl);
164}
165
166void
168{
169 JLOG(journal_.trace()) << "Delta " << deltaHash << " ready for task " << hash_;
171 if (!isDone())
172 tryAdvance(sl);
173}
174
175void
177{
178 JLOG(journal_.trace()) << "tryAdvance task " << hash_
179 << (parameter_.full ? ", full parameter" : ", waiting to fill parameter")
180 << ", deltaIndex=" << deltaToBuild_ << ", totalDeltas=" << deltas_.size()
181 << ", parent " << (parent_ ? parent_->header().hash : uint256());
182
183 bool const shouldTry =
184 parent_ && parameter_.full && parameter_.totalLedgers - 1 == deltas_.size();
185 if (!shouldTry)
186 return;
187
188 try
189 {
190 for (; deltaToBuild_ < deltas_.size(); ++deltaToBuild_)
191 {
192 auto& delta = deltas_[deltaToBuild_];
193 XRPL_ASSERT(
194 parent_->seq() + 1 == delta->ledgerSeq_,
195 "xrpl::LedgerReplayTask::tryAdvance : consecutive sequence");
196 if (auto l = delta->tryBuild(parent_); l)
197 {
198 JLOG(journal_.debug())
199 << "Task " << hash_ << " got ledger " << l->header().hash
200 << " deltaIndex=" << deltaToBuild_ << " totalDeltas=" << deltas_.size();
201 parent_ = l;
202 }
203 else
204 {
205 return;
206 }
207 }
208
209 complete_ = true;
210 JLOG(journal_.info()) << "Completed " << hash_;
211 }
212 catch (std::runtime_error const&)
213 {
214 failed_ = true;
215 }
216}
217
218void
220 uint256 const& hash,
221 std::uint32_t seq,
222 std::vector<uint256> const& sList)
223{
224 {
225 ScopedLockType const sl(mtx_);
226 if (isDone())
227 return;
228 if (!parameter_.update(hash, seq, sList))
229 {
230 JLOG(journal_.error()) << "Parameter update failed " << hash_;
231 failed_ = true;
232 return;
233 }
234 }
235
236 replayer_.createDeltas(shared_from_this());
238 if (!isDone())
239 trigger(sl);
240}
241
242void
244{
245 JLOG(journal_.trace()) << "timeouts_=" << timeouts_ << " for " << hash_;
247 {
248 failed_ = true;
249 JLOG(journal_.debug()) << "LedgerReplayTask Failed, too many timeouts " << hash_;
250 }
251 else
252 {
253 trigger(sl);
254 }
255}
256
262
263void
265{
267 delta->addDataCallback(parameter_.reason, [wptr](bool good, uint256 const& hash) {
268 if (auto sptr = wptr.lock(); sptr)
269 {
270 if (!good)
271 {
272 sptr->cancel();
273 }
274 else
275 {
276 sptr->deltaReady(hash);
277 }
278 }
279 });
280
281 ScopedLockType const sl(mtx_);
282 if (!isDone())
283 {
284 JLOG(journal_.trace()) << "addDelta task " << hash_ << " deltaIndex=" << deltaToBuild_
285 << " totalDeltas=" << deltas_.size();
286 XRPL_ASSERT(
287 deltas_.empty() || deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_,
288 "xrpl::LedgerReplayTask::addDelta : no deltas or consecutive "
289 "sequence");
290 deltas_.push_back(delta);
291 }
292}
293
294bool
296{
297 ScopedLockType const sl(mtx_);
298 return isDone();
299}
300
301} // namespace xrpl
bool isNonZero() const
Definition base_uint.h:567
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 trigger(ScopedLockType &sl)
Trigger another round.
void onTimer(bool progress, ScopedLockType &sl) override
Hook called from invokeOnTimer().
LedgerReplayer & replayer_
LedgerReplayTask(Application &app, InboundLedgers &inboundLedgers, LedgerReplayer &replayer, std::shared_ptr< SkipListAcquire > &skipListAcquirer, TaskParameter const &parameter)
Constructor.
InboundLedgers & inboundLedgers_
void updateSkipList(uint256 const &hash, std::uint32_t seq, std::vector< uint256 > const &sList)
Update this task (by a SkipListAcquire subtask) when skip list is ready.
void tryAdvance(ScopedLockType &sl)
Try to build more ledgers.
void deltaReady(uint256 const &deltaHash)
Notify this task (by a LedgerDeltaAcquire subtask) that a delta is ready.
std::weak_ptr< TimeoutCounter > pmDowncast() override
Return a weak pointer to this.
std::vector< std::shared_ptr< LedgerDeltaAcquire > > deltas_
bool finished() const
return if the task is finished
void addDelta(std::shared_ptr< LedgerDeltaAcquire > const &delta)
add a new LedgerDeltaAcquire subtask
std::shared_ptr< Ledger const > parent_
std::shared_ptr< SkipListAcquire > skipListAcquirer_
void init()
Start the task.
Manages the lifetime of ledger replay tasks.
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_.
T find(T... args)
T lock(T... args)
T max(T... args)
constexpr std::uint32_t kTaskMaxTimeoutsMultiplier
constexpr std::uint32_t kMaxQueuedTasks
constexpr std::uint32_t kTaskMaxTimeoutsMinimum
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 size(T... args)