77template <
typename T,
typename Comparator>
79 std::vector<T>& elements, Comparator comparator,
size_t k,
82 std::sort(elements.begin(), elements.end(), comparator);
83 size_t eraseSize = std::min(k, elements.size());
84 elements.erase(std::remove_if(elements.end() - eraseSize, elements.end(), predicate), elements.end());
89 eviction_candidates.erase(std::remove_if(eviction_candidates.begin(), eviction_candidates.end(),
93 eviction_candidates.end());
98 eviction_candidates.erase(std::remove_if(eviction_candidates.begin(), eviction_candidates.end(),
100 return n.m_conn_type != ConnectionType::INBOUND;
102 eviction_candidates.end());
113 const size_t initial_size = eviction_candidates.size();
114 const size_t total_protect_size{initial_size / 2};
118 struct Net {
bool is_local;
Network id;
size_t count; };
119 std::array<Net, 4> networks{
120 {{
false,
NET_CJDNS, 0}, {
false,
NET_I2P, 0}, {
true,
NET_MAX, 0}, {
false,
NET_ONION, 0}}};
123 for (Net& n : networks) {
124 n.count = std::count_if(eviction_candidates.cbegin(), eviction_candidates.cend(),
126 return n.is_local ? c.m_is_local : c.m_network == n.id;
131 std::stable_sort(networks.begin(), networks.end(), [](Net a, Net b) { return a.count < b.count; });
134 const size_t max_protect_by_network{total_protect_size / 2};
135 size_t num_protected{0};
137 while (num_protected < max_protect_by_network) {
139 auto num_networks = std::count_if(networks.begin(), networks.end(), [](
const Net& n) { return n.count; });
140 if (num_networks == 0) {
143 const size_t disadvantaged_to_protect{max_protect_by_network - num_protected};
144 const size_t protect_per_network{std::max(disadvantaged_to_protect / num_networks,
static_cast<size_t>(1))};
146 bool protected_at_least_one{
false};
148 for (Net& n : networks) {
149 if (n.count == 0)
continue;
150 const size_t before = eviction_candidates.size();
153 return n.is_local ? c.m_is_local : c.m_network == n.id;
155 const size_t after = eviction_candidates.size();
156 if (before > after) {
157 protected_at_least_one =
true;
158 const size_t delta{before - after};
159 num_protected += delta;
160 if (num_protected >= max_protect_by_network) {
166 if (!protected_at_least_one) {
173 assert(num_protected == initial_size - eviction_candidates.size());
174 const size_t remaining_to_protect{total_protect_size - num_protected};
178[[nodiscard]] std::optional<NodeId>
SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
207 if (vEvictionCandidates.empty())
return std::nullopt;
212 if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](
NodeEvictionCandidate const &n){return n.prefer_evict;})) {
213 vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
219 uint64_t naMostConnections;
220 unsigned int nMostConnections = 0;
221 std::chrono::seconds nMostConnectionsTime{0};
222 std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
224 std::vector<NodeEvictionCandidate> &
group = mapNetGroupNodes[
node.nKeyedNetGroup];
226 const auto grouptime{
group[0].m_connected};
228 if (
group.size() > nMostConnections || (
group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
229 nMostConnections =
group.size();
230 nMostConnectionsTime = grouptime;
231 naMostConnections =
node.nKeyedNetGroup;
236 vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
239 return vEvictionCandidates.front().id;
static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
static void EraseLastKElements(std::vector< T > &elements, Comparator comparator, size_t k, std::function< bool(const NodeEvictionCandidate &)> predicate=[](const NodeEvictionCandidate &n) { return true;})
Sort an array by the specified comparator, then erase the last K elements where predicate is true.
static bool CompareNodeBlockRelayOnlyTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
void ProtectNoBanConnections(std::vector< NodeEvictionCandidate > &eviction_candidates)
static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
void ProtectEvictionCandidatesByRatio(std::vector< NodeEvictionCandidate > &eviction_candidates)
Protect desirable or disadvantaged inbound peers from eviction by ratio.
std::optional< NodeId > SelectNodeToEvict(std::vector< NodeEvictionCandidate > &&vEvictionCandidates)
Select an inbound peer to evict after filtering out (protecting) peers having distinct,...
static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
void ProtectOutboundConnections(std::vector< NodeEvictionCandidate > &eviction_candidates)
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
@ NET_MAX
Dummy value to indicate the number of NET_* constants.
@ NET_ONION
TOR (v2 or v3)
Sort eviction candidates by network/localhost and connection uptime.
CompareNodeNetworkTime(bool is_local, Network network)
bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) const
std::chrono::seconds m_last_tx_time
std::chrono::seconds m_connected
std::chrono::seconds m_last_block_time
std::chrono::microseconds m_min_ping_time