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