rippled
Loading...
Searching...
No Matches
InboundLedgers.cpp
1#include <xrpld/app/ledger/InboundLedgers.h>
2#include <xrpld/app/ledger/LedgerMaster.h>
3#include <xrpld/app/main/Application.h>
4
5#include <xrpl/basics/DecayingSample.h>
6#include <xrpl/basics/Log.h>
7#include <xrpl/basics/scope.h>
8#include <xrpl/beast/container/aged_map.h>
9#include <xrpl/core/JobQueue.h>
10#include <xrpl/core/PerfLog.h>
11#include <xrpl/protocol/jss.h>
12#include <xrpl/server/NetworkOPs.h>
13
14#include <exception>
15#include <memory>
16#include <mutex>
17#include <vector>
18
19namespace xrpl {
20
22{
23private:
26 // measures ledgers per second, constants are important
29
30public:
31 // How long before we try again to acquire the same ledger
32 static constexpr std::chrono::minutes const kReacquireInterval{5};
33
35 Application& app,
36 clock_type& clock,
37 beast::insight::Collector::ptr const& collector,
39 : app_(app)
40 , fetchRate_(clock.now())
41 , j_(app.journal("InboundLedger"))
42 , m_clock(clock)
43 , mRecentFailures(clock)
44 , mCounter(collector->make_counter("ledger_fetches"))
45 , mPeerSetBuilder(std::move(peerSetBuilder))
46 {
47 }
48
51 acquire(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
52 {
53 auto doAcquire = [&, seq, reason]() -> std::shared_ptr<Ledger const> {
54 XRPL_ASSERT(
55 hash.isNonZero(), "xrpl::InboundLedgersImp::acquire::doAcquire : nonzero hash");
56
57 // probably not the right rule
60 return {};
61
62 bool isNew = true;
64 {
66 if (stopping_)
67 {
68 return {};
69 }
70
71 auto it = mLedgers.find(hash);
72 if (it != mLedgers.end())
73 {
74 isNew = false;
75 inbound = it->second;
76 }
77 else
78 {
80 app_, hash, seq, reason, std::ref(m_clock), mPeerSetBuilder->build());
81 mLedgers.emplace(hash, inbound);
82 inbound->init(sl);
83 ++mCounter;
84 }
85 }
86
87 if (inbound->isFailed())
88 return {};
89
90 if (!isNew)
91 inbound->update(seq);
92
93 if (!inbound->isComplete())
94 return {};
95
96 return inbound->getLedger();
97 };
98 using namespace std::chrono_literals;
100 perf::measureDurationAndLog(doAcquire, "InboundLedgersImp::acquire", 500ms, j_);
101
102 return ledger;
103 }
104
105 void
106 acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
107 {
109 try
110 {
111 if (pendingAcquires_.contains(hash))
112 return;
113 pendingAcquires_.insert(hash);
114 scope_unlock unlock(lock);
115 acquire(hash, seq, reason);
116 }
117 catch (std::exception const& e)
118 {
119 JLOG(j_.warn()) << "Exception thrown for acquiring new inbound ledger " << hash << ": "
120 << e.what();
121 }
122 catch (...)
123 {
124 JLOG(j_.warn()) << "Unknown exception thrown for acquiring new inbound ledger " << hash;
125 }
126 pendingAcquires_.erase(hash);
127 }
128
130 find(uint256 const& hash) override
131 {
132 XRPL_ASSERT(hash.isNonZero(), "xrpl::InboundLedgersImp::find : nonzero input");
133
135
136 {
138
139 auto it = mLedgers.find(hash);
140 if (it != mLedgers.end())
141 {
142 ret = it->second;
143 }
144 }
145
146 return ret;
147 }
148
149 /*
150 This gets called when
151 "We got some data from an inbound ledger"
152
153 inboundLedgerTrigger:
154 "What do we do with this partial data?"
155 Figures out what to do with the responses to our requests for information.
156
157 */
158 // means "We got some data from an inbound ledger"
159
160 // VFALCO TODO Remove the dependency on the Peer object.
163 bool
165 LedgerHash const& hash,
168 {
169 if (auto ledger = find(hash))
170 {
171 JLOG(j_.trace()) << "Got data (" << packet->nodes().size()
172 << ") for acquiring ledger: " << hash;
173
174 // Stash the data for later processing and see if we need to
175 // dispatch
176 if (ledger->gotData(std::weak_ptr<Peer>(peer), packet))
178 jtLEDGER_DATA, "ProcessLData", [ledger]() { ledger->runData(); });
179
180 return true;
181 }
182
183 JLOG(j_.trace()) << "Got data for ledger " << hash << " which we're no longer acquiring";
184
185 // If it's state node data, stash it because it still might be
186 // useful.
187 if (packet->type() == protocol::liAS_NODE)
188 {
190 jtLEDGER_DATA, "GotStaleData", [this, packet]() { gotStaleData(packet); });
191 }
192
193 return false;
194 }
195
196 void
197 logFailure(uint256 const& h, std::uint32_t seq) override
198 {
200
201 mRecentFailures.emplace(h, seq);
202 }
203
204 bool
205 isFailure(uint256 const& h) override
206 {
208
210 return mRecentFailures.find(h) != mRecentFailures.end();
211 }
212
219 void
221 {
222 Serializer s;
223 try
224 {
225 for (int i = 0; i < packet_ptr->nodes().size(); ++i)
226 {
227 auto const& node = packet_ptr->nodes(i);
228
229 if (!node.has_nodeid() || !node.has_nodedata())
230 return;
231
232 auto newNode = SHAMapTreeNode::makeFromWire(makeSlice(node.nodedata()));
233
234 if (!newNode)
235 return;
236
237 s.erase();
238 newNode->serializeWithPrefix(s);
239
241 newNode->getHash().as_uint256(), std::make_shared<Blob>(s.begin(), s.end()));
242 }
243 }
244 catch (std::exception const&)
245 {
246 }
247 }
248
249 void
250 clearFailures() override
251 {
253
254 mRecentFailures.clear();
255 mLedgers.clear();
256 }
257
259 fetchRate() override
260 {
262 return 60 * fetchRate_.value(m_clock.now());
263 }
264
265 // Should only be called with an inboundledger that has
266 // a reason of history
267 void
269 {
272 }
273
275 getInfo() override
276 {
278
280
281 {
283
284 acqs.reserve(mLedgers.size());
285 for (auto const& it : mLedgers)
286 {
287 XRPL_ASSERT(it.second, "xrpl::InboundLedgersImp::getInfo : non-null ledger");
288 acqs.push_back(it);
289 }
290 for (auto const& it : mRecentFailures)
291 {
292 if (it.second > 1)
293 ret[std::to_string(it.second)][jss::failed] = true;
294 else
295 ret[to_string(it.first)][jss::failed] = true;
296 }
297 }
298
299 for (auto const& it : acqs)
300 {
301 // getJson is expensive, so call without the lock
302 std::uint32_t seq = it.second->getSeq();
303 if (seq > 1)
304 ret[std::to_string(seq)] = it.second->getJson(0);
305 else
306 ret[to_string(it.first)] = it.second->getJson(0);
307 }
308
309 return ret;
310 }
311
312 void
313 gotFetchPack() override
314 {
316 {
318
319 acquires.reserve(mLedgers.size());
320 for (auto const& it : mLedgers)
321 {
322 XRPL_ASSERT(
323 it.second,
324 "xrpl::InboundLedgersImp::gotFetchPack : non-null "
325 "ledger");
326 acquires.push_back(it.second);
327 }
328 }
329
330 for (auto const& acquire : acquires)
331 {
332 acquire->checkLocal();
333 }
334 }
335
336 void
337 sweep() override
338 {
339 auto const start = m_clock.now();
340
341 // Make a list of things to sweep, while holding the lock
343 std::size_t total;
344
345 {
347 MapType::iterator it(mLedgers.begin());
348 total = mLedgers.size();
349
350 stuffToSweep.reserve(total);
351
352 while (it != mLedgers.end())
353 {
354 auto const la = it->second->getLastAction();
355
356 if (la > start)
357 {
358 it->second->touch();
359 ++it;
360 }
361 else if ((la + std::chrono::minutes(1)) < start)
362 {
363 stuffToSweep.push_back(it->second);
364 // shouldn't cause the actual final delete
365 // since we are holding a reference in the vector.
366 it = mLedgers.erase(it);
367 }
368 else
369 {
370 ++it;
371 }
372 }
373
375 }
376
377 JLOG(j_.debug())
378 << "Swept " << stuffToSweep.size() << " out of " << total
379 << " inbound ledgers. Duration: "
380 << std::chrono::duration_cast<std::chrono::milliseconds>(m_clock.now() - start).count()
381 << "ms";
382 }
383
384 void
385 stop() override
386 {
387 ScopedLockType lock(mLock);
388 stopping_ = true;
389 mLedgers.clear();
390 mRecentFailures.clear();
391 }
392
394 cacheSize() override
395 {
396 ScopedLockType lock(mLock);
397 return mLedgers.size();
398 }
399
400private:
402
405
406 bool stopping_ = false;
409
411
413
415
418};
419
420//------------------------------------------------------------------------------
421
424 Application& app,
426 beast::insight::Collector::ptr const& collector)
427{
428 return std::make_unique<InboundLedgersImp>(app, clock, collector, make_PeerSetBuilder(app));
429}
430
431} // namespace xrpl
T begin(T... args)
Represents a JSON value.
Definition json_value.h:130
A generic endpoint for log messages.
Definition Journal.h:40
Stream debug() const
Definition Journal.h:301
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Stream warn() const
Definition Journal.h:313
virtual time_point now() const =0
Returns the current time.
Associative container where each element is also indexed by time.
A metric for measuring an integral value.
Definition Counter.h:19
Sampling function using exponential decay to provide a continuous value.
void add(double value, time_point now)
double value(time_point now)
InboundLedgersImp(Application &app, clock_type &clock, beast::insight::Collector::ptr const &collector, std::unique_ptr< PeerSetBuilder > peerSetBuilder)
beast::aged_map< uint256, std::uint32_t > mRecentFailures
Json::Value getInfo() override
void onLedgerFetched() override
Called when a complete ledger is obtained.
static constexpr std::chrono::minutes const kReacquireInterval
std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason reason) override
std::recursive_mutex mLock
std::unique_ptr< PeerSetBuilder > mPeerSetBuilder
DecayWindow< 30, clock_type > fetchRate_
void acquireAsync(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason reason) override
std::size_t fetchRate() override
Returns the rate of historical ledger fetches per minute.
std::set< uint256 > pendingAcquires_
bool gotLedgerData(LedgerHash const &hash, std::shared_ptr< Peer > peer, std::shared_ptr< protocol::TMLedgerData > packet) override
We received a TMLedgerData from a peer.
beast::Journal const j_
std::size_t cacheSize() override
beast::insight::Counter mCounter
void clearFailures() override
bool isFailure(uint256 const &h) override
void gotStaleData(std::shared_ptr< protocol::TMLedgerData > packet_ptr) override
We got some data for a ledger we are no longer acquiring Since we paid the price to receive it,...
void logFailure(uint256 const &h, std::uint32_t seq) override
std::shared_ptr< InboundLedger > find(uint256 const &hash) override
Manages the lifetime of inbound ledgers.
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition JobQueue.h:146
void addFetchPack(uint256 const &hash, std::shared_ptr< Blob > data)
virtual bool isNeedNetworkLedger()=0
static intr_ptr::SharedPtr< SHAMapTreeNode > makeFromWire(Slice rawNode)
Blob::iterator begin()
Definition Serializer.h:226
Blob::iterator end()
Definition Serializer.h:231
virtual JobQueue & getJobQueue()=0
virtual NetworkOPs & getOPs()=0
virtual LedgerMaster & getLedgerMaster()=0
bool isNonZero() const
Definition base_uint.h:516
Automatically unlocks and re-locks a unique_lock object.
Definition scope.h:202
T clear(T... args)
T emplace(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T is_same_v
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:26
std::enable_if< is_aged_container< AgedContainer >::value, std::size_t >::type expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
STL namespace.
auto measureDurationAndLog(Func &&func, std::string const &actionDescription, std::chrono::duration< Rep, Period > maxDelay, beast::Journal const &journal)
Definition PerfLog.h:162
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:600
std::unique_ptr< InboundLedgers > make_InboundLedgers(Application &app, InboundLedgers::clock_type &clock, beast::insight::Collector::ptr const &collector)
@ jtLEDGER_DATA
Definition Job.h:45
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:215
std::unique_ptr< PeerSetBuilder > make_PeerSetBuilder(Application &app)
Definition PeerSet.cpp:122
T push_back(T... args)
T ref(T... args)
T reserve(T... args)
T size(T... args)
T to_string(T... args)
T what(T... args)