private void Reset() { if (batchingMode) { phase = ReceivePhase.MetaHeader; // MetaHeader MUST NOT set to null because it will be re-used. lengthBuffer = null; lengths = null; header = null; body = null; headerLengths = null; bodyLengths = null; headerBodies = null; headerBodiesLength = 0; numberOfMessages = 0; offset = 0; } else { phase = ReceivePhase.Lengths; headerLength = 0; bodyLength = 0; offset = 0; header = null; body = null; } }
public ReceiveCallbackContext(Socket sock, IncomingMessageAcceptor ima) { batchingMode = ima.MessageCenter.MessagingConfiguration.UseMessageBatching; if (batchingMode) { phase = ReceivePhase.MetaHeader; Sock = sock; RemoteEndPoint = sock.RemoteEndPoint; IMA = ima; metaHeaderBuffer = new byte[Message.LENGTH_META_HEADER]; metaHeader = new List <ArraySegment <byte> >() { new ArraySegment <byte>(metaHeaderBuffer) }; // LengthBuffer and Lengths cannot be allocated here because the sizes varies in response to the number of received messages lengthBuffer = null; lengths = null; header = null; body = null; headerBodies = null; headerLengths = null; bodyLengths = null; headerBodiesLength = 0; numberOfMessages = 0; offset = 0; } else { phase = ReceivePhase.Lengths; Sock = sock; RemoteEndPoint = sock.RemoteEndPoint; IMA = ima; lengthBuffer = new byte[Message.LENGTH_HEADER_SIZE]; lengths = new List <ArraySegment <byte> >() { new ArraySegment <byte>(lengthBuffer) }; header = null; body = null; headerLength = 0; bodyLength = 0; offset = 0; } }
public void ProcessReceivedBuffer(int bytes) { offset += bytes; if (offset < CurrentLength) { return; // Nothing to do except start the next receive } #if TRACK_DETAILED_STATS ThreadTrackingStatistic tracker = null; if (StatisticsCollector.CollectThreadTimeTrackingStats) { int id = System.Threading.Thread.CurrentThread.ManagedThreadId; if (!trackers.TryGetValue(id, out tracker)) { tracker = new ThreadTrackingStatistic("ThreadPoolThread." + System.Threading.Thread.CurrentThread.ManagedThreadId); bool added = trackers.TryAdd(id, tracker); if (added) { tracker.OnStartExecution(); } } tracker.OnStartProcessing(); } #endif try { if (batchingMode) { switch (phase) { case ReceivePhase.MetaHeader: numberOfMessages = BitConverter.ToInt32(metaHeaderBuffer, 0); lengthBuffer = new byte[numberOfMessages * Message.LENGTH_HEADER_SIZE]; lengths = new List <ArraySegment <byte> >() { new ArraySegment <byte>(lengthBuffer) }; phase = ReceivePhase.Lengths; offset = 0; break; case ReceivePhase.Lengths: headerBodies = new List <ArraySegment <byte> >(); headerLengths = new int[numberOfMessages]; bodyLengths = new int[numberOfMessages]; for (int i = 0; i < numberOfMessages; i++) { headerLengths[i] = BitConverter.ToInt32(lengthBuffer, i * 8); bodyLengths[i] = BitConverter.ToInt32(lengthBuffer, i * 8 + 4); headerBodiesLength += (headerLengths[i] + bodyLengths[i]); // We need to set the boundary of ArraySegment<byte>s to the same as the header/body boundary headerBodies.AddRange(BufferPool.GlobalPool.GetMultiBuffer(headerLengths[i])); headerBodies.AddRange(BufferPool.GlobalPool.GetMultiBuffer(bodyLengths[i])); } phase = ReceivePhase.HeaderBodies; offset = 0; break; case ReceivePhase.HeaderBodies: int lengtshSoFar = 0; for (int i = 0; i < numberOfMessages; i++) { header = ByteArrayBuilder.BuildSegmentListWithLengthLimit(headerBodies, lengtshSoFar, headerLengths[i]); body = ByteArrayBuilder.BuildSegmentListWithLengthLimit(headerBodies, lengtshSoFar + headerLengths[i], bodyLengths[i]); lengtshSoFar += (headerLengths[i] + bodyLengths[i]); var msg = new Message(header, body); MessagingStatisticsGroup.OnMessageReceive(msg, headerLengths[i], bodyLengths[i]); if (IMA.Log.IsVerbose3) { IMA.Log.Verbose3("Received a complete message of {0} bytes from {1}", headerLengths[i] + bodyLengths[i], msg.SendingAddress); } if (headerLengths[i] + bodyLengths[i] > Message.LargeMessageSizeThreshold) { IMA.Log.Info(ErrorCode.Messaging_LargeMsg_Incoming, "Receiving large message Size={0} HeaderLength={1} BodyLength={2}. Msg={3}", headerLengths[i] + bodyLengths[i], headerLengths[i], bodyLengths[i], msg.ToString()); if (IMA.Log.IsVerbose3) { IMA.Log.Verbose3("Received large message {0}", msg.ToLongString()); } } IMA.HandleMessage(msg, Sock); } MessagingStatisticsGroup.OnMessageBatchReceive(IMA.SocketDirection, numberOfMessages, lengtshSoFar); Reset(); break; } } else { // We've completed a buffer. What we do depends on which phase we were in switch (phase) { case ReceivePhase.Lengths: // Pull out the header and body lengths headerLength = BitConverter.ToInt32(lengthBuffer, 0); bodyLength = BitConverter.ToInt32(lengthBuffer, 4); header = BufferPool.GlobalPool.GetMultiBuffer(headerLength); body = BufferPool.GlobalPool.GetMultiBuffer(bodyLength); phase = ReceivePhase.Header; offset = 0; break; case ReceivePhase.Header: phase = ReceivePhase.Body; offset = 0; break; case ReceivePhase.Body: var msg = new Message(header, body); MessagingStatisticsGroup.OnMessageReceive(msg, headerLength, bodyLength); if (IMA.Log.IsVerbose3) { IMA.Log.Verbose3("Received a complete message of {0} bytes from {1}", headerLength + bodyLength, msg.SendingAddress); } if (headerLength + bodyLength > Message.LargeMessageSizeThreshold) { IMA.Log.Info(ErrorCode.Messaging_LargeMsg_Incoming, "Receiving large message Size={0} HeaderLength={1} BodyLength={2}. Msg={3}", headerLength + bodyLength, headerLength, bodyLength, msg.ToString()); if (IMA.Log.IsVerbose3) { IMA.Log.Verbose3("Received large message {0}", msg.ToLongString()); } } IMA.HandleMessage(msg, Sock); Reset(); break; } } } catch (Exception exc) { try { // Log details of receive state machine IMA.Log.Error(ErrorCode.MessagingProcessReceiveBufferException, string.Format( "Exception trying to process {0} bytes from endpoint {1} at offset {2} in phase {3}" + " CurrentLength={4} HeaderLength={5} BodyLength={6}", bytes, RemoteEndPoint, offset, phase, CurrentLength, headerLength, bodyLength ), exc); } catch (Exception) { } Reset(); // Reset back to a hopefully good base state throw; } finally { #if TRACK_DETAILED_STATS if (StatisticsCollector.CollectThreadTimeTrackingStats) { tracker.IncrementNumberOfProcessed(); tracker.OnStopProcessing(); } #endif } }