@@ -42,10 +42,12 @@ import qualified Data.Set as Set
48import Data.Foldable (forM_)
49import Data.Foldable (forM_)
50+import Data.List (foldl')
49import Data.Maybe (isJust, fromJust, isNothing, catMaybes)
51import Data.Maybe (isJust, fromJust, isNothing, catMaybes)
50import Data.Typeable (Typeable)
52import Data.Typeable (Typeable)
51import Control.Category ((>>>))
53import Control.Category ((>>>))
@@ -71,6 +73,8 @@ import qualified Control.Exception as Exception
73import Control.Concurrent (forkIO, killThread)
75import Control.Concurrent (forkIO, killThread)
76+import Control.Distributed.Process.Internal.BiMultiMap (BiMultiMap)
77+import qualified Control.Distributed.Process.Internal.BiMultiMap as BiMultiMap
74import Control.Distributed.Process.Internal.StrictMVar
78import Control.Distributed.Process.Internal.StrictMVar
76 , withMVar
80 , withMVar
@@ -656,9 +660,9 @@ runNodeController node =
657data NCState = NCState
661data NCState = NCState
658 { -- Mapping from remote processes to linked local processes
662 { -- Mapping from remote processes to linked local processes
659− _links :: !(Map Identifier (Set ProcessId))
663+ _links :: !(BiMultiMap Identifier ProcessId ())
660 -- Mapping from remote processes to monitoring local processes
664 -- Mapping from remote processes to monitoring local processes
661− , _monitors :: !(Map Identifier (Set (ProcessId, MonitorRef)))
665+ , _monitors :: !(BiMultiMap Identifier ProcessId MonitorRef)
662 -- Process registry: names and where they live, mapped to the PIDs
666 -- Process registry: names and where they live, mapped to the PIDs
663 , _registeredHere :: !(Map String ProcessId)
667 , _registeredHere :: !(Map String ProcessId)
664 , _registeredOnNodes :: !(Map ProcessId [(NodeId,Int)])
668 , _registeredOnNodes :: !(Map ProcessId [(NodeId,Int)])
@@ -674,8 +678,8 @@ newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
676initNCState :: NCState
680initNCState :: NCState
677−initNCState = NCState { _links = Map.empty
681+initNCState = NCState { _links = BiMultiMap.empty
678− , _monitors = Map.empty
682+ , _monitors = BiMultiMap.empty
679 , _registeredHere = Map.empty
683 , _registeredHere = Map.empty
680 , _registeredOnNodes = Map.empty
684 , _registeredOnNodes = Map.empty
@@ -818,8 +822,8 @@ ncEffectMonitor from them mRef = do
818 case (shouldLink, isLocal node (ProcessIdentifier from)) of
822 case (shouldLink, isLocal node (ProcessIdentifier from)) of
819 (True, _) -> -- [Unified: first rule]
823 (True, _) -> -- [Unified: first rule]
820 case mRef of
824 case mRef of
821− Just ref -> modify' $ monitorsFor them ^: Set.insert (from, ref)
825+ Just ref -> modify' $ monitors ^: BiMultiMap.insert them from ref
822− Nothing -> modify' $ linksFor them ^: Set.insert from
826+ Nothing -> modify' $ links ^: BiMultiMap.insert them from ()
823 (False, True) -> -- [Unified: second rule]
827 (False, True) -> -- [Unified: second rule]
824 notifyDied from them DiedUnknownId mRef
828 notifyDied from them DiedUnknownId mRef
825 (False, False) -> -- [Unified: third rule]
829 (False, False) -> -- [Unified: third rule]
@@ -843,7 +847,7 @@ ncEffectUnlink from them = do
843 postAsMessage from $ DidUnlinkNode nid
847 postAsMessage from $ DidUnlinkNode nid
844 SendPortIdentifier cid ->
848 SendPortIdentifier cid ->
845 postAsMessage from $ DidUnlinkPort cid
849 postAsMessage from $ DidUnlinkPort cid
846− modify' $ linksFor them ^: Set.delete from
850+ modify' $ links ^: BiMultiMap.delete them from ()
848-- [Unified: Table 11]
852-- [Unified: Table 11]
849ncEffectUnmonitor :: ProcessId -> MonitorRef -> NC ()
853ncEffectUnmonitor :: ProcessId -> MonitorRef -> NC ()
@@ -851,7 +855,7 @@ ncEffectUnmonitor from ref = do
851 node <- ask
855 node <- ask
852 when (isLocal node (ProcessIdentifier from)) $
856 when (isLocal node (ProcessIdentifier from)) $
853 postAsMessage from $ DidUnmonitor ref
857 postAsMessage from $ DidUnmonitor ref
854− modify' $ monitorsFor (monitorRefIdent ref) ^: Set.delete (from, ref)
858+ modify' $ monitors ^: BiMultiMap.delete (monitorRefIdent ref) from ref
856-- [Unified: Table 12]
860-- [Unified: Table 12]
857ncEffectDied :: Identifier -> DiedReason -> NC ()
861ncEffectDied :: Identifier -> DiedReason -> NC ()
@@ -866,7 +870,7 @@ ncEffectDied ident reason = do
866 let localOnly = case ident of NodeIdentifier _ -> True ; _ -> False
870 let localOnly = case ident of NodeIdentifier _ -> True ; _ -> False
868 forM_ (Map.toList affectedLinks) $ \(them, uss) ->
872 forM_ (Map.toList affectedLinks) $ \(them, uss) ->
869− forM_ uss $ \us ->
873+ forM_ uss $ \(us, _) ->
870 when (localOnly <= isLocal node (ProcessIdentifier us)) $
874 when (localOnly <= isLocal node (ProcessIdentifier us)) $
871 notifyDied us them reason Nothing
875 notifyDied us them reason Nothing
@@ -875,7 +879,15 @@ ncEffectDied ident reason = do
875 when (localOnly <= isLocal node (ProcessIdentifier us)) $
879 when (localOnly <= isLocal node (ProcessIdentifier us)) $
876 notifyDied us them reason (Just ref)
880 notifyDied us them reason (Just ref)
882+ let (unaffectedLinks', unaffectedMons') =
884+ ProcessIdentifier pid ->
885+ ( BiMultiMap.deleteAllBy2nd pid unaffectedLinks
886+ , BiMultiMap.deleteAllBy2nd pid unaffectedMons
888+ _ -> (unaffectedLinks, unaffectedMons)
878− modify' $ (links ^= unaffectedLinks) . (monitors ^= unaffectedMons)
890+ modify' $ (links ^= unaffectedLinks') . (monitors ^= unaffectedMons')
880 modify' $ registeredHere ^: Map.filter (\pid -> not $ ident `impliesDeathOf` ProcessIdentifier pid)
892 modify' $ registeredHere ^: Map.filter (\pid -> not $ ident `impliesDeathOf` ProcessIdentifier pid)
@@ -1045,8 +1057,9 @@ ncEffectGetInfo from pid =
1045 Nothing -> dispatch (isLocal node (ProcessIdentifier from))
1057 Nothing -> dispatch (isLocal node (ProcessIdentifier from))
1046 from (ProcessInfoNone DiedUnknownId)
1058 from (ProcessInfoNone DiedUnknownId)
1047 Just proc -> do
1059 Just proc -> do
1048− itsLinks <- gets (^. linksFor them)
1060+ itsLinks <- Set.map fst . BiMultiMap.lookup them <$>
1049− itsMons <- gets (^. monitorsFor them)
1061+ gets (^. links)
1062+ itsMons <- BiMultiMap.lookup them <$> gets (^. monitors)
1050 registered <- gets (^. registeredHere)
1063 registered <- gets (^. registeredHere)
1051 size <- liftIO $ queueSize $ processQueue $ proc
1064 size <- liftIO $ queueSize $ processQueue $ proc
@@ -1082,8 +1095,8 @@ ncEffectGetNodeStats from _nid = do
1082 NodeStats {
1095 NodeStats {
1083 nodeStatsNode = localNodeId node
1096 nodeStatsNode = localNodeId node
1084 , nodeStatsRegisteredNames = Map.size $ ncState ^. registeredHere
1097 , nodeStatsRegisteredNames = Map.size $ ncState ^. registeredHere
1085− , nodeStatsMonitors = Map.size $ ncState ^. monitors
1098+ , nodeStatsMonitors = BiMultiMap.size $ ncState ^. monitors
1086− , nodeStatsLinks = Map.size $ ncState ^. links
1099+ , nodeStatsLinks = BiMultiMap.size $ ncState ^. links
1087 , nodeStatsProcesses = Map.size (nodeState ^. localProcesses)
1100 , nodeStatsProcesses = Map.size (nodeState ^. localProcesses)
1089 postAsMessage from stats
1102 postAsMessage from stats
@@ -1204,10 +1217,10 @@ withLocalProc node pid p =
1204-- Accessors --
1217-- Accessors --
1205--------------------------------------------------------------------------------
1218--------------------------------------------------------------------------------
1207−links :: Accessor NCState (Map Identifier (Set ProcessId))
1220+links :: Accessor NCState (BiMultiMap Identifier ProcessId ())
1208links = accessor _links (\ls st -> st { _links = ls })
1221links = accessor _links (\ls st -> st { _links = ls })
1210−monitors :: Accessor NCState (Map Identifier (Set (ProcessId, MonitorRef)))
1223+monitors :: Accessor NCState (BiMultiMap Identifier ProcessId MonitorRef)
1211monitors = accessor _monitors (\ms st -> st { _monitors = ms })
1224monitors = accessor _monitors (\ms st -> st { _monitors = ms })
1213registeredHere :: Accessor NCState (Map String ProcessId)
1226registeredHere :: Accessor NCState (Map String ProcessId)
@@ -1216,12 +1229,6 @@ registeredHere = accessor _registeredHere (\ry st -> st { _registeredHere = ry }
1216registeredOnNodes :: Accessor NCState (Map ProcessId [(NodeId, Int)])
1229registeredOnNodes :: Accessor NCState (Map ProcessId [(NodeId, Int)])
1217registeredOnNodes = accessor _registeredOnNodes (\ry st -> st { _registeredOnNodes = ry })
1230registeredOnNodes = accessor _registeredOnNodes (\ry st -> st { _registeredOnNodes = ry })
1219−linksFor :: Identifier -> Accessor NCState (Set ProcessId)
1220−linksFor ident = links >>> DAC.mapDefault Set.empty ident
1222−monitorsFor :: Identifier -> Accessor NCState (Set (ProcessId, MonitorRef))
1223−monitorsFor ident = monitors >>> DAC.mapDefault Set.empty ident
1225registeredHereFor :: String -> Accessor NCState (Maybe ProcessId)
1232registeredHereFor :: String -> Accessor NCState (Maybe ProcessId)
1226registeredHereFor ident = registeredHere >>> DAC.mapMaybe ident
1233registeredHereFor ident = registeredHere >>> DAC.mapMaybe ident
@@ -1248,10 +1255,12 @@ registeredOnNodesFor ident = registeredOnNodes >>> DAC.mapMaybe ident
1248-- * the notifications for typed channels to that process.
1255-- * the notifications for typed channels to that process.
1250-- See https://github.com/haskell/containers/issues/14 for the bang on _v.
1257-- See https://github.com/haskell/containers/issues/14 for the bang on _v.
1258+splitNotif :: (Ord a, Ord v)
1251−splitNotif :: Identifier
1259+ => Identifier
1252− -> Map Identifier a
1260+ -> BiMultiMap Identifier a v
1253− -> (Map Identifier a, Map Identifier a)
1261+ -> (Map Identifier (Set (a,v)), BiMultiMap Identifier a v)
1254−splitNotif ident = Map.partitionWithKey (\k !_v -> ident `impliesDeathOf` k)
1263+ BiMultiMap.partitionWithKey (\k !_v -> ident `impliesDeathOf` k)
1256--------------------------------------------------------------------------------
1265--------------------------------------------------------------------------------
1257-- Auxiliary --
1266-- Auxiliary --