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