Example #1
0
        /// <summary>
        /// Writes an operation to the output buffer. Handles the case where the op does not fit the buffer fully.
        /// </summary>
        /// <param name="data"></param>
        protected virtual void WriteOp(OpQueueEntry data)
        {
            if (currentWriteCopier != null)
            {
                throw new InvalidOperationException("Cannot write an operation while another is in progress.");
            }

            var request = data.Op.CreateRequest();

            if (!request.WriteTo(socket.WriteBuffer))             // no pending IO => fully written
            {
                readQueue.Enqueue(data);
                request.Dispose();

                #region Diagnostics
                npm.EnqueueReadOp();
                CoreEventSource.EnqueueReadOp(name);

                LogTo.Trace($"Full send of {data.Op}");
                #endregion
            }
            else
            {
                // it did not fit into the write buffer, so save the current op
                // as "in-progress"; DoRun will loop until it's fully sent
                currentWriteOp     = data;
                currentWriteCopier = request;

                LogTo.Trace($"Partial send of {data.Op}");
            }
        }
Example #2
0
        /// <summary>
        /// Sends the current chunked op. Happens when an op's data cannot fit the write buffer in one pass.
        /// </summary>
        /// <returns>returns true if further IO is required; false if no inprogress op present or the last chunk was successfully added to the buffer</returns>
        private bool ContinueWritingCurrentOp()
        {
            // check if we have an op in progress
            if (currentWriteCopier == null)
            {
                return(false);
            }
            if (currentWriteCopier.WriteTo(socket.WriteBuffer))
            {
                return(true);
            }

            // last chunk was sent
            LogTo.Trace($"Sent & finished {currentWriteOp.Op}");

            // op is sent fully; response can be expected
            readQueue.Enqueue(currentWriteOp);

            #region Diagnostics
            npm.EnqueueReadOp();
            CoreEventSource.EnqueueReadOp(name);
            #endregion

            // clean up
            currentWriteCopier.Dispose();
            currentWriteCopier = null;
            currentWriteOp     = OpQueueEntry.Empty;

            return(false);
        }
        protected override void WriteOp(OpQueueEntry data)
        {
            // remember of the last op was silent so that when we
            // run out of ops we'll know if we have to emit an additional NoOp
            // ***SSSSS<EOF>
            // * = normal
            // S = Silent
            // noop should be at <EOF> otherwise we won't get responses to the last
            // command until we get a new op queued up
            var silent = data.Op as ICanBeSilent;

            lastWasSilent = silent != null && silent.Silent;

            base.WriteOp(data);
        }
Example #4
0
        private bool FailMe(Exception e)
        {
            lock (failLock)
            {
                LogTo.Error(e, $"Node {name} has failed during IO.");
                var fail = (e is IOException) ? e : new IOException("io fail; see inner exception", e);

                // empty all queues
                FailQueue(writeQueue, fail);
                FailQueue(readQueue, fail);

                npm.ResetQueues();

                // kill the partially sent op (if any)
                if (currentWriteCopier != null)
                {
                    currentWriteOp.Task.SetException(fail);
                    currentWriteOp     = OpQueueEntry.Empty;
                    currentWriteCopier = null;
                }

                // kill the partially read response
                if (inprogressResponse != null)
                {
                    inprogressResponse.Dispose();
                    inprogressResponse = null;
                }

                _FinishedReading();
                _FinishedWriting();

                // mark as dead if policy says so...
                if (failurePolicy.ShouldFail(this))
                {
                    IsAlive = false;
                    return(true);
                }

                // ...otherwise reconnect immediately (when it's our turn)
                mustReconnect = true;
                LogTo.Info($"Node {endpoint} will reconnect immediately.");

                // reconnect from IO thread
                owner.NeedsIO(this);

                return(false);
            }
        }