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