Flow 1.0.2
Flow project: Full implementation reference.
Public Types | Public Member Functions | Static Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
flow::net_flow::Drop_timer Class Reference

Internal net_flow class that maintains the Drop Timer for DATA packet(s) to have been sent out over a connection but not yet acknowledged by the receiver. More...

#include <drop_timer.hpp>

Inheritance diagram for flow::net_flow::Drop_timer:
[legend]
Collaboration diagram for flow::net_flow::Drop_timer:
[legend]

Public Types

using packet_id_t = Sequence_number::seq_num_t
 Type to uniquely identify a packet sent over the wire in the socket to which this Drop_timer applies. More...
 
- Public Types inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Drop_timer > >
using Ptr = boost::shared_ptr< Drop_timer >
 Short-hand for ref-counted pointer to mutable values of type Target_type::element_type (a-la T*). More...
 
using Const_ptr = Const_target_ptr
 Short-hand for ref-counted pointer to immutable values of type Target_type::element_type (a-la T const *). More...
 

Public Member Functions

 ~Drop_timer ()
 Destructor. More...
 
void start_contemporaneous_events ()
 Indicates the start of a series of zero or more contemporary on_*() event calls, to be marked as finished via end_contemporaneous_events(). More...
 
void on_packet_in_flight (packet_id_t packet_id)
 Indicates that a packet identified by the given unique ID has just been sent over the wire (the low-level transport, currently UDP). More...
 
void on_packet_no_longer_in_flight (packet_id_t packet_id)
 Indicates that a packet for which on_packet_in_flight() was called is now no longer considered In-flight in the Peer_socket sense; see Peer_socket::m_snd_flying_pkts_by_sent_when for definition of In-flight. More...
 
void on_no_packets_in_flight_any_longer ()
 Equivalent to on_packet_no_longer_in_flight(P), for all P currently In-flight as registered by on_packet_in_flight(P). More...
 
void on_ack (packet_id_t packet_id)
 Indicates that a packet for which on_packet_in_flight() was called has just been validly acked. More...
 
void end_contemporaneous_events ()
 Finishes the group started by start start_contemporaneous_events(). More...
 
void done ()
 Causes the Drop_timer to guarantee none of the action callbacks provided at construction will be called from this point on. More...
 
- Public Member Functions inherited from flow::log::Log_context
 Log_context (Logger *logger=0)
 Constructs Log_context by storing the given pointer to a Logger and a null Component. More...
 
template<typename Component_payload >
 Log_context (Logger *logger, Component_payload component_payload)
 Constructs Log_context by storing the given pointer to a Logger and a new Component storing the specified generically typed payload (an enum value). More...
 
 Log_context (const Log_context &src)
 Copy constructor that stores equal Logger* and Component values as the source. More...
 
 Log_context (Log_context &&src)
 Move constructor that makes this equal to src, while the latter becomes as-if default-constructed. More...
 
Log_contextoperator= (const Log_context &src)
 Assignment operator that behaves similarly to the copy constructor. More...
 
Log_contextoperator= (Log_context &&src)
 Move assignment operator that behaves similarly to the move constructor. More...
 
void swap (Log_context &other)
 Swaps Logger pointers and Component objects held by *this and other. More...
 
Loggerget_logger () const
 Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect. More...
 
const Componentget_log_component () const
 Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect. More...
 

Static Public Member Functions

static Ptr create_drop_timer (log::Logger *logger_ptr, util::Task_engine *node_task_engine, Fine_duration *sock_drop_timeout, Peer_socket::Const_ptr &&sock, const Function< void(const Error_code &err_code)> &timer_failure, const Function< void(bool drop_all_packets)> &timer_fired)
 Constructs Drop_timer and returns a ref-counted pointer wrapping it. More...
 
- Static Public Member Functions inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Drop_timer > >
static Ptr ptr_cast (const From_ptr &ptr_to_cast)
 Provides syntactic-sugary way to perform a static_pointer_cast<> from a compatible smart pointer type From_ptr, typically From_ptr::element_type being in the same class hierarchy as Target_ptr::element_type. More...
 
static Const_ptr const_ptr_cast (const From_ptr &ptr_to_cast)
 Identical to ptr_cast() but adds const-ness (immutability) to the pointed-to type. More...
 
static Ptr dynamic_ptr_cast (const From_ptr &ptr_to_cast)
 Equivalent to ptr_cast() but a dynamic_pointer_cast instead of static. More...
 
static Const_ptr dynamic_const_ptr_cast (const From_ptr &ptr_to_cast)
 Identical to const_ptr_cast() but a dynamic_pointer_cast instead of static. More...
 

Private Types

using timer_wait_id_t = uint64_t
 The counter type used to distinguish a given start_timer() call from any other such call (for this object). More...
 

Private Member Functions

 Drop_timer (log::Logger *logger, util::Task_engine *node_task_engine, Fine_duration *sock_drop_timeout, Peer_socket::Const_ptr &&sock, const Function< void(const Error_code &err_code)> &timer_failure, const Function< void(bool drop_all_packets)> &timer_fired)
 Constructs Drop_timer as described in the factory constructor create_drop_timer(). More...
 
void start_timer ()
 Starts a new wait on the timer, so that is it asynchronously triggered according to the current DTO value. More...
 
void disable_timer ()
 Invalidates the running asynchronous wait on m_timer. Pre-condition: m_timer_running. More...
 
void handle_timer_firing (Ptr prevent_destruction, timer_wait_id_t wait_id, const Error_code &sys_err_code)
 Called by boost.asio when the Drop Timer fires; disables timer and calls an outside action callback (given in constructor). More...
 
void timer_failure (Ptr prevent_destruction, const Error_code &err_code)
 Called by boost.asio after we post it, in the event of some timer error. More...
 

Private Attributes

util::Task_enginem_node_task_engine
 Node::m_task_engine of the containing Node. Used to schedule timer events. More...
 
Fine_durationm_sock_drop_timeout
 Reference to the containing Peer_socket's Peer_socket::m_snd_drop_timeout data member (= DTO, Drop Timeout, RTO). More...
 
const Peer_socket::Const_ptr m_sock
 The containing Peer_socket (note that this is read-only access). More...
 
util::Timer m_timer
 The Drop Timer itself. More...
 
bool m_timer_running
 Is there an active (non-obsolete, not-canceled) asynchronous wait in progress on m_timer? More precisely, this is true if the latest start_timer() call was later than the latest disable_timer() or handle_timer_firing(), or if start_timer() has been called but disable_timer() or handle_timer_firing() has not. More...
 
timer_wait_id_t m_current_wait_id
 Unique (within this object) identifier of the last start_timer() call. More...
 
bool m_done
 true if and only if done() has been called. Starts at false, can only change to true. More...
 
Function< void(const Error_code &err_code)> m_timer_failure
 Called on error. See Drop_timer constructor. More...
 
Function< void(bool drop_all_packets)> m_timer_fired
 Called on Drop Timeout. See Drop_timer constructor. More...
 
std::set< packet_id_tm_flying_packets
 Packet IDs of packets to have been sent over wire and still considered In-flight, ordered from earliest to latest to have been sent out. More...
 
packet_id_t m_at_events_start_oldest_flying_packet
 The packet ID of the least recently sent In-flight packet at last start_contemporaneous_events() call; or 0 if m_flying_packets.empty() at the time. More...
 
packet_id_t m_during_events_newest_acked_packet
 During the time period starting with the last start_contemporaneous_events() call and ending with the subsequent end_contemporaneous_events() call, if any – in other words, during the last contemporary events group, finished or otherwise – this is the ID of the most-recently-sent packet (highest packet ID) such that that packet was acknowledged during that time period. More...
 
bool m_in_events_group
 true if and only if the last start_contemporaneous_events() call exists, and either end_contemporaneous_events() hasn't been called at all or was called before the former call. More...
 

Detailed Description

Internal net_flow class that maintains the Drop Timer for DATA packet(s) to have been sent out over a connection but not yet acknowledged by the receiver.

This is similar to the Retransmission Timer of TCP (although the way that timer works is not solidly standardized, though there are recommended setups in RFCs like RFC 6298). However, this applies even with retransmission disabled (which is allowed in NetFlow but not in TCP), so it would be incorrect to call it Rexmit_timer; on the other hand when retransmission is enabled, Drop_timer will still be an accurate name (as a packet has to be considered Dropped before we retransmit it). net_flow users should not use this class directly.

The basic idea is: if you send a packet, and it's not acknowledged within some amount of time, then consider that packet Dropped. (At that point you can take it out of the In-flight window, or retransmit it, or whatever else is appropriate.) Beyond this concept the details are ambiguous, and there is no one right/standard/accepted answer for how it should work. For example, when to restart the timer? What to do with the timer after it fires? Etc. Therefore the class is reasonably configurable, so that we can experiment with different approaches.

This class works together with Node, Peer_socket, and Server_socket and accordingly assumes very specific algorithms are used in sending and handling acknowledgments. However it could pretty easily be swapped out with another implementationr

A Drop_timer works as follows. It keeps an internal timer that fires every DTO seconds, where DTO is computed externally (from SRTT, etc.). Certain events start or restart the timer (e.g., receiving an acknowledgment). Other events stop the timer (namely having no more In-flight packets). Then when the timer fires, certain actions have to be taken, such as considering packets Dropped and/or restarting the timer. Additionally the DTO value itself can be written to by Drop_timer (e.g., timer backoff).

Therefore, the interface of Drop_timer is simple: you call on_...(), when a Drop Timer-influencing event has occurred; and when some action needs to be taken due to a Drop Timer firing, it calls a user-supplied callback which will perform that action. The action callbacks are supplied at construction. Drop_timer internally takes care of everything in-between: running/stopping the timer, catching the timer firing, etc. All of the "policy" about how the timer operates is also inside. Calling done() means the socket is done, and no action callbacks will subsequently fire.

To schedule the timer, Drop_timer shares Node's main event queue (Node::m_task_engine).

Thread safety

To be used in the containing Node's thread W only.

Implementation notes

Having written this class, it looks over-engineered. The code would be shorter (no shared_ptr, callbacks, factory, enable_shared_from_this) if it were directly in Node and Peer_socket. On the other hand the Strategy Pattern setup used here is nice for segregating the Drop Timer logic and for future modification, and it does make Node (which is huge) much easier to understand. So could go either way... rewrite in Node and Peer_socket or leave it alone.

We use a Ptr-emitting factory, because wrapping the object in a Ptr helps with some internal book-keeping and is useful to the user as well.

Regarding events

You'll note the interface is extremely simple: essentially, outside code just registers whenever packet becomes In-flight (a/k/a is sent over wire); and the opposite. This simplicity comes at an implementation cost, because it requires us to keep – internally – an ordered (by send time) set of packets currently In-flight. Why do this? Because the true events we are interested in are slightly more complex than what the Drop_timer API exposes: we want to detect when no packets are In-flight and suddenly a packet is sent off; the reverse; the acknowledgment of a packet that is NOT the oldest one currently In-flight; and the changing of the oldest currently In-flight packet from packet A to packet B =/= A. (That's as of this writing; perhaps this set of events could change.)

One might wonder whether it would be – overall – simpler to just have the event API of Drop_timer (the set of on_...() methods) just be those exact events I just listed. Then outside code could just call them when detecting those events. After all, Peer_socket has complex structures keeping track all sorts of details including how many and which packets are In-flight, so Peer_socket and Node code could easily detect all those situations.

In fact, that IS how Drop_timer was implemented in the past. Here is why I changed it: There is a small caveat about what "In-flight" means. Peer_socket's m_snd_flying_pkts_... data structures define "In-flight packet" as "packet that has been determined to be fit to send over the wire, having passed the availability and CWND constraints." For Drop_timer's ideal operation, "In-flight packet" is defined as "packet that has been sent over the wire." The practical difference between the two definitions is that the former may be awaiting certain send pacing conditions to actually be sent off; whereas the latter means it has been sent off – period. (See struct Send_pacing_data and related code for info on pacing. Essentially, though, any packet that's definitely going to be sent out barring existential disaster may be delayed a bit in a pacing queue to avoid bunching up packets in the pipe.) However, we lack a data structure that specifically stores packets to have been sent off over the wire, except indirectly in Peer_socket::m_snd_flying_pkts_by_sent_when minus Send_pacing_data::m_packet_q. The former is unwieldy for our purposes, let along when combined with the other. So it made more sense to just let outside code report truly In-flight packets appearing and disappearing to us, then we store the (rather minimal) information internally. Thus we separate concerns and divide labor among modules in an accurate fashion instead of Drop_timer becoming ultra-dependent on other modules' implementation details. That said, there is probably some memory cost and (maybe) a little processor cycle cost to this approach. (One could also say that the pacing delay is so minor as to make it ignorable here. However, I decided I don't need the headache of wondering/worrying about that ad infinitum; and solved the problem instead.)

Update regarding events

In order to increase performance by smooshing together lots of little checks and actions that might occur when handling lots of little events, namely received acknowledgments, the class user must now bracket groups of on_...() method calls with start_contemporaneous_events() and end_contemporaneous_events(). Thus each on_...() call performs only very basic/quick book-keeping; while end_contemporaneous_events() is what compares the situation against what it was at start_contemporaneous_events() and possibly detects the true events of interest that may actually trigger something (start timer, stop timer, restart running timer).

Timer vs util::schedule_task_from_now()

In other places we have tended to replace a Timer with the far simpler util::schedule_task_from_now() (etc.) facility (which internally uses a Timer but hides its various annoyances and caveats). Why not here? Answer: We don't happen to use any of Timer's advanced features that the simpler facility lacks; we just schedule and cancel, and the other facility supports those. So that just leaves the potential performance effects as the reason not to use the simpler facility (as listed in util::schedule_task_from_now() doc header). The logic concerning the delay before each scheduled task, and how often it might be canceled and/or rescheduled is not simple. It's hard to make iron-clad guarantees, therefore, that using a single repeatedly-reused Timer is no better perf-wise than using multiple schedulings using the simpler facility. So we do the perf-conservative thing and use Timer despite having to worry about a couple of the associated corner cases.

Or to put it concisely: The timer logic here is complicated, so the perf and flexibility aspects of directly using the advanced Timer feature are suitable.

Todo:
Drop_timer has data members that are references to non-const. These should be pointers for max consistency of style with other code in the project (and that style is encouraged for certain good reasons). Scour rest of code for other such data members as well.

Definition at line 145 of file drop_timer.hpp.

Member Typedef Documentation

◆ packet_id_t

Type to uniquely identify a packet sent over the wire in the socket to which this Drop_timer applies.

Caution: keep in sync with Peer_socket::order_num_t. That way Peer_socket code can easily form a packet_id_t from an order_num_t which, too, uniquely identifies a packet. 0 is reserved, not to be used for any actual packets.

Definition at line 162 of file drop_timer.hpp.

◆ timer_wait_id_t

The counter type used to distinguish a given start_timer() call from any other such call (for this object).

Definition at line 297 of file drop_timer.hpp.

Constructor & Destructor Documentation

◆ ~Drop_timer()

flow::net_flow::Drop_timer::~Drop_timer ( )

Destructor.

Definition at line 316 of file drop_timer.cpp.

References FLOW_LOG_TRACE.

◆ Drop_timer()

flow::net_flow::Drop_timer::Drop_timer ( log::Logger logger,
util::Task_engine node_task_engine,
Fine_duration sock_drop_timeout,
Peer_socket::Const_ptr &&  sock,
const Function< void(const Error_code &err_code)> &  timer_failure,
const Function< void(bool drop_all_packets)> &  timer_fired 
)
explicitprivate

Constructs Drop_timer as described in the factory constructor create_drop_timer().

Why have the factory method? We guarantee that this won't get deleted before the timer callback executes (causing a crash therein), by passing a Ptr(this) to basic_waitable_timer::async_wait(). However that can only work if all users of the object also access it by a sharing Ptr. Thus we only provide access to the outside via a Ptr (the factory).

Parameters
loggerSee create_drop_timer().
node_task_engineSee create_drop_timer().
sock_drop_timeoutSee create_drop_timer().
sockSee create_drop_timer().
timer_failureSee create_drop_timer().
timer_firedSee create_drop_timer().

Definition at line 293 of file drop_timer.cpp.

References FLOW_LOG_TRACE.

Referenced by create_drop_timer().

Here is the caller graph for this function:

Member Function Documentation

◆ create_drop_timer()

Drop_timer::Ptr flow::net_flow::Drop_timer::create_drop_timer ( log::Logger logger_ptr,
util::Task_engine node_task_engine,
Fine_duration sock_drop_timeout,
Peer_socket::Const_ptr &&  sock,
const Function< void(const Error_code &err_code)> &  timer_failure,
const Function< void(bool drop_all_packets)> &  timer_fired 
)
static

Constructs Drop_timer and returns a ref-counted pointer wrapping it.

Saves the "action callbacks" to call when various events fire in this Drop_timer. The callbacks may be placed onto *node_task_engine in the manner of Task_engine::post(), at any future time until done() is called. At construction, the timer is guaranteed not to fire until the first on_...() call.

After construction, call on_...() as events occur. If an event described by the doc comment of an on_...() method occurs, you MUST call it or results are undefined (the state machine breaks down).

Parameters
logger_ptrThe Logger implementation to use subsequently.
node_task_engineThe containing Node's &m_task_engine. Asyncronous callbacks will be placed on it (see below).
sock_drop_timeoutPointer to the containing Peer_socket's m_snd_drop_timeout. Drop_timer may write to this member if it feels the need to modify Drop Timeout value (as in RFC 6298 section 5.5)!
sockPointer to the containing Peer_socket. Access is read-only.
timer_failureFunction F with signature void F(const Error_code& err_code). F(<failure code>) will be called if and only if there was an internal system timer failure. Required action of timer_failure(): RST/close with the given error.
timer_firedFunction F with signature void F(bool drop_all_packets). F(drop_all_packets) will be called if and only if the Drop Timer has fired. Required action of timer_fired(): mark either all (if drop_all_packets) or just the earliest (otherwise) In-flight packet(s) as Dropped.
Returns
A ref-counted pointer wrapping a newly created Drop_timer as described above.

Definition at line 27 of file drop_timer.cpp.

References Drop_timer(), and timer_failure().

Referenced by flow::net_flow::Node::setup_drop_timer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ disable_timer()

void flow::net_flow::Drop_timer::disable_timer ( )
private

Invalidates the running asynchronous wait on m_timer. Pre-condition: m_timer_running.

Definition at line 452 of file drop_timer.cpp.

References FLOW_LOG_TRACE, m_current_wait_id, m_timer, and m_timer_running.

Referenced by done(), and end_contemporaneous_events().

Here is the caller graph for this function:

◆ done()

void flow::net_flow::Drop_timer::done ( )

Causes the Drop_timer to guarantee none of the action callbacks provided at construction will be called from this point on.

Call this once you have no need of the Drop_timer (probably upon exiting Peer_socket::Int_state::S_ESTABLISHED). Subsequent calls to done() are harmless.

Behavior is undefined if calling any other methods after done().

Definition at line 321 of file drop_timer.cpp.

References disable_timer(), FLOW_LOG_TRACE, m_done, m_timer_failure, m_timer_fired, and m_timer_running.

Here is the call graph for this function:

◆ end_contemporaneous_events()

void flow::net_flow::Drop_timer::end_contemporaneous_events ( )

Finishes the group started by start start_contemporaneous_events().

This may trigger various on-event behavior such as starting, stopping, or restarting the Drop_timer.

Definition at line 118 of file drop_timer.cpp.

References disable_timer(), FLOW_LOG_TRACE, flow::util::key_exists(), m_at_events_start_oldest_flying_packet, m_during_events_newest_acked_packet, m_flying_packets, m_in_events_group, m_sock, and start_timer().

Here is the call graph for this function:

◆ handle_timer_firing()

void flow::net_flow::Drop_timer::handle_timer_firing ( Ptr  prevent_destruction,
timer_wait_id_t  wait_id,
const Error_code sys_err_code 
)
private

Called by boost.asio when the Drop Timer fires; disables timer and calls an outside action callback (given in constructor).

If m_done or m_current_wait_id != wait_id or err_code is operation_aborted (meaning this invokation by boost.asio is obsolete and replaced by a subsequent async_wait(), or canceled), does nothing.

Parameters
wait_idThe value of m_current_wait_id at the time that m_timer.async_wait() was called with this method invokation as an argument.
prevent_destructionshared_from_this() at the time of m_timer.async_wait(). It assures this cannot be deleted until this handle_timer_firing() is called and returns.
sys_err_codeboost.asio error code indicating the circumstances of the callback executing. If this is boost::error::operation_aborted, method does nothing.

Definition at line 477 of file drop_timer.cpp.

References FLOW_ERROR_SYS_ERROR_LOG_WARNING, FLOW_LOG_TRACE, m_current_wait_id, m_done, m_sock, m_sock_drop_timeout, m_timer_fired, and m_timer_running.

Referenced by start_timer().

Here is the caller graph for this function:

◆ on_ack()

void flow::net_flow::Drop_timer::on_ack ( packet_id_t  packet_id)

Indicates that a packet for which on_packet_in_flight() was called has just been validly acked.

To be validly acked means that an acknowledgment was received while the packet was considered In-flight in the Peer_socket sense. See Peer_socket::m_snd_flying_pkts_by_sent_when for definition of In-flight.

Such a packet also requires an on_packet_no_longer_in_flight() call. You must call on_ack() first; and the latter subsequently. Otherwise behavior is undefined.

A contemporary event group must be in progress via start_contemporaneous_events(); or behavior is undefined.

Parameters
packet_idID of a packet for which on_packet_in_flight() has been called exactly once for *this. Otherwise behavior is undefined.

Definition at line 72 of file drop_timer.cpp.

References FLOW_LOG_TRACE, flow::util::key_exists(), m_during_events_newest_acked_packet, m_flying_packets, and m_in_events_group.

Here is the call graph for this function:

◆ on_no_packets_in_flight_any_longer()

void flow::net_flow::Drop_timer::on_no_packets_in_flight_any_longer ( )

Equivalent to on_packet_no_longer_in_flight(P), for all P currently In-flight as registered by on_packet_in_flight(P).

When you know it would be correct, call it instead of the former method many times for better efficiency. (Do not do "both." Trying to register more than once that P is no longer In-flight leads to undefined behavior.)

Calling this when no packets are In-flight already leads to undefined behavior.

A contemporary event group must be in progress via start_contemporaneous_events(); or behavior is undefined.

Definition at line 105 of file drop_timer.cpp.

References FLOW_LOG_TRACE, m_flying_packets, and m_in_events_group.

◆ on_packet_in_flight()

void flow::net_flow::Drop_timer::on_packet_in_flight ( packet_id_t  packet_id)

Indicates that a packet identified by the given unique ID has just been sent over the wire (the low-level transport, currently UDP).

Subtlety: Peer_socket may consider a packet In-flight before it has actually been sent out over the wire, namely if it is queued in the pacing module. This should be called only once it is actually sent. Note, however, that IF on_packet_in_flight(P) is called, then indeed the packet identified by P must be considered In-flight in the Peer_socket sense. See Peer_socket::m_snd_flying_pkts_by_sent_when for definition of In-flight.

A contemporary event group must be in progress via start_contemporaneous_events(); or behavior is undefined.

Parameters
packet_idID of the packet that was sent out. This can be any number as long as it increases with each subsequent call to this method for *this Drop_timer (in particular, it'll therefore also be unique per Drop_timer). Behavior is undefined if this rule is not followed.

Definition at line 52 of file drop_timer.cpp.

References FLOW_LOG_TRACE, m_flying_packets, and m_in_events_group.

◆ on_packet_no_longer_in_flight()

void flow::net_flow::Drop_timer::on_packet_no_longer_in_flight ( packet_id_t  packet_id)

Indicates that a packet for which on_packet_in_flight() was called is now no longer considered In-flight in the Peer_socket sense; see Peer_socket::m_snd_flying_pkts_by_sent_when for definition of In-flight.

Since on_packet_in_flight(P) must be called only if P was then In-flight, on_packet_no_longer_in_flight(P) can be called at most once and only after the former call.

A contemporary event group must be in progress via start_contemporaneous_events(); or behavior is undefined.

Parameters
packet_idID of a packet for which on_packet_in_flight() has been called exactly once for *this. Otherwise behavior is undefined.

Definition at line 92 of file drop_timer.cpp.

References FLOW_LOG_TRACE, m_flying_packets, and m_in_events_group.

◆ start_contemporaneous_events()

void flow::net_flow::Drop_timer::start_contemporaneous_events ( )

Indicates the start of a series of zero or more contemporary on_*() event calls, to be marked as finished via end_contemporaneous_events().

Contemporary means to be treated as occurring in that order but essentially simultaneously. (It is recommended but not enforced that they be registered in the same boost.asio task.) This call should be followed by the 0+ on_*() calls; and finally end_contemporaneous_events(). Grouping events in this way allows for better performance than, for example, a series of one-event groups.

Definition at line 41 of file drop_timer.cpp.

References FLOW_LOG_TRACE, m_at_events_start_oldest_flying_packet, m_during_events_newest_acked_packet, m_flying_packets, and m_in_events_group.

◆ start_timer()

void flow::net_flow::Drop_timer::start_timer ( )
private

Starts a new wait on the timer, so that is it asynchronously triggered according to the current DTO value.

Pre-condition: !m_timer_running.

Definition at line 347 of file drop_timer.cpp.

References FLOW_ERROR_SYS_ERROR_LOG_WARNING, FLOW_LOG_TRACE, flow::log::Log_context::get_log_component(), flow::log::Log_context::get_logger(), handle_timer_firing(), m_current_wait_id, m_node_task_engine, m_sock, m_sock_drop_timeout, m_timer, m_timer_running, flow::net_flow::error::S_INTERNAL_ERROR_SYSTEM_ERROR_ASIO_TIMER, flow::log::Logger::should_log(), and timer_failure().

Referenced by end_contemporaneous_events().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ timer_failure()

void flow::net_flow::Drop_timer::timer_failure ( Ptr  prevent_destruction,
const Error_code err_code 
)
private

Called by boost.asio after we post it, in the event of some timer error.

If m_done, does nothing (meaning the object was turned off before this had a chance to be executed). Otherwise executes the m_timer_failure() callback.

Parameters
prevent_destructionshared_from_this() at the time of m_timer.async_wait(). It assures this cannot be deleted until this->handle_timer_firing() is called and returns.
err_codeThe portable error to pass to the m_timer_failure().

Definition at line 571 of file drop_timer.cpp.

References m_done, and m_timer_failure.

Referenced by create_drop_timer(), and start_timer().

Here is the caller graph for this function:

Member Data Documentation

◆ m_at_events_start_oldest_flying_packet

packet_id_t flow::net_flow::Drop_timer::m_at_events_start_oldest_flying_packet
private

The packet ID of the least recently sent In-flight packet at last start_contemporaneous_events() call; or 0 if m_flying_packets.empty() at the time.

Definition at line 459 of file drop_timer.hpp.

Referenced by end_contemporaneous_events(), and start_contemporaneous_events().

◆ m_current_wait_id

timer_wait_id_t flow::net_flow::Drop_timer::m_current_wait_id
private

Unique (within this object) identifier of the last start_timer() call.

Each time start_timer() calls boost::asio::basic_waitable_timer::async_wait(), it passes ++m_current_wait_id to the timer firing callback. Then when that callback runs, it can check whether this passed wait_id is equal to m_current_wait_id; if not then it knows the callback is called for an obsolete wait and should do nothing. This is to help deal with the fact that a basic_waitable_timer callback can fire after it is cancel()ed if the callback was already queued by the time cancel() is called (see boost::asio::basic_waitable_timer documentation).

For example, if I schedule wait 1, and it is queued to fire 5 seconds later, but at that point something causes me to cancel and schedule wait 2 for another 5 seconds later, then wait 1's callback, though soon called, will detect that wait_id < m_current_wait_id and do nothing, as desired. Another 5 seconds later, wait 2's callback will see that wait_id == m_current_wait_id and do stuff, as desired.

This must only change via increment and start at zero. Wrap-around is impossible due to the range of timer_wait_id_t and the time periods practically involved.

m_current_wait_id should not be checked unless m_timer_running.

Definition at line 430 of file drop_timer.hpp.

Referenced by disable_timer(), handle_timer_firing(), and start_timer().

◆ m_done

bool flow::net_flow::Drop_timer::m_done
private

true if and only if done() has been called. Starts at false, can only change to true.

Definition at line 433 of file drop_timer.hpp.

Referenced by done(), handle_timer_firing(), and timer_failure().

◆ m_during_events_newest_acked_packet

packet_id_t flow::net_flow::Drop_timer::m_during_events_newest_acked_packet
private

During the time period starting with the last start_contemporaneous_events() call and ending with the subsequent end_contemporaneous_events() call, if any – in other words, during the last contemporary events group, finished or otherwise – this is the ID of the most-recently-sent packet (highest packet ID) such that that packet was acknowledged during that time period.

0 if none were acknowledged.

Definition at line 467 of file drop_timer.hpp.

Referenced by end_contemporaneous_events(), on_ack(), and start_contemporaneous_events().

◆ m_flying_packets

std::set<packet_id_t> flow::net_flow::Drop_timer::m_flying_packets
private

Packet IDs of packets to have been sent over wire and still considered In-flight, ordered from earliest to latest to have been sent out.

These are packet IDs for which on_packet_in_flight() but not yet on_packet_no_longer_in_flight() has been called.

Since the iterator ordering is increasing numerical order (ordered set of packet_ids), and packet_ids passed to on_packet_in_flight() must be increasing from call to call, the aforementioned ordering (by time sent) is expressed via the iterator ordering. Thus the earliest-sent packet is easily accessible via begin(); this is needed for certain drop-timer situations.

Logarithmic-time erasure for on_packet_no_longer_in_flight() is also available.

Definition at line 453 of file drop_timer.hpp.

Referenced by end_contemporaneous_events(), on_ack(), on_no_packets_in_flight_any_longer(), on_packet_in_flight(), on_packet_no_longer_in_flight(), and start_contemporaneous_events().

◆ m_in_events_group

bool flow::net_flow::Drop_timer::m_in_events_group
private

true if and only if the last start_contemporaneous_events() call exists, and either end_contemporaneous_events() hasn't been called at all or was called before the former call.

Definition at line 473 of file drop_timer.hpp.

Referenced by end_contemporaneous_events(), on_ack(), on_no_packets_in_flight_any_longer(), on_packet_in_flight(), on_packet_no_longer_in_flight(), and start_contemporaneous_events().

◆ m_node_task_engine

util::Task_engine& flow::net_flow::Drop_timer::m_node_task_engine
private

Node::m_task_engine of the containing Node. Used to schedule timer events.

Definition at line 376 of file drop_timer.hpp.

Referenced by start_timer().

◆ m_sock

const Peer_socket::Const_ptr flow::net_flow::Drop_timer::m_sock
private

The containing Peer_socket (note that this is read-only access).

This may be used to, at least, get the time point at which a packet was originally sent, to schedule the timer, as well to get socket options related to Drop Timer.

Definition at line 392 of file drop_timer.hpp.

Referenced by end_contemporaneous_events(), handle_timer_firing(), and start_timer().

◆ m_sock_drop_timeout

Fine_duration& flow::net_flow::Drop_timer::m_sock_drop_timeout
private

Reference to the containing Peer_socket's Peer_socket::m_snd_drop_timeout data member (= DTO, Drop Timeout, RTO).

Why is this not const? Because under certain policies this object is allowed to CHANGE the value of the DTO. E.g., RFC 6298 says that RTO MUST be doubled each time the Retransmit Timer fires. (However a subsequent RTT measurement and SRTT recalculation will change it back to the normally computed value.)

Definition at line 385 of file drop_timer.hpp.

Referenced by handle_timer_firing(), and start_timer().

◆ m_timer

util::Timer flow::net_flow::Drop_timer::m_timer
private

The Drop Timer itself.

This class maintains it (including based on input events reported by the user) and informs the user when it expires and what to do about it if so.

Definition at line 398 of file drop_timer.hpp.

Referenced by disable_timer(), and start_timer().

◆ m_timer_failure

Function<void (const Error_code& err_code)> flow::net_flow::Drop_timer::m_timer_failure
private

Called on error. See Drop_timer constructor.

Definition at line 436 of file drop_timer.hpp.

Referenced by done(), and timer_failure().

◆ m_timer_fired

Function<void (bool drop_all_packets)> flow::net_flow::Drop_timer::m_timer_fired
private

Called on Drop Timeout. See Drop_timer constructor.

Definition at line 439 of file drop_timer.hpp.

Referenced by done(), and handle_timer_firing().

◆ m_timer_running

bool flow::net_flow::Drop_timer::m_timer_running
private

Is there an active (non-obsolete, not-canceled) asynchronous wait in progress on m_timer? More precisely, this is true if the latest start_timer() call was later than the latest disable_timer() or handle_timer_firing(), or if start_timer() has been called but disable_timer() or handle_timer_firing() has not.

m_timer_running should not be checked unless !m_done.

Definition at line 408 of file drop_timer.hpp.

Referenced by disable_timer(), done(), handle_timer_firing(), and start_timer().


The documentation for this class was generated from the following files: