{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Ouroboros.Network.PeerSelection.Governor
(
PeerSelectionPolicy (..)
, PeerSelectionTargets (..)
, PeerSelectionActions (..)
, PeerStateActions (..)
, TracePeerSelection (..)
, DebugPeerSelection (..)
, peerSelectionGovernor
, peerChurnGovernor
, assertPeerSelectionState
, sanePeerSelectionTargets
, establishedPeersStatus
, PeerSelectionState (..)
, PeerSelectionCounters (..)
, nullPeerSelectionTargets
, emptyPeerSelectionState
, ChurnMode (..)
) where
import Data.Cache
import Data.Semigroup (Min (..))
import Data.Void (Void)
import Control.Applicative (Alternative ((<|>)))
import Control.Concurrent.JobPool (JobPool)
import qualified Control.Concurrent.JobPool as JobPool
import Control.Monad.Class.MonadAsync
import Control.Monad.Class.MonadSTM.Strict
import Control.Monad.Class.MonadThrow
import Control.Monad.Class.MonadTime
import Control.Monad.Class.MonadTimer
import Control.Tracer (Tracer (..), traceWith)
import System.Random
import Ouroboros.Network.BlockFetch (FetchMode (..))
import Ouroboros.Network.Diffusion.Policies (closeConnectionTimeout)
import qualified Ouroboros.Network.PeerSelection.EstablishedPeers as EstablishedPeers
import qualified Ouroboros.Network.PeerSelection.Governor.ActivePeers as ActivePeers
import qualified Ouroboros.Network.PeerSelection.Governor.EstablishedPeers as EstablishedPeers
import qualified Ouroboros.Network.PeerSelection.Governor.KnownPeers as KnownPeers
import qualified Ouroboros.Network.PeerSelection.Governor.Monitor as Monitor
import qualified Ouroboros.Network.PeerSelection.Governor.RootPeers as RootPeers
import Ouroboros.Network.PeerSelection.Governor.Types
import qualified Ouroboros.Network.PeerSelection.KnownPeers as KnownPeers
import Ouroboros.Network.PeerSelection.PeerMetric
peerSelectionGovernor :: (MonadAsync m, MonadLabelledSTM m, MonadMask m,
MonadTime m, MonadTimer m, Ord peeraddr)
=> Tracer m (TracePeerSelection peeraddr)
-> Tracer m (DebugPeerSelection peeraddr peerconn)
-> Tracer m PeerSelectionCounters
-> StdGen
-> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionPolicy peeraddr m
-> m Void
peerSelectionGovernor :: Tracer m (TracePeerSelection peeraddr)
-> Tracer m (DebugPeerSelection peeraddr peerconn)
-> Tracer m PeerSelectionCounters
-> StdGen
-> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionPolicy peeraddr m
-> m Void
peerSelectionGovernor Tracer m (TracePeerSelection peeraddr)
tracer Tracer m (DebugPeerSelection peeraddr peerconn)
debugTracer Tracer m PeerSelectionCounters
countersTracer StdGen
fuzzRng PeerSelectionActions peeraddr peerconn m
actions PeerSelectionPolicy peeraddr m
policy =
(JobPool () m (Completion m peeraddr peerconn) -> m Void) -> m Void
forall group (m :: * -> *) a b.
(MonadAsync m, MonadThrow m, MonadLabelledSTM m) =>
(JobPool group m a -> m b) -> m b
JobPool.withJobPool ((JobPool () m (Completion m peeraddr peerconn) -> m Void)
-> m Void)
-> (JobPool () m (Completion m peeraddr peerconn) -> m Void)
-> m Void
forall a b. (a -> b) -> a -> b
$ \JobPool () m (Completion m peeraddr peerconn)
jobPool ->
Tracer m (TracePeerSelection peeraddr)
-> Tracer m (DebugPeerSelection peeraddr peerconn)
-> Tracer m PeerSelectionCounters
-> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionPolicy peeraddr m
-> JobPool () m (Completion m peeraddr peerconn)
-> PeerSelectionState peeraddr peerconn
-> m Void
forall (m :: * -> *) peeraddr peerconn.
(MonadAsync m, MonadMask m, MonadTime m, MonadTimer m,
Ord peeraddr) =>
Tracer m (TracePeerSelection peeraddr)
-> Tracer m (DebugPeerSelection peeraddr peerconn)
-> Tracer m PeerSelectionCounters
-> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionPolicy peeraddr m
-> JobPool () m (Completion m peeraddr peerconn)
-> PeerSelectionState peeraddr peerconn
-> m Void
peerSelectionGovernorLoop
Tracer m (TracePeerSelection peeraddr)
tracer
Tracer m (DebugPeerSelection peeraddr peerconn)
debugTracer
Tracer m PeerSelectionCounters
countersTracer
PeerSelectionActions peeraddr peerconn m
actions
PeerSelectionPolicy peeraddr m
policy
JobPool () m (Completion m peeraddr peerconn)
jobPool
(StdGen -> PeerSelectionState peeraddr peerconn
forall peeraddr peerconn.
StdGen -> PeerSelectionState peeraddr peerconn
emptyPeerSelectionState StdGen
fuzzRng)
peerSelectionGovernorLoop :: forall m peeraddr peerconn.
(MonadAsync m, MonadMask m,
MonadTime m, MonadTimer m,
Ord peeraddr)
=> Tracer m (TracePeerSelection peeraddr)
-> Tracer m (DebugPeerSelection peeraddr peerconn)
-> Tracer m PeerSelectionCounters
-> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionPolicy peeraddr m
-> JobPool () m (Completion m peeraddr peerconn)
-> PeerSelectionState peeraddr peerconn
-> m Void
peerSelectionGovernorLoop :: Tracer m (TracePeerSelection peeraddr)
-> Tracer m (DebugPeerSelection peeraddr peerconn)
-> Tracer m PeerSelectionCounters
-> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionPolicy peeraddr m
-> JobPool () m (Completion m peeraddr peerconn)
-> PeerSelectionState peeraddr peerconn
-> m Void
peerSelectionGovernorLoop Tracer m (TracePeerSelection peeraddr)
tracer
Tracer m (DebugPeerSelection peeraddr peerconn)
debugTracer
Tracer m PeerSelectionCounters
countersTracer
PeerSelectionActions peeraddr peerconn m
actions
PeerSelectionPolicy peeraddr m
policy
JobPool () m (Completion m peeraddr peerconn)
jobPool =
PeerSelectionState peeraddr peerconn -> m Void
loop
where
loop :: PeerSelectionState peeraddr peerconn -> m Void
loop :: PeerSelectionState peeraddr peerconn -> m Void
loop !PeerSelectionState peeraddr peerconn
st = PeerSelectionState peeraddr peerconn -> m Void -> m Void
forall peeraddr peerconn a.
Ord peeraddr =>
PeerSelectionState peeraddr peerconn -> a -> a
assertPeerSelectionState PeerSelectionState peeraddr peerconn
st (m Void -> m Void) -> m Void -> m Void
forall a b. (a -> b) -> a -> b
$ do
Time
blockedAt <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
let knownPeers' :: KnownPeers peeraddr
knownPeers' = Time -> KnownPeers peeraddr -> KnownPeers peeraddr
forall peeraddr.
Ord peeraddr =>
Time -> KnownPeers peeraddr -> KnownPeers peeraddr
KnownPeers.setCurrentTime Time
blockedAt (PeerSelectionState peeraddr peerconn -> KnownPeers peeraddr
forall peeraddr peerconn.
PeerSelectionState peeraddr peerconn -> KnownPeers peeraddr
knownPeers PeerSelectionState peeraddr peerconn
st)
establishedPeers' :: EstablishedPeers peeraddr peerconn
establishedPeers' = Time
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
forall peeraddr peerconn.
Ord peeraddr =>
Time
-> EstablishedPeers peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
EstablishedPeers.setCurrentTime Time
blockedAt (PeerSelectionState peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
forall peeraddr peerconn.
PeerSelectionState peeraddr peerconn
-> EstablishedPeers peeraddr peerconn
establishedPeers PeerSelectionState peeraddr peerconn
st)
st' :: PeerSelectionState peeraddr peerconn
st' = PeerSelectionState peeraddr peerconn
st { knownPeers :: KnownPeers peeraddr
knownPeers = KnownPeers peeraddr
knownPeers',
establishedPeers :: EstablishedPeers peeraddr peerconn
establishedPeers = EstablishedPeers peeraddr peerconn
establishedPeers' }
TimedDecision m peeraddr peerconn
timedDecision <- Time
-> PeerSelectionState peeraddr peerconn
-> m (TimedDecision m peeraddr peerconn)
evalGuardedDecisions Time
blockedAt PeerSelectionState peeraddr peerconn
st'
Time
now <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
let Decision { TracePeerSelection peeraddr
decisionTrace :: forall (m :: * -> *) peeraddr peerconn.
Decision m peeraddr peerconn -> TracePeerSelection peeraddr
decisionTrace :: TracePeerSelection peeraddr
decisionTrace, [Job () m (Completion m peeraddr peerconn)]
decisionJobs :: forall (m :: * -> *) peeraddr peerconn.
Decision m peeraddr peerconn
-> [Job () m (Completion m peeraddr peerconn)]
decisionJobs :: [Job () m (Completion m peeraddr peerconn)]
decisionJobs, PeerSelectionState peeraddr peerconn
decisionState :: forall (m :: * -> *) peeraddr peerconn.
Decision m peeraddr peerconn
-> PeerSelectionState peeraddr peerconn
decisionState :: PeerSelectionState peeraddr peerconn
decisionState } =
TimedDecision m peeraddr peerconn
timedDecision Time
now
newCounters :: PeerSelectionCounters
newCounters = PeerSelectionState peeraddr peerconn -> PeerSelectionCounters
forall peeraddr peerconn.
Ord peeraddr =>
PeerSelectionState peeraddr peerconn -> PeerSelectionCounters
peerStateToCounters PeerSelectionState peeraddr peerconn
decisionState
Tracer m (TracePeerSelection peeraddr)
-> TracePeerSelection peeraddr -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TracePeerSelection peeraddr)
tracer TracePeerSelection peeraddr
decisionTrace
Tracer m PeerSelectionCounters
-> Cache PeerSelectionCounters -> PeerSelectionCounters -> m ()
forall (m :: * -> *) a.
(Applicative m, Eq a) =>
Tracer m a -> Cache a -> a -> m ()
traceWithCache Tracer m PeerSelectionCounters
countersTracer
(PeerSelectionState peeraddr peerconn -> Cache PeerSelectionCounters
forall peeraddr peerconn.
PeerSelectionState peeraddr peerconn -> Cache PeerSelectionCounters
countersCache PeerSelectionState peeraddr peerconn
decisionState)
PeerSelectionCounters
newCounters
(Job () m (Completion m peeraddr peerconn) -> m ())
-> [Job () m (Completion m peeraddr peerconn)] -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (JobPool () m (Completion m peeraddr peerconn)
-> Job () m (Completion m peeraddr peerconn) -> m ()
forall group (m :: * -> *) a.
(MonadAsync m, MonadMask m, Ord group) =>
JobPool group m a -> Job group m a -> m ()
JobPool.forkJob JobPool () m (Completion m peeraddr peerconn)
jobPool) [Job () m (Completion m peeraddr peerconn)]
decisionJobs
PeerSelectionState peeraddr peerconn -> m Void
loop (PeerSelectionState peeraddr peerconn
decisionState { countersCache :: Cache PeerSelectionCounters
countersCache = PeerSelectionCounters -> Cache PeerSelectionCounters
forall a. a -> Cache a
Cache PeerSelectionCounters
newCounters })
evalGuardedDecisions :: Time
-> PeerSelectionState peeraddr peerconn
-> m (TimedDecision m peeraddr peerconn)
evalGuardedDecisions :: Time
-> PeerSelectionState peeraddr peerconn
-> m (TimedDecision m peeraddr peerconn)
evalGuardedDecisions Time
blockedAt PeerSelectionState peeraddr peerconn
st =
case Time
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
guardedDecisions Time
blockedAt PeerSelectionState peeraddr peerconn
st of
GuardedSkip Maybe (Min Time)
_ ->
[Char] -> m (TimedDecision m peeraddr peerconn)
forall a. HasCallStack => [Char] -> a
error [Char]
"peerSelectionGovernorLoop: impossible: nothing to do"
Guarded Nothing decisionAction -> do
Tracer m (DebugPeerSelection peeraddr peerconn)
-> DebugPeerSelection peeraddr peerconn -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (DebugPeerSelection peeraddr peerconn)
debugTracer (Time
-> Maybe DiffTime
-> PeerSelectionState peeraddr peerconn
-> DebugPeerSelection peeraddr peerconn
forall peeraddr peerconn.
Time
-> Maybe DiffTime
-> PeerSelectionState peeraddr peerconn
-> DebugPeerSelection peeraddr peerconn
TraceGovernorState Time
blockedAt Maybe DiffTime
forall a. Maybe a
Nothing PeerSelectionState peeraddr peerconn
st)
STM m (TimedDecision m peeraddr peerconn)
-> m (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically STM m (TimedDecision m peeraddr peerconn)
decisionAction
Guarded (Just (Min wakeupAt)) decisionAction -> do
let wakeupIn :: DiffTime
wakeupIn = Time -> Time -> DiffTime
diffTime Time
wakeupAt Time
blockedAt
Tracer m (DebugPeerSelection peeraddr peerconn)
-> DebugPeerSelection peeraddr peerconn -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (DebugPeerSelection peeraddr peerconn)
debugTracer (Time
-> Maybe DiffTime
-> PeerSelectionState peeraddr peerconn
-> DebugPeerSelection peeraddr peerconn
forall peeraddr peerconn.
Time
-> Maybe DiffTime
-> PeerSelectionState peeraddr peerconn
-> DebugPeerSelection peeraddr peerconn
TraceGovernorState Time
blockedAt (DiffTime -> Maybe DiffTime
forall a. a -> Maybe a
Just DiffTime
wakeupIn) PeerSelectionState peeraddr peerconn
st)
Timeout m
wakupTimeout <- DiffTime -> m (Timeout m)
forall (m :: * -> *). MonadTimer m => DiffTime -> m (Timeout m)
newTimeout DiffTime
wakeupIn
let wakeup :: STM m (TimedDecision m peeraddr peerconn)
wakeup = Timeout m -> STM m Bool
forall (m :: * -> *). MonadTimer m => Timeout m -> STM m Bool
awaitTimeout Timeout m
wakupTimeout STM m Bool
-> STM m (TimedDecision m peeraddr peerconn)
-> STM m (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TimedDecision m peeraddr peerconn
-> STM m (TimedDecision m peeraddr peerconn)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PeerSelectionState peeraddr peerconn
-> TimedDecision m peeraddr peerconn
forall peeraddr peerconn (m :: * -> *).
PeerSelectionState peeraddr peerconn
-> TimedDecision m peeraddr peerconn
wakeupDecision PeerSelectionState peeraddr peerconn
st)
TimedDecision m peeraddr peerconn
timedDecision <- STM m (TimedDecision m peeraddr peerconn)
-> m (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m (TimedDecision m peeraddr peerconn)
decisionAction STM m (TimedDecision m peeraddr peerconn)
-> STM m (TimedDecision m peeraddr peerconn)
-> STM m (TimedDecision m peeraddr peerconn)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> STM m (TimedDecision m peeraddr peerconn)
forall (m :: * -> *). STM m (TimedDecision m peeraddr peerconn)
wakeup)
Timeout m -> m ()
forall (m :: * -> *). MonadTimer m => Timeout m -> m ()
cancelTimeout Timeout m
wakupTimeout
TimedDecision m peeraddr peerconn
-> m (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) a. Monad m => a -> m a
return TimedDecision m peeraddr peerconn
timedDecision
guardedDecisions :: Time
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
guardedDecisions :: Time
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
guardedDecisions Time
blockedAt PeerSelectionState peeraddr peerconn
st =
PeerSelectionActions peeraddr peerconn m
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) peeraddr peerconn.
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
Monitor.connections PeerSelectionActions peeraddr peerconn m
actions PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> JobPool () m (Completion m peeraddr peerconn)
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) peeraddr peerconn.
MonadSTM m =>
JobPool () m (Completion m peeraddr peerconn)
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
Monitor.jobs JobPool () m (Completion m peeraddr peerconn)
jobPool PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) peeraddr peerconn.
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
Monitor.targetPeers PeerSelectionActions peeraddr peerconn m
actions PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall peeraddr peerconn (m :: * -> *).
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
Monitor.localRoots PeerSelectionActions peeraddr peerconn m
actions PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> Time
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall (m :: * -> *) peeraddr peerconn.
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> Time
-> PeerSelectionState peeraddr peerconn
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
RootPeers.belowTarget PeerSelectionActions peeraddr peerconn m
actions Time
blockedAt PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
forall (m :: * -> *) peeraddr peerconn.
(MonadAsync m, MonadTimer m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
KnownPeers.belowTarget PeerSelectionActions peeraddr peerconn m
actions PeerSelectionPolicy peeraddr m
policy PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> MkGuardedDecision peeraddr peerconn m
forall (m :: * -> *) peeraddr peerconn.
(MonadSTM m, Ord peeraddr) =>
MkGuardedDecision peeraddr peerconn m
KnownPeers.aboveTarget PeerSelectionPolicy peeraddr m
policy PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
forall peeraddr peerconn (m :: * -> *).
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
EstablishedPeers.belowTarget PeerSelectionActions peeraddr peerconn m
actions PeerSelectionPolicy peeraddr m
policy PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
forall peeraddr peerconn (m :: * -> *).
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
EstablishedPeers.aboveTarget PeerSelectionActions peeraddr peerconn m
actions PeerSelectionPolicy peeraddr m
policy PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
forall peeraddr peerconn (m :: * -> *).
(MonadDelay m, MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
ActivePeers.belowTarget PeerSelectionActions peeraddr peerconn m
actions PeerSelectionPolicy peeraddr m
policy PeerSelectionState peeraddr peerconn
st
Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
-> Guarded (STM m) (TimedDecision m peeraddr peerconn)
forall a. Semigroup a => a -> a -> a
<> PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
forall peeraddr peerconn (m :: * -> *).
(MonadSTM m, Ord peeraddr) =>
PeerSelectionActions peeraddr peerconn m
-> MkGuardedDecision peeraddr peerconn m
ActivePeers.aboveTarget PeerSelectionActions peeraddr peerconn m
actions PeerSelectionPolicy peeraddr m
policy PeerSelectionState peeraddr peerconn
st
wakeupDecision :: PeerSelectionState peeraddr peerconn
-> TimedDecision m peeraddr peerconn
wakeupDecision :: PeerSelectionState peeraddr peerconn
-> TimedDecision m peeraddr peerconn
wakeupDecision PeerSelectionState peeraddr peerconn
st Time
_now =
Decision :: forall (m :: * -> *) peeraddr peerconn.
TracePeerSelection peeraddr
-> PeerSelectionState peeraddr peerconn
-> [Job () m (Completion m peeraddr peerconn)]
-> Decision m peeraddr peerconn
Decision {
decisionTrace :: TracePeerSelection peeraddr
decisionTrace = TracePeerSelection peeraddr
forall peeraddr. TracePeerSelection peeraddr
TraceGovernorWakeup,
decisionState :: PeerSelectionState peeraddr peerconn
decisionState = PeerSelectionState peeraddr peerconn
st,
decisionJobs :: [Job () m (Completion m peeraddr peerconn)]
decisionJobs = []
}
peerChurnGovernor :: forall m peeraddr.
( MonadSTM m
, MonadMonotonicTime m
, MonadDelay m
)
=> Tracer m (TracePeerSelection peeraddr)
-> PeerMetrics m peeraddr
-> StrictTVar m ChurnMode
-> StdGen
-> STM m FetchMode
-> PeerSelectionTargets
-> StrictTVar m PeerSelectionTargets
-> m Void
peerChurnGovernor :: Tracer m (TracePeerSelection peeraddr)
-> PeerMetrics m peeraddr
-> StrictTVar m ChurnMode
-> StdGen
-> STM m FetchMode
-> PeerSelectionTargets
-> StrictTVar m PeerSelectionTargets
-> m Void
peerChurnGovernor Tracer m (TracePeerSelection peeraddr)
tracer PeerMetrics m peeraddr
_metrics StrictTVar m ChurnMode
churnModeVar StdGen
inRng STM m FetchMode
getFetchMode PeerSelectionTargets
base StrictTVar m PeerSelectionTargets
peerSelectionVar = do
Time
startTs0 <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
threadDelay DiffTime
3
ChurnMode
mode <- STM m ChurnMode -> m ChurnMode
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically STM m ChurnMode
updateChurnMode
STM m () -> m ()
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m () -> m ()) -> STM m () -> m ()
forall a b. (a -> b) -> a -> b
$ ChurnMode -> STM m ()
increaseActivePeers ChurnMode
mode
Time
endTs0 <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
StdGen -> DiffTime -> m StdGen
fuzzyDelay StdGen
inRng (Time
endTs0 Time -> Time -> DiffTime
`diffTime` Time
startTs0) m StdGen -> (StdGen -> m Void) -> m Void
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= StdGen -> m Void
go
where
updateChurnMode :: STM m ChurnMode
updateChurnMode :: STM m ChurnMode
updateChurnMode = do
FetchMode
fm <- STM m FetchMode
getFetchMode
let mode :: ChurnMode
mode = case FetchMode
fm of
FetchMode
FetchModeDeadline -> ChurnMode
ChurnModeNormal
FetchMode
FetchModeBulkSync -> ChurnMode
ChurnModeBulkSync
StrictTVar m ChurnMode -> ChurnMode -> STM m ()
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
StrictTVar m a -> a -> STM m ()
writeTVar StrictTVar m ChurnMode
churnModeVar ChurnMode
mode
ChurnMode -> STM m ChurnMode
forall (m :: * -> *) a. Monad m => a -> m a
return ChurnMode
mode
increaseActivePeers :: ChurnMode -> STM m ()
increaseActivePeers :: ChurnMode -> STM m ()
increaseActivePeers ChurnMode
mode = do
StrictTVar m PeerSelectionTargets
-> (PeerSelectionTargets -> PeerSelectionTargets) -> STM m ()
forall (m :: * -> *) a.
MonadSTM m =>
StrictTVar m a -> (a -> a) -> STM m ()
modifyTVar StrictTVar m PeerSelectionTargets
peerSelectionVar (\PeerSelectionTargets
targets -> PeerSelectionTargets
targets {
targetNumberOfActivePeers :: Int
targetNumberOfActivePeers =
case ChurnMode
mode of
ChurnMode
ChurnModeNormal ->
PeerSelectionTargets -> Int
targetNumberOfActivePeers PeerSelectionTargets
base
ChurnMode
ChurnModeBulkSync ->
Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
2 (PeerSelectionTargets -> Int
targetNumberOfActivePeers PeerSelectionTargets
base)
})
decreaseActivePeers :: ChurnMode -> STM m ()
decreaseActivePeers :: ChurnMode -> STM m ()
decreaseActivePeers ChurnMode
mode = do
StrictTVar m PeerSelectionTargets
-> (PeerSelectionTargets -> PeerSelectionTargets) -> STM m ()
forall (m :: * -> *) a.
MonadSTM m =>
StrictTVar m a -> (a -> a) -> STM m ()
modifyTVar StrictTVar m PeerSelectionTargets
peerSelectionVar (\PeerSelectionTargets
targets -> PeerSelectionTargets
targets {
targetNumberOfActivePeers :: Int
targetNumberOfActivePeers =
case ChurnMode
mode of
ChurnMode
ChurnModeNormal ->
Int -> Int
decrease (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ PeerSelectionTargets -> Int
targetNumberOfActivePeers PeerSelectionTargets
base
ChurnMode
ChurnModeBulkSync ->
Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
1 (PeerSelectionTargets -> Int
targetNumberOfActivePeers PeerSelectionTargets
base Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
})
go :: StdGen -> m Void
go :: StdGen -> m Void
go !StdGen
rng = do
Time
startTs <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
ChurnMode
churnMode <- STM m ChurnMode -> m ChurnMode
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically STM m ChurnMode
updateChurnMode
Tracer m (TracePeerSelection peeraddr)
-> TracePeerSelection peeraddr -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TracePeerSelection peeraddr)
tracer (TracePeerSelection peeraddr -> m ())
-> TracePeerSelection peeraddr -> m ()
forall a b. (a -> b) -> a -> b
$ ChurnMode -> TracePeerSelection peeraddr
forall peeraddr. ChurnMode -> TracePeerSelection peeraddr
TraceChurnMode ChurnMode
churnMode
STM m () -> m ()
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m () -> m ()) -> STM m () -> m ()
forall a b. (a -> b) -> a -> b
$ ChurnMode -> STM m ()
decreaseActivePeers ChurnMode
churnMode
DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
threadDelay DiffTime
1
STM m () -> m ()
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m () -> m ()) -> STM m () -> m ()
forall a b. (a -> b) -> a -> b
$ ChurnMode -> STM m ()
increaseActivePeers ChurnMode
churnMode
DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
threadDelay DiffTime
1
STM m () -> m ()
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m () -> m ()) -> STM m () -> m ()
forall a b. (a -> b) -> a -> b
$ StrictTVar m PeerSelectionTargets
-> (PeerSelectionTargets -> PeerSelectionTargets) -> STM m ()
forall (m :: * -> *) a.
MonadSTM m =>
StrictTVar m a -> (a -> a) -> STM m ()
modifyTVar StrictTVar m PeerSelectionTargets
peerSelectionVar (\PeerSelectionTargets
targets -> PeerSelectionTargets
targets {
targetNumberOfRootPeers :: Int
targetNumberOfRootPeers = Int -> Int
decrease (PeerSelectionTargets -> Int
targetNumberOfRootPeers PeerSelectionTargets
base)
, targetNumberOfKnownPeers :: Int
targetNumberOfKnownPeers = Int -> Int
decrease (PeerSelectionTargets -> Int
targetNumberOfKnownPeers PeerSelectionTargets
base)
, targetNumberOfEstablishedPeers :: Int
targetNumberOfEstablishedPeers =
Int -> Int
decrease (PeerSelectionTargets -> Int
targetNumberOfEstablishedPeers PeerSelectionTargets
base)
})
DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
threadDelay (DiffTime -> m ()) -> DiffTime -> m ()
forall a b. (a -> b) -> a -> b
$ DiffTime
1 DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
+ DiffTime
closeConnectionTimeout
STM m () -> m ()
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically (STM m () -> m ()) -> STM m () -> m ()
forall a b. (a -> b) -> a -> b
$ StrictTVar m PeerSelectionTargets
-> (PeerSelectionTargets -> PeerSelectionTargets) -> STM m ()
forall (m :: * -> *) a.
MonadSTM m =>
StrictTVar m a -> (a -> a) -> STM m ()
modifyTVar StrictTVar m PeerSelectionTargets
peerSelectionVar (\PeerSelectionTargets
targets -> PeerSelectionTargets
targets {
targetNumberOfRootPeers :: Int
targetNumberOfRootPeers = PeerSelectionTargets -> Int
targetNumberOfRootPeers PeerSelectionTargets
base
, targetNumberOfKnownPeers :: Int
targetNumberOfKnownPeers = PeerSelectionTargets -> Int
targetNumberOfKnownPeers PeerSelectionTargets
base
, targetNumberOfEstablishedPeers :: Int
targetNumberOfEstablishedPeers = PeerSelectionTargets -> Int
targetNumberOfEstablishedPeers PeerSelectionTargets
base
})
Time
endTs <- m Time
forall (m :: * -> *). MonadMonotonicTime m => m Time
getMonotonicTime
StdGen -> DiffTime -> m StdGen
fuzzyDelay StdGen
rng (Time
endTs Time -> Time -> DiffTime
`diffTime` Time
startTs) m StdGen -> (StdGen -> m Void) -> m Void
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= StdGen -> m Void
go
fuzzyDelay :: StdGen -> DiffTime -> m StdGen
fuzzyDelay :: StdGen -> DiffTime -> m StdGen
fuzzyDelay StdGen
rng DiffTime
execTime = do
FetchMode
mode <- STM m FetchMode -> m FetchMode
forall (m :: * -> *) a.
(MonadSTM m, HasCallStack) =>
STM m a -> m a
atomically STM m FetchMode
getFetchMode
case FetchMode
mode of
FetchMode
FetchModeDeadline -> StdGen -> DiffTime -> m StdGen
longDelay StdGen
rng DiffTime
execTime
FetchMode
FetchModeBulkSync -> StdGen -> DiffTime -> m StdGen
shortDelay StdGen
rng DiffTime
execTime
fuzzyDelay' :: DiffTime -> Double -> StdGen -> DiffTime -> m StdGen
fuzzyDelay' :: DiffTime -> Double -> StdGen -> DiffTime -> m StdGen
fuzzyDelay' DiffTime
baseDelay Double
maxFuzz StdGen
rng DiffTime
execTime = do
let (Double
fuzz, StdGen
rng') = (Double, Double) -> StdGen -> (Double, StdGen)
forall a g. (Random a, RandomGen g) => (a, a) -> g -> (a, g)
randomR (Double
0, Double
maxFuzz) StdGen
rng
delay :: DiffTime
delay = Double -> DiffTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
fuzz DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
+ DiffTime
baseDelay DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
- DiffTime
execTime
Tracer m (TracePeerSelection peeraddr)
-> TracePeerSelection peeraddr -> m ()
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m (TracePeerSelection peeraddr)
tracer (TracePeerSelection peeraddr -> m ())
-> TracePeerSelection peeraddr -> m ()
forall a b. (a -> b) -> a -> b
$ DiffTime -> TracePeerSelection peeraddr
forall peeraddr. DiffTime -> TracePeerSelection peeraddr
TraceChurnWait DiffTime
delay
DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
threadDelay DiffTime
delay
StdGen -> m StdGen
forall (m :: * -> *) a. Monad m => a -> m a
return StdGen
rng'
longDelay :: StdGen -> DiffTime -> m StdGen
longDelay :: StdGen -> DiffTime -> m StdGen
longDelay = DiffTime -> Double -> StdGen -> DiffTime -> m StdGen
fuzzyDelay' DiffTime
churnInterval Double
600
shortDelay :: StdGen -> DiffTime -> m StdGen
shortDelay :: StdGen -> DiffTime -> m StdGen
shortDelay = DiffTime -> Double -> StdGen -> DiffTime -> m StdGen
fuzzyDelay' DiffTime
churnIntervalBulk Double
60
churnInterval :: DiffTime
churnInterval :: DiffTime
churnInterval = DiffTime
3300
churnIntervalBulk :: DiffTime
churnIntervalBulk :: DiffTime
churnIntervalBulk = DiffTime
300
decrease :: Int -> Int
decrease :: Int -> Int
decrease Int
v = Int
v Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int
v Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
5)