xrpld
Loading...
Searching...
No Matches
Bootcache.cpp
1#include <xrpl/peerfinder/detail/Bootcache.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/net/IPEndpoint.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/utility/PropertyStream.h>
7#include <xrpl/beast/utility/instrumentation.h>
8#include <xrpl/peerfinder/Types.h>
9#include <xrpl/peerfinder/detail/Store.h>
10#include <xrpl/peerfinder/detail/Tuning.h>
11
12#include <algorithm>
13#include <cstdint>
14#include <cstdlib>
15#include <iomanip>
16#include <ios>
17#include <vector>
18
19namespace xrpl::peer_finder {
20
22 : store_(store), clock_(clock), journal_(journal), whenUpdate_(clock_.now())
23
24{
25}
26
31
32bool
34{
35 return map_.empty();
36}
37
38Bootcache::map_type::size_type
40{
41 return map_.size();
42}
43
46{
47 return const_iterator(map_.right.begin());
48}
49
52{
53 return const_iterator(map_.right.begin());
54}
55
58{
59 return const_iterator(map_.right.end());
60}
61
64{
65 return const_iterator(map_.right.end());
66}
67
68void
70{
71 map_.clear();
72 needsUpdate_ = true;
73}
74
75//--------------------------------------------------------------------------
76
77void
79{
80 clear();
81 auto const n(store_.load([this](beast::ip::Endpoint const& endpoint, int valence) {
82 auto const result(this->map_.insert(value_type(endpoint, valence)));
83 if (!result.second)
84 {
85 JLOG(this->journal_.error())
86 << std::left << std::setw(18) << "Bootcache discard " << endpoint;
87 }
88 }));
89
90 if (n > 0)
91 {
92 JLOG(journal_.info()) << std::left << std::setw(18) << "Bootcache loaded " << n
93 << ((n > 1) ? " addresses" : " address");
94 prune();
95 }
96}
97
98bool
100{
101 auto const result(map_.insert(value_type(endpoint, 0)));
102 if (result.second)
103 {
104 JLOG(journal_.trace()) << std::left << std::setw(18) << "Bootcache insert " << endpoint;
105 prune();
107 }
108 return result.second;
109}
110
111bool
113{
114 auto result(map_.insert(value_type(endpoint, kStaticValence)));
115
116 if (!result.second && (result.first->right.valence() < kStaticValence))
117 {
118 // An existing entry has too low a valence, replace it
119 map_.erase(result.first);
120 result = map_.insert(value_type(endpoint, kStaticValence));
121 }
122
123 if (result.second)
124 {
125 JLOG(journal_.trace()) << std::left << std::setw(18) << "Bootcache insert " << endpoint;
126 prune();
128 }
129 return result.second;
130}
131
132void
134{
135 auto result(map_.insert(value_type(endpoint, 1)));
136 if (result.second)
137 {
138 prune();
139 }
140 else
141 {
142 Entry entry(result.first->right);
143 entry.valence() = std::max(entry.valence(), 0);
144 ++entry.valence();
145 map_.erase(result.first);
146 result = map_.insert(value_type(endpoint, entry));
147 XRPL_ASSERT(result.second, "xrpl::peer_finder::Bootcache::onSuccess : endpoint inserted");
148 }
149 Entry const& entry(result.first->right);
150 JLOG(journal_.info()) << std::left << std::setw(18) << "Bootcache connect " << endpoint
151 << " with " << entry.valence()
152 << ((entry.valence() > 1) ? " successes" : " success");
154}
155
156void
158{
159 auto result(map_.insert(value_type(endpoint, -1)));
160 if (result.second)
161 {
162 prune();
163 }
164 else
165 {
166 Entry entry(result.first->right);
167 entry.valence() = std::min(entry.valence(), 0);
168 --entry.valence();
169 map_.erase(result.first);
170 result = map_.insert(value_type(endpoint, entry));
171 XRPL_ASSERT(result.second, "xrpl::peer_finder::Bootcache::onFailure : endpoint inserted");
172 }
173 Entry const& entry(result.first->right);
174 auto const n(std::abs(entry.valence()));
175 JLOG(journal_.debug()) << std::left << std::setw(18) << "Bootcache failed " << endpoint
176 << " with " << n << ((n > 1) ? " attempts" : " attempt");
178}
179
180void
185
186//--------------------------------------------------------------------------
187
188void
190{
191 beast::PropertyStream::Set entries("entries", map);
192 for (auto iter = map_.right.begin(); iter != map_.right.end(); ++iter)
193 {
194 beast::PropertyStream::Map entry(entries);
195 entry["endpoint"] = iter->get_left().toString();
196 entry["valence"] = std::int32_t(iter->get_right().valence());
197 }
198}
199
200// Checks the cache size and prunes if its over the limit.
201void
203{
205 return;
206
207 // Calculate the amount to remove
208 auto count((size() * tuning::kBootcachePrunePercent) / 100);
209 decltype(count) pruned(0);
210
211 // Work backwards because bimap doesn't handle
212 // erasing using a reverse iterator very well.
213 //
214 for (auto iter(map_.right.end()); count > 0 && iter != map_.right.begin(); ++pruned)
215 {
216 --count;
217 --iter;
218 beast::ip::Endpoint const& endpoint(iter->get_left());
219 Entry const& entry(iter->get_right());
220 JLOG(journal_.trace()) << std::left << std::setw(18) << "Bootcache pruned" << endpoint
221 << " at valence " << entry.valence();
222 iter = map_.right.erase(iter);
223 }
224
225 JLOG(journal_.debug()) << std::left << std::setw(18) << "Bootcache pruned " << pruned
226 << " entries total";
227}
228
229// Updates the Store with the current set of entries if needed.
230void
232{
233 if (!needsUpdate_)
234 return;
236 list.reserve(map_.size());
237 for (auto const& e : map_)
238 {
239 Store::Entry se;
240 se.endpoint = e.get_left();
241 se.valence = e.get_right().valence();
242 list.push_back(se);
243 }
244 store_.save(list);
245 // Reset the flag and cooldown timer
246 needsUpdate_ = false;
248}
249
250// Checks the clock and calls update if we are off the cooldown.
251void
253{
254 if (needsUpdate_ && whenUpdate_ < clock_.now())
255 update();
256}
257
258// Called when changes to an entry will affect the Store.
259void
261{
262 needsUpdate_ = true;
263 checkUpdate();
264}
265
266} // namespace xrpl::peer_finder
A generic endpoint for log messages.
Definition Journal.h:44
A version-independent IP address and port combination.
Definition IPEndpoint.h:24
static constexpr int kStaticValence
Definition Bootcache.h:101
bool insertStatic(beast::ip::Endpoint const &endpoint)
Add a staticallyconfigured address to the cache.
void onWrite(beast::PropertyStream::Map &map)
Write the cache state to the property stream.
map_type::value_type value_type
Definition Bootcache.h:71
void load()
Load the persisted data from the Store into the container.
Definition Bootcache.cpp:78
const_iterator begin() const
ip::Endpoint iterators that traverse in decreasing valence.
Definition Bootcache.cpp:45
bool insert(beast::ip::Endpoint const &endpoint)
Add a newly-learned address to the cache.
Definition Bootcache.cpp:99
bool empty() const
Returns true if the cache is empty.
Definition Bootcache.cpp:33
clock_type::time_point whenUpdate_
Definition Bootcache.h:95
const_iterator end() const
Definition Bootcache.cpp:57
map_type::size_type size() const
Returns the number of entries in the cache.
Definition Bootcache.cpp:39
void onFailure(beast::ip::Endpoint const &endpoint)
Called when an outbound connection attempt fails to handshake.
const_iterator cend() const
Definition Bootcache.cpp:63
void onSuccess(beast::ip::Endpoint const &endpoint)
Called when an outbound connection handshake completes.
void periodicActivity()
Stores the cache in the persistent database on a timer.
const_iterator cbegin() const
Definition Bootcache.cpp:51
Bootcache(Store &store, clock_type &clock, beast::Journal journal)
Definition Bootcache.cpp:21
Abstract persistence for PeerFinder data.
Definition Store.h:15
T left(T... args)
T max(T... args)
T min(T... args)
static std::chrono::seconds const kBootcacheCooldownTime(60)
beast::AbstractClock< std::chrono::steady_clock > clock_type
T push_back(T... args)
T reserve(T... args)
T setw(T... args)
beast::ip::Endpoint endpoint
Definition Store.h:29