/// <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}"); } }
/// <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); }
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); } }