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#include <xrpl/basics/Log.h>
27#include <xrpl/basics/random.h>
28#include <xrpl/beast/container/aged_map.h>
29#include <xrpl/beast/utility/maybe_const.h>
30#include <boost/intrusive/list.hpp>
31#include <boost/iterator/transform_iterator.hpp>
32
33#include <algorithm>
34
35namespace ripple {
36namespace PeerFinder {
37
38template <class>
39class Livecache;
40
41namespace detail {
42
44{
45public:
46 explicit LivecacheBase() = default;
47
48protected:
49 struct Element : boost::intrusive::list_base_hook<>
50 {
51 Element(Endpoint const& endpoint_) : endpoint(endpoint_)
52 {
53 }
54
56 };
57
58 using list_type = boost::intrusive::
59 make_list<Element, boost::intrusive::constant_time_size<false>>::type;
60
61public:
66 template <bool IsConst>
67 class Hop
68 {
69 public:
70 // Iterator transformation to extract the endpoint from Element
71 struct Transform
72 {
75
76 explicit Transform() = default;
77
78 Endpoint const&
79 operator()(Element const& e) const
80 {
81 return e.endpoint;
82 }
83 };
84
85 public:
86 using iterator = boost::
87 transform_iterator<Transform, typename list_type::const_iterator>;
88
90
91 using reverse_iterator = boost::transform_iterator<
93 typename list_type::const_reverse_iterator>;
94
96
98 begin() const
99 {
100 return iterator(m_list.get().cbegin(), Transform());
101 }
102
104 cbegin() const
105 {
106 return iterator(m_list.get().cbegin(), Transform());
107 }
108
110 end() const
111 {
112 return iterator(m_list.get().cend(), Transform());
113 }
114
116 cend() const
117 {
118 return iterator(m_list.get().cend(), Transform());
119 }
120
122 rbegin() const
123 {
124 return reverse_iterator(m_list.get().crbegin(), Transform());
125 }
126
128 crbegin() const
129 {
130 return reverse_iterator(m_list.get().crbegin(), Transform());
131 }
132
134 rend() const
135 {
136 return reverse_iterator(m_list.get().crend(), Transform());
137 }
138
140 crend() const
141 {
142 return reverse_iterator(m_list.get().crend(), Transform());
143 }
144
145 // move the element to the end of the container
146 void
148 {
149 auto& e(const_cast<Element&>(*pos.base()));
150 m_list.get().erase(m_list.get().iterator_to(e));
151 m_list.get().push_back(e);
152 }
153
154 private:
155 explicit Hop(
157 : m_list(list)
158 {
159 }
160
161 friend class LivecacheBase;
162
166 };
167
168protected:
169 // Work-around to call Hop's private constructor from Livecache
170 template <bool IsConst>
171 static Hop<IsConst>
173 {
174 return Hop<IsConst>(list);
175 }
176};
177
178} // namespace detail
179
180//------------------------------------------------------------------------------
181
194template <class Allocator = std::allocator<char>>
196{
197private:
200 Element,
203 Allocator>;
204
207
208public:
209 using allocator_type = Allocator;
210
212 Livecache(
213 clock_type& clock,
214 beast::Journal journal,
215 Allocator alloc = Allocator());
216
217 //
218 // Iteration by hops
219 //
220 // The range [begin, end) provides a sequence of list_type
221 // where each list contains endpoints at a given hops.
222 //
223
224 class hops_t
225 {
226 private:
227 // An endpoint at hops=0 represents the local node.
228 // Endpoints coming in at maxHops are stored at maxHops +1,
229 // but not given out (since they would exceed maxHops). They
230 // are used for automatic connection attempts.
231 //
234
235 template <bool IsConst>
237 {
238 using first_argument = typename lists_type::value_type;
240
241 explicit Transform() = default;
242
245 IsConst,
246 typename lists_type::value_type>::type& list) const
247 {
248 return make_hop<IsConst>(list);
249 }
250 };
251
252 public:
253 using iterator = boost::
254 transform_iterator<Transform<false>, typename lists_type::iterator>;
255
256 using const_iterator = boost::transform_iterator<
258 typename lists_type::const_iterator>;
259
260 using reverse_iterator = boost::transform_iterator<
262 typename lists_type::reverse_iterator>;
263
264 using const_reverse_iterator = boost::transform_iterator<
266 typename lists_type::const_reverse_iterator>;
267
270 {
272 }
273
275 begin() const
276 {
278 }
279
281 cbegin() const
282 {
284 }
285
288 {
290 }
291
293 end() const
294 {
296 }
297
299 cend() const
300 {
302 }
303
306 {
308 }
309
311 rbegin() const
312 {
314 }
315
317 crbegin() const
318 {
320 }
321
324 {
326 }
327
329 rend() const
330 {
332 }
333
335 crend() const
336 {
338 }
339
341 void
342 shuffle();
343
345 histogram() const;
346
347 private:
348 explicit hops_t(Allocator const& alloc);
349
350 void
351 insert(Element& e);
352
353 // Reinsert e at a new hops
354 void
356
357 void
358 remove(Element& e);
359
360 friend class Livecache;
364
366 bool
367 empty() const
368 {
369 return m_cache.empty();
370 }
371
373 typename cache_type::size_type
374 size() const
375 {
376 return m_cache.size();
377 }
378
380 void
381 expire();
382
384 void
385 insert(Endpoint const& ep);
386
388 void
390};
391
392//------------------------------------------------------------------------------
393
394template <class Allocator>
396 clock_type& clock,
397 beast::Journal journal,
398 Allocator alloc)
399 : m_journal(journal), m_cache(clock, alloc), hops(alloc)
400{
401}
402
403template <class Allocator>
404void
406{
407 std::size_t n(0);
408 typename cache_type::time_point const expired(
410 for (auto iter(m_cache.chronological.begin());
411 iter != m_cache.chronological.end() && iter.when() <= expired;)
412 {
413 Element& e(iter->second);
414 hops.remove(e);
415 iter = m_cache.erase(iter);
416 ++n;
417 }
418 if (n > 0)
419 {
420 JLOG(m_journal.debug()) << beast::leftw(18) << "Livecache expired " << n
421 << ((n > 1) ? " entries" : " entry");
422 }
423}
424
425template <class Allocator>
426void
428{
429 // The caller already incremented hop, so if we got a
430 // message at maxHops we will store it at maxHops + 1.
431 // This means we won't give out the address to other peers
432 // but we will use it to make connections and hand it out
433 // when redirecting.
434 //
435 XRPL_ASSERT(
436 ep.hops <= (Tuning::maxHops + 1),
437 "ripple::PeerFinder::Livecache::insert : maximum input hops");
438 auto result = m_cache.emplace(ep.address, ep);
439 Element& e(result.first->second);
440 if (result.second)
441 {
442 hops.insert(e);
443 JLOG(m_journal.debug()) << beast::leftw(18) << "Livecache insert "
444 << ep.address << " at hops " << ep.hops;
445 return;
446 }
447 else if (!result.second && (ep.hops > e.endpoint.hops))
448 {
449 // Drop duplicates at higher hops
450 std::size_t const excess(ep.hops - e.endpoint.hops);
451 JLOG(m_journal.trace()) << beast::leftw(18) << "Livecache drop "
452 << ep.address << " at hops +" << excess;
453 return;
454 }
455
456 m_cache.touch(result.first);
457
458 // Address already in the cache so update metadata
459 if (ep.hops < e.endpoint.hops)
460 {
461 hops.reinsert(e, ep.hops);
462 JLOG(m_journal.debug()) << beast::leftw(18) << "Livecache update "
463 << ep.address << " at hops " << ep.hops;
464 }
465 else
466 {
467 JLOG(m_journal.trace()) << beast::leftw(18) << "Livecache refresh "
468 << ep.address << " at hops " << ep.hops;
469 }
470}
471
472template <class Allocator>
473void
475{
476 typename cache_type::time_point const expired(
478 map["size"] = size();
479 map["hist"] = hops.histogram();
480 beast::PropertyStream::Set set("entries", map);
481 for (auto iter(m_cache.cbegin()); iter != m_cache.cend(); ++iter)
482 {
483 auto const& e(iter->second);
485 item["hops"] = e.endpoint.hops;
486 item["address"] = e.endpoint.address.to_string();
488 ss << (iter.when() - expired).count();
489 item["expires"] = ss.str();
490 }
491}
492
493//------------------------------------------------------------------------------
494
495template <class Allocator>
496void
498{
499 for (auto& list : m_lists)
500 {
502 v.reserve(list.size());
503 std::copy(list.begin(), list.end(), std::back_inserter(v));
504 std::shuffle(v.begin(), v.end(), default_prng());
505 list.clear();
506 for (auto& e : v)
507 list.push_back(e);
508 }
509}
510
511template <class Allocator>
514{
515 std::string s;
516 for (auto const& h : m_hist)
517 {
518 if (!s.empty())
519 s += ", ";
520 s += std::to_string(h);
521 }
522 return s;
523}
524
525template <class Allocator>
527{
528 std::fill(m_hist.begin(), m_hist.end(), 0);
529}
530
531template <class Allocator>
532void
534{
535 XRPL_ASSERT(
537 "ripple::PeerFinder::Livecache::hops_t::insert : maximum input hops");
538 // This has security implications without a shuffle
539 m_lists[e.endpoint.hops].push_front(e);
540 ++m_hist[e.endpoint.hops];
541}
542
543template <class Allocator>
544void
546{
547 XRPL_ASSERT(
548 numHops <= Tuning::maxHops + 1,
549 "ripple::PeerFinder::Livecache::hops_t::reinsert : maximum hops input");
550
551 auto& list = m_lists[e.endpoint.hops];
552 list.erase(list.iterator_to(e));
553
554 --m_hist[e.endpoint.hops];
555
556 e.endpoint.hops = numHops;
557 insert(e);
558}
559
560template <class Allocator>
561void
563{
564 --m_hist[e.endpoint.hops];
565
566 auto& list = m_lists[e.endpoint.hops];
567 list.erase(list.iterator_to(e));
568}
569
570} // namespace PeerFinder
571} // namespace ripple
572
573#endif
T back_inserter(T... args)
T begin(T... args)
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
A generic endpoint for log messages.
Definition: Journal.h:59
Stream debug() const
Definition: Journal.h:317
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
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:258
const_iterator begin() const
Definition: Livecache.h:275
void shuffle()
Shuffle each hop list.
Definition: Livecache.h:497
const_iterator end() const
Definition: Livecache.h:293
hops_t(Allocator const &alloc)
Definition: Livecache.h:526
const_reverse_iterator crend() const
Definition: Livecache.h:335
const_reverse_iterator rend() const
Definition: Livecache.h:329
void reinsert(Element &e, std::uint32_t hops)
Definition: Livecache.h:545
const_reverse_iterator rbegin() const
Definition: Livecache.h:311
boost::transform_iterator< Transform< false >, typename lists_type::reverse_iterator > reverse_iterator
Definition: Livecache.h:262
const_iterator cbegin() const
Definition: Livecache.h:281
boost::transform_iterator< Transform< false >, typename lists_type::iterator > iterator
Definition: Livecache.h:254
const_iterator cend() const
Definition: Livecache.h:299
const_reverse_iterator crbegin() const
Definition: Livecache.h:317
boost::transform_iterator< Transform< true >, typename lists_type::const_reverse_iterator > const_reverse_iterator
Definition: Livecache.h:266
The Livecache holds the short-lived relayed Endpoint messages.
Definition: Livecache.h:196
cache_type::size_type size() const
Returns the number of entries in the cache.
Definition: Livecache.h:374
void expire()
Erase entries whose time has expired.
Definition: Livecache.h:405
Livecache(clock_type &clock, beast::Journal journal, Allocator alloc=Allocator())
Create the cache.
Definition: Livecache.h:395
void insert(Endpoint const &ep)
Creates or updates an existing Element based on a new message.
Definition: Livecache.h:427
void onWrite(beast::PropertyStream::Map &map)
Output statistics.
Definition: Livecache.h:474
class ripple::PeerFinder::Livecache::hops_t hops
bool empty() const
Returns true if the cache is empty.
Definition: Livecache.h:367
A list of Endpoint at the same hops This is a lightweight wrapper around a reference to the underlyin...
Definition: Livecache.h:68
Hop(typename beast::maybe_const< IsConst, list_type >::type &list)
Definition: Livecache.h:155
std::reference_wrapper< typename beast::maybe_const< IsConst, list_type >::type > m_list
Definition: Livecache.h:165
boost::transform_iterator< Transform, typename list_type::const_iterator > iterator
Definition: Livecache.h:87
boost::transform_iterator< Transform, typename list_type::const_reverse_iterator > reverse_iterator
Definition: Livecache.h:93
static Hop< IsConst > make_hop(typename beast::maybe_const< IsConst, list_type >::type &list)
Definition: Livecache.h:172
boost::intrusive::make_list< Element, boost::intrusive::constant_time_size< false > >::type list_type
Definition: Livecache.h:59
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:26
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,...
Definition: BasicConfig.h:313
@ 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:244
typename lists_type::value_type first_argument
Definition: Livecache.h:238
Endpoint const & operator()(Element const &e) const
Definition: Livecache.h:79
T to_string(T... args)