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