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