rippled
Bootcache.cpp
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 #include <ripple/peerfinder/impl/Bootcache.h>
21 #include <ripple/peerfinder/impl/iosformat.h>
22 #include <ripple/peerfinder/impl/Tuning.h>
23 #include <ripple/basics/Log.h>
24 
25 namespace ripple {
26 namespace PeerFinder {
27 
29  Store& store,
30  clock_type& clock,
31  beast::Journal journal)
32  : m_store (store)
33  , m_clock (clock)
34  , m_journal (journal)
35  , m_whenUpdate (m_clock.now ())
36  , m_needsUpdate (false)
37 {
38 }
39 
41 {
42  update();
43 }
44 
45 bool
47 {
48  return m_map.empty();
49 }
50 
51 Bootcache::map_type::size_type
53 {
54  return m_map.size();
55 }
56 
59 {
60  return const_iterator (m_map.right.begin());
61 }
62 
65 {
66  return const_iterator (m_map.right.begin());
67 }
68 
71 {
72  return const_iterator (m_map.right.end());
73 }
74 
77 {
78  return const_iterator (m_map.right.end());
79 }
80 
81 void
83 {
84  m_map.clear();
85  m_needsUpdate = true;
86 }
87 
88 //--------------------------------------------------------------------------
89 
90 void
92 {
93  clear();
94  auto const n (m_store.load (
95  [this](beast::IP::Endpoint const& endpoint, int valence)
96  {
97  auto const result (this->m_map.insert (
98  value_type (endpoint, valence)));
99  if (! result.second)
100  {
101  JLOG(this->m_journal.error())
102  << beast::leftw (18) <<
103  "Bootcache discard " << endpoint;
104  }
105  }));
106 
107  if (n > 0)
108  {
109  JLOG(m_journal.info()) << beast::leftw (18) <<
110  "Bootcache loaded " << n <<
111  ((n > 1) ? " addresses" : " address");
112  prune ();
113  }
114 }
115 
116 bool
117 Bootcache::insert (beast::IP::Endpoint const& endpoint)
118 {
119  auto const result (m_map.insert (
120  value_type (endpoint, 0)));
121  if (result.second)
122  {
123  JLOG(m_journal.trace()) << beast::leftw (18) <<
124  "Bootcache insert " << endpoint;
125  prune ();
126  flagForUpdate();
127  }
128  return result.second;
129 }
130 
131 bool
132 Bootcache::insertStatic (beast::IP::Endpoint const& endpoint)
133 {
134  auto result (m_map.insert (
135  value_type (endpoint, staticValence)));
136 
137  if (! result.second && (result.first->right.valence() < staticValence))
138  {
139  // An existing entry has too low a valence, replace it
140  m_map.erase (result.first);
141  result = m_map.insert (
142  value_type (endpoint, staticValence));
143  }
144 
145  if (result.second)
146  {
147  JLOG(m_journal.trace()) << beast::leftw (18) <<
148  "Bootcache insert " << endpoint;
149  prune ();
150  flagForUpdate();
151  }
152  return result.second;
153 }
154 
155 void
156 Bootcache::on_success (beast::IP::Endpoint const& endpoint)
157 {
158  auto result (m_map.insert (
159  value_type (endpoint, 1)));
160  if (result.second)
161  {
162  prune ();
163  }
164  else
165  {
166  Entry entry (result.first->right);
167  if (entry.valence() < 0)
168  entry.valence() = 0;
169  ++entry.valence();
170  m_map.erase (result.first);
171  result = m_map.insert (
172  value_type (endpoint, entry));
173  assert (result.second);
174  }
175  Entry const& entry (result.first->right);
176  JLOG(m_journal.info()) << beast::leftw (18) <<
177  "Bootcache connect " << endpoint <<
178  " with " << entry.valence() <<
179  ((entry.valence() > 1) ? " successes" : " success");
180  flagForUpdate();
181 }
182 
183 void
184 Bootcache::on_failure (beast::IP::Endpoint const& endpoint)
185 {
186  auto result (m_map.insert (
187  value_type (endpoint, -1)));
188  if (result.second)
189  {
190  prune();
191  }
192  else
193  {
194  Entry entry (result.first->right);
195  if (entry.valence() > 0)
196  entry.valence() = 0;
197  --entry.valence();
198  m_map.erase (result.first);
199  result = m_map.insert (
200  value_type (endpoint, entry));
201  assert (result.second);
202  }
203  Entry const& entry (result.first->right);
204  auto const n (std::abs (entry.valence()));
205  JLOG(m_journal.debug()) << beast::leftw (18) <<
206  "Bootcache failed " << endpoint <<
207  " with " << n <<
208  ((n > 1) ? " attempts" : " attempt");
209  flagForUpdate();
210 }
211 
212 void
213 Bootcache::periodicActivity ()
214 {
215  checkUpdate();
216 }
217 
218 //--------------------------------------------------------------------------
219 
220 void
221 Bootcache::onWrite (beast::PropertyStream::Map& map)
222 {
223  beast::PropertyStream::Set entries ("entries", map);
224  for (auto iter = m_map.right.begin(); iter != m_map.right.end(); ++iter)
225  {
226  beast::PropertyStream::Map entry (entries);
227  entry["endpoint"] = iter->get_left().to_string();
228  entry["valence"] = std::int32_t (iter->get_right().valence());
229  }
230 }
231 
232  // Checks the cache size and prunes if its over the limit.
233 void
234 Bootcache::prune ()
235 {
236  if (size() <= Tuning::bootcacheSize)
237  return;
238 
239  // Calculate the amount to remove
240  auto count ((size() *
241  Tuning::bootcachePrunePercent) / 100);
242  decltype(count) pruned (0);
243 
244  // Work backwards because bimap doesn't handle
245  // erasing using a reverse iterator very well.
246  //
247  for (auto iter (m_map.right.end());
248  count-- > 0 && iter != m_map.right.begin(); ++pruned)
249  {
250  --iter;
251  beast::IP::Endpoint const& endpoint (iter->get_left());
252  Entry const& entry (iter->get_right());
253  JLOG(m_journal.trace()) << beast::leftw (18) <<
254  "Bootcache pruned" << endpoint <<
255  " at valence " << entry.valence();
256  iter = m_map.right.erase (iter);
257  }
258 
259  JLOG(m_journal.debug()) << beast::leftw (18) <<
260  "Bootcache pruned " << pruned << " entries total";
261 }
262 
263 // Updates the Store with the current set of entries if needed.
264 void
265 Bootcache::update ()
266 {
267  if (! m_needsUpdate)
268  return;
270  list.reserve (m_map.size());
271  for (auto const& e : m_map)
272  {
273  Store::Entry se;
274  se.endpoint = e.get_left();
275  se.valence = e.get_right().valence();
276  list.push_back (se);
277  }
278  m_store.save (list);
279  // Reset the flag and cooldown timer
280  m_needsUpdate = false;
281  m_whenUpdate = m_clock.now() + Tuning::bootcacheCooldownTime;
282 }
283 
284 // Checks the clock and calls update if we are off the cooldown.
285 void
286 Bootcache::checkUpdate ()
287 {
288  if (m_needsUpdate && m_whenUpdate < m_clock.now())
289  update ();
290 }
291 
292 // Called when changes to an entry will affect the Store.
293 void
294 Bootcache::flagForUpdate ()
295 {
296  m_needsUpdate = true;
297  checkUpdate ();
298 }
299 
300 }
301 }
ripple::PeerFinder::Bootcache::cend
const_iterator cend() const
Definition: Bootcache.cpp:76
beast::PropertyStream::Map
Definition: PropertyStream.h:185
std::vector::reserve
T reserve(T... args)
ripple::PeerFinder::Bootcache::m_store
Store & m_store
Definition: Bootcache.h:112
std::vector
STL class.
ripple::PeerFinder::Bootcache::clear
void clear()
Definition: Bootcache.cpp:82
ripple::PeerFinder::Store
Abstract persistence for PeerFinder data.
Definition: Store.h:27
beast::PropertyStream::Set
Definition: PropertyStream.h:246
ripple::PeerFinder::Bootcache::load
void load()
Load the persisted data from the Store into the container.
Definition: Bootcache.cpp:91
std::vector::push_back
T push_back(T... args)
ripple::PeerFinder::Bootcache::size
map_type::size_type size() const
Returns the number of entries in the cache.
Definition: Bootcache.cpp:52
ripple::PeerFinder::Bootcache::const_iterator
iterator const_iterator
Definition: Bootcache.h:128
ripple::PeerFinder::Bootcache::~Bootcache
~Bootcache()
Definition: Bootcache.cpp:40
ripple::PeerFinder::Bootcache::end
const_iterator end() const
Definition: Bootcache.cpp:70
ripple::PeerFinder::Bootcache::Bootcache
Bootcache(Store &store, clock_type &clock, beast::Journal journal)
Definition: Bootcache.cpp:28
ripple::PeerFinder::Bootcache::m_map
map_type m_map
Definition: Bootcache.h:110
ripple::PeerFinder::Store::Entry::valence
int valence
Definition: Store.h:42
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::int32_t
beast::abstract_clock< std::chrono::steady_clock >
ripple::PeerFinder::Bootcache::update
void update()
Definition: Bootcache.cpp:265
beast::leftw
Left justifies a field at the specified width.
Definition: iosformat.h:33
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::PeerFinder::Bootcache::value_type
map_type::value_type value_type
Definition: Bootcache.h:85
ripple::PeerFinder::Bootcache::m_needsUpdate
bool m_needsUpdate
Definition: Bootcache.h:120
ripple::PeerFinder::Bootcache::cbegin
const_iterator cbegin() const
Definition: Bootcache.cpp:64
ripple::PeerFinder::Bootcache::empty
bool empty() const
Returns true if the cache is empty.
Definition: Bootcache.cpp:46
ripple::PeerFinder::Bootcache::begin
const_iterator begin() const
IP::Endpoint iterators that traverse in decreasing valence.
Definition: Bootcache.cpp:58
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
ripple::PeerFinder::Store::Entry
Definition: Store.h:37
ripple::PeerFinder::Store::load
virtual std::size_t load(load_callback const &cb)=0
ripple::PeerFinder::Store::Entry::endpoint
beast::IP::Endpoint endpoint
Definition: Store.h:41
ripple::PeerFinder::Bootcache::Entry::valence
int & valence()
Definition: Bootcache.h:61
ripple::PeerFinder::Bootcache::Entry
Definition: Bootcache.h:53