예제 #1
0
        private void PerformReceive()
        {
fill:
            // no data to process => read the socket
            if (socket.ReadBuffer.IsEmpty)
            {
                if (LogTraceEnabled)
                {
                    log.Trace("Read buffer is empty, ask for more.");
                }

                socket.ScheduleReceive(success =>
                {
                    if (success)
                    {
                        MarkAsReady();
                        owner.NeedsIO(this);
                    }
                    else
                    {
                        // this is a soft fail (cannot throw from other thread),
                        // so we requeue for IO and exception will be thrown by Receive()
                        FailMe(new IOException("Failed receiving from " + endpoint));
                    }
                });

                return;
            }

            // process the commands in the readQueue
            while (readQueue.Count > 0)
            {
                // continue filling the previously unfinished response,
                // or create a new one
                var response = inprogressResponse ?? CreateResponse();

                // continue filling the Response object from the buffer
                // Read() returns true if further data (IO) is required
                // (usually when the current response data is larger than the receive buffer size)
                if (response.Read(socket.ReadBuffer))
                {
                    inprogressResponse = response;
                    if (LogTraceEnabled)
                    {
                        log.Trace("Response is not read fully, continue reading from the socket.");
                    }

                    // refill the buffer
                    // TODO if Receive returns synchrously several times, a node with a huge inprogress response can monopolize the IO thread
                    goto fill;
                }

                // successfully read a response from the read buffer
                inprogressResponse = null;
                var matching = false;

                while (!matching && readQueue.Count > 0)
                {
                    var data = readQueue.Peek();
                    Debug.Assert(!data.IsEmpty);

                    // if the response does not matches the current op, it means it's a
                    // response to later command in the queue, so all commands before it are silent commands
                    // successful silent ops will receive null as response (since we have no real response)
                    // (or we've ran into a bug)
                    matching = data.Op.Handles(response);
                    if (LogTraceEnabled)
                    {
                        log.Trace("Command {0} handles reponse: {1}", data.Op, matching);
                    }

                    // returns false when no more IO is required => command is processed
                    // otherwise continue filling the buffer
                    if (!data.Op.ProcessResponse(matching ? response : null))
                    {
                        readQueue.Dequeue();
                        counterReadQueue.Decrement();
                        counterOpReadPerSec.Increment();
                        if (trace.IsEnabled())
                        {
                            trace.DequeueReadOp(name);
                        }

                        if (data.Task != null)
                        {
                            data.Task.TrySetResult(data.Op);
                        }
                    }
                }

                response.Dispose();
            }

            // set the node into send mode and requeue for IO
            Volatile.Write(ref runMode, MODE_SEND);
            MarkAsReady();
            owner.NeedsIO(this);
        }
예제 #2
0
        private void TryProcessReceivedData()
        {
            // process the commands in the readQueue
            while (readQueue.Count > 0)
            {
                // continue filling the previously unfinished response,
                // or create a new one
                var response = inprogressResponse ?? CreateResponse();

                // continue filling the Response object from the buffer
                // Read() returns true if further data (IO) is required
                // (usually when the current response data is larger than the receive buffer size)
                if (response.Read(socket.ReadBuffer))
                {
                    inprogressResponse = response;
                    LogTo.Trace("Response is not read fully, continue reading from the socket.");

                    // refill the buffer
                    _FinishedReading();
                    owner.NeedsIO(this);

                    return;
                }

                // successfully read a response from the read buffer
                inprogressResponse = null;
                var isHandled = false;

                while (!isHandled && readQueue.Count > 0)
                {
                    var data = readQueue.Peek();
                    Debug.Assert(!data.IsEmpty);

                    // If the response does not matches the current op, it means it's a
                    // response to a later command in the queue, so all commands before it
                    // were silent commands without a response (== usually success).
                    // So, successful silent ops will receive null as response (since
                    // we have no real response (or we've ran into a bug))
                    isHandled = data.Op.Handles(response);
                    LogTo.Trace($"Command {data.Op} handles reponse: {isHandled}");

                    // operations are allowed to hanndle subsequent responses
                    // they returns false when no more IO (response) is required => done processing
                    if (!data.Op.ProcessResponse(isHandled ? response : null))
                    {
                        readQueue.Dequeue();
                        data.Task.TrySetResult(data.Op);

                        #region Diagnostics
                        npm.DequeueReadOp();
                        CoreEventSource.DequeueReadOp(name);
                        #endregion
                    }
                }

                response.Dispose();
            }

            LogTo.Trace($"{name} fininshed RECEIVE, unlock read");
            _FinishedReading();
        }