rippled
Loading...
Searching...
No Matches
Livecache.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 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#ifndef RIPPLE_PEERFINDER_LIVECACHE_H_INCLUDED
21#define RIPPLE_PEERFINDER_LIVECACHE_H_INCLUDED
22
23#include <xrpld/peerfinder/PeerfinderManager.h>
24#include <xrpld/peerfinder/detail/Tuning.h>
25#include <xrpld/peerfinder/detail/iosformat.h>
26
27#include <xrpl/basics/Log.h>
28#include <xrpl/basics/random.h>
29#include <xrpl/beast/container/aged_map.h>
30#include <xrpl/beast/utility/maybe_const.h>
31
32#include <boost/intrusive/list.hpp>
33#include <boost/iterator/transform_iterator.hpp>
34
35#include <algorithm>
36
37namespace ripple {
38namespace PeerFinder {
39
40template <class>
41class Livecache;
42
43namespace detail {
44
46{
47public:
48 explicit LivecacheBase() = default;
49
50protected:
51 struct Element : boost::intrusive::list_base_hook<>
52 {
53 Element(Endpoint const& endpoint_) : endpoint(endpoint_)
54 {
55 }
56
58 };
59
60 using list_type = boost::intrusive::
61 make_list<Element, boost::intrusive::constant_time_size<false>>::type;
62
63public:
68 template <bool IsConst>
69 class Hop
70 {
71 public:
72 // Iterator transformation to extract the endpoint from Element
73 struct Transform
74 {
77
78 explicit Transform() = default;
79
80 Endpoint const&
81 operator()(Element const& e) const
82 {
83 return e.endpoint;
84 }
85 };
86
87 public:
88 using iterator = boost::
89 transform_iterator<Transform, typename list_type::const_iterator>;
90
92
93 using reverse_iterator = boost::transform_iterator<
95 typename list_type::const_reverse_iterator>;
96
98
100 begin() const
101 {
102 return iterator(m_list.get().cbegin(), Transform());
103 }
104
106 cbegin() const
107 {
108 return iterator(m_list.get().cbegin(), Transform());
109 }
110
112 end() const
113 {
114 return iterator(m_list.get().cend(), Transform());
115 }
116
118 cend() const
119 {
120 return iterator(m_list.get().cend(), Transform());
121 }
122
124 rbegin() const
125 {
126 return reverse_iterator(m_list.get().crbegin(), Transform());
127 }
128
130 crbegin() const
131 {
132 return reverse_iterator(m_list.get().crbegin(), Transform());
133 }
134
136 rend() const
137 {
138 return reverse_iterator(m_list.get().crend(), Transform());
139 }
140
142 crend() const
143 {
144 return reverse_iterator(m_list.get().crend(), Transform());
145 }
146
147 // move the element to the end of the container
148 void
150 {
151 auto& e(const_cast<Element&>(*pos.base()));
152 m_list.get().erase(m_list.get().iterator_to(e));
153 m_list.get().push_back(e);
154 }
155
156 private:
157 explicit Hop(
159 : m_list(list)
160 {
161 }
162
163 friend class LivecacheBase;
164
168 };
169
170protected:
171 // Work-around to call Hop's private constructor from Livecache
172 template <bool IsConst>
173 static Hop<IsConst>
175 {
176 return Hop<IsConst>(list);
177 }
178};
179
180} // namespace detail
181
182//------------------------------------------------------------------------------
183
196template <class Allocator = std::allocator<char>>
198{
199private:
202 Element,
205 Allocator>;
206
209
210public:
211 using allocator_type = Allocator;
212
214 Livecache(
215 clock_type& clock,
216 beast::Journal journal,
217 Allocator alloc = Allocator());
218
219 //
220 // Iteration by hops
221 //
222 // The range [begin, end) provides a sequence of list_type
223 // where each list contains endpoints at a given hops.
224 //
225
226 class hops_t
227 {
228 private:
229 // An endpoint at hops=0 represents the local node.
230 // Endpoints coming in at maxHops are stored at maxHops +1,
231 // but not given out (since they would exceed maxHops). They
232 // are used for automatic connection attempts.
233 //
236
237 template <bool IsConst>
239 {
240 using first_argument = typename lists_type::value_type;
242
243 explicit Transform() = default;
244
247 IsConst,
248 typename lists_type::value_type>::type& list) const
249 {
250 return make_hop<IsConst>(list);
251 }
252 };
253
254 public:
255 using iterator = boost::
256 transform_iterator<Transform<false>, typename lists_type::iterator>;
257
258 using const_iterator = boost::transform_iterator<
260 typename lists_type::const_iterator>;
261
262 using reverse_iterator = boost::transform_iterator<
264 typename lists_type::reverse_iterator>;
265
266 using const_reverse_iterator = boost::transform_iterator<
268 typename lists_type::const_reverse_iterator>;
269
272 {
274 }
275
277 begin() const
278 {
280 }
281
283 cbegin() const
284 {
286 }
287
290 {
292 }
293
295 end() const
296 {
298 }
299
301 cend() const
302 {
304 }
305
308 {
310 }
311
313 rbegin() const
314 {
316 }
317
319 crbegin() const
320 {
322 }
323
326 {
328 }
329
331 rend() const
332 {
334 }
335
337 crend() const
338 {
340 }
341
343 void
344 shuffle();
345
347 histogram() const;
348
349 private:
350 explicit hops_t(Allocator const& alloc);
351
352 void
353 insert(Element& e);
354
355 // Reinsert e at a new hops
356 void
358
359 void
360 remove(Element& e);
361
362 friend class Livecache;
366
368 bool
369 empty() const
370 {
371 return m_cache.empty();
372 }
373
375 typename cache_type::size_type
376 size() const
377 {
378 return m_cache.size();
379 }
380
382 void
383 expire();
384
386 void
387 insert(Endpoint const& ep);
388
390 void
392};
393
394//------------------------------------------------------------------------------
395
396template <class Allocator>
398 clock_type& clock,
399 beast::Journal journal,
400 Allocator alloc)
401 : m_journal(journal), m_cache(clock, alloc), hops(alloc)
402{
403}
404
405template <class Allocator>
406void
408{
409 std::size_t n(0);
410 typename cache_type::time_point const expired(
412 for (auto iter(m_cache.chronological.begin());
413 iter != m_cache.chronological.end() && iter.when() <= expired;)
414 {
415 Element& e(iter->second);
416 hops.remove(e);
417 iter = m_cache.erase(iter);
418 ++n;
419 }
420 if (n > 0)
421 {
422 JLOG(m_journal.debug()) << beast::leftw(18) << "Livecache expired " << n
423 << ((n > 1) ? " entries" : " entry");
424 }
425}
426
427template <class Allocator>
428void
430{
431 // The caller already incremented hop, so if we got a
432 // message at maxHops we will store it at maxHops + 1.
433 // This means we won't give out the address to other peers
434 // but we will use it to make connections and hand it out
435 // when redirecting.
436 //
437 XRPL_ASSERT(
438 ep.hops <= (Tuning::maxHops + 1),
439 "ripple::PeerFinder::Livecache::insert : maximum input hops");
440 auto result = m_cache.emplace(ep.address, ep);
441 Element& e(result.first->second);
442 if (result.second)
443 {
444 hops.insert(e);
445 JLOG(m_journal.debug()) << beast::leftw(18) << "Livecache insert "
446 << ep.address << " at hops " << ep.hops;
447 return;
448 }
449 else if (!result.second && (ep.hops > e.endpoint.hops))
450 {
451 // Drop duplicates at higher hops
452 std::size_t const excess(ep.hops - e.endpoint.hops);
453 JLOG(m_journal.trace()) << beast::leftw(18) << "Livecache drop "
454 << ep.address << " at hops +" << excess;
455 return;
456 }
457
458 m_cache.touch(result.first);
459
460 // Address already in the cache so update metadata
461 if (ep.hops < e.endpoint.hops)
462 {
463 hops.reinsert(e, ep.hops);
464 JLOG(m_journal.debug()) << beast::leftw(18) << "Livecache update "
465 << ep.address << " at hops " << ep.hops;
466 }
467 else
468 {
469 JLOG(m_journal.trace()) << beast::leftw(18) << "Livecache refresh "
470 << ep.address << " at hops " << ep.hops;
471 }
472}
473
474template <class Allocator>
475void
477{
478 typename cache_type::time_point const expired(
480 map["size"] = size();
481 map["hist"] = hops.histogram();
482 beast::PropertyStream::Set set("entries", map);
483 for (auto iter(m_cache.cbegin()); iter != m_cache.cend(); ++iter)
484 {
485 auto const& e(iter->second);
487 item["hops"] = e.endpoint.hops;
488 item["address"] = e.endpoint.address.to_string();
490 ss << (iter.when() - expired).count();
491 item["expires"] = ss.str();
492 }
493}
494
495//------------------------------------------------------------------------------
496
497template <class Allocator>
498void
500{
501 for (auto& list : m_lists)
502 {
504 v.reserve(list.size());
505 std::copy(list.begin(), list.end(), std::back_inserter(v));
506 std::shuffle(v.begin(), v.end(), default_prng());
507 list.clear();
508 for (auto& e : v)
509 list.push_back(e);
510 }
511}
512
513template <class Allocator>
516{
517 std::string s;
518 for (auto const& h : m_hist)
519 {
520 if (!s.empty())
521 s += ", ";
522 s += std::to_string(h);
523 }
524 return s;
525}
526
527template <class Allocator>
529{
530 std::fill(m_hist.begin(), m_hist.end(), 0);
531}
532
533template <class Allocator>
534void
536{
537 XRPL_ASSERT(
539 "ripple::PeerFinder::Livecache::hops_t::insert : maximum input hops");
540 // This has security implications without a shuffle
541 m_lists[e.endpoint.hops].push_front(e);
542 ++m_hist[e.endpoint.hops];
543}
544
545template <class Allocator>
546void
548{
549 XRPL_ASSERT(
550 numHops <= Tuning::maxHops + 1,
551 "ripple::PeerFinder::Livecache::hops_t::reinsert : maximum hops input");
552
553 auto& list = m_lists[e.endpoint.hops];
554 list.erase(list.iterator_to(e));
555
556 --m_hist[e.endpoint.hops];
557
558 e.endpoint.hops = numHops;
559 insert(e);
560}
561
562template <class Allocator>
563void
565{
566 --m_hist[e.endpoint.hops];
567
568 auto& list = m_lists[e.endpoint.hops];
569 list.erase(list.iterator_to(e));
570}
571
572} // namespace PeerFinder
573} // namespace ripple
574
575#endif
T back_inserter(T... args)
T begin(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:38
A generic endpoint for log messages.
Definition Journal.h:60
Stream debug() const
Definition Journal.h:328
Stream trace() const
Severity stream access functions.
Definition Journal.h:322
virtual time_point now() const =0
Returns the current time.
Associative container where each element is also indexed by time.
beast::detail::aged_container_iterator< false, Iterator > erase(beast::detail::aged_container_iterator< is_const, Iterator > pos)
void touch(beast::detail::aged_container_iterator< is_const, Iterator > pos)
class beast::detail::aged_ordered_container::chronological_t chronological
auto emplace(Args &&... args) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
typename clock_type::time_point time_point
boost::transform_iterator< Transform< true >, typename lists_type::const_iterator > const_iterator
Definition Livecache.h:260
void shuffle()
Shuffle each hop list.
Definition Livecache.h:499
hops_t(Allocator const &alloc)
Definition Livecache.h:528
const_reverse_iterator crend() const
Definition Livecache.h:337
const_reverse_iterator rend() const
Definition Livecache.h:331
void reinsert(Element &e, std::uint32_t hops)
Definition Livecache.h:547
const_reverse_iterator rbegin() const
Definition Livecache.h:313
boost::transform_iterator< Transform< false >, typename lists_type::reverse_iterator > reverse_iterator
Definition Livecache.h:264
const_iterator cbegin() const
Definition Livecache.h:283
boost::transform_iterator< Transform< false >, typename lists_type::iterator > iterator
Definition Livecache.h:256
const_reverse_iterator crbegin() const
Definition Livecache.h:319
boost::transform_iterator< Transform< true >, typename lists_type::const_reverse_iterator > const_reverse_iterator
Definition Livecache.h:268
The Livecache holds the short-lived relayed Endpoint messages.
Definition Livecache.h:198
cache_type::size_type size() const
Returns the number of entries in the cache.
Definition Livecache.h:376
void expire()
Erase entries whose time has expired.
Definition Livecache.h:407
Livecache(clock_type &clock, beast::Journal journal, Allocator alloc=Allocator())
Create the cache.
Definition Livecache.h:397
void insert(Endpoint const &ep)
Creates or updates an existing Element based on a new message.
Definition Livecache.h:429
void onWrite(beast::PropertyStream::Map &map)
Output statistics.
Definition Livecache.h:476
class ripple::PeerFinder::Livecache::hops_t hops
bool empty() const
Returns true if the cache is empty.
Definition Livecache.h:369
A list of Endpoint at the same hops This is a lightweight wrapper around a reference to the underlyin...
Definition Livecache.h:70
Hop(typename beast::maybe_const< IsConst, list_type >::type &list)
Definition Livecache.h:157
std::reference_wrapper< typename beast::maybe_const< IsConst, list_type >::type > m_list
Definition Livecache.h:167
boost::transform_iterator< Transform, typename list_type::const_iterator > iterator
Definition Livecache.h:89
boost::transform_iterator< Transform, typename list_type::const_reverse_iterator > reverse_iterator
Definition Livecache.h:95
static Hop< IsConst > make_hop(typename beast::maybe_const< IsConst, list_type >::type &list)
Definition Livecache.h:174
boost::intrusive::make_list< Element, boost::intrusive::constant_time_size< false > >::type list_type
Definition Livecache.h:61
T copy(T... args)
T empty(T... args)
T end(T... args)
T fill(T... args)
std::chrono::seconds constexpr liveCacheSecondsToLive(30)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
@ expired
List is expired, but has the largest non-pending sequence seen so far.
beast::xor_shift_engine & default_prng()
Return the default random engine.
T shuffle(T... args)
T rbegin(T... args)
T rend(T... args)
T reserve(T... args)
T str(T... args)
Left justifies a field at the specified width.
Definition iosformat.h:34
Makes T const or non const depending on a bool.
Definition maybe_const.h:30
typename std::conditional< IsConst, typename std::remove_const< T >::type const, typename std::remove_const< T >::type >::type type
Definition maybe_const.h:35
Describes a connectible peer address along with some metadata.
Hop< IsConst > operator()(typename beast::maybe_const< IsConst, typename lists_type::value_type >::type &list) const
Definition Livecache.h:246
typename lists_type::value_type first_argument
Definition Livecache.h:240
Endpoint const & operator()(Element const &e) const
Definition Livecache.h:81
T to_string(T... args)