public void PutMessage(MessageLevel messageLevel, ushort receiverNodeId, ushort receiverWorkerId, ushort senderNodeId, ushort senderWorkerId, int messageType, object content) { //see if it is a local worker that is the receiver lock (_localWorkers) { //Message msg = new Message(messageLevel, new WorkerAddress(receiverNodeId, receiverWorkerId), new WorkerAddress(senderNodeId, senderWorkerId), messageType, content); if (WorkerAddress.IsBroadcastAddress(receiverNodeId, receiverWorkerId)) //broadcast address { foreach (var worker in _localWorkers.Values) { worker.PutMessage(messageLevel, receiverNodeId, receiverWorkerId, senderNodeId, senderWorkerId, messageType, CloneContent(content)); //clone the message to prevent shared state } } else if (_localWorkers.ContainsKey(receiverWorkerId)) { _localWorkers[receiverWorkerId].PutMessage(messageLevel, receiverNodeId, receiverWorkerId, senderNodeId, senderWorkerId, messageType, CloneContent(content)); } else if (!SystemMessages.IsSystemMessageType(messageType)) //we don't care about that { Log.Error("Node.PutMessage : Cannot dispatch message"); } } }
/// <summary> /// This method handles the dispatching of messages in the send buffer. /// /// This is done in a separate thread so that local workers do not wait for each other, /// or wait for the relatively slow communication over the remoting framework. /// </summary> /// <param name="state"></param> private void SendBufferThreadProc(object state) { while (!SendBufferThreadTerminate) { _sendBufferWaitHandle.WaitOne(); //fetch the first message Message msg = null; lock (_sendBuffer) { LinkedListNode <Message> firstNode = _sendBuffer.First; if (firstNode != null) { msg = firstNode.Value; _sendBuffer.RemoveFirst(); } else { _sendBufferWaitHandle.Reset(); } } /* Keep processing messages if there are any (no sleep - the thread * will be switched out naturally), otherwise force the thread to be switched * out of context. */ if (msg != null) { //is it a broad cast message? if (WorkerAddress.IsBroadcastAddress(msg.ReceiverAddress)) { //send it to all local workers (except the sender) lock (_localWorkers) { foreach (Worker worker in _localWorkers.Values) { if (msg.SenderAddress.NodeId != _id || worker.Id != msg.SenderAddress.WorkerId) { worker.PutMessage(msg.MessageLevel, msg.ReceiverAddress.NodeId, msg.ReceiverAddress.WorkerId, msg.SenderAddress.NodeId, msg.SenderAddress.WorkerId, msg.MessageType, CloneContent(msg.Content)); //clone to prevent shared state } } } //broadcast it to all remote nodes lock (_remoteNodes) { foreach (INode remoteNode in _remoteNodes.Values) { remoteNode.PutMessage(msg.MessageLevel, msg.ReceiverAddress.NodeId, msg.ReceiverAddress.WorkerId, msg.SenderAddress.NodeId, msg.SenderAddress.WorkerId, msg.MessageType, msg.Content); } } } else if (msg.ReceiverAddress.NodeId == _id) //it is a local receiver { lock (_localWorkers) { if (_localWorkers.ContainsKey(msg.ReceiverAddress.WorkerId)) { _localWorkers[msg.ReceiverAddress.WorkerId].PutMessage(msg.MessageLevel, msg.ReceiverAddress.NodeId, msg.ReceiverAddress.WorkerId, msg.SenderAddress.NodeId, msg.SenderAddress.WorkerId, msg.MessageType, CloneContent(msg.Content)); } } } else //not a broadcast, not a local receiver, then find the remote node to send it to { lock (_remoteNodes) { ushort nodeId = msg.ReceiverAddress.NodeId; if (_remoteNodes.ContainsKey(nodeId)) { try { _remoteNodes[nodeId].PutMessage(msg.MessageLevel, msg.ReceiverAddress.NodeId, msg.ReceiverAddress.WorkerId, msg.SenderAddress.NodeId, msg.SenderAddress.WorkerId, msg.MessageType, msg.Content); } catch (Exception) { Log.Error("Node.SendBufferThreadProc : Remote node {0} appears to be offline", nodeId); _remoteNodes.Remove(nodeId); _registrationServerProxy.UnregisterNode(nodeId); } } } } } } }