/// <summary> /// Begins profiling for the given context. /// /// If the same context object is returned by the registered IProfiler, the IProfiledCommands /// will be associated with each other. /// /// Call FinishProfiling with the same context to get the assocated commands. /// /// Note that forContext cannot be a WeakReference or a WeakReference<T> /// </summary> public void BeginProfiling(object forContext) { if (profiler == null) { throw new InvalidOperationException("Cannot begin profiling if no IProfiler has been registered with RegisterProfiler"); } if (forContext == null) { throw new ArgumentNullException(nameof(forContext)); } if (forContext is WeakReference) { throw new ArgumentException("Context object cannot be a WeakReference", nameof(forContext)); } if (!profiledCommands.TryCreate(forContext)) { throw ExceptionFactory.BeganProfilingWithDuplicateContext(forContext); } }
public ServerEndPoint Select(Message message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } int slot = NoSlot; switch (serverType) { case ServerType.Cluster: case ServerType.Twemproxy: // strictly speaking twemproxy uses a different hashing algo, but the hash-tag behavior is // the same, so this does a pretty good job of spotting illegal commands before sending them slot = message.GetHashSlot(this); if (slot == MultipleSlots) { throw ExceptionFactory.MultiSlot(multiplexer.IncludeDetailInExceptions, message); } break; } return(Select(slot, message.Command, message.Flags)); }
private RawResult ReadArray(byte[] buffer, ref int offset, ref int count) { var itemCount = ReadLineTerminatedString(ResultType.Integer, buffer, ref offset, ref count); if (itemCount.HasValue) { long i64; if (!itemCount.TryGetInt64(out i64)) { throw ExceptionFactory.ConnectionFailure(Multiplexer.IncludeDetailInExceptions, ConnectionFailureType.ProtocolFailure, "Invalid array length", Bridge.ServerEndPoint); } int itemCountActual = checked ((int)i64); if (itemCountActual < 0) { //for null response by command like EXEC, RESP array: *-1\r\n return(new RawResult(ResultType.SimpleString, null, 0, 0)); } else if (itemCountActual == 0) { //for zero array response by command like SCAN, Resp array: *0\r\n return(RawResult.EmptyArray); } var arr = new RawResult[itemCountActual]; for (int i = 0; i < itemCountActual; i++) { if (!(arr[i] = TryParseResult(buffer, ref offset, ref count)).HasValue) { return(RawResult.Nil); } } return(new RawResult(arr)); } return(RawResult.Nil); }
internal override Task <T> ExecuteAsync <T>(Message message, ResultProcessor <T> processor, ServerEndPoint server = null) { // inject our expected server automatically if (server == null) { server = this.server; } FixFlags(message, server); if (!server.IsConnected) { if (message == null) { return(CompletedTask <T> .Default(asyncState)); } if (message.IsFireAndForget) { return(CompletedTask <T> .Default(null)); // F+F explicitly does not get async-state } // no need to deny exec-sync here; will be complete before they see if var tcs = TaskSource.Create <T>(asyncState); ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapshot())); return(tcs.Task); } return(base.ExecuteAsync <T>(message, processor, server)); }
private bool WriteMessageToServer(PhysicalConnection connection, Message message) { if (message == null) { return(true); } try { var cmd = message.Command; bool isMasterOnly = message.IsMasterOnly(); if (isMasterOnly && ServerEndPoint.IsSlave && (ServerEndPoint.SlaveReadOnly || !ServerEndPoint.AllowSlaveWrites)) { throw ExceptionFactory.MasterOnly(Multiplexer.IncludeDetailInExceptions, message.Command, message, ServerEndPoint); } SelectDatabase(connection, message); if (!connection.TransactionActive) { var readmode = connection.GetReadModeCommand(isMasterOnly); if (readmode != null) { connection.Enqueue(readmode); readmode.WriteTo(connection); readmode.SetRequestSent(); IncrementOpCount(); } if (message.IsAsking) { var asking = ReusableAskingCommand; connection.Enqueue(asking); asking.WriteImpl(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.Enqueue(message); message.WriteImpl(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.DISCARD: case RedisCommand.EXEC: connection.SetUnknownDatabase(); break; } return(true); } catch (RedisCommandException ex) { Trace("Write failed: " + ex.Message); message.Fail(ConnectionFailureType.ProtocolFailure, ex); CompleteSyncOrAsync(message); // this failed without actually writing; we're OK with that... unless there's a transaction if (connection != null && connection.TransactionActive) { // we left it in a broken state; need to kill the connection connection.RecordConnectionFailed(ConnectionFailureType.ProtocolFailure, ex); return(false); } return(true); } catch (Exception ex) { Trace("Write failed: " + ex.Message); message.Fail(ConnectionFailureType.InternalFailure, ex); CompleteSyncOrAsync(message); // we're not sure *what* happened here; probably an IOException; kill the connection connection?.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex); return(false); } }
internal void OnHeartbeat(bool ifConnectedOnly) { bool runThisTime = false; try { runThisTime = !isDisposed && Interlocked.CompareExchange(ref beating, 1, 0) == 0; if (!runThisTime) { return; } uint index = (uint)Interlocked.Increment(ref profileLogIndex); long newSampleCount = Interlocked.Read(ref operationCount); Interlocked.Exchange(ref profileLog[index % ProfileLogSamples], newSampleCount); Interlocked.Exchange(ref profileLastLog, newSampleCount); Trace("OnHeartbeat: " + (State)state); switch (state) { case (int)State.Connecting: int connectTimeMilliseconds = unchecked (Environment.TickCount - VolatileWrapper.Read(ref connectStartTicks)); if (connectTimeMilliseconds >= Multiplexer.RawConfig.ConnectTimeout) { LastException = ExceptionFactory.UnableToConnect("ConnectTimeout"); Trace("Aborting connect"); // abort and reconnect var snapshot = physical; bool isCurrent; State oldState; OnDisconnected(ConnectionFailureType.UnableToConnect, snapshot, out isCurrent, out oldState); using (snapshot) { } // dispose etc TryConnect(null); } if (!ifConnectedOnly) { AbortUnsent(); } break; case (int)State.ConnectedEstablishing: case (int)State.ConnectedEstablished: var tmp = physical; if (tmp != null) { if (state == (int)State.ConnectedEstablished) { tmp.Bridge.ServerEndPoint.ClearUnselectable(UnselectableFlags.DidNotRespond); } tmp.OnHeartbeat(); int writeEverySeconds = ServerEndPoint.WriteEverySeconds, checkConfigSeconds = Multiplexer.RawConfig.ConfigCheckSeconds; if (state == (int)State.ConnectedEstablished && ConnectionType == ConnectionType.Interactive && checkConfigSeconds > 0 && ServerEndPoint.LastInfoReplicationCheckSecondsAgo >= checkConfigSeconds && ServerEndPoint.CheckInfoReplication()) { // that serves as a keep-alive, if it is accepted } else if (writeEverySeconds > 0 && tmp.LastWriteSecondsAgo >= writeEverySeconds) { Trace("OnHeartbeat - overdue"); if (state == (int)State.ConnectedEstablished) { KeepAlive(); } else { bool ignore; State oldState; OnDisconnected(ConnectionFailureType.SocketFailure, tmp, out ignore, out oldState); } } else if (!queue.Any() && tmp.GetSentAwaitingResponseCount() != 0) { // there's a chance this is a dead socket; sending data will shake that // up a bit, so if we have an empty unsent queue and a non-empty sent // queue, test the socket KeepAlive(); } } break; case (int)State.Disconnected: if (!ifConnectedOnly) { AbortUnsent(); Multiplexer.Trace("Resurrecting " + this.ToString()); GetConnection(null); } break; default: if (!ifConnectedOnly) { AbortUnsent(); } break; } } catch (Exception ex) { OnInternalError(ex); Trace("OnHeartbeat error: " + ex.Message); } finally { if (runThisTime) { Interlocked.Exchange(ref beating, 0); } } }