void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb) { var pending = messages; if (ExecutePreconditions(conn, ref currentDb)) { conn.WriteRaw(this); // MULTI List <QueuedMessage> newlyQueued = new List <QueuedMessage>(pending.Length); // estimate same length for (int i = 0; i < pending.Length; i++) { conn.WriteMessage(ref currentDb, pending[i], newlyQueued); } newlyQueued.TrimExcess(); conn.WriteMessage(ref currentDb, Execute(newlyQueued), null); } else { // preconditions failed; ABORT conn.WriteMessage(ref currentDb, RedisMessage.Create(-1, RedisLiteral.UNWATCH).ExpectOk().Critical(), null); // even though these weren't written, we still need to mark them cancelled exec.Abort(pending); // spoof a rollback; same appearance to the caller exec.Complete(RedisResult.Multi(null), false); } }
private bool ExecutePreconditions(RedisConnectionBase conn, ref int currentDb) { if (conditions == null || conditions.Count == 0) { return(true); } Task lastTask = null; foreach (Condition cond in conditions) { lastTask = cond.Task; foreach (RedisMessage msg in cond.CreateMessages()) { conn.WriteMessage(ref currentDb, msg, null); } } conn.Flush(true); // make sure we send it all // now need to check all the preconditions passed if (lastTask != null) { conn.Wait(lastTask); } foreach (Condition cond in conditions) { if (!cond.Validate()) { return(false); } } return(true); }
public void Execute(RedisConnectionBase conn, ref int currentDb) { for (int i = 0; i < messages.Length; i++) { conn.WriteMessage(ref currentDb, messages[i], null); } }
internal virtual void Complete(RedisResult result, bool includeDetail) { RedisConnectionBase.Trace("completed", "~ {0}", command); var snapshot = Interlocked.Exchange(ref messageResult, null); // only run once ChangeState(MessageState.Sent, MessageState.Complete); if (snapshot != null) { snapshot.Complete(result, this, includeDetail); } }
void IMessageResult.Complete(RedisResult result, RedisMessage message, bool includeDetail) { if (result.IsCancellation) { RedisConnectionBase.Trace("transaction", "cancelled"); SetInnerReplies(result); completion.TrySetCanceled(); } else if (result.IsError) { RedisConnectionBase.Trace("transaction", "error"); SetInnerReplies(result); completion.SafeSetException(result.Error()); } else { try { if (result.IsNil) { // aborted RedisConnectionBase.Trace("transaction", "aborted"); SetInnerReplies(RedisResult.Cancelled); completion.TrySetResult(false); } else { var items = result.ValueItems; if (items.Length != (queued == null ? 0 : queued.Length)) { throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length)); } RedisConnectionBase.Trace("transaction", "success"); for (int i = 0; i < items.Length; i++) { RedisResult reply = items[i]; RedisConnectionBase.CallbackMode callbackMode; var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode); RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply); parent.ProcessCallbacks(ctx, reply, callbackMode); } completion.TrySetResult(true); } } catch (Exception ex) { completion.SafeSetException(ex); throw; } } }
public void Abort(RedisMessage[] messages) { if (messages != null) { for (int i = 0; i < messages.Length; i++) { var reply = RedisResult.Cancelled; RedisConnectionBase.CallbackMode callbackMode; var ctx = parent.ProcessReply(ref reply, messages[i], out callbackMode); RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply); parent.ProcessCallbacks(ctx, reply, callbackMode); } } }
void SetInnerReplies(RedisResult result) { if (queued != null) { for (int i = 0; i < queued.Length; i++) { var reply = result; // need to be willing for this to be mutated RedisConnectionBase.CallbackMode callbackMode; var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage, out callbackMode); RedisConnectionBase.Trace("transaction", "{0} = {1}", ctx, reply); parent.ProcessCallbacks(ctx, reply, callbackMode); } } }
protected void WriteCommand(Stream stream, int argCount) { try { RedisConnectionBase.Trace("send", "write @{1}: {0}", this, stream.Position); stream.WriteByte((byte)'*'); WriteRaw(stream, argCount + 1); WriteUnified(stream, command); } catch (Exception ex) { RedisConnectionBase.Trace("send", ex.Message); throw; } }
private bool ExecutePreconditions(RedisConnectionBase conn, ref int currentDb) { if (conditions == null || conditions.Count == 0) { return(true); } Task lastTask = null; foreach (var cond in conditions) { lastTask = cond.Task; foreach (var msg in cond.CreateMessages()) { msg.ForceSync(); conn.WriteMessage(ref currentDb, msg, null); } } conn.Flush(true); // make sure we send it all // now need to check all the preconditions passed if (lastTask != null) { // didn't get result fast enough; treat as abort if (!lastTask.Wait(conn.SyncTimeout)) { return(false); } } foreach (var cond in conditions) { if (!cond.Validate()) { return(false); } } return(true); }
void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb) { RedisMessage[] pending = messages; int estimateCount = pending.Length; if (ExecutePreconditions(conn, ref currentDb)) { conn.WriteRaw(this); // MULTI var newlyQueued = new List <QueuedMessage>(pending.Length); for (int i = 0; i < pending.Length; i++) { conn.WriteMessage(ref currentDb, pending[i], newlyQueued); } newlyQueued.TrimExcess(); conn.WriteMessage(ref currentDb, Execute(newlyQueued), null); } else { // preconditions failed; ABORT conn.WriteMessage(ref currentDb, Create(-1, RedisLiteral.UNWATCH).ExpectOk().Critical(), null); exec.Complete(RedisResult.Multi(null)); // spoof a rollback; same appearance to the caller } }
internal Counters(int messagesSent, int messagesReceived, int queueJumpers, int messagesCancelled, int timeouts, int unsentQueue, int errorMessages, int syncCallbacks, int asyncCallbacks, int syncCallbacksInProgress, int asyncCallbacksInProgress, int sentQueue, IDictionary<int, int> dbUsage, int lastSentMillisecondsAgo, int lastKeepAliveMillisecondsAgo, int keepAliveSeconds, RedisConnectionBase.ConnectionState state, int ping) { this.messagesSent = messagesSent; this.messagesReceived = messagesReceived; this.queueJumpers = queueJumpers; this.messagesCancelled = messagesCancelled; this.timeouts = timeouts; this.unsentQueue = unsentQueue; this.errorMessages = errorMessages; this.sentQueue = sentQueue; this.dbUsage = dbUsage; this.ping = ping; this.syncCallbacks = syncCallbacks; this.asyncCallbacks = asyncCallbacks; this.syncCallbacksInProgress = syncCallbacksInProgress; this.asyncCallbacksInProgress = asyncCallbacksInProgress; this.lastSentMillisecondsAgo = lastSentMillisecondsAgo; this.lastKeepAliveMillisecondsAgo = lastKeepAliveMillisecondsAgo; this.keepAliveSeconds = keepAliveSeconds; this.state = state; }
void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb) { RedisMessage[] pending = messages; int estimateCount = pending.Length; if (ExecutePreconditions(conn, ref currentDb)) { conn.WriteRaw(this); // MULTI var newlyQueued = new List<QueuedMessage>(pending.Length); for (int i = 0; i < pending.Length; i++) { conn.WriteMessage(ref currentDb, pending[i], newlyQueued); } newlyQueued.TrimExcess(); conn.WriteMessage(ref currentDb, Execute(newlyQueued), null); } else { // preconditions failed; ABORT conn.WriteMessage(ref currentDb, Create(-1, RedisLiteral.UNWATCH).ExpectOk().Critical(), null); exec.Complete(RedisResult.Multi(null)); // spoof a rollback; same appearance to the caller } }
private bool ExecutePreconditions(RedisConnectionBase conn, ref int currentDb) { if (conditions == null || conditions.Count == 0) return true; Task lastTask = null; foreach (var cond in conditions) { lastTask = cond.Task; foreach (var msg in cond.CreateMessages()) { msg.ForceSync(); conn.WriteMessage(ref currentDb, msg, null); } } conn.Flush(true); // make sure we send it all // now need to check all the preconditions passed if (lastTask != null) { // didn't get result fast enough; treat as abort if (!lastTask.Wait(conn.SyncTimeout)) return false; } foreach (var cond in conditions) { if (!cond.Validate()) return false; } return true; }
void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb) { var pending = messages; if (ExecutePreconditions(conn, ref currentDb)) { conn.WriteRaw(this); // MULTI List<QueuedMessage> newlyQueued = new List<QueuedMessage>(pending.Length); // estimate same length for (int i = 0; i < pending.Length; i++) { conn.WriteMessage(ref currentDb, pending[i], newlyQueued); } newlyQueued.TrimExcess(); conn.WriteMessage(ref currentDb, Execute(newlyQueued), null); } else { // preconditions failed; ABORT conn.WriteMessage(ref currentDb, RedisMessage.Create(-1, RedisLiteral.UNWATCH).ExpectOk().Critical(), null); // even though these weren't written, we still need to mark them cancelled exec.Abort(pending); // spoof a rollback; same appearance to the caller exec.Complete(RedisResult.Multi(null), false); } }
public void Execute(RedisConnectionBase conn, ref int currentDb) { for(int i = 0 ; i < messages.Length ; i++) { conn.WriteMessage(ref currentDb, messages[i], null); } }
void IMultiMessage.Execute(RedisConnectionBase conn, ref int currentDb) { var pending = messages; List<QueuedMessage> newlyQueued = new List<QueuedMessage>(pending.Length); for (int i = 0; i < pending.Length; i++) { conn.WriteMessage(ref currentDb, pending[i], newlyQueued); } newlyQueued.TrimExcess(); conn.WriteMessage(ref currentDb, Execute(newlyQueued), null); }
void IMultiMessage.Execute(RedisConnectionBase connection, ref int currentDb) { // note: composite command in a tight time-frame! most user-facing code won't look this bad; this is just ugly // because it is infrastructure code; tough! var existsResult = new MessageResultBoolean(); var existsMessage = RedisMessage.Create(Db, RedisLiteral.EXISTS, key); // watch the key; we want changes to cause abort existsMessage.SetMessageResult(existsResult); connection.WriteMessage(ref currentDb, existsMessage, null); connection.Flush(true); // make sure it goes to the server! if we wait for it, and it is stuck // in the buffer, we've deadlocked ourself // now, we need to issue the rest of the composite command immediately to avoid multiplex issues, // so we must wait on the EXISTS, and act accordingly bool exists = connection.Wait(existsResult.Task); if (exists) { // obviously locked; just unwatch and return false connection.WriteMessage(ref currentDb, RedisMessage.Create(Db, RedisLiteral.UNWATCH), null); base.Complete(RedisResult.Integer(0)); } else { // isn't obviously locked; try a multi/setnx/expire/exec; if someone else has touched the key, this will fail and // we'll return false; otherwise, we get a lock with an expiry set connection.WriteMessage(ref currentDb, RedisMessage.Create(-1, RedisLiteral.MULTI), null); var pending = new List<QueuedMessage>(); connection.WriteMessage(ref currentDb, RedisMessage.Create(Db, RedisLiteral.SETNX, key, value), pending); connection.WriteMessage(ref currentDb, RedisMessage.Create(Db, RedisLiteral.EXPIRE, key, timeout), pending); var execResult = new MessageLockResult(); var exec = RedisMessage.Create(-1, RedisLiteral.EXEC).Critical(); exec.SetMessageResult(execResult); execResult.Task.ContinueWith(task => { if (task.Status == TaskStatus.RanToCompletion) { base.Complete(RedisResult.Integer(task.Result ? 1 : 0)); } else { base.Complete(RedisResult.Error(GetErrorMessage(task.Exception))); } }); connection.WriteMessage(ref currentDb, exec, null); } }
private static void ConnectToNodes(TextWriter log, string tieBreakerKey, int syncTimeout, int keepAlive, bool allowAdmin, string clientName, string[] arr, List <RedisConnection> connections, out Task <string>[] infos, out Task <string>[] aux, AuxMode mode) { TraceWriteTime("Infos"); infos = new Task <string> [arr.Length]; aux = new Task <string> [arr.Length]; var opens = new Task[arr.Length]; for (int i = 0; i < arr.Length; i++) { var option = arr[i]; if (string.IsNullOrWhiteSpace(option)) { continue; } RedisConnection conn = null; try { var parts = option.Split(':'); if (parts.Length == 0) { continue; } string host = parts[0].Trim(); int port = 6379, tmp; if (parts.Length > 1 && int.TryParse(parts[1].Trim(), out tmp)) { port = tmp; } conn = new RedisConnection(host, port, syncTimeout: syncTimeout, allowAdmin: allowAdmin); conn.Name = clientName; log.WriteLine("Opening connection to {0}:{1}...", host, port); if (keepAlive >= 0) { conn.SetKeepAlive(keepAlive); } opens[i] = conn.Open(); var info = conn.GetInfoImpl(null, false, false); connections.Add(conn); infos[i] = info; switch (mode) { case AuxMode.TieBreakers: if (tieBreakerKey != null) { aux[i] = conn.Strings.GetString(0, tieBreakerKey); } break; case AuxMode.ClusterNodes: aux[i] = conn.Cluster.GetNodes(); break; } } catch (Exception ex) { if (conn == null) { log.WriteLine("Error parsing option \"{0}\": {1}", option, ex.Message); } else { log.WriteLine("Error connecting: {0}", ex.Message); } } } TraceWriteTime("Wait for infos"); RedisConnectionBase.Trace("select-create", "wait..."); var watch = new Stopwatch(); foreach (Task task in infos.Concat(aux).Concat(opens)) { if (task != null) { try { int remaining = unchecked ((int)(syncTimeout - watch.ElapsedMilliseconds)); if (remaining > 0) { task.Wait(remaining); } } catch { } } } watch.Stop(); RedisConnectionBase.Trace("select-create", "complete"); }
private static bool NeedsReset(RedisConnectionBase conn) { return conn == null || (conn.State != RedisConnectionBase.ConnectionState.Open && conn.State != RedisConnectionBase.ConnectionState.Opening); }
private bool ExecutePreconditions(RedisConnectionBase conn, ref int currentDb) { if (conditions == null || conditions.Count == 0) return true; Task lastTask = null; foreach (Condition cond in conditions) { lastTask = cond.Task; foreach (RedisMessage msg in cond.CreateMessages()) { conn.WriteMessage(ref currentDb, msg, null); } } conn.Flush(true); // make sure we send it all // now need to check all the preconditions passed if (lastTask != null) conn.Wait(lastTask); foreach (Condition cond in conditions) { if (!cond.Validate()) return false; } return true; }