rippled
Loading...
Searching...
No Matches
LedgerReplayer.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/LedgerReplayer.h>
21#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
22#include <xrpld/app/ledger/detail/SkipListAcquire.h>
23#include <xrpld/core/JobQueue.h>
24
25namespace ripple {
26
28 Application& app,
29 InboundLedgers& inboundLedgers,
31 : app_(app)
32 , inboundLedgers_(inboundLedgers)
33 , peerSetBuilder_(std::move(peerSetBuilder))
34 , j_(app.journal("LedgerReplayer"))
35{
36}
37
39{
41 tasks_.clear();
42}
43
44void
47 uint256 const& finishLedgerHash,
48 std::uint32_t totalNumLedgers)
49{
50 XRPL_ASSERT(
51 finishLedgerHash.isNonZero() && totalNumLedgers > 0 &&
53 "ripple::LedgerReplayer::replay : valid inputs");
54
56 r, finishLedgerHash, totalNumLedgers);
57
60 bool newSkipList = false;
61 {
63 if (app_.isStopping())
64 return;
66 {
67 JLOG(j_.info()) << "Too many replay tasks, dropping new task "
68 << parameter.finishHash_;
69 return;
70 }
71
72 for (auto const& t : tasks_)
73 {
74 if (parameter.canMergeInto(t->getTaskParameter()))
75 {
76 JLOG(j_.info()) << "Task " << parameter.finishHash_ << " with "
77 << totalNumLedgers
78 << " ledgers merged into an existing task.";
79 return;
80 }
81 }
82 JLOG(j_.info()) << "Replay " << totalNumLedgers
83 << " ledgers. Finish ledger hash "
84 << parameter.finishHash_;
85
86 auto i = skipLists_.find(parameter.finishHash_);
87 if (i != skipLists_.end())
88 skipList = i->second.lock();
89
90 if (!skipList) // cannot find, or found but cannot lock
91 {
92 skipList = std::make_shared<SkipListAcquire>(
93 app_,
95 parameter.finishHash_,
96 peerSetBuilder_->build());
97 skipLists_[parameter.finishHash_] = skipList;
98 newSkipList = true;
99 }
100
101 task = std::make_shared<LedgerReplayTask>(
102 app_, inboundLedgers_, *this, skipList, std::move(parameter));
103 tasks_.push_back(task);
104 }
105
106 if (newSkipList)
107 skipList->init(1);
108 // task init after skipList init, could save a timeout
109 task->init();
110}
111
112void
114{
115 {
116 // TODO for use cases like Consensus (i.e. totalLedgers = 1 or small):
117 // check if the last closed or validated ledger l the local node has
118 // is in the skip list and is an ancestor of parameter.startLedger
119 // that has to be downloaded, if so expand the task to start with l.
120 }
121
122 auto const& parameter = task->getTaskParameter();
123 JLOG(j_.trace()) << "Creating " << parameter.totalLedgers_ - 1 << " deltas";
124 if (parameter.totalLedgers_ > 1)
125 {
126 auto skipListItem = std::find(
127 parameter.skipList_.begin(),
128 parameter.skipList_.end(),
129 parameter.startHash_);
130 if (skipListItem == parameter.skipList_.end() ||
131 ++skipListItem == parameter.skipList_.end())
132 {
133 JLOG(j_.error()) << "Task parameter error when creating deltas "
134 << parameter.finishHash_;
135 return;
136 }
137
138 for (std::uint32_t seq = parameter.startSeq_ + 1;
139 seq <= parameter.finishSeq_ &&
140 skipListItem != parameter.skipList_.end();
141 ++seq, ++skipListItem)
142 {
144 bool newDelta = false;
145 {
147 if (app_.isStopping())
148 return;
149 auto i = deltas_.find(*skipListItem);
150 if (i != deltas_.end())
151 delta = i->second.lock();
152
153 if (!delta) // cannot find, or found but cannot lock
154 {
155 delta = std::make_shared<LedgerDeltaAcquire>(
156 app_,
158 *skipListItem,
159 seq,
160 peerSetBuilder_->build());
161 deltas_[*skipListItem] = delta;
162 newDelta = true;
163 }
164 }
165
166 task->addDelta(delta);
167 if (newDelta)
168 delta->init(1);
169 }
170 }
171}
172
173void
175 LedgerInfo const& info,
176 boost::intrusive_ptr<SHAMapItem const> const& item)
177{
179 {
181 auto i = skipLists_.find(info.hash);
182 if (i == skipLists_.end())
183 return;
184 skipList = i->second.lock();
185 if (!skipList)
186 {
187 skipLists_.erase(i);
188 return;
189 }
190 }
191
192 if (skipList)
193 skipList->processData(info.seq, item);
194}
195
196void
198 LedgerInfo const& info,
200{
202 {
204 auto i = deltas_.find(info.hash);
205 if (i == deltas_.end())
206 return;
207 delta = i->second.lock();
208 if (!delta)
209 {
210 deltas_.erase(i);
211 return;
212 }
213 }
214
215 if (delta)
216 delta->processData(info, std::move(txns));
217}
218
219void
221{
222 auto const start = std::chrono::steady_clock::now();
223 {
225 JLOG(j_.debug()) << "Sweeping, LedgerReplayer has " << tasks_.size()
226 << " tasks, " << skipLists_.size()
227 << " skipLists, and " << deltas_.size() << " deltas.";
228
229 tasks_.erase(
231 tasks_.begin(),
232 tasks_.end(),
233 [this](auto const& t) -> bool {
234 if (t->finished())
235 {
236 JLOG(j_.debug()) << "Sweep task "
237 << t->getTaskParameter().finishHash_;
238 return true;
239 }
240 return false;
241 }),
242 tasks_.end());
243
244 auto removeCannotLocked = [](auto& subTasks) {
245 for (auto it = subTasks.begin(); it != subTasks.end();)
246 {
247 if (auto item = it->second.lock(); !item)
248 {
249 it = subTasks.erase(it);
250 }
251 else
252 ++it;
253 }
254 };
255 removeCannotLocked(skipLists_);
256 removeCannotLocked(deltas_);
257 }
258 JLOG(j_.debug()) << " LedgerReplayer sweep lock duration "
259 << std::chrono::duration_cast<std::chrono::milliseconds>(
261 .count()
262 << "ms";
263}
264
265void
266LedgerReplayer::stop()
267{
268 JLOG(j_.info()) << "Stopping...";
269 {
272 tasks_.begin(), tasks_.end(), [](auto& i) { i->cancel(); });
273 tasks_.clear();
274 auto lockAndCancel = [](auto& i) {
275 if (auto sptr = i.second.lock(); sptr)
276 {
277 sptr->cancel();
278 }
279 };
280 std::for_each(skipLists_.begin(), skipLists_.end(), lockAndCancel);
281 skipLists_.clear();
282 std::for_each(deltas_.begin(), deltas_.end(), lockAndCancel);
283 deltas_.clear();
284 }
285
286 JLOG(j_.info()) << "Stopped";
287}
288
289} // namespace ripple
Stream error() const
Definition: Journal.h:345
Stream debug() const
Definition: Journal.h:327
Stream info() const
Definition: Journal.h:333
Stream trace() const
Severity stream access functions.
Definition: Journal.h:321
virtual bool isStopping() const =0
Manages the lifetime of inbound ledgers.
bool canMergeInto(TaskParameter const &existingTask) const
check if this task can be merged into an existing task
void gotReplayDelta(LedgerInfo const &info, std::map< std::uint32_t, std::shared_ptr< STTx const > > &&txns)
Process a ledger delta (extracted from a TMReplayDeltaResponse message)
void createDeltas(std::shared_ptr< LedgerReplayTask > task)
Create LedgerDeltaAcquire subtasks for the LedgerReplayTask task.
void sweep()
Remove completed tasks.
std::vector< std::shared_ptr< LedgerReplayTask > > tasks_
std::unique_ptr< PeerSetBuilder > peerSetBuilder_
LedgerReplayer(Application &app, InboundLedgers &inboundLedgers, std::unique_ptr< PeerSetBuilder > peerSetBuilder)
void gotSkipList(LedgerInfo const &info, boost::intrusive_ptr< SHAMapItem const > const &data)
Process a skip list (extracted from a TMProofPathResponse message)
hash_map< uint256, std::weak_ptr< SkipListAcquire > > skipLists_
void replay(InboundLedger::Reason r, uint256 const &finishLedgerHash, std::uint32_t totalNumLedgers)
Replay a range of ledgers.
InboundLedgers & inboundLedgers_
hash_map< uint256, std::weak_ptr< LedgerDeltaAcquire > > deltas_
bool isNonZero() const
Definition: base_uint.h:544
T find(T... args)
T for_each(T... args)
std::uint32_t constexpr MAX_TASK_SIZE
std::uint32_t constexpr MAX_TASKS
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
STL namespace.
T remove_if(T... args)
Information about the notional ledger backing the view.
Definition: LedgerHeader.h:34