Changeset View
Changeset View
Standalone View
Standalone View
src/invrequest.cpp
Show First 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | struct ByPeerViewExtractor { | ||||
} | } | ||||
}; | }; | ||||
// The ByInvId index is sorted by (invid, state, priority). | // The ByInvId index is sorted by (invid, state, priority). | ||||
// | // | ||||
// Note: priority == 0 whenever state != CANDIDATE_READY. | // Note: priority == 0 whenever state != CANDIDATE_READY. | ||||
// | // | ||||
// Uses: | // Uses: | ||||
// * Deleting all announcements with a given invid in ForgetTxId. | // * Deleting all announcements with a given invid in ForgetInvId. | ||||
// * Finding the best CANDIDATE_READY to convert to CANDIDATE_BEST, when no | // * Finding the best CANDIDATE_READY to convert to CANDIDATE_BEST, when no | ||||
// other CANDIDATE_READY or REQUESTED announcement exists for that invid. | // other CANDIDATE_READY or REQUESTED announcement exists for that invid. | ||||
// * Determining when no more non-COMPLETED announcements for a given invid | // * Determining when no more non-COMPLETED announcements for a given invid | ||||
// exist, so the COMPLETED ones can be deleted. | // exist, so the COMPLETED ones can be deleted. | ||||
struct ByInvId {}; | struct ByInvId {}; | ||||
using ByInvIdView = std::tuple<const uint256 &, State, Priority>; | using ByInvIdView = std::tuple<const uint256 &, State, Priority>; | ||||
class ByInvIdViewExtractor { | class ByInvIdViewExtractor { | ||||
const PriorityComputer &m_computer; | const PriorityComputer &m_computer; | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | for (const Announcement &ann : index) { | ||||
// (so we can detect duplicates). | // (so we can detect duplicates). | ||||
info.m_peers.push_back(ann.m_peer); | info.m_peers.push_back(ann.m_peer); | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
} // namespace | } // namespace | ||||
/** Actual implementation for TxRequestTracker's data structure. */ | /** Actual implementation for InvRequestTracker's data structure. */ | ||||
class ImplConcrete : public Impl { | class ImplConcrete : public Impl { | ||||
//! The current sequence number. Increases for every announcement. This is | //! The current sequence number. Increases for every announcement. This is | ||||
//! used to sort invid returned by GetRequestable in announcement order. | //! used to sort invid returned by GetRequestable in announcement order. | ||||
SequenceNumber m_current_sequence{0}; | SequenceNumber m_current_sequence{0}; | ||||
//! This tracker's priority computer. | //! This tracker's priority computer. | ||||
const PriorityComputer m_computer; | const PriorityComputer m_computer; | ||||
▲ Show 20 Lines • Show All 239 Lines • ▼ Show 20 Lines | void SetTimePoint(std::chrono::microseconds now, | ||||
} | } | ||||
} | } | ||||
while (!m_index.empty()) { | while (!m_index.empty()) { | ||||
// If time went backwards, we may need to demote CANDIDATE_BEST and | // If time went backwards, we may need to demote CANDIDATE_BEST and | ||||
// CANDIDATE_READY announcements back to CANDIDATE_DELAYED. This is | // CANDIDATE_READY announcements back to CANDIDATE_DELAYED. This is | ||||
// an unusual edge case, and unlikely to matter in production. | // an unusual edge case, and unlikely to matter in production. | ||||
// However, it makes it much easier to specify and test | // However, it makes it much easier to specify and test | ||||
// TxRequestTracker::Impl's behaviour. | // InvRequestTracker::Impl's behaviour. | ||||
auto it = std::prev(m_index.get<ByTime>().end()); | auto it = std::prev(m_index.get<ByTime>().end()); | ||||
if (it->IsSelectable() && it->m_time > now) { | if (it->IsSelectable() && it->m_time > now) { | ||||
ChangeAndReselect(m_index.project<ByInvId>(it), | ChangeAndReselect(m_index.project<ByInvId>(it), | ||||
State::CANDIDATE_DELAYED); | State::CANDIDATE_DELAYED); | ||||
} else { | } else { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | void DisconnectedPeer(NodeId peer) { | ||||
// Then actually delete the announcement (unless it was already | // Then actually delete the announcement (unless it was already | ||||
// deleted by MakeCompleted). | // deleted by MakeCompleted). | ||||
Erase<ByPeer>(it); | Erase<ByPeer>(it); | ||||
} | } | ||||
it = it_next; | it = it_next; | ||||
} | } | ||||
} | } | ||||
void ForgetTxId(const uint256 &invid) { | void ForgetInvId(const uint256 &invid) { | ||||
auto it = m_index.get<ByInvId>().lower_bound( | auto it = m_index.get<ByInvId>().lower_bound( | ||||
ByInvIdView{invid, State::CANDIDATE_DELAYED, 0}); | ByInvIdView{invid, State::CANDIDATE_DELAYED, 0}); | ||||
while (it != m_index.get<ByInvId>().end() && it->m_invid == invid) { | while (it != m_index.get<ByInvId>().end() && it->m_invid == invid) { | ||||
it = Erase<ByInvId>(it); | it = Erase<ByInvId>(it); | ||||
} | } | ||||
} | } | ||||
void ReceivedInv(NodeId peer, const uint256 &invid, bool preferred, | void ReceivedInv(NodeId peer, const uint256 &invid, bool preferred, | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | std::vector<uint256> GetRequestable(NodeId peer, | ||||
std::vector<uint256> ret; | std::vector<uint256> ret; | ||||
ret.reserve(selected.size()); | ret.reserve(selected.size()); | ||||
std::transform(selected.begin(), selected.end(), | std::transform(selected.begin(), selected.end(), | ||||
std::back_inserter(ret), | std::back_inserter(ret), | ||||
[](const Announcement *ann) { return ann->m_invid; }); | [](const Announcement *ann) { return ann->m_invid; }); | ||||
return ret; | return ret; | ||||
} | } | ||||
void RequestedTx(NodeId peer, const uint256 &invid, | void RequestedData(NodeId peer, const uint256 &invid, | ||||
std::chrono::microseconds expiry) { | std::chrono::microseconds expiry) { | ||||
auto it = m_index.get<ByPeer>().find(ByPeerView{peer, true, invid}); | auto it = m_index.get<ByPeer>().find(ByPeerView{peer, true, invid}); | ||||
if (it == m_index.get<ByPeer>().end()) { | if (it == m_index.get<ByPeer>().end()) { | ||||
// There is no CANDIDATE_BEST announcement, look for a _READY or | // There is no CANDIDATE_BEST announcement, look for a _READY or | ||||
// _DELAYED instead. If the caller only ever invokes RequestedTx | // _DELAYED instead. If the caller only ever invokes RequestedData | ||||
// with the values returned by GetRequestable, and no other | // with the values returned by GetRequestable, and no other | ||||
// non-const functions other than ForgetTxId and GetRequestable in | // non-const functions other than ForgetInvId and GetRequestable in | ||||
// between, this branch will never execute (as invids returned by | // between, this branch will never execute (as invids returned by | ||||
// GetRequestable always correspond to CANDIDATE_BEST | // GetRequestable always correspond to CANDIDATE_BEST | ||||
// announcements). | // announcements). | ||||
it = m_index.get<ByPeer>().find(ByPeerView{peer, false, invid}); | it = m_index.get<ByPeer>().find(ByPeerView{peer, false, invid}); | ||||
if (it == m_index.get<ByPeer>().end() || | if (it == m_index.get<ByPeer>().end() || | ||||
(it->GetState() != State::CANDIDATE_DELAYED && | (it->GetState() != State::CANDIDATE_DELAYED && | ||||
it->GetState() != State::CANDIDATE_READY)) { | it->GetState() != State::CANDIDATE_READY)) { | ||||
// There is no CANDIDATE announcement tracked for this peer, so | // There is no CANDIDATE announcement tracked for this peer, so | ||||
// we have nothing to do. Either this invid wasn't tracked at | // we have nothing to do. Either this invid wasn't tracked at | ||||
// all (and the caller should have called ReceivedInv), or it | // all (and the caller should have called ReceivedInv), or it | ||||
// was already requested and/or completed for other reasons and | // was already requested and/or completed for other reasons and | ||||
// this is just a superfluous RequestedTx call. | // this is just a superfluous RequestedData call. | ||||
return; | return; | ||||
} | } | ||||
// Look for an existing CANDIDATE_BEST or REQUESTED with the same | // Look for an existing CANDIDATE_BEST or REQUESTED with the same | ||||
// invid. We only need to do this if the found announcement had a | // invid. We only need to do this if the found announcement had a | ||||
// different state than CANDIDATE_BEST. If it did, invariants | // different state than CANDIDATE_BEST. If it did, invariants | ||||
// guarantee that no other CANDIDATE_BEST or REQUESTED can exist. | // guarantee that no other CANDIDATE_BEST or REQUESTED can exist. | ||||
auto it_old = m_index.get<ByInvId>().lower_bound( | auto it_old = m_index.get<ByInvId>().lower_bound( | ||||
▲ Show 20 Lines • Show All 85 Lines • Show Last 20 Lines |