git.iko.soy/distributed-process
on master help sign in
[no-ci] TEMP: this commit is broken, to be ammended
commit268bee3ad076902abeecfb9311c30ea528d42766 authorTim Watson <watson.timothy@gmail.com> dateThu 9 Feb 2017, 10:34 (10 years ago) parentf1ad074
11 files changed+324−86
distributed-process-tests/src/Control/Distributed/Process/Tests/Mx.hs+114−1 distributed-process-tests/src/Control/Distributed/Process/Tests/Tracing.hs+26−14 src/Control/Distributed/Process/Internal/Primitives.hs+71−21 src/Control/Distributed/Process/Management.hs+2 src/Control/Distributed/Process/Management/Internal/Agent.hs+2−2 src/Control/Distributed/Process/Management/Internal/Trace/Primitives.hs+4−1 src/Control/Distributed/Process/Management/Internal/Trace/Tracer.hs+29−15 src/Control/Distributed/Process/Management/Internal/Types.hs+56−15 src/Control/Distributed/Process/Node.hs+1 stack-ghc-8.0.1.yaml+18 stack.yaml+1−17
distributed-process-tests/src/Control/Distributed/Process/Tests/Mx.hs+114−1
@@ -5,10 +5,19 @@ import Control.Distributed.Process.Tests.Internal.Utils
55import Network.Transport.Test (TestTransport(..))
66
77import Control.Concurrent (threadDelay)
8+import Control.Concurrent.STM (atomically)
9+import Control.Concurrent.STM.TChan
10+ ( newBroadcastTChanIO
11+ , readTChan
12+ , writeTChan
13+ , dupTChan
14+ )
15+
816import Control.Distributed.Process
917import Control.Distributed.Process.Node
1018import Control.Distributed.Process.Management
1119 ( MxEvent(..)
20+ , Destination(..)
1221 , MxAgentId(..)
1322 , mxAgent
1423 , mxSink
@@ -23,7 +32,7 @@ import Control.Distributed.Process.Management
2332 , mxBroadcast
2433 , mxGetId
2534 )
26−import Control.Monad (void)
35+import Control.Monad (void, replicateM_, when)
2736import Data.Binary
2837import Data.List (find, sort)
2938import Data.Maybe (isJust)
@@ -175,6 +184,109 @@ testAgentEventHandling result = do
175184
176185 stash result $ seenAlive && seenDead
177186
187+testAgentSendRecvHandling :: LocalNode -> IO ()
188+testAgentSendRecvHandling node = do
189+ runProcess node $ do
190+ testPid <- getSelfPid
191+ agent <- mxAgent (MxAgentId "sendrecv-listener-agent") initState [
192+ (mxSink $ \(p1, p2, sp) -> do
193+ mxSetLocal [p1, p2]
194+ liftMX $ sendChan sp ()
195+ mxReady
196+ ),
197+ (mxSink $ \ev -> do
198+ st <- mxGetLocal
199+ let possiblyNotifyTestProcess pid = when (pid `elem` st) (liftMX $ send testPid ev)
200+ let act = case ev of
201+ MxSent{..} -> possiblyNotifyTestProcess whichProcess
202+ MxReceived{..} -> possiblyNotifyTestProcess whichProcess
203+ _ -> return ()
204+ act >> mxReady)
205+ ]
206+
207+ mRef <- monitor agent
208+
209+ goSignal <- liftIO newBroadcastTChanIO
210+ p1Ready <- liftIO $ atomically (dupTChan goSignal)
211+ p2Ready <- liftIO $ atomically (dupTChan goSignal)
212+
213+ p1 <- spawnLocal $ do
214+ link testPid
215+ liftIO $ atomically (readTChan p1Ready)
216+
217+ -- first we expect a message via send
218+ () <- expect
219+
220+ -- then another, via nsend
221+ liftIO $ atomically (readTChan p1Ready)
222+ () <- expect
223+
224+ -- then another, via usend
225+ liftIO $ atomically (readTChan p1Ready)
226+ () <- expect
227+
228+ return ()
229+
230+ p2 <- spawnLocal $ do
231+ link testPid
232+ liftIO $ atomically (readTChan p2Ready)
233+
234+ send p1 ()
235+
236+ liftIO $ atomically (readTChan p2Ready)
237+ nsend "test.process.1" ()
238+
239+ liftIO $ atomically (readTChan p2Ready)
240+ usend p1 ()
241+ -- and using unsafe primitives...
242+
243+
244+ register testProcName p1
245+ (Just _) <- whereis testProcName
246+
247+ (agentGo, agentReady) <- newChan
248+ mxNotify (p1, p2, agentGo)
249+
250+ () <- receiveChan agentReady
251+
252+ replicateM_ 3 $ checkOnce p1 p2 goSignal
253+
254+ kill agent "finished"
255+ receiveWait [ matchIf (\(ProcessMonitorNotification ref _ _) -> ref == mRef)
256+ (const $ return ()) ]
257+
258+ where
259+ checkOnce p1' p2' sig = do
260+ -- tell both the sending and receiving actors to take a step
261+ liftIO $ atomically $ writeTChan sig ()
262+
263+ -- ensure we saw the send first...
264+ receiveWait [
265+ matchIf (\(ev :: MxEvent) ->
266+ case ev of
267+ (MxSent p' d' _) -> p' == p2' && destProc d' p1'
268+ -- we should never get any other kind of MxEvent here...
269+ _ -> error "unexpected MxEvent"
270+ ) (const $ return ()) ]
271+
272+ -- and the receive after...
273+ receiveWait [
274+ matchIf (\(ev :: MxEvent) ->
275+ case ev of
276+ (MxReceived p' _) -> p' == p1'
277+ -- we should never get any other kind of MxEvent here...
278+ _ -> error "unexpected MxEvent"
279+ ) (const $ return ()) ]
280+
281+ initState :: [ProcessId]
282+ initState = []
283+
284+ testProcName = "test.process.1"
285+
286+ destProc (ProcId p) p' = p == p'
287+ destProc (ProcName n) _ = n == testProcName
288+ destProc _ _ = False
289+
178290tests :: TestTransport -> IO [Test]
179291tests TestTransport{..} = do
180292 node1 <- newLocalNode testTransport initRemoteTable
@@ -184,6 +296,7 @@ tests TestTransport{..} = do
184296 (delayedAssertion
185297 "expected True, but events where not as expected"
186298 node1 True testAgentEventHandling)
299+-- , testCase "Send & Receive" (testAgentSendRecvHandling node1)
187300 , testCase "Inter-Agent Broadcast"
188301 (delayedAssertion
189302 "expected (), but no broadcast was received"
distributed-process-tests/src/Control/Distributed/Process/Tests/Tracing.hs+26−14
@@ -1,4 +1,3 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
21{-# OPTIONS_GHC -fno-warn-orphans #-}
32module Control.Distributed.Process.Tests.Tracing (tests) where
43
@@ -19,6 +18,7 @@ import Control.Distributed.Process.Node
1918import Control.Distributed.Process.Debug
2019import Control.Distributed.Process.Management
2120 ( MxEvent(..)
21+ , Destination(..)
2222 )
2323import qualified Control.Exception as IO (bracket)
2424import Data.List (isPrefixOf, isSuffixOf)
@@ -124,10 +124,11 @@ testTraceSending result = do
124124 withTracer
125125 (\ev ->
126126 case ev of
127− (MxSent to from msg) -> do
128− (Just s) <- unwrapMessage msg :: Process (Maybe String)
129− stash res (to == pid && from == self && s == "hello there")
130− stash res (to == pid && from == self)
127+ MxSent{..} -> do
128+ let to = procId whereTo
129+ (Just s) <- unwrapMessage message :: Process (Maybe String)
130+ stash res (to == pid && whichProcess == self && s == "hello there")
131+ stash res (to == pid && whichProcess == self)
131132 _ ->
132133 return ()) $ do
133134 send pid "hello there"
@@ -314,24 +315,29 @@ testSystemLoggerMsg t action interestingMessage =
314315 runProcess n $ do
315316 self <- getSelfPid
316317 reregister "trace.logger" self
318+
317319 a <- action
318320 let interestingMessage' (_ :: String, msg) = interestingMessage a msg
319321 -- Wait for the trace message.
320322 receiveWait [ matchIf interestingMessage' $ const $ return () ]
321323 -- Only one interesting message should arrive.
322324 Nothing <- receiveTimeout 100000
323− [ matchIf interestingMessage' $ const $ return () ]
325+ [ matchIf interestingMessage' $ const $ return () ]
326+ -- return ()
327+ _ <- expectTimeout 5000000 :: Process (Maybe ())
324328 return ()
325329
330+ closeLocalNode n
326331
327332-- | Tests that one and only one trace message is produced when a message is
328333-- received.
329334testSystemLoggerMxReceive :: TestTransport -> IO ()
330335testSystemLoggerMxReceive t = testSystemLoggerMsg t
331− (getSelfPid >>= flip send ())
332− (\_ msg -> "MxReceived" `isPrefixOf` msg
336+ -- this is never going to work because we are trace.logger dumbass
337+ ((spawnLocal expect) >>= \pid -> send pid () >> return pid)
338+ (\pid msg -> ("MxReceived" `isPrefixOf` msg)
333339 -- discard traces of internal messages
334− && not (":: RegisterReply" `isSuffixOf` msg)
340+ && not (":: RegisterReply}" `isSuffixOf` msg)
335341 )
336342
337343-- | Tests that one and only one trace message is produced when a message is
@@ -339,33 +345,39 @@ testSystemLoggerMxReceive t = testSystemLoggerMsg t
339345testSystemLoggerMxSent :: TestTransport -> IO ()
340346testSystemLoggerMxSent t = testSystemLoggerMsg t
341347 (getSelfPid >>= flip send ())
342− (const $ isPrefixOf "MxSent")
348+ (\pid msg -> (("MxSent {whichProcess = " ++ show pid) `isPrefixOf` msg)
349+ -- discard traces of internal messages
350+ && not (":: RegisterReply}" `isSuffixOf` msg)
351+ )
343352
344353-- | Tests that one and only one trace message is produced when a process dies.
345354testSystemLoggerMxProcessDied :: TestTransport -> IO ()
346355testSystemLoggerMxProcessDied t = testSystemLoggerMsg t
347356 (spawnLocal $ return ())
348− (\pid -> isPrefixOf $ "MxProcessDied " ++ show pid)
357+ (\pid -> (== "MxProcessDied {whichProcess = " ++
358+ show pid ++ ", why = DiedNormal}"))
349359
350360-- | Tests that one and only one trace message appears when a process spawns.
351361testSystemLoggerMxSpawned :: TestTransport -> IO ()
352362testSystemLoggerMxSpawned t = testSystemLoggerMsg t
353363 (spawnLocal $ return ())
354− (\pid -> isPrefixOf $ "MxSpawned " ++ show pid)
364+ (\pid -> isPrefixOf $ "MxSpawned {whichProcess = " ++ show pid)
355365
356366-- | Tests that one and only one trace message appears when a process is
357367-- registered.
358368testSystemLoggerMxRegistered :: TestTransport -> IO ()
359369testSystemLoggerMxRegistered t = testSystemLoggerMsg t
360370 (getSelfPid >>= register "a" >> getSelfPid)
361− (\self -> isPrefixOf $ "MxRegistered " ++ show self ++ " " ++ show "a")
371+ (\pid -> (== "MxRegistered {whichProcess = " ++ show pid ++
372+ ", whichName = " ++ show "a" ++ "}"))
362373
363374-- | Tests that one and only one trace message appears when a process is
364375-- unregistered.
365376testSystemLoggerMxUnRegistered :: TestTransport -> IO ()
366377testSystemLoggerMxUnRegistered t = testSystemLoggerMsg t
367378 (getSelfPid >>= register "a" >> unregister "a" >> getSelfPid)
368− (\self -> isPrefixOf $ "MxUnRegistered " ++ show self ++ " " ++ show "a")
379+ (\pid -> (== "MxUnRegistered {whichProcess = " ++
380+ show pid ++ ", whichName = " ++ show "a" ++ "}"))
369381
370382tests :: TestTransport -> IO [Test]
371383tests testtrans@TestTransport{..} = do
src/Control/Distributed/Process/Internal/Primitives.hs+71−21
@@ -226,6 +226,7 @@ import Control.Distributed.Process.Internal.Messaging
226226 )
227227import Control.Distributed.Process.Management.Internal.Types
228228 ( MxEvent(..)
229+ , Destination(..)
229230 )
230231import Control.Distributed.Process.Management.Internal.Trace.Types
231232 ( traceEvent
@@ -256,14 +257,16 @@ send them msg = do
256257 case destNode == nodeId of
257258 True -> sendLocal them msg
258259 False -> liftIO $ sendMessage (processNode proc)
259− (ProcessIdentifier (processId proc))
260− (ProcessIdentifier them)
261− NoImplicitReconnect
262− msg
263− -- We do not fire the trace event until after the sending is complete;
264− -- In the remote case, 'sendMessage' can block in the networking stack.
260+ (ProcessIdentifier (processId proc))
261+ (ProcessIdentifier them)
262+ NoImplicitReconnect
263+ msg
264+ -- see note [trace MxSent]
265265 liftIO $ traceEvent (localEventBus node)
266− (MxSent them us (createUnencodedMessage msg))
266+ MxSent { whichProcess = us
267+ , whereTo = ProcId them
268+ , message = (createUnencodedMessage msg)
269+ }
267270
268271-- | /Unsafe/ variant of 'send'. This function makes /no/ attempt to serialize
269272-- and (in the case when the destination process resides on the same local
@@ -283,12 +286,22 @@ unsafeSend = Unsafe.send
283286--
284287usend :: Serializable a => ProcessId -> a -> Process ()
285288usend them msg = do
286− here <- getSelfNode
287− let there = processNodeId them
288− if here == there
289+ proc <- ask
290+ let us = processId proc
291+ node = processNode proc
292+ nodeId = localNodeId node
293+ let destNodeId = processNodeId them
294+ if nodeId == destNodeId
289295 then sendLocal them msg
290− else sendCtrlMsg (Just there) $ UnreliableSend (processLocalId them)
291− (createMessage msg)
296+ else do -- see note [trace MxSent]
297+ let evBus = localEventBus node
298+ let msg' = createMessage msg
299+ sendCtrlMsg (Just destNodeId) $ UnreliableSend (processLocalId them) msg'
300+ liftIO $ traceEvent evBus $ MxSent { whichProcess = us
301+ , whereTo = ProcId them
302+ , message = msg'
303+ }
304+
292305
293306-- | /Unsafe/ variant of 'usend'. This function makes /no/ attempt to serialize
294307-- the message when the destination process resides on the same local
@@ -487,10 +500,12 @@ forward msg them = do
487500 (ProcessIdentifier them)
488501 NoImplicitReconnect
489502 (messageToPayload msg)
490− -- We do not fire the trace event until after the sending is complete;
491− -- In the remote case, 'sendMessage' can block in the networking stack.
503+
492504 liftIO $ traceEvent (localEventBus node)
493− (MxSent them us msg)
505+ MxSent { whichProcess = us
506+ , whereTo = ProcId them
507+ , message = msg
508+ }
494509
495510-- | Forward a raw 'Message' to the given 'ProcessId'.
496511--
@@ -511,7 +526,10 @@ uforward msg them = do
511526 -- We do not fire the trace event until after the sending is complete;
512527 -- In the remote case, 'sendCtrlMsg' can block in the networking stack.
513528 liftIO $ traceEvent (localEventBus node)
514− (MxSent them us msg)
529+ MxSent { whichProcess = us
530+ , whereTo = ProcId them
531+ , message = msg
532+ }
515533
516534-- | Wrap a 'Serializable' value in a 'Message'. Note that 'Message's are
517535-- 'Serializable' - like the datum they contain - but also note, deserialising
@@ -1220,8 +1238,20 @@ whereisRemoteAsync nid label = do
12201238
12211239-- | Named send to a process in the local registry (asynchronous)
12221240nsend :: Serializable a => String -> a -> Process ()
1223−nsend label msg =
1224− sendCtrlMsg Nothing (NamedSend label (createUnencodedMessage msg))
1241+nsend label msg = do
1242+ proc <- ask
1243+ let us = processId proc
1244+ node = processNode proc
1245+ msg' = createMessage msg -- NB: using UnencodedMessage here causes chaos... :/
1246+
1247+ sendCtrlMsg Nothing (NamedSend label msg')
1248+
1249+ -- see note [trace MxSent]
1250+ liftIO $ traceEvent (localEventBus node)
1251+ MxSent { whichProcess = us
1252+ , whereTo = ProcName label
1253+ , message = msg'
1254+ }
12251255
12261256-- | Named send to a process in the local registry (asynchronous).
12271257-- This function makes /no/ attempt to serialize and (in the case when the
@@ -1233,9 +1263,19 @@ unsafeNSend = Unsafe.nsend
12331263-- | Named send to a process in a remote registry (asynchronous)
12341264nsendRemote :: Serializable a => NodeId -> String -> a -> Process ()
12351265nsendRemote nid label msg = do
1266+ proc <- ask
1267+ let us = processId proc
1268+ node = processNode proc
12361269 here <- getSelfNode
12371270 if here == nid then nsend label msg
1238− else sendCtrlMsg (Just nid) (NamedSend label (createMessage msg))
1271+ else do let msg' = createMessage msg
1272+ sendCtrlMsg (Just nid) (NamedSend label msg')
1273+ -- see note [trace MxSent]
1274+ liftIO $ traceEvent (localEventBus node)
1275+ MxSent { whichProcess = us
1276+ , whereTo = ProcName label
1277+ , message = msg'
1278+ }
12391279
12401280-- | Named send to a process in a remote registry (asynchronous)
12411281-- This function makes /no/ attempt to serialize and (in the case when the
@@ -1306,8 +1346,18 @@ reconnectPort them = do
13061346--------------------------------------------------------------------------------
13071347
13081348sendLocal :: (Serializable a) => ProcessId -> a -> Process ()
1309−sendLocal to msg =
1310− sendCtrlMsg Nothing $ LocalSend to (createUnencodedMessage msg)
1349+sendLocal to msg = do
1350+ proc <- ask
1351+ let us = processId proc
1352+ node = processNode proc
1353+ msg' = createUnencodedMessage msg
1354+
1355+ sendCtrlMsg Nothing $ LocalSend to msg'
1356+ liftIO $ traceEvent (localEventBus node)
1357+ MxSent { whichProcess = us
1358+ , whereTo = ProcId to
1359+ , message = msg'
1360+ }
13111361
13121362sendChanLocal :: (Serializable a) => SendPortId -> a -> Process ()
13131363sendChanLocal spId msg =
src/Control/Distributed/Process/Management.hs+2
@@ -219,6 +219,7 @@
219219module Control.Distributed.Process.Management
220220 (
221221 MxEvent(..)
222+ , Destination(..)
222223 -- * Firing Arbitrary /Mx Events/
223224 , mxNotify
224225 -- * Constructing Mx Agents
@@ -276,6 +277,7 @@ import Control.Distributed.Process.Management.Internal.Types
276277 , MxAgentState(..)
277278 , MxSink
278279 , MxEvent(..)
280+ , Destination(..)
279281 )
280282import Control.Distributed.Process.Serializable (Serializable)
281283import Control.Monad.IO.Class (liftIO)
src/Control/Distributed/Process/Management/Internal/Agent.hs+2−2
@@ -57,8 +57,8 @@ type AgentConfig =
5757 (Tracer, Weak (CQueue Message),
5858 (((TChan Message, TChan Message) -> Process ()) -> IO ProcessId))
5959
60−-- | Starts a management agent for the current node. The agent process
61−-- must not crash or be killed, so we generally avoid publishing its
60+-- | Starts a management agent controller for the current node. The process
61+-- must not crash or be killed, so we generally try to avoid publishing its
6262-- @ProcessId@ where possible.
6363--
6464-- Our process is also responsible for forwarding messages to the trace
src/Control/Distributed/Process/Management/Internal/Trace/Primitives.hs+4−1
@@ -167,7 +167,10 @@ withRegisteredTracer act = do
167167 (sp, rp) <- newChan
168168 withLocalTracer $ \t -> liftIO $ Tracer.getCurrentTraceClient t sp
169169 currentTracer <- receiveChan rp
170+ -- TODO: there is an obvious race here, whereby tracer.initial could
171+ -- die or be replaced (via reregister) between the call to whereis
172+ -- and the expression acting on the pid. Maybe pass the trace client
173+ -- instead???
170174 case currentTracer of
171175 Nothing -> do { (Just p') <- whereis "tracer.initial"; act p' }
172176 (Just p) -> act p
173−
src/Control/Distributed/Process/Management/Internal/Trace/Tracer.hs+29−15
@@ -1,5 +1,7 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE RecordWildCards #-}
4+{-# LANGUAGE PatternGuards #-}
35-- | Tracing/Debugging support - Trace Implementation
46module Control.Distributed.Process.Management.Internal.Trace.Tracer
57 ( -- * API for the Management Agent
@@ -142,21 +144,28 @@ nullTracer =
142144
143145systemLoggerTracer :: Process ()
144146systemLoggerTracer = do
145− node <- processNode <$> ask
146− let tr = sendTraceLog node
147− forever' $ receiveWait [ matchAny (\m -> handleMessage m tr) ]
147+ proc <- ask
148+ let pid = processId proc
149+ node = processNode proc
150+ forever' $ receiveWait [ matchAny (\m -> handleMessage m (sendTraceLog pid node)) ]
148151 where
149− sendTraceLog :: LocalNode -> MxEvent -> Process ()
150− sendTraceLog node ev = do
151− now <- liftIO $ getCurrentTime
152− msg <- return $ (formatTime defaultTimeLocale "%c" now, buildTxt ev)
153− emptyPid <- return $ (nullProcessId (localNodeId node))
154− traceMsg <- return $ NCMsg {
155− ctrlMsgSender = ProcessIdentifier (emptyPid)
156− , ctrlMsgSignal = (NamedSend "trace.logger"
157− (createUnencodedMessage msg))
158− }
159− liftIO $ writeChan (localCtrlChan node) traceMsg
152+ sendTraceLog :: ProcessId -> LocalNode -> MxEvent -> Process ()
153+ sendTraceLog pid' node' ev
154+ -- because process is the trace client, the trace coordinator cannot
155+ -- filter out messages pertaining to the trace.logger, so we do so here
156+ | MxReceived{..} <- ev
157+ , whichProcess == pid' = return ()
158+ | otherwise = do
159+ now <- liftIO $ getCurrentTime
160+ msg <- return $ (formatTime defaultTimeLocale "%c" now, buildTxt ev)
161+ emptyPid <- return $ nullPid node'
162+ traceMsg <- return $ NCMsg { ctrlMsgSender = ProcessIdentifier (emptyPid)
163+ , ctrlMsgSignal = (NamedSend "trace.logger"
164+ (createUnencodedMessage msg))
165+ }
166+ liftIO $ writeChan (localCtrlChan node') traceMsg
167+
168+ nullPid node'' = nullProcessId (localNodeId node'')
160169
161170 buildTxt :: MxEvent -> String
162171 buildTxt (MxLog msg) = msg
@@ -235,7 +244,8 @@ traceController mv = do
235244 sendOk confResp >> applyTraceFlags flags' st)
236245 , match (\chGetFlags -> sendChan chGetFlags (flags st) >> return st)
237246 , match (\chGetCurrent -> sendChan chGetCurrent (client st) >> return st)
238− -- we dequeue incoming events even if we don't process them
247+ -- we do not forward messages to the client that pertain to itself
248+ -- also, we de-queue incoming events even if we don't process them
239249 , matchAny (\ev ->
240250 handleMessage ev (handleTrace st ev) >>= return . fromMaybe st)
241251 ]
@@ -332,6 +342,10 @@ traceEv ev msg (Just (TraceProcs pids)) st = do
332342traceEv ev msg (Just (TraceNames names)) st = do
333343 -- if we have recorded regnames for p, then we forward the trace iif
334344 -- there are overlapping trace targets
345+ -- NB: this will now be broken for instances of Destination that cannot be
346+ -- resolved, thus we need to re-examine this branch of the tracing code
347+ -- to understand what the impact of that will actually be...
348+
335349 node <- processNode <$> ask
336350 let p = case resolveToPid ev of
337351 Nothing -> (nullProcessId (localNodeId node))
src/Control/Distributed/Process/Management/Internal/Types.hs+56−15
@@ -11,6 +11,7 @@ module Control.Distributed.Process.Management.Internal.Types
1111 , Fork
1212 , MxSink
1313 , MxEvent(..)
14+ , Destination(..)
1415 , Addressable(..)
1516 ) where
1617
@@ -18,10 +19,12 @@ import Control.Applicative (Applicative)
1819import Control.Concurrent.STM
1920 ( TChan
2021 )
22+import Control.DeepSeq (NFData(..))
2123import Control.Distributed.Process.Internal.Types
2224 ( Process
2325 , ProcessId
2426 , Message
27+ , SendPort
2528 , DiedReason
2629 , NodeId
2730 )
@@ -38,35 +41,68 @@ import Network.Transport
3841 , EndPointAddress
3942 )
4043
44+-- | A simple means of mapping send events to their destinations
45+data Destination =
46+ ProcId { procId :: !ProcessId }
47+ | ProcName { procName :: !String }
48+ | RemoteProcName { procName :: !String
49+ , procNode :: !NodeId }
50+ | UserDefined { userData :: !Message }
51+ deriving (Typeable, Generic, Show)
52+instance Binary Destination where
53+instance NFData Destination where
54+ rnf (ProcId p) = rnf p `seq` ()
55+ rnf (ProcName s) = rnf s `seq` ()
56+ rnf (RemoteProcName s n) = rnf s `seq` rnf n `seq` ()
57+ rnf (UserDefined m) = rnf m `seq` ()
58+
59+
4160-- | This is the /default/ management event, fired for various internal
4261-- events around the NT connection and Process lifecycle. All published
4362-- events that conform to this type, are eligible for tracing - i.e.,
4463-- they will be delivered to the trace controller.
4564--
4665data MxEvent =
47− MxSpawned ProcessId
66+ MxSpawned { whichProcess :: ProcessId }
4867 -- ^ fired whenever a local process is spawned
49− | MxRegistered ProcessId String
68+ | MxRegistered { whichProcess :: ProcessId
69+ , whichName :: String
70+ }
5071 -- ^ fired whenever a process/name is registered (locally)
51− | MxUnRegistered ProcessId String
72+ | MxUnRegistered { whichProcess :: ProcessId
73+ , whichName :: String
74+ }
5275 -- ^ fired whenever a process/name is unregistered (locally)
53− | MxProcessDied ProcessId DiedReason
76+ | MxProcessDied { whichProcess :: ProcessId
77+ , why :: DiedReason
78+ }
5479 -- ^ fired whenever a process dies
55− | MxNodeDied NodeId DiedReason
80+ | MxNodeDied { whichNode :: NodeId
81+ , why :: DiedReason
82+ }
5683 -- ^ fired whenever a node /dies/ (i.e., the connection is broken/disconnected)
57− | MxSent ProcessId ProcessId Message
84+ | MxSent { whichProcess :: ProcessId
85+ , whereTo :: Destination
86+ , message :: Message
87+ }
5888 -- ^ fired whenever a message is sent from a local process
59− | MxReceived ProcessId Message
89+ | MxReceived { whichProcess :: ProcessId
90+ , message :: Message
91+ }
6092 -- ^ fired whenever a message is received by a local process
61− | MxConnected ConnectionId EndPointAddress
93+ | MxConnected { whichConnection :: ConnectionId
94+ , whichEndoint :: EndPointAddress
95+ }
6296 -- ^ fired when a network-transport connection is first established
63− | MxDisconnected ConnectionId EndPointAddress
97+ | MxDisconnected { whichConnection :: ConnectionId
98+ , whichEndpoint :: EndPointAddress
99+ }
64100 -- ^ fired when a network-transport connection is broken/disconnected
65− | MxUser Message
101+ | MxUser { message :: Message }
66102 -- ^ a user defined trace event
67− | MxLog String
103+ | MxLog { text :: String }
68104 -- ^ a /logging/ event - used for debugging purposes only
69− | MxTraceTakeover ProcessId
105+ | MxTraceTakeover { whichProcess :: ProcessId }
70106 -- ^ notifies a trace listener that all subsequent traces will be sent to /pid/
71107 | MxTraceDisable
72108 -- ^ notifies a trace listener that it has been disabled/removed
@@ -74,15 +110,20 @@ data MxEvent =
74110
75111instance Binary MxEvent where
76112
77−-- | The class of things that we might be able to resolve to
78−-- a @ProcessId@ (or not).
113+-- The class of things that we might be able to resolve to
114+-- a @ProcessId@ (or not). Note we don't want to export this!
79115class Addressable a where
80116 resolveToPid :: a -> Maybe ProcessId
81117
118+instance Addressable Destination where
119+ resolveToPid dest
120+ | (ProcId pid) <- dest = Just pid
121+ | otherwise = Nothing
122+
82123instance Addressable MxEvent where
83124 resolveToPid (MxSpawned p) = Just p
84125 resolveToPid (MxProcessDied p _) = Just p
85− resolveToPid (MxSent _ p _) = Just p
126+ resolveToPid (MxSent _ p _) = resolveToPid p
86127 resolveToPid (MxReceived p _) = Just p
87128 resolveToPid _ = Nothing
88129
src/Control/Distributed/Process/Node.hs+1
@@ -550,6 +550,7 @@ handleIncomingMessages node = go initConnectionState
550550 forM_ mChan $ \chan -> atomically $
551551 -- We make sure the message is fully decoded when it is enqueued
552552 writeTQueue chan $! decode (BSL.fromChunks payload)
553+ -- trace node (MxReceived pid msg)
553554 go st
554555 Just (_, ToNode) -> do
555556 let ctrlMsg = decode . BSL.fromChunks $ payload
stack-ghc-8.0.1.yamlnew file+18
@@ -0,0 +1,18 @@
1+# Specifies the GHC version and set of packages available
2+resolver: lts-7.14
3+
4+packages:
5+- '.'
6+- distributed-process-tests/
7+
8+extra-deps:
9+- rank1dynamic-0.3.3.0
10+- distributed-static-0.3.5.0
11+- network-transport-0.4.4.0
12+- network-transport-tcp-0.5.1
13+- network-transport-inmemory-0.5.1
14+- rematch-0.2.0.0
15+
16+flags:
17+ distributed-process-tests:
18+ tcp: true
stack.yamlmode 100644 → 120000+1−17
@@ -1,17 +0,0 @@
1−resolver: nightly-2016-06-09
2−
3−packages:
4−- '.'
5−- distributed-process-tests/
6−
7−extra-deps:
8−- rank1dynamic-0.3.3.0
9−- distributed-static-0.3.5.0
10−- network-transport-0.4.4.0
11−- network-transport-tcp-0.5.1
12−- network-transport-inmemory-0.5.1
13−- rematch-0.2.0.0
14−
15−flags:
16− distributed-process-tests:
17− tcp: true
@@ -0,0 +1 @@
1+stack-ghc-8.0.1.yaml