@@ -24,6 +24,8 @@ import Data.Map (Map)
24import qualified Data.Map as Map
24import qualified Data.Map as Map
27 , partitionWithKey
29 , partitionWithKey
29 , filterWithKey
31 , filterWithKey
@@ -31,7 +33,7 @@ import qualified Data.Map as Map
31import Data.Set (Set)
33import Data.Set (Set)
32import qualified Data.Set as Set (empty, insert, delete, member)
34import qualified Data.Set as Set (empty, insert, delete, member)
33import Data.Foldable (forM_)
35import Data.Foldable (forM_)
34−import Data.Maybe (isJust)
36+import Data.Maybe (isJust, isNothing, catMaybes)
35import Data.Typeable (Typeable)
37import Data.Typeable (Typeable)
36import Control.Category ((>>>))
38import Control.Category ((>>>))
37import Control.Applicative ((<$>))
39import Control.Applicative ((<$>))
@@ -118,6 +120,7 @@ import Control.Distributed.Process.Internal.Types
119 , SendPortId(..)
121 , SendPortId(..)
120 , typedChannelWithId
122 , typedChannelWithId
121 , WhereIsReply(..)
124 , WhereIsReply(..)
122 , messageToPayload
125 , messageToPayload
123 , payloadToMessage
126 , payloadToMessage
@@ -437,8 +440,9 @@ data NCState = NCState
437 _links :: !(Map Identifier (Set ProcessId))
440 _links :: !(Map Identifier (Set ProcessId))
438 -- Mapping from remote processes to monitoring local processes
441 -- Mapping from remote processes to monitoring local processes
439 , _monitors :: !(Map Identifier (Set (ProcessId, MonitorRef)))
442 , _monitors :: !(Map Identifier (Set (ProcessId, MonitorRef)))
440− -- Process registry
443+ -- Process registry: names and where they live, mapped to the PIDs
441− , _registry :: !(Map String ProcessId)
444+ , _registeredHere :: !(Map String ProcessId)
445+ , _registeredOnNodes :: !(Map ProcessId [(NodeId,Int)])
444newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
448newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
@@ -447,7 +451,8 @@ newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
447initNCState :: NCState
451initNCState :: NCState
448initNCState = NCState { _links = Map.empty
452initNCState = NCState { _links = Map.empty
449 , _monitors = Map.empty
453 , _monitors = Map.empty
450− , _registry = Map.empty
454+ , _registeredHere = Map.empty
455+ , _registeredOnNodes = Map.empty
453--------------------------------------------------------------------------------
458--------------------------------------------------------------------------------
@@ -485,8 +490,8 @@ nodeController = do
485 ncEffectDied ident reason
490 ncEffectDied ident reason
486 NCMsg (ProcessIdentifier from) (Spawn proc ref) ->
491 NCMsg (ProcessIdentifier from) (Spawn proc ref) ->
487 ncEffectSpawn from proc ref
492 ncEffectSpawn from proc ref
488− NCMsg _from (Register label pid) ->
493+ NCMsg (ProcessIdentifier from) (Register label atnode pid force) ->
489− ncEffectRegister label pid
494+ ncEffectRegister from label atnode pid force
490 NCMsg (ProcessIdentifier from) (WhereIs label) ->
495 NCMsg (ProcessIdentifier from) (WhereIs label) ->
491 ncEffectWhereIs from label
496 ncEffectWhereIs from label
492 NCMsg from (NamedSend label msg') ->
497 NCMsg from (NamedSend label msg') ->
@@ -554,6 +559,8 @@ ncEffectDied ident reason = do
554 (affectedLinks, unaffectedLinks) <- gets (splitNotif ident . (^. links))
559 (affectedLinks, unaffectedLinks) <- gets (splitNotif ident . (^. links))
555 (affectedMons, unaffectedMons) <- gets (splitNotif ident . (^. monitors))
560 (affectedMons, unaffectedMons) <- gets (splitNotif ident . (^. monitors))
562+-- _registry :: !(Map (String,NodeId) ProcessId)
557 let localOnly = case ident of NodeIdentifier _ -> True ; _ -> False
564 let localOnly = case ident of NodeIdentifier _ -> True ; _ -> False
559 forM_ (Map.toList affectedLinks) $ \(them, uss) ->
566 forM_ (Map.toList affectedLinks) $ \(them, uss) ->
@@ -564,10 +571,34 @@ ncEffectDied ident reason = do
564 forM_ (Map.toList affectedMons) $ \(them, refs) ->
571 forM_ (Map.toList affectedMons) $ \(them, refs) ->
565 forM_ refs $ \(us, ref) ->
572 forM_ refs $ \(us, ref) ->
566 when (localOnly <= isLocal node (ProcessIdentifier us)) $
573 when (localOnly <= isLocal node (ProcessIdentifier us)) $
567− notifyDied us them reason (Just ref)
574+ notifyDied us them reason (Just ref)
569 modify' $ (links ^= unaffectedLinks) . (monitors ^= unaffectedMons)
576 modify' $ (links ^= unaffectedLinks) . (monitors ^= unaffectedMons)
578+ modify' $ registeredHere ^: Map.filter (\pid -> not $ ident `impliesDeathOf` ProcessIdentifier pid)
580+ remaining <- fmap Map.toList (gets (^. registeredOnNodes)) >>=
581+ mapM (\(pid,nidlist) ->
582+ case ident `impliesDeathOf` ProcessIdentifier pid of
584+ do forM_ nidlist $ \(nid,_) ->
585+ when (not $ isLocal node (NodeIdentifier nid))
586+ (forwardNameDeath node nid)
588+ False -> return $ Just (pid,nidlist) )
589+ modify' $ registeredOnNodes ^= (Map.fromList (catMaybes remaining))
591+ forwardNameDeath node nid =
592+ liftIO $ sendBinary node
593+ (NodeIdentifier $ localNodeId node)
594+ (NodeIdentifier $ nid)
595+ WithImplicitReconnect
597+ { ctrlMsgSender = NodeIdentifier (localNodeId node)
598+ , ctrlMsgSignal = Died ident reason
571-- [Unified: Table 13]
602-- [Unified: Table 13]
572ncEffectSpawn :: ProcessId -> Closure (Process ()) -> SpawnRef -> NC ()
603ncEffectSpawn :: ProcessId -> Closure (Process ()) -> SpawnRef -> NC ()
573ncEffectSpawn pid cProc ref = do
604ncEffectSpawn pid cProc ref = do
@@ -587,18 +618,71 @@ ncEffectSpawn pid cProc ref = do
588-- Unified semantics does not explicitly describe how to implement 'register',
619-- Unified semantics does not explicitly describe how to implement 'register',
589-- but mentions it's "very similar to nsend" (Table 14)
620-- but mentions it's "very similar to nsend" (Table 14)
621+-- We send a response indicated if the operation is invalid
590−ncEffectRegister :: String -> Maybe ProcessId -> NC ()
622+ncEffectRegister :: ProcessId -> String -> NodeId -> Maybe ProcessId -> Bool -> NC ()
591−ncEffectRegister label mPid =
623+ncEffectRegister from label atnode mPid reregistration = do
625+ currentVal <- gets (^. registeredHereFor label)
628+ Nothing -> -- unregister request
629+ return $ isJust currentVal
630+ Just thepid -> -- register request
631+ do isvalidlocal <- isValidLocalIdentifier (ProcessIdentifier thepid)
632+ return $ (isNothing currentVal /= reregistration) &&
633+ (not (isLocal node (ProcessIdentifier thepid) ) || isvalidlocal )
634+ if isLocal node (NodeIdentifier atnode)
635+ then do when (isOk) $
592− modify' $ registryFor label ^= mPid
636+ do modify' $ registeredHereFor label ^= mPid
593− -- An acknowledgement is not necessary. If we want a synchronous register,
637+ updateRemote node currentVal mPid
594− -- it suffices to send a whereis requiry immediately after the register
638+ liftIO $ sendMessage node
595− -- (that may not suffice if we do decide for unreliable messaging instead)
639+ (NodeIdentifier (localNodeId node))
640+ (ProcessIdentifier from)
641+ WithImplicitReconnect
642+ (RegisterReply label isOk)
643+ else let operation =
644+ case reregistration of
645+ True -> flip decList
646+ False -> flip incList
648+ Nothing -> return ()
649+ Just pid -> modify' $ registeredOnNodesFor pid ^: (maybeify $ operation atnode)
650+ where updateRemote node (Just oldval) (Just newval) | processNodeId oldval /= processNodeId newval =
651+ do forward node (processNodeId oldval) (Register label atnode (Just oldval) True)
652+ forward node (processNodeId newval) (Register label atnode (Just newval) False)
653+ updateRemote node Nothing (Just newval) =
654+ forward node (processNodeId newval) (Register label atnode (Just newval) False)
655+ updateRemote node (Just oldval) Nothing =
656+ forward node (processNodeId oldval) (Register label atnode (Just oldval) True)
657+ updateRemote _ _ _ = return ()
658+ maybeify f Nothing = unmaybeify $ f []
659+ maybeify f (Just x) = unmaybeify $ f x
660+ unmaybeify [] = Nothing
661+ unmaybeify x = Just x
662+ incList [] tag = [(tag,1)]
663+ incList ((atag,acount):xs) tag | tag==atag = (atag,acount+1) : xs
664+ incList (x:xs) tag = x : incList xs tag
666+ decList ((atag,1):xs) tag | atag == tag = xs
667+ decList ((atag,n):xs) tag | atag == tag = (atag,n-1):xs
668+ decList (x:xs) tag = x:decList xs tag
669+ forward node to reg =
670+ when (not $ isLocal node (NodeIdentifier to)) $
671+ liftIO $ sendBinary node
672+ (ProcessIdentifier from)
674+ WithImplicitReconnect
676+ { ctrlMsgSender = ProcessIdentifier from
677+ , ctrlMsgSignal = reg
597-- Unified semantics does not explicitly describe 'whereis'
681-- Unified semantics does not explicitly describe 'whereis'
598ncEffectWhereIs :: ProcessId -> String -> NC ()
682ncEffectWhereIs :: ProcessId -> String -> NC ()
599ncEffectWhereIs from label = do
683ncEffectWhereIs from label = do
600 node <- ask
684 node <- ask
601− mPid <- gets (^. registryFor label)
685+ mPid <- gets (^. registeredHereFor label)
602 liftIO $ sendMessage node
686 liftIO $ sendMessage node
603 (NodeIdentifier (localNodeId node))
687 (NodeIdentifier (localNodeId node))
604 (ProcessIdentifier from)
688 (ProcessIdentifier from)
@@ -608,9 +692,9 @@ ncEffectWhereIs from label = do
608-- [Unified: Table 14]
692-- [Unified: Table 14]
609ncEffectNamedSend :: Identifier -> String -> Message -> NC ()
693ncEffectNamedSend :: Identifier -> String -> Message -> NC ()
610ncEffectNamedSend from label msg = do
694ncEffectNamedSend from label msg = do
611− mPid <- gets (^. registryFor label)
696+ mPid <- gets (^. registeredHereFor label)
612 -- If mPid is Nothing, we just ignore the named send (as per Table 14)
697 -- If mPid is Nothing, we just ignore the named send (as per Table 14)
614 forM_ mPid $ \pid ->
698 forM_ mPid $ \pid ->
615 liftIO $ sendPayload node
699 liftIO $ sendPayload node
@@ -660,7 +744,7 @@ destNid (Unlink ident) = Just $ nodeOf ident
660destNid (Monitor ref) = Just $ nodeOf (monitorRefIdent ref)
744destNid (Monitor ref) = Just $ nodeOf (monitorRefIdent ref)
661destNid (Unmonitor ref) = Just $ nodeOf (monitorRefIdent ref)
745destNid (Unmonitor ref) = Just $ nodeOf (monitorRefIdent ref)
662destNid (Spawn _ _) = Nothing
746destNid (Spawn _ _) = Nothing
663−destNid (Register _ _) = Nothing
747+destNid (Register _ _ _ _) = Nothing
664destNid (WhereIs _) = Nothing
748destNid (WhereIs _) = Nothing
665destNid (NamedSend _ _) = Nothing
749destNid (NamedSend _ _) = Nothing
666-- We don't need to forward 'Died' signals; if monitoring/linking is setup,
750-- We don't need to forward 'Died' signals; if monitoring/linking is setup,
@@ -732,8 +816,11 @@ links = accessor _links (\ls st -> st { _links = ls })
732monitors :: Accessor NCState (Map Identifier (Set (ProcessId, MonitorRef)))
816monitors :: Accessor NCState (Map Identifier (Set (ProcessId, MonitorRef)))
733monitors = accessor _monitors (\ms st -> st { _monitors = ms })
817monitors = accessor _monitors (\ms st -> st { _monitors = ms })
735−registry :: Accessor NCState (Map String ProcessId)
819+registeredHere :: Accessor NCState (Map String ProcessId)
736−registry = accessor _registry (\ry st -> st { _registry = ry })
820+registeredHere = accessor _registeredHere (\ry st -> st { _registeredHere = ry })
822+registeredOnNodes :: Accessor NCState (Map ProcessId [(NodeId, Int)])
823+registeredOnNodes = accessor _registeredOnNodes (\ry st -> st { _registeredOnNodes = ry })
738linksFor :: Identifier -> Accessor NCState (Set ProcessId)
825linksFor :: Identifier -> Accessor NCState (Set ProcessId)
739linksFor ident = links >>> DAC.mapDefault Set.empty ident
826linksFor ident = links >>> DAC.mapDefault Set.empty ident
@@ -741,8 +828,11 @@ linksFor ident = links >>> DAC.mapDefault Set.empty ident
741monitorsFor :: Identifier -> Accessor NCState (Set (ProcessId, MonitorRef))
828monitorsFor :: Identifier -> Accessor NCState (Set (ProcessId, MonitorRef))
742monitorsFor ident = monitors >>> DAC.mapDefault Set.empty ident
829monitorsFor ident = monitors >>> DAC.mapDefault Set.empty ident
744−registryFor :: String -> Accessor NCState (Maybe ProcessId)
831+registeredHereFor :: String -> Accessor NCState (Maybe ProcessId)
745−registryFor ident = registry >>> DAC.mapMaybe ident
832+registeredHereFor ident = registeredHere >>> DAC.mapMaybe ident
834+registeredOnNodesFor :: ProcessId -> Accessor NCState (Maybe [(NodeId,Int)])
835+registeredOnNodesFor ident = registeredOnNodes >>> DAC.mapMaybe ident
747-- | @splitNotif ident@ splits a notifications map into those
837-- | @splitNotif ident@ splits a notifications map into those
748-- notifications that should trigger when 'ident' fails and those links that
838-- notifications that should trigger when 'ident' fails and those links that