Skip to content

Commit 37b0263

Browse files
committed
Changed semantics of register/unregister to match Erlang
register will now throw an exception if the name is already registered unregister will throw an exception if the name isn't registered registerRemote and unregisterRemote have been replaced with Async versions, such that the user application is now responsible for checking the remote control process's response
1 parent af14826 commit 37b0263

File tree

5 files changed

+76
-22
lines changed

5 files changed

+76
-22
lines changed

distributed-process/distributed-process.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Name: distributed-process
2-
Version: 0.4.0.2
2+
Version: 0.4.0.3
33
Cabal-Version: >=1.8
44
Build-Type: Simple
55
License: BSD3

distributed-process/src/Control/Distributed/Process.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ module Control.Distributed.Process
8080
, unregister
8181
, whereis
8282
, nsend
83-
, registerRemote
84-
, unregisterRemote
83+
, registerRemoteAsync
84+
, unregisterRemoteAsync
8585
, whereisRemoteAsync
8686
, nsendRemote
8787
, WhereIsReply(..)
@@ -200,8 +200,8 @@ import Control.Distributed.Process.Internal.Primitives
200200
, unregister
201201
, whereis
202202
, nsend
203-
, registerRemote
204-
, unregisterRemote
203+
, registerRemoteAsync
204+
, unregisterRemoteAsync
205205
, whereisRemoteAsync
206206
, nsendRemote
207207
-- Closures

distributed-process/src/Control/Distributed/Process/Internal/Primitives.hs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ module Control.Distributed.Process.Internal.Primitives
3838
, unregister
3939
, whereis
4040
, nsend
41-
, registerRemote
42-
, unregisterRemote
41+
, registerRemoteAsync
42+
, unregisterRemoteAsync
4343
, whereisRemoteAsync
4444
, nsendRemote
4545
-- * Closures
@@ -76,6 +76,7 @@ import Data.Time.Clock (getCurrentTime)
7676
import Data.Time.Format (formatTime)
7777
import System.Locale (defaultTimeLocale)
7878
import System.Timeout (timeout)
79+
import Control.Monad (when)
7980
import Control.Monad.Reader (ask)
8081
import Control.Monad.IO.Class (MonadIO, liftIO)
8182
import Control.Applicative ((<$>))
@@ -127,6 +128,8 @@ import Control.Distributed.Process.Internal.Types
127128
, DidUnlinkNode(..)
128129
, DidUnlinkPort(..)
129130
, WhereIsReply(..)
131+
, RegisterReply(..)
132+
, ProcessRegistrationException(..)
130133
, createMessage
131134
, runLocalProcess
132135
, ImplicitReconnect(WithImplicitReconnect, NoImplicitReconnect)
@@ -542,24 +545,44 @@ say string = do
542545
--
543546
-- The process to be registered does not have to be local itself.
544547
register :: String -> ProcessId -> Process ()
545-
register label pid =
548+
register label pid = do
546549
sendCtrlMsg Nothing (Register label (Just pid))
550+
receiveWait [ matchIf (\(RegisterReply label' _) -> label == label')
551+
(\(RegisterReply _ ok) -> handleRegistrationReply label ok)
552+
]
547553

548554
-- | Register a process with a remote registry (asynchronous).
549555
--
550556
-- The process to be registered does not have to live on the same remote node.
551-
registerRemote :: NodeId -> String -> ProcessId -> Process ()
552-
registerRemote nid label pid =
557+
-- Reply wil come in the form of a 'RegisterReply' message
558+
--
559+
-- See comments in 'whereisRemoteAsync'
560+
registerRemoteAsync :: NodeId -> String -> ProcessId -> Process ()
561+
registerRemoteAsync nid label pid =
553562
sendCtrlMsg (Just nid) (Register label (Just pid))
554563

555564
-- | Remove a process from the local registry (asynchronous).
556565
unregister :: String -> Process ()
557-
unregister label =
566+
unregister label = do
558567
sendCtrlMsg Nothing (Register label Nothing)
568+
receiveWait [ matchIf (\(RegisterReply label' _) -> label == label')
569+
(\(RegisterReply _ ok) -> handleRegistrationReply label ok)
570+
]
571+
572+
-- | Deal with the result from an attempted registration or unregistration
573+
-- by throwing an exception if necessary
574+
handleRegistrationReply :: String -> Bool -> Process ()
575+
handleRegistrationReply label ok =
576+
when (not ok) $
577+
liftIO $ throwIO $ ProcessRegistrationException label
559578

560579
-- | Remove a process from a remote registry (asynchronous).
561-
unregisterRemote :: NodeId -> String -> Process ()
562-
unregisterRemote nid label =
580+
--
581+
-- Reply wil come in the form of a 'RegisterReply' message
582+
--
583+
-- See comments in 'whereisRemoteAsync'
584+
unregisterRemoteAsync :: NodeId -> String -> Process ()
585+
unregisterRemoteAsync nid label =
563586
sendCtrlMsg (Just nid) (Register label Nothing)
564587

565588
-- | Query the local process registry

distributed-process/src/Control/Distributed/Process/Internal/Types.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ module Control.Distributed.Process.Internal.Types
3939
, ProcessLinkException(..)
4040
, NodeLinkException(..)
4141
, PortLinkException(..)
42+
, ProcessRegistrationException(..)
4243
, DiedReason(..)
4344
, DidUnmonitor(..)
4445
, DidUnlinkProcess(..)
@@ -47,6 +48,7 @@ module Control.Distributed.Process.Internal.Types
4748
, SpawnRef(..)
4849
, DidSpawn(..)
4950
, WhereIsReply(..)
51+
, RegisterReply(..)
5052
-- * Node controller internal data types
5153
, NCMsg(..)
5254
, ProcessSignal(..)
@@ -359,9 +361,17 @@ data PortLinkException =
359361
PortLinkException !SendPortId !DiedReason
360362
deriving (Typeable, Show)
361363

364+
-- | Exception thrown when a process attempts to register
365+
-- a process under an already-registered name or to
366+
-- unregister a name that hasn't been registered
367+
data ProcessRegistrationException =
368+
ProcessRegistrationException !String
369+
deriving (Typeable, Show)
370+
362371
instance Exception ProcessLinkException
363372
instance Exception NodeLinkException
364373
instance Exception PortLinkException
374+
instance Exception ProcessRegistrationException
365375

366376
-- | Why did a process die?
367377
data DiedReason =
@@ -406,6 +416,10 @@ data DidSpawn = DidSpawn SpawnRef ProcessId
406416
data WhereIsReply = WhereIsReply String (Maybe ProcessId)
407417
deriving (Show, Typeable)
408418

419+
-- | (Asynchronous) reply from 'register' and 'unregister'
420+
data RegisterReply = RegisterReply String Bool
421+
deriving (Show, Typeable)
422+
409423
--------------------------------------------------------------------------------
410424
-- Node controller internal data types --
411425
--------------------------------------------------------------------------------
@@ -526,6 +540,10 @@ instance Binary WhereIsReply where
526540
put (WhereIsReply label mPid) = put label >> put mPid
527541
get = WhereIsReply <$> get <*> get
528542

543+
instance Binary RegisterReply where
544+
put (RegisterReply label ok) = put label >> put ok
545+
get = RegisterReply <$> get <*> get
546+
529547
--------------------------------------------------------------------------------
530548
-- Accessors --
531549
--------------------------------------------------------------------------------

distributed-process/src/Control/Distributed/Process/Node.hs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import qualified Data.Map as Map
3131
import Data.Set (Set)
3232
import qualified Data.Set as Set (empty, insert, delete, member)
3333
import Data.Foldable (forM_)
34-
import Data.Maybe (isJust)
34+
import Data.Maybe (isJust, isNothing)
3535
import Data.Typeable (Typeable)
3636
import Control.Category ((>>>))
3737
import Control.Applicative ((<$>))
@@ -118,6 +118,7 @@ import Control.Distributed.Process.Internal.Types
118118
, nodeOf
119119
, SendPortId(..)
120120
, typedChannelWithId
121+
, RegisterReply(..)
121122
, WhereIsReply(..)
122123
, messageToPayload
123124
, payloadToMessage
@@ -485,8 +486,8 @@ nodeController = do
485486
ncEffectDied ident reason
486487
NCMsg (ProcessIdentifier from) (Spawn proc ref) ->
487488
ncEffectSpawn from proc ref
488-
NCMsg _from (Register label pid) ->
489-
ncEffectRegister label pid
489+
NCMsg (ProcessIdentifier from) (Register label pid) ->
490+
ncEffectRegister from label pid
490491
NCMsg (ProcessIdentifier from) (WhereIs label) ->
491492
ncEffectWhereIs from label
492493
NCMsg from (NamedSend label msg') ->
@@ -587,12 +588,24 @@ ncEffectSpawn pid cProc ref = do
587588

588589
-- Unified semantics does not explicitly describe how to implement 'register',
589590
-- but mentions it's "very similar to nsend" (Table 14)
590-
ncEffectRegister :: String -> Maybe ProcessId -> NC ()
591-
ncEffectRegister label mPid =
592-
modify' $ registryFor label ^= mPid
593-
-- An acknowledgement is not necessary. If we want a synchronous register,
594-
-- it suffices to send a whereis requiry immediately after the register
595-
-- (that may not suffice if we do decide for unreliable messaging instead)
591+
-- We send a response indicated if the operation is invalid
592+
ncEffectRegister :: ProcessId -> String -> Maybe ProcessId -> NC ()
593+
ncEffectRegister from label mPid = do
594+
node <- ask
595+
currentVal <- gets (^. registryFor label)
596+
let isOk =
597+
case mPid of
598+
Nothing -> -- unregister request
599+
isJust currentVal
600+
Just _ -> -- register request
601+
isNothing currentVal
602+
when (isOk) $
603+
modify' $ registryFor label ^= mPid
604+
liftIO $ sendMessage node
605+
(NodeIdentifier (localNodeId node))
606+
(ProcessIdentifier from)
607+
WithImplicitReconnect
608+
(RegisterReply label isOk)
596609

597610
-- Unified semantics does not explicitly describe 'whereis'
598611
ncEffectWhereIs :: ProcessId -> String -> NC ()

0 commit comments

Comments
 (0)