Skip to content
This repository has been archived by the owner on Sep 6, 2022. It is now read-only.

Commit

Permalink
Shared backoffs interface proposal.
Browse files Browse the repository at this point in the history
  • Loading branch information
petar committed Mar 8, 2020
1 parent 1f6edd8 commit d1503bf
Showing 1 changed file with 56 additions and 57 deletions.
113 changes: 56 additions & 57 deletions backoff/backoff.go
@@ -1,80 +1,79 @@
// Package backoff provides facilities for creating interdependent backoff timers.
// Package backoff provides facilities for working with interdependent backoff timers.
//
// The design of "backoff trees" proposed in this package is motivated by
// https://github.com/libp2p/go-libp2p-swarm/issues/37.
// This package is motivated by https://github.com/libp2p/go-libp2p-swarm/issues/37.
//
// The design proposed here can be dubbed "backoff trees", and is motivated by the following use case in libp2p:
//
// (1) Each peer has an associated backoff timer, whose significance is that no interaction
// with this peer can commence unless the timer is clear.
// (2) Each peer has a subordinate "find peer" timer, such that find peer operations should not
// be attempted unless the "find peer" timer is clear and the "peer" timer is clear, as well.
// (3) Each peer has any number of subordinate "transport" timers, such that dial attempts on any
// given transport should not happen unless the "transport" timer is clear and the "peer" timer is clear, as well.
// (4) Each TCP transport may have subordinate "IP" timers, such that TCP dial attempts to the given IP
// should not commence unless the "IP", "transport" and "peer" timers are all clear.
// We would like to associate backoff logic to each component of a multiaddr.
// For instance, consider a typical multiaddr of the form IP/transport/protocol.
// The backoff associated with IP dictates whether any multiaddr
// using that IP can be dialed (regardless of transport and protocol).
// The backoff associated with IP and transport dictates whether
// any multiaddr using that IP and transport can be dialed (regardless of protocol).
// And so on.
//
// This example highlights a hierarchical relationship that one might express, for instance as, as:
// peer operations
// find operations
// transport-related operations
// TCP-related operations
// IP-related operations
// Port-related operations
// QUIC-related operations
//
// All nodes in this hierarchy may wish to use a different backoff policy.
// However, in all cases, a timer node is considered "clear" if its own backoff timer is clear,
// as well as the timers of all of its ancestors (all the way to the root).
//
// REMARKS
// Furthermore, we stipulate that software components that utilize backoffs on multiaddrs
// should share the backoff timers in order to benefit from each other's learnings.
//
// Note that this design can be extended to "backoff DAGS", wherein a timer can have multiple parents.
// This can be useful, for instance, in the case when an IP address is viewed as a subordinate timer to multiple protocols,
// like TCP and QUIC.
//
// While supporting timers with multiple parents is straightforward, it is not clear that it can be used conveniently
// by independent code paths. In particular, a runtime instance of the QUIC transport may not (and probably should not)
// be aware that a TCP transport instance is running in parallel.
// To this end, this package provides the definition of a backoff timer (as the interface BackoffTimer),
// as well as an interface for a shared set of backoff timers, called SharedBackoffs.
package backoff

import (
"time"

ma "github.com/multiformats/go-multiaddr"
)

// NewBackoffTimer creates a new backoff timer.
// The timer name is for display purposes only.
func NewBackoffTimer(name string, policy BackoffPolicy, parent BackoffTimer) BackoffTimer {
panic("not implemented")
}
// SharedBackoffs maintains backoff timers that are shared by multiple IPFS components.
// Some of the timers are correlated. If this is the case, the relationships are documented in the access methods below.
type SharedBackoffs interface {

// BackoffPolicy represents a specific backoff logic.
//
// Implementations of BackoffPolicy are purely concerned with the "arithmetic"
// of computing when the respective timer should be cleared (e.g. for making new connection retries).
//
// This interface allows for the implementation of flexible backoff policies.
// For instance, a policy could treat a burst of backoffs as a single one.
type BackoffPolicy interface {
// Timers for dialing multiaddresses.

// Clear informs the policy of the current time and sets its state to cleared.
Clear(now time.Time)
// IP returns the timer associated with a given IP address.
// If the argument multiaddr does not start with an IP component, a panic is thrown.
// The IP timer should be backed off, if it is determined that the IP itself is unreachable
// (e.g. in response to a "no route to IP" error).
// The IP timer should be cleared whenever any successful connection to this IP is established.
IP(ma.Multiaddr) BackoffTimer

// Backoff informs the policy of the current time and sets its state to backing off.
Backoff(now time.Time)
// IPTransport returns the timer associated with a given IP address and a transport (TCP, UDP, etc.).
// If the argument multiaddr does not start with an IP and transport components, a panic is thrown.
// The IP/Transport timer should be backed off, if it is determined that the IP is reachable but the transport is not.
// The IP/Transport timer should be cleared whenever any successful connection to this IP/transport pair is established.
// The IP/Transport timer will report a clear state whenever the IP and IP/Transport timers are both clear.
IPTransport(ma.Multiaddr) BackoffTimer

This comment has been minimized.

Copy link
@willscott

willscott Mar 8, 2020

Contributor

Some of this distinction (IP vs ip+transport) can be encoded within a Multiaddr. ("ip4/1.2.3.4" vs "ip4/1.2.3.4/tcp/443")

Can you figure out how specific of a timer in the tree to return based on how specific of a Multiaddr is passed in?

This comment has been minimized.

Copy link
@petar

petar Mar 9, 2020

Author

The difference between IPTransport() and IPTransportSwarm() cannot be distinguished from looking at the multiaddr alone. This is a subtlety that I discussed with @Stebalien.

Also being explicit about what timer you want to access makes for safer code.


// TimeToClear informs the policy of the current time and returns the duration
// remaining until the back off state is cleared. Zero or negative durations indicate
// that the state is already cleared.
TimeToClear(now time.Time) time.Duration
// IPTransportSwarm returns the timer associated with a given IP address, a transport (TCP, UDP, etc.) and the swarm service.
// If the argument multiaddr does not start with an IP and transport components, a panic is thrown.
// The IP/Transport/Swarm timer should be backed off, if it is determined that the IP is reachable
// using the given transport, but the swarm service is not supported.
// The IP/Transport/Swarm timer should be cleared whenever any successful connection to the IP/transport pair is established
// and the swarm service is available.
// The IP/Transport/Swarm timer will report a clear state whenever the respective IP, IP/Transport and IP/Transport/Swarm
// timers are all clear.
IPTransportSwarm(ma.Multiaddr) BackoffTimer

// IPTransportSwarmProtocol returns the timer associated with a given IP address, transport (TCP, UDP, etc.) and
// protocol, supported through the swarm service.
// If the argument multiaddr does not start with an IP, transport and protocol components, a panic is thrown.
// The IP/Transport/Swarm/Protocol timer should be backed off, if it is determined that the IP is reachable
// using the given transport, the swarm service is supported, but the protocol is not.
// The IP/Transport/Swarm/Protocol timer should be cleared whenever any successful connection to the protocol
// is established through the swarm service on the given IP/transport.
// The IP/Transport/Swarm/Protocol timer will report a clear state whenever the respective
// IP, IP/Transport and IP/Transport/Swarm, and IP/Transport/Swarm/Protocol timers are all clear.
IPTransportSwarmProtocol(ma.Multiaddr) BackoffTimer

// Other shared backoff timers should be added here.
}

// BackoffTimer is a synchronous user-facing interface to a backoff timer.
// Timers are created using NewBackoffTimer.
// BackoffTimer is a user-facing interface to a backoff timer.
type BackoffTimer interface {
// Wait blocks until the timer and all of its ancestors (parent, grandparent, etc.), if any, have been cleared.
Wait()
// TimeToClear returns the duration remaining until the back off state is cleared.
// Zero or negative durations indicate that the state is already cleared.
TimeToClear(now time.Time) time.Duration
// Clear clears this timer and returns instantaneously.
// For example, a user might call this function after a successul connection attempt.
Clear()
Expand Down

0 comments on commit d1503bf

Please sign in to comment.