20 #ifndef RIPPLE_OVERLAY_SLOT_H_INCLUDED
21 #define RIPPLE_OVERLAY_SLOT_H_INCLUDED
23 #include <ripple/app/main/Application.h>
24 #include <ripple/basics/chrono.h>
25 #include <ripple/beast/container/aged_unordered_map.h>
26 #include <ripple/beast/utility/Journal.h>
27 #include <ripple/overlay/Peer.h>
28 #include <ripple/overlay/Squelch.h>
29 #include <ripple/overlay/SquelchCommon.h>
30 #include <ripple/protocol/PublicKey.h>
31 #include <ripple.pb.h>
45 template <
typename clock_type>
60 template <
typename Unit,
typename TP>
64 return duration_cast<Unit>(t.time_since_epoch());
103 template <
typename clock_type>
188 unordered_map<id_t, std::tuple<PeerState, uint16_t, uint32_t, uint32_t>>
230 template <
typename clock_type>
234 auto now = clock_type::now();
235 for (
auto it = peers_.begin(); it != peers_.end();)
237 auto& peer = it->second;
240 if (now - peer.lastMessage >
IDLED)
242 JLOG(journal_.debug())
243 <<
"deleteIdlePeer: " <<
Slice(validator) <<
" " <<
id
245 << duration_cast<seconds>(now - peer.lastMessage).count()
247 deletePeer(validator,
id,
false);
252 template <
typename clock_type>
257 protocol::MessageType type)
259 auto now = clock_type::now();
260 auto it = peers_.find(
id);
262 if (it == peers_.end())
264 JLOG(journal_.debug())
265 <<
"update: adding peer " <<
Slice(validator) <<
" " << id;
274 JLOG(journal_.debug())
275 <<
"update: squelch expired " <<
Slice(validator) <<
" " << id;
277 it->second.lastMessage = now;
282 auto& peer = it->second;
284 JLOG(journal_.debug())
285 <<
"update: existing peer " <<
Slice(validator) <<
" " <<
id
286 <<
" slot state " <<
static_cast<int>(state_) <<
" peer state "
287 <<
static_cast<int>(peer.state) <<
" count " << peer.count <<
" last "
288 << duration_cast<milliseconds>(now - peer.lastMessage).count()
289 <<
" pool " << considered_.
size() <<
" threshold " << reachedThreshold_
290 <<
" " << (type == protocol::mtVALIDATION ?
"validation" :
"proposal");
292 peer.lastMessage = now;
298 considered_.insert(
id);
304 JLOG(journal_.debug())
305 <<
"update: resetting due to inactivity " <<
Slice(validator) <<
" "
306 <<
id <<
" " << duration_cast<seconds>(now - lastSelected_).count();
320 auto const consideredPoolSize = considered_.
size();
324 considered_.size() == 1 ? 0 :
rand_int(considered_.size() - 1);
325 auto it =
std::next(considered_.begin(), i);
327 considered_.erase(it);
328 auto const& itpeers = peers_.find(
id);
329 if (itpeers == peers_.end())
331 JLOG(journal_.error()) <<
"update: peer not found "
332 <<
Slice(validator) <<
" " << id;
335 if (now - itpeers->second.lastMessage <
IDLED)
341 JLOG(journal_.debug())
342 <<
"update: selection failed " <<
Slice(validator) <<
" " << id;
349 auto s = selected.
begin();
350 JLOG(journal_.debug())
351 <<
"update: " <<
Slice(validator) <<
" " <<
id <<
" pool size "
352 << consideredPoolSize <<
" selected " << *s <<
" "
358 for (
auto& [k, v] : peers_)
362 if (selected.
find(k) != selected.
end())
366 if (journal_.debug())
374 duration_cast<milliseconds>(
duration).count());
377 JLOG(journal_.debug()) <<
"update: squelching " <<
Slice(validator)
378 <<
" " <<
id <<
" " << str.
str();
380 reachedThreshold_ = 0;
385 template <
typename clock_type>
389 auto it = peers_.find(
id);
390 if (it != peers_.end())
392 JLOG(journal_.debug())
393 <<
"deletePeer: " <<
Slice(validator) <<
" " <<
id <<
" selected "
395 << (considered_.find(
id) != considered_.end()) <<
" erase "
397 auto now = clock_type::now();
400 for (
auto& [k, v] : peers_)
403 handler_.unsquelch(validator, k);
410 reachedThreshold_ = 0;
413 else if (considered_.find(
id) != considered_.end())
417 considered_.erase(
id);
420 it->second.lastMessage = now;
421 it->second.count = 0;
428 template <
typename clock_type>
432 for (
auto& [_, peer] : peers_)
439 template <
typename clock_type>
445 reachedThreshold_ = 0;
449 template <
typename clock_type>
453 return std::count_if(peers_.begin(), peers_.end(), [&](
auto const& it) {
454 return (it.second.state == state);
458 template <
typename clock_type>
462 return std::count_if(peers_.begin(), peers_.end(), [&](
auto const& it) {
463 return (it.second.state != state);
467 template <
typename clock_type>
473 peers_.begin(), peers_.end(), init, [](
auto& init,
auto const& it) {
474 if (it.second.state == PeerState::Selected)
476 init.insert(it.first);
483 template <
typename clock_type>
493 peers_.begin(), peers_.end(), init, [](
auto& init,
auto const& it) {
494 init.emplace(std::make_pair(
496 std::move(std::make_tuple(
499 epoch<milliseconds>(it.second.expire).count(),
500 epoch<milliseconds>(it.second.lastMessage).count()))));
509 template <
typename clock_type>
526 : handler_(handler), app_(app), journal_(app.journal(
"Slots"))
538 updateSlotAndSquelch(
542 protocol::MessageType type);
554 auto const& it = slots_.find(validator);
555 if (it != slots_.end())
556 return it->second.inState(state);
564 auto const& it = slots_.find(validator);
565 if (it != slots_.end())
566 return it->second.notInState(state);
574 auto const& it = slots_.find(validator);
575 if (it != slots_.end())
576 return it->second.state_ == state;
584 auto const& it = slots_.find(validator);
585 if (it != slots_.end())
586 return it->second.getSelected();
598 auto const& it = slots_.find(validator);
599 if (it != slots_.end())
600 return it->second.getPeers();
608 auto const& it = slots_.find(validator);
609 if (it != slots_.end())
610 return it->second.getState();
621 deletePeer(id_t
id,
bool erase);
628 addPeerMessage(
uint256 const& key, id_t
id);
639 beast::get_abstract_clock<clock_type>()};
642 template <
typename clock_type>
650 auto it = peersWithMessage_.find(key);
651 if (it == peersWithMessage_.end())
653 JLOG(journal_.trace())
654 <<
"addPeerMessage: new " <<
to_string(key) <<
" " << id;
659 if (it->second.find(
id) != it->second.end())
661 JLOG(journal_.trace()) <<
"addPeerMessage: duplicate message "
666 JLOG(journal_.trace())
667 <<
"addPeerMessage: added " <<
to_string(key) <<
" " << id;
675 template <
typename clock_type>
681 protocol::MessageType type)
683 if (!addPeerMessage(key,
id))
686 auto it = slots_.find(validator);
687 if (it == slots_.end())
689 JLOG(journal_.debug())
690 <<
"updateSlotAndSquelch: new slot " <<
Slice(validator);
696 it->second.update(validator,
id, type);
699 it->second.update(validator,
id, type);
702 template <
typename clock_type>
706 for (
auto& [validator, slot] : slots_)
710 template <
typename clock_type>
714 auto now = clock_type::now();
716 for (
auto it = slots_.begin(); it != slots_.end();)
718 it->second.deleteIdlePeer(it->first);
719 if (now - it->second.getLastSelected() > MAX_UNSQUELCH_EXPIRE)
721 JLOG(journal_.debug())
722 <<
"deleteIdlePeers: deleting idle slot " <<
Slice(it->first);
723 it = slots_.erase(it);
734 #endif // RIPPLE_OVERLAY_SLOT_H_INCLUDED
Slots(Application &app, SquelchHandler const &handler)
std::size_t size() const noexcept
Returns the number of bytes in the storage.
std::optional< std::uint16_t > notInState(PublicKey const &validator, PeerState state) const
Return number of peers not in state.
virtual ~SquelchHandler()
static constexpr seconds MAX_UNSQUELCH_EXPIRE
Slot(SquelchHandler const &handler, beast::Journal journal)
Constructor.
static constexpr uint16_t MAX_SELECTED_PEERS
An immutable linear range of bytes.
std::optional< SlotState > getState(PublicKey const &validator)
Get Slot's state.
hash_map< PublicKey, Slot< clock_type > > slots_
std::uint32_t id_t
Uniquely identifies a peer.
std::uint16_t notInState(PeerState state) const
Return number of peers not in state.
std::set< id_t > getSelected() const
Return selected peers.
static seconds getSquelchDuration()
Get random squelch duration between MIN_UNSQUELCH_EXPIRE and MAX_UNSQUELCH_EXPIRE.
SquelchHandler const & handler_
void deletePeer(id_t id, bool erase)
Called when a peer is deleted.
std::unordered_map< id_t, PeerInfo > peers_
bool inState(PublicKey const &validator, SlotState state) const
Return true if Slot is in state.
std::string to_string(ListDisposition disposition)
void erase(STObject &st, TypedField< U > const &f)
Remove a field in an STObject.
std::optional< std::uint16_t > inState(PublicKey const &validator, PeerState state) const
Return number of peers in state.
const beast::Journal journal_
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
void initCounting()
Initialize slot to Counting state.
Data maintained for each peer.
clock_type::time_point lastSelected_
static constexpr uint16_t MAX_MESSAGE_THRESHOLD
std::uint16_t reachedThreshold_
std::unordered_map< id_t, std::tuple< PeerState, uint16_t, uint32_t, uint32_t > > getPeers() const
Get peers info.
Seed functor once per construction.
virtual void squelch(PublicKey const &validator, Peer::id_t id, std::uint32_t duration) const =0
Squelch handler.
A generic endpoint for log messages.
std::enable_if< is_aged_container< AgedContainer >::value, std::size_t >::type expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
void deleteIdlePeer(PublicKey const &validator)
Check if peers stopped relaying messages.
std::uint16_t inState(PeerState state) const
Return number of peers in state.
Associative container where each element is also indexed by time.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::unordered_set< id_t > considered_
static constexpr seconds IDLED
void resetCounts()
Reset counts of peers in Selected or Counting state.
std::unordered_map< typename Peer::id_t, std::tuple< PeerState, uint16_t, uint32_t, std::uint32_t > > getPeers(PublicKey const &validator)
Get peers info.
virtual void unsquelch(PublicKey const &validator, Peer::id_t id) const =0
Unsquelch handler.
Slots is a container for validator's Slot and handles Slot update when a message is received from a v...
Slot is associated with a specific validator via validator's public key.
const beast::Journal journal_
typename ripple::UptimeClock ::time_point time_point
const time_point & getLastSelected() const
Get the time of the last peer selection round.
SlotState getState() const
Return Slot's state.
typename ripple::UptimeClock ::time_point time_point
void deletePeer(PublicKey const &validator, id_t id, bool erase)
Handle peer deletion when a peer disconnects.
std::set< id_t > getSelected(PublicKey const &validator)
Get selected peers.
SquelchHandler const & handler_
static constexpr uint16_t MIN_MESSAGE_THRESHOLD
void update(PublicKey const &validator, id_t id, protocol::MessageType type)
Update peer info.