private WriteResult FailDueToNoConnection(Message message) { message.Cancel(); Multiplexer?.OnMessageFaulted(message, null); message.Complete(); return(WriteResult.NoConnectionAvailable); }
private WriteResult TimedOutBeforeWrite(Message message) { message.Cancel(); Multiplexer?.OnMessageFaulted(message, null); message.Complete(); return(WriteResult.TimeoutBeforeWrite); }
internal WriteResult WriteMessageTakingWriteLockSync(PhysicalConnection physical, Message message) { Trace("Writing: " + message); message.SetEnqueued(physical); // this also records the read/write stats at this point LockToken token = default; try { token = _singleWriterMutex.TryWait(WaitOptions.NoDelay); if (!token.Success) { // we can't get it *instantaneously*; is there // perhaps a backlog and active backlog processor? bool haveBacklog; lock (_backlog) { haveBacklog = _backlog.Count != 0; } if (haveBacklog) { PushToBacklog(message); return(WriteResult.Success); // queued counts as success } // no backlog... try to wait with the timeout; // if we *still* can't get it: that counts as // an actual timeout token = _singleWriterMutex.TryWait(); if (!token.Success) { message.Cancel(); Multiplexer?.OnMessageFaulted(message, null); message.Complete(); return(WriteResult.TimeoutBeforeWrite); } } var result = WriteMessageInsideLock(physical, message); if (result == WriteResult.Success) { #pragma warning disable CS0618 result = physical.FlushSync(false, TimeoutMilliseconds); #pragma warning restore CS0618 } UnmarkActiveMessage(message); physical.SetIdle(); return(result); } catch (Exception ex) { return(HandleWriteException(message, ex)); } finally { token.Dispose(); } }
private WriteResult WriteMessageInsideLock(PhysicalConnection physical, Message message) { WriteResult result; var existingMessage = Interlocked.CompareExchange(ref _activeMesssage, message, null); if (existingMessage != null) { Multiplexer?.OnInfoMessage($"reentrant call to WriteMessageTakingWriteLock for {message.CommandAndKey}, {existingMessage.CommandAndKey} is still active"); return(WriteResult.NoConnectionAvailable); } physical.SetWriting(); var messageIsSent = false; if (message is IMultiMessage) { SelectDatabaseInsideWriteLock(physical, message); // need to switch database *before* the transaction foreach (var subCommand in ((IMultiMessage)message).GetMessages(physical)) { result = WriteMessageToServerInsideWriteLock(physical, subCommand); if (result != WriteResult.Success) { // we screwed up; abort; note that WriteMessageToServer already // killed the underlying connection Trace("Unable to write to server"); message.Fail(ConnectionFailureType.ProtocolFailure, null, "failure before write: " + result.ToString()); message.Complete(); return(result); } //The parent message (next) may be returned from GetMessages //and should not be marked as sent again below messageIsSent = messageIsSent || subCommand == message; } if (!messageIsSent) { message.SetRequestSent(); // well, it was attempted, at least... } return(WriteResult.Success); } else { return(WriteMessageToServerInsideWriteLock(physical, message)); } }
private WriteResult QueueOrFailMessage(Message message) { if (message.IsInternalCall && message.Command != RedisCommand.QUIT) { // you can go in the queue, but we won't be starting // a worker, because the handshake has not completed lock (_backlog) { _backlog.Enqueue(message); } message.SetEnqueued(null); return(WriteResult.Success); // we'll take it... } else { // sorry, we're just not ready for you yet; message.Cancel(); Multiplexer?.OnMessageFaulted(message, null); message.Complete(); return(WriteResult.NoConnectionAvailable); } }
private WriteResult WriteMessageToServerInsideWriteLock(PhysicalConnection connection, Message message) { if (message == null) { return(WriteResult.Success); // for some definition of success } bool isQueued = false; try { var cmd = message.Command; LastCommand = cmd; bool isMasterOnly = message.IsMasterOnly(); if (isMasterOnly && ServerEndPoint.IsSlave && (ServerEndPoint.SlaveReadOnly || !ServerEndPoint.AllowSlaveWrites)) { throw ExceptionFactory.MasterOnly(Multiplexer.IncludeDetailInExceptions, message.Command, message, ServerEndPoint); } switch (cmd) { case RedisCommand.QUIT: connection.RecordQuit(); break; case RedisCommand.EXEC: Multiplexer.OnPreTransactionExec(message); // testing purposes, to force certain errors break; } SelectDatabaseInsideWriteLock(connection, message); if (!connection.TransactionActive) { var readmode = connection.GetReadModeCommand(isMasterOnly); if (readmode != null) { connection.EnqueueInsideWriteLock(readmode); readmode.WriteTo(connection); readmode.SetRequestSent(); IncrementOpCount(); } if (message.IsAsking) { var asking = ReusableAskingCommand; connection.EnqueueInsideWriteLock(asking); asking.WriteTo(connection); asking.SetRequestSent(); IncrementOpCount(); } } switch (cmd) { case RedisCommand.WATCH: case RedisCommand.MULTI: connection.TransactionActive = true; break; case RedisCommand.UNWATCH: case RedisCommand.EXEC: case RedisCommand.DISCARD: connection.TransactionActive = false; break; } connection.EnqueueInsideWriteLock(message); isQueued = true; message.WriteTo(connection); message.SetRequestSent(); IncrementOpCount(); // some commands smash our ability to trust the database; some commands // demand an immediate flush switch (cmd) { case RedisCommand.EVAL: case RedisCommand.EVALSHA: if (!ServerEndPoint.GetFeatures().ScriptingDatabaseSafe) { connection.SetUnknownDatabase(); } break; case RedisCommand.UNKNOWN: case RedisCommand.DISCARD: case RedisCommand.EXEC: connection.SetUnknownDatabase(); break; } return(WriteResult.Success); } catch (RedisCommandException ex) when(!isQueued) { Trace("Write failed: " + ex.Message); message.Fail(ConnectionFailureType.InternalFailure, ex, null); message.Complete(); // this failed without actually writing; we're OK with that... unless there's a transaction if (connection?.TransactionActive == true) { // we left it in a broken state; need to kill the connection connection.RecordConnectionFailed(ConnectionFailureType.ProtocolFailure, ex); return(WriteResult.WriteFailure); } return(WriteResult.Success); } catch (Exception ex) { Trace("Write failed: " + ex.Message); message.Fail(ConnectionFailureType.InternalFailure, ex, null); message.Complete(); // we're not sure *what* happened here; probably an IOException; kill the connection connection?.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex); return(WriteResult.WriteFailure); } }