Skip to content

Commit 6b02529

Browse files
committed
simulation: fix Relay: were adding to inFlightVar too soon.
1 parent 7e5deb8 commit 6b02529

File tree

2 files changed

+72
-67
lines changed

2 files changed

+72
-67
lines changed

simulation/src/LeiosProtocol/Relay.hs

+50-59
Original file line numberDiff line numberDiff line change
@@ -711,23 +711,11 @@ relayConsumerPipelined config sst =
711711
-- It's important not to pipeline more requests for headers when we
712712
-- have no bodies to ask for, since (with no other guard) this will
713713
-- put us into a busy-polling loop.
714-
--
715-
-- Question (Andrea) : Here we have a branching in the local state:
716-
-- - `rb` continues using the state that tracks we have requested more bodies
717-
--
718-
-- - `handleResponse lst'` instead doesn't know about
719-
-- more bodies requested but shrinks the pending
720-
-- requests (which makes sense, because it's the one
721-
-- used when a response is received.)
722-
--
723-
-- Both of those eventually go back to idle, but there
724-
-- doesn't seem to be a mechanism to reconcile the
725-
-- states, nor to stop one of the branches?
726-
--
727-
-- Aside from the state branching, don't you get more and
728-
-- more `RelayConsumer id header body n 'StIdle m ()` continuations to
729-
-- process (probably retaining data we no longer need?) this way?
730714
let lst' = lst0{pendingRequests = pendingRequests'}
715+
716+
-- Note: the peer will proceed with only one of the two
717+
-- arguments of Collect, depending on whether responses are
718+
-- available or not.
731719
return $ TS.Collect (Just rb) (handleResponse lst')
732720
Left lst -> do
733721
-- In this case there is nothing else to do so we block until we
@@ -751,56 +739,59 @@ relayConsumerPipelined config sst =
751739
buffer' = lst.buffer <> Map.map (const Nothing) ignored
752740
(idsToAcknowledge, window') =
753741
Seq.spanl (`Map.member` buffer') lst.window
742+
new_buffer =
743+
forceElemsToWHNF $ -- TODO: Do we need this?
744+
Map.restrictKeys buffer' (Set.fromList $ Foldable.toList window')
754745
in
755-
assertRelayConsumerLocalStateInvariant $
756-
lst
757-
{ buffer =
758-
forceElemsToWHNF $ -- TODO: Do we need this?
759-
Map.restrictKeys buffer' (Set.fromList $ Foldable.toList window')
760-
, available = available'
761-
, window = window'
762-
, pendingShrink = lst.pendingShrink + fromIntegral (Seq.length idsToAcknowledge)
763-
}
746+
assert (all isNothing $ Map.elems $ Map.difference buffer' new_buffer) $
747+
assertRelayConsumerLocalStateInvariant $
748+
lst
749+
{ buffer = new_buffer
750+
, available = available'
751+
, window = window'
752+
, pendingShrink = lst.pendingShrink + fromIntegral (Seq.length idsToAcknowledge)
753+
}
764754

765755
tryRequestBodies ::
766756
forall (n :: N).
767757
RelayConsumerLocalState id header body n ->
768758
m (Either (RelayConsumerLocalState id header body n) (RelayConsumer id header body n 'StIdle m ()))
769759
tryRequestBodies lst0 = do
770-
isIgnored <- config.shouldIgnore
771-
atomically $ do
772-
-- New headers are filtered before becoming available, but we have
773-
-- to filter `lst.available` again in the same STM tx that sets them as
774-
-- `inFlight`.
775-
inFlight <- readTVar sst.inFlightVar
776-
let !lst =
777-
dropFromLST
778-
( \k hd ->
779-
k `Set.member` inFlight
780-
|| isIgnored hd
781-
)
782-
lst0
783-
784-
let hdrsToRequest =
785-
take (fromIntegral config.maxBodiesToRequest) $
786-
config.prioritize lst.available (mapMaybe (`Map.lookup` lst.available) $ Foldable.toList $ lst.window)
787-
let idsToRequest = map config.headerId hdrsToRequest
788-
let idsToRequestSet = Set.fromList idsToRequest
789-
if Set.null idsToRequestSet
790-
then return (Left lst)
791-
else do
792-
let available2 = Map.withoutKeys lst.available idsToRequestSet
793-
modifyTVar' sst.inFlightVar $ Set.union idsToRequestSet
794-
let !lst2 = lst{pendingRequests = Succ lst.pendingRequests, available = available2}
795-
return $
796-
Right $
797-
TS.YieldPipelined
798-
(MsgRequestBodies idsToRequest)
799-
( TS.ReceiverAwait $ \case
800-
MsgRespondBodies bodies ->
801-
TS.ReceiverDone (CollectBodies hdrsToRequest bodies)
802-
)
803-
(requestHeadersNonBlocking lst2)
760+
if (min (Map.size lst0.available) (fromIntegral config.maxBodiesToRequest)) == 0
761+
then return (Left lst0)
762+
else return . Right . TS.Effect $ do
763+
isIgnored <- config.shouldIgnore
764+
atomically $ do
765+
-- New headers are filtered before becoming available, but we have
766+
-- to filter `lst.available` again in the same STM tx that sets them as
767+
-- `inFlight`.
768+
inFlight <- readTVar sst.inFlightVar
769+
let !lst =
770+
dropFromLST
771+
( \k hd ->
772+
k `Set.member` inFlight
773+
|| isIgnored hd
774+
)
775+
lst0
776+
let hdrsToRequest =
777+
take (fromIntegral config.maxBodiesToRequest) $
778+
config.prioritize lst.available (mapMaybe (`Map.lookup` lst.available) $ Foldable.toList $ lst.window)
779+
let idsToRequest = map config.headerId hdrsToRequest
780+
let idsToRequestSet = Set.fromList idsToRequest
781+
if Set.null idsToRequestSet
782+
then return (idle lst)
783+
else do
784+
let available2 = Map.withoutKeys lst.available idsToRequestSet
785+
modifyTVar' sst.inFlightVar $ Set.union idsToRequestSet
786+
let !lst2 = lst{pendingRequests = Succ lst.pendingRequests, available = available2}
787+
return $
788+
TS.YieldPipelined
789+
(MsgRequestBodies idsToRequest)
790+
( TS.ReceiverAwait $ \case
791+
MsgRespondBodies bodies ->
792+
TS.ReceiverDone (CollectBodies hdrsToRequest bodies)
793+
)
794+
(requestHeadersNonBlocking lst2)
804795

805796
windowAdjust ::
806797
forall (n :: N).

simulation/src/LeiosProtocol/Short/Sim.hs

+22-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Data.Aeson
3030
import Data.Aeson.Encoding (pair)
3131
import Data.Coerce
3232
import Data.Default (Default (..))
33+
import Data.Foldable
3334
import Data.Map.Strict (Map)
3435
import qualified Data.Map.Strict as Map
3536
import Data.Maybe
@@ -40,7 +41,7 @@ import GHC.Records
4041
import qualified LeiosEvents as Shared
4142
import LeiosProtocol.Common hiding (Point)
4243
import LeiosProtocol.Config
43-
import LeiosProtocol.Relay (Message (..), RelayMessage, relayMessageLabel)
44+
import LeiosProtocol.Relay
4445
import LeiosProtocol.Short
4546
import LeiosProtocol.Short.Node
4647
import ModelTCP
@@ -164,18 +165,31 @@ logLeiosEvent nodeNames emitControl e = case e of
164165
[cpuTag, node nid, "task" .= task]
165166
logPraos _ (PraosNodeEventNewTip _chain) = Nothing
166167
logMsg :: LeiosMessage -> Maybe Series
167-
logMsg (RelayIB msg) = (ibKind <>) <$> logRelay msg
168-
logMsg (RelayEB msg) = (ebKind <>) <$> logRelay msg
169-
logMsg (RelayVote msg) = (vtKind <>) <$> logRelay msg
168+
logMsg (RelayIB msg) = (ibKind <>) <$> logRelay (.id) msg
169+
logMsg (RelayEB msg) = (ebKind <>) <$> logRelay (.id) msg
170+
logMsg (RelayVote msg) = (vtKind <>) <$> logRelay (.id) msg
170171
logMsg (PraosMsg (PraosMessage (Right (ProtocolMessage (SomeMessage (MsgBlock hash _body)))))) =
171172
Just $ rbKind <> "id" .= show (coerce @_ @Int hash)
172173
logMsg (PraosMsg msg)
173174
| emitControl = Just $ mconcat ["id" .= asString "control", "label" .= praosMessageLabel msg]
174175
| otherwise = Nothing
175-
logRelay :: (HasField "node" id NodeId, HasField "num" id Int) => RelayMessage id h b -> Maybe Series
176-
logRelay (ProtocolMessage (SomeMessage (MsgRespondBodies xs))) =
177-
Just $ "ids" .= map (mkStringId . fst) xs
178-
logRelay (ProtocolMessage (SomeMessage msg))
176+
logRelay :: (HasField "node" id NodeId, HasField "num" id Int) => (h -> id) -> RelayMessage id h b -> Maybe Series
177+
logRelay _getId (ProtocolMessage (SomeMessage (MsgRespondBodies xs))) =
178+
Just $ "ids" .= map (mkStringId . fst) xs <> "msg_label" .= asString "respond-bodies"
179+
logRelay _getId (ProtocolMessage (SomeMessage (MsgRequestBodies xs))) =
180+
Just $
181+
"ids" .= map mkStringId xs
182+
<> "msg_label" .= asString "request-bodies"
183+
logRelay getId (ProtocolMessage (SomeMessage (MsgRespondHeaders xs))) =
184+
Just $
185+
"ids" .= map (mkStringId . getId) (toList xs)
186+
<> "msg_label" .= asString "respond-headers"
187+
logRelay _getId (ProtocolMessage (SomeMessage (MsgRequestHeaders _ ws we))) =
188+
Just $
189+
"shrink" .= ws.value
190+
<> "expand" .= we.value
191+
<> "msg_label" .= asString "request-headers"
192+
logRelay _ (ProtocolMessage (SomeMessage msg))
179193
| emitControl = Just $ "id" .= asString "control" <> "label" .= relayMessageLabel msg
180194
| otherwise = Nothing
181195
asString x = x :: String

0 commit comments

Comments
 (0)