Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- data PeerStateActionsArguments (muxMode :: MuxMode) socket responderCtx peerAddr versionData versionNumber (m :: Type -> Type) a b = PeerStateActionsArguments {
- spsTracer :: Tracer m (PeerSelectionActionsTrace peerAddr versionNumber)
- spsDeactivateTimeout :: DiffTime
- spsCloseConnectionTimeout :: DiffTime
- spsConnectionManager :: MuxConnectionManager muxMode socket (ExpandedInitiatorContext peerAddr m) responderCtx peerAddr versionData versionNumber ByteString m a b
- spsExitPolicy :: ExitPolicy a
- data PeerConnectionHandle (muxMode :: MuxMode) responderCtx peerAddr versionData bytes (m :: Type -> Type) a b
- withPeerStateActions :: forall (muxMode :: MuxMode) socket responderCtx peerAddr versionData versionNumber m a b x. (Alternative (STM m), MonadAsync m, MonadCatch m, MonadLabelledSTM m, MonadMask m, MonadTimer m, MonadThrow (STM m), HasInitiator muxMode ~ 'True, Typeable versionNumber, Show versionNumber, Ord peerAddr, Typeable peerAddr, Show peerAddr) => PeerStateActionsArguments muxMode socket responderCtx peerAddr versionData versionNumber m a b -> (PeerStateActions peerAddr (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) m -> m x) -> m x
- pchPeerSharing :: forall versionData (muxMode :: MuxMode) responderCtx peerAddr bytes (m :: Type -> Type) a b. (versionData -> PeerSharing) -> PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b -> PeerSharing
- data PeerSelectionActionException = Exception e => PeerSelectionActionException e
- data EstablishConnectionException versionNumber
- = ClientException !(HandshakeException versionNumber)
- | ServerException !(HandshakeException versionNumber)
- data PeerSelectionTimeoutException peerAddr = DeactivationTimeout !(ConnectionId peerAddr)
- data MonitorPeerConnectionBlocked = MonitorPeerConnectionBlocked
- data PeerSelectionActionsTrace peerAddr vNumber
- = PeerStatusChanged (PeerStatusChangeType peerAddr)
- | PeerStatusChangeFailure (PeerStatusChangeType peerAddr) (FailureType vNumber)
- | PeerMonitoringError (ConnectionId peerAddr) SomeException
- | PeerMonitoringResult (ConnectionId peerAddr) (Maybe (WithSomeProtocolTemperature FirstToFinishResult))
- data PeerStatusChangeType peerAddr
- = ColdToWarm !(Maybe peerAddr) !peerAddr
- | WarmToHot !(ConnectionId peerAddr)
- | HotToWarm !(ConnectionId peerAddr)
- | WarmToCooling !(ConnectionId peerAddr)
- | HotToCooling !(ConnectionId peerAddr)
- | CoolingToCold !(ConnectionId peerAddr)
- data FailureType versionNumber
- = HandshakeClientFailure !(HandshakeException versionNumber)
- | HandshakeServerFailure !(HandshakeException versionNumber)
- | HandleFailure !SomeException
- | MuxStoppedFailure
- | TimeoutError
- | ActiveCold
- | ApplicationFailure ![MiniProtocolException]
Introduction
This module implements withPeerStateActions
, giving the user access to the
PeerStateActions
API, which provides the following capabilities:
- synchronous promotions / demotions
- *
establishPeerConnection
*activatePeerConnection
*deactivatePeerConnection
*closePeerConnection
- monitoring
monitorPeerConnection
- returns the state of the connection.- asynchronous demotions
- happens when a mini-protocol terminates or errors.
Synchronous promotions / demotions
Synchronous promotions / demotions are used by
peerSelectionGovernor
.
- synchronous cold → warm transition
- This transition starts with creating or reusing an inbound connection, do handshake (functionality provided by connection manager), start established and warm mini-protocols, start monitoring thread specified below.
- synchronous warm → hot transition
- This transition quiesces warm protocols and starts hot protocols. There is no timeout to quiesce warm mini-protocols. The tip-sample protocol which is the only planned warm protocol has some states that have a longer timeout when the remote peer has agency, but it does not transfer much data.
- synchronous hot → warm transition
- Within a timeout, stop hot protocols and let the warm protocols continue running. If the timeout expires the connection is closed. Note that this will impact inbound side of a duplex connection. We cannot do any better: closing is a cooperative action since we require to arrive at a well defined state of the multiplexer (no outstanding data in ingress queue). This transition must use last to finish synchronisation of all hot mini-protocols.
- synchronous warm → cold transition
- Shutdown established and warm protocols. As in the previous transition it must use last to finish synchronisation on established and warm protocol termination, if this synchronisation timeouts the connection is closed.
Monitoring Loop
The monitoring loop is responsible for taking an action when one of the mini-protocols either terminates or errors. When a mini-protocol terminates
- if (mini-protocol was hot): trigger a synchronous hot → warm transition.
- otherwise: close the connection.
The monitoring loop is supposed to stop when the multiplexer stops.
Note that the monitoring loop must act as soon as one of the mini-protocols terminates or errors, hence the use of first to finish synchronisation.
The multiplexer guarantees that whenever one of the mini-protocols errors the connection is closed. This simplifies the actions needed to be taken by the monitoring loop.
Asynchronous demotions
- asynchronous * → cold transition
- This demotion is triggered whenever any of the mini-protocol errors. This does not require a further action by the monitoring loop: mux will close the connection, monitoring loop will terminate.
- asynchronous hot → warm demotion
- This demotion is triggered if a hot mini-protocol terminates cleanly. In this case we trigger synchronous hot → warm demotion which will halt all hot mini-protocols and will notify the peer-to-peer governor about the change.
Implementation details
PeerStateActions
are build on top of ConnectionManager
which provides
a primitive to present us a negotiated connection (i.e. after running
the handshake) and the multiplexer api which allows to start mini-protocols
and track their termination via an STM
interface. Each connection has an
associated PeerConnectionHandle
which holds all the data associated with
a connection.
Most important are pchMux :: Mux mode m
which allows us
to interact with the multiplexer and pchAppHandles
. The latter contains
information about each mini-protocol and its STM
mini-protocol monitoring
action. ahMiniProtocolResults
allows us to build last-to-finish
awaitAllResults
and first-to-finish awaitFirstResult
synchronisations that
we need in synchronous transitions and monitoring loop respectively.
ahControlVar
is a per-temperature TVar
which holds ControlMessage
. It
is passed from ConnectionHandler
via Handle
. This variable allows
us to terminate, quiesce or re-enable mini-protocols.
Below is a schematic illustration of function calls / threads and shared
state variables. Reads done just make assertions are not included. The
diagram does not include establishPeerConnection
.
Legend: ─ - functions │░ - threads ━ - STM mutable variables ├──▶┃ - write to a TVar │◀──┨ - read from a TVar ├──▶│ - function call PeerStateVar - 'pchPeerStatus' 'TVar' MiniProtocolResults - 'ahMiniProtocolResults' 'TVar' ControlVar - 'ahControlVar' 'TVar' ┌──────────────────────────────────────────┐ │ ┌────────┐ │ │ │ │ │ ┌────────────────┴─┴─┐ │ │ ┌────────────────────┐│ ▼ ▼ ┌────────────────────┐││ ┌──────────────────────────┐ ┌─────────────────────┐ │░░░░░░░░░░░░░░░░░░░░│││ │ │ │ │ │░peerMonitoringLoop░││┘ │ deactivatePeerConnection │ │ closePeerConnection │ │░░░░░░░░░░░░░░░░░░░░│┘ │ │ │ │ └┬───────────────────┘ └┬────────────────────┬────┘ └───────┬─────────────┘ │ ▲ │ ▲ │ ▲ ▲ │ │ ┌───┼────────────────────┘ │ │ │ │ │ │ │ ┌─┼────────────────────────┼────────────────┼──────────────┘ │ │ │ │ │ │ │ ┌──────────┼────────────────┘ │ │ │ │ │ │ │ │ ┌────────────────┘ ▒▒│▒│▒│▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒│▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒ │ │ │ └───────────────┐ │ │ │ │ ▒▒▒ ▒ ▼ ▼ ▼ │ │ │ ▼ ▼ ▒ ▒▒▒ ▒┏━━━━━━━━━━━━━━┓ ┏┷━━━━━━━━┷━━━━━┷┓ ┏━━━━━━━━━━━━━━━━┓ ▒ ▒ ▒ ▒┃ ┃┓ ┃ ┃┓ ┃ ┃┓ ▒ ▒ ▒ ▒┃ PeerStateVar ┃┃┓ ┃ MiniProtocol ┃┃┓ ┃ ControlVar ┃┃┓ ▒ ▒ ▒ ▒┃ ┃┃┃ ┃ Results ┃┃┃ ┃ - established ┃┃┃ ▒ ▒ ▒ ▒┃ ┃┃┃ ┃ - established ┃┃┃ ┃ - warm ┃┃┃ ▒ ▒ ▒ ▒┗━━━━━━━━━━━━━━┛┃┃ ┃ - warm ┃┃┃ ┃ - hot ┃┃┃ ▒ ▒ ▒ ▒ ┗━━━━━━━━━━━━━━┛┃ ┃ - hot ┃┃┃ ┃ ┃┃┃ ▒ ▒ ▒ ▒ ┗━━━━━━━━━━━━━━┛ ┃ ┃┃┃ ┃ ┃┃┃ ▒ ▒ ▒ ▒ ▲ ┗━━━━━━━━━━━━━━━━┛┃┃ ┗━━━━━━━━━━━━━━━━┛┃┃ ▒ ▒ ▒ ▒ │ ┗━━━━━━━━━━━━━━━━┛┃ ┗━━━━━━━━━━━━━━━━┛┃ ▒ ▒ ▒ ▒ │ ┗━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━┛ ▒ ▒ ▒ ▒ │ ▲ ▒ ▒ ▒ ▒ │ PeerConnectionHandles │ ▒ ▒ ▒ ▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒ ▒ ▒ │ │ ▒ ▒ ▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒ ▒│ │ ▒ ▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ │ ┌─────────────────────────┘ ┌─┴───────────────────┴──┐ │ │ │ activatePeerConnection │ │ │ └────────────────────────┘
Notes:
All three upper boxes: peerMonitoringLoop
, deactivatePeerConnection
and
closePeerConnection
are reading ahMiniProtocolResults
via the
last-to-finish awaitAllResults
synchronisation.
All of the thin boxes are writing to pchPeerStatus
variable; which is read
by 'monitorPeerConnection. Also all of them writing to ahControlVar
:
peerMonitoringLoop
does that through a call to deactivePeerConnection
or
closePeerConnection
.
data PeerStateActionsArguments (muxMode :: MuxMode) socket responderCtx peerAddr versionData versionNumber (m :: Type -> Type) a b Source #
Record of arguments of peerSelectionActions
.
PeerStateActionsArguments | |
|
data PeerConnectionHandle (muxMode :: MuxMode) responderCtx peerAddr versionData bytes (m :: Type -> Type) a b Source #
Each established connection has access to PeerConnectionHandle
. It
allows to promote / demote or close the connection, by having access to
Mux
, three bundles of miniprotocols: for hot, warm and established peers
together with their state StrictTVar
s.
Instances
(Show peerAddr, Show versionData) => Show (PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions showsPrec :: Int -> PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b -> ShowS # show :: PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b -> String # showList :: [PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b] -> ShowS # |
withPeerStateActions :: forall (muxMode :: MuxMode) socket responderCtx peerAddr versionData versionNumber m a b x. (Alternative (STM m), MonadAsync m, MonadCatch m, MonadLabelledSTM m, MonadMask m, MonadTimer m, MonadThrow (STM m), HasInitiator muxMode ~ 'True, Typeable versionNumber, Show versionNumber, Ord peerAddr, Typeable peerAddr, Show peerAddr) => PeerStateActionsArguments muxMode socket responderCtx peerAddr versionData versionNumber m a b -> (PeerStateActions peerAddr (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) m -> m x) -> m x Source #
pchPeerSharing :: forall versionData (muxMode :: MuxMode) responderCtx peerAddr bytes (m :: Type -> Type) a b. (versionData -> PeerSharing) -> PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b -> PeerSharing Source #
Exceptions
data PeerSelectionActionException Source #
Parent exception of all peer selection action exceptions.
Instances
data EstablishConnectionException versionNumber Source #
ClientException !(HandshakeException versionNumber) | Handshake client failed |
ServerException !(HandshakeException versionNumber) | Handshake server failed |
Instances
(Show versionNumber, Typeable versionNumber) => Exception (EstablishConnectionException versionNumber) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions toException :: EstablishConnectionException versionNumber -> SomeException # fromException :: SomeException -> Maybe (EstablishConnectionException versionNumber) # displayException :: EstablishConnectionException versionNumber -> String # backtraceDesired :: EstablishConnectionException versionNumber -> Bool # | |
Show versionNumber => Show (EstablishConnectionException versionNumber) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions showsPrec :: Int -> EstablishConnectionException versionNumber -> ShowS # show :: EstablishConnectionException versionNumber -> String # showList :: [EstablishConnectionException versionNumber] -> ShowS # |
data PeerSelectionTimeoutException peerAddr Source #
DeactivationTimeout !(ConnectionId peerAddr) |
Instances
(Show peerAddr, Typeable peerAddr) => Exception (PeerSelectionTimeoutException peerAddr) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions toException :: PeerSelectionTimeoutException peerAddr -> SomeException # fromException :: SomeException -> Maybe (PeerSelectionTimeoutException peerAddr) # displayException :: PeerSelectionTimeoutException peerAddr -> String # backtraceDesired :: PeerSelectionTimeoutException peerAddr -> Bool # | |
Show peerAddr => Show (PeerSelectionTimeoutException peerAddr) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions showsPrec :: Int -> PeerSelectionTimeoutException peerAddr -> ShowS # show :: PeerSelectionTimeoutException peerAddr -> String # showList :: [PeerSelectionTimeoutException peerAddr] -> ShowS # |
data MonitorPeerConnectionBlocked Source #
Throw an exception when monitorPeerConnection
blocks.
Instances
Trace
data PeerSelectionActionsTrace peerAddr vNumber Source #
Traces produced by peerSelectionActions
.
PeerStatusChanged (PeerStatusChangeType peerAddr) | |
PeerStatusChangeFailure (PeerStatusChangeType peerAddr) (FailureType vNumber) | |
PeerMonitoringError (ConnectionId peerAddr) SomeException | |
PeerMonitoringResult (ConnectionId peerAddr) (Maybe (WithSomeProtocolTemperature FirstToFinishResult)) |
Instances
(Show peerAddr, Show vNumber) => Show (PeerSelectionActionsTrace peerAddr vNumber) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions showsPrec :: Int -> PeerSelectionActionsTrace peerAddr vNumber -> ShowS # show :: PeerSelectionActionsTrace peerAddr vNumber -> String # showList :: [PeerSelectionActionsTrace peerAddr vNumber] -> ShowS # |
data PeerStatusChangeType peerAddr Source #
All transitions.
ColdToWarm | During the |
| |
WarmToHot !(ConnectionId peerAddr) | |
HotToWarm !(ConnectionId peerAddr) | |
WarmToCooling !(ConnectionId peerAddr) | |
HotToCooling !(ConnectionId peerAddr) | |
CoolingToCold !(ConnectionId peerAddr) |
Instances
Show peerAddr => Show (PeerStatusChangeType peerAddr) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions showsPrec :: Int -> PeerStatusChangeType peerAddr -> ShowS # show :: PeerStatusChangeType peerAddr -> String # showList :: [PeerStatusChangeType peerAddr] -> ShowS # |
data FailureType versionNumber Source #
Type of failure with additional exception context; We don't log handshake errors as this will be done by the handshake tracer.
HandshakeClientFailure !(HandshakeException versionNumber) | |
HandshakeServerFailure !(HandshakeException versionNumber) | |
HandleFailure !SomeException | |
MuxStoppedFailure | |
TimeoutError | |
ActiveCold | |
ApplicationFailure ![MiniProtocolException] |
Instances
Show versionNumber => Show (FailureType versionNumber) Source # | |
Defined in Ouroboros.Network.PeerSelection.PeerStateActions showsPrec :: Int -> FailureType versionNumber -> ShowS # show :: FailureType versionNumber -> String # showList :: [FailureType versionNumber] -> ShowS # |