internal override void ProcessCallbacks(object ctx, RedisResult result) { RedisResult[] subItems; if (!result.IsError && (subItems = result.ValueItems) != null) { switch (subItems.Length) { case 3: RedisResult msgType = subItems[0]; if (msgType.IsMatch(message)) { string key = subItems[1].ValueString; OnMessageReceived(key, key, subItems[2]); } else if (msgType.IsMatch(subscribe) || msgType.IsMatch(unsubscribe) || msgType.IsMatch(psubscribe) || msgType.IsMatch(punsubscribe)) { var newCount = (int)subItems[2].ValueInt64; Interlocked.Exchange(ref subscriptionCount, newCount); } break; case 4: if (subItems[0].IsMatch(pmessage)) { OnMessageReceived(subItems[1].ValueString, subItems[2].ValueString, subItems[3]); } break; } } }
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); } }
internal override void Complete(RedisResult result) { received = DateTime.UtcNow; base.Complete(result.IsError ? result : new RedisResult.TimingRedisResult( sent - created, received - sent)); }
protected virtual void ProcessError(RedisResult result, RedisMessage message, bool includeDetail) { var ex = result.Error(); if (message != null && includeDetail) { ex.Data.Add("redis-command", message.ToString()); } source.SafeSetException(ex); }
internal void CancelUnsent() { RedisMessage[] all = unsent.DequeueAll(); for (int i = 0; i < all.Length; i++) { RedisResult result = RedisResult.Cancelled; object ctx = ProcessReply(ref result, all[i]); ProcessCallbacks(ctx, result); } }
internal void CompleteMessage(RedisMessage message, RedisResult result) { try { message.Complete(result); } catch (Exception ex) { OnError("Completing message", ex, false); } }
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); } }
internal virtual void Complete(RedisResult result) { #if VERBOSE Trace.WriteLine("< " + command); #endif IMessageResult snapshot = Interlocked.Exchange(ref messageResult, null); // only run once ChangeState(MessageState.Sent, MessageState.Complete); if (snapshot != null) { snapshot.Complete(result); } }
private void SetInnerReplies(RedisResult result) { if (queued != null) { for (int i = 0; i < queued.Length; i++) { RedisResult reply = result; // need to be willing for this to be mutated object ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage); parent.ProcessCallbacks(ctx, reply); } } }
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; } } }
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 override void ProcessError(RedisResult result, RedisMessage message, bool includeDetail) { try { var msg = result.Error().Message; if (msg.StartsWith("NOSCRIPT")) { // only way of unloading is to unload all ("SCRIPT FLUSH")... so our // existing cache is now completely toast connection.ResetScriptCache(); } } catch { /* best efforts only */ } base.ProcessError(result, message, includeDetail); }
void IMessageResult.Complete(RedisResult result) { if (result.IsCancellation) { completion.SetCanceled(); SetInnerReplies(result); } else if (result.IsError) { completion.SetException(result.Error()); SetInnerReplies(result); } else { try { if (result.IsNil) { // aborted SetInnerReplies(RedisResult.Cancelled); completion.SetResult(false); } else { RedisResult[] 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)); } for (int i = 0; i < items.Length; i++) { RedisResult reply = items[i]; object ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage); parent.ProcessCallbacks(ctx, reply); } completion.SetResult(true); } } catch (Exception ex) { completion.SetException(ex); throw; } } }
private void Outgoing() { try { OnOpened(); int db = 0; RedisMessage next; Trace.WriteLine("Redis send-pump is starting"); bool isHigh, shouldFlush; while (unsent.TryDequeue(false, out next, out isHigh, out shouldFlush)) { if (abort) { CompleteMessage(next, RedisResult.Error("The system aborted before this message was sent")); continue; } if (!next.ChangeState(MessageState.NotSent, MessageState.Sent)) { // already cancelled; not our problem any more... Interlocked.Increment(ref messagesCancelled); continue; } if (isHigh) { Interlocked.Increment(ref queueJumpers); } WriteMessage(ref db, next, null); Flush(shouldFlush); } Interlocked.CompareExchange(ref state, (int)ConnectionState.Closing, (int)ConnectionState.Open); if (redisStream != null) { RedisMessage quit = RedisMessage.Create(-1, RedisLiteral.QUIT).ExpectOk().Critical(); RecordSent(quit, !abort); quit.Write(outBuffer); outBuffer.Flush(); redisStream.Flush(); Interlocked.Increment(ref messagesSent); } Trace.WriteLine("Redis send-pump is exiting"); } catch (Exception ex) { OnError("Outgoing queue", ex, true); } }
internal override object ProcessReply(ref RedisResult result, RedisMessage message) { byte[] expected; if (!result.IsError && (expected = message.Expected) != null) { result = result.IsMatch(expected) ? RedisResult.Pass : RedisResult.Error(result.ValueString); } if (result.IsError && message.MustSucceed) { throw new RedisException("A critical operation failed: " + message); } return(message); }
private void RaiseEvent(Action <string, byte[]> handler, string key, RedisResult value) { if (handler == null) { return; } foreach (Action <string, byte[]> child in handler.GetInvocationList()) { try { child(key, value.ValueBytes); } catch (Exception ex) { OnError("Subscriber callback", ex, false); } } }
internal override object ProcessReply(ref RedisResult result) { RedisMessage message; lock (sent) { int count = sent.Count; if (count == 0) { throw new RedisException("Data received with no matching message"); } message = sent.Dequeue(); if (count == 1) { Monitor.Pulse(sent); // in case the outbound stream is closing and needs to know we're up-to-date } } return(ProcessReply(ref result, message)); }
internal override void ProcessCallbacksImpl(object ctx, RedisResult result) { RedisResult[] subItems; bool callBase = true; if (!result.IsError && (subItems = result.ValueItems) != null) { switch (subItems.Length) { case 3: var msgType = subItems[0]; if (msgType.IsMatch(message)) { string key = subItems[1].ValueString; OnMessageReceived(key, key, subItems[2]); callBase = false; } else if (msgType.IsMatch(subscribe) || msgType.IsMatch(unsubscribe) || msgType.IsMatch(psubscribe) || msgType.IsMatch(punsubscribe)) { int newCount = (int)subItems[2].ValueInt64; Interlocked.Exchange(ref subscriptionCount, newCount); } break; case 4: if (subItems[0].IsMatch(pmessage)) { OnMessageReceived(subItems[1].ValueString, subItems[2].ValueString, subItems[3]); callBase = false; } break; } } if (ctx != null && callBase) // don't call down to the base for things that aren't related to outbound messages { base.ProcessCallbacksImpl(ctx, result); } }
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 override object ProcessReply(ref RedisResult result, out CallbackMode callbackMode) { RedisResult[] subItems; if (!result.IsError && (subItems = result.ValueItems) != null) { // detect "message" and "pmessage" and don't dequeue for those switch (subItems.Length) { case 3: // special-case message if (subItems[0].IsMatch(message)) { callbackMode = CallbackMode.Continuation; // events are a lot like continuations return(null); } break; case 4: // special-case pmessage if (subItems[0].IsMatch(pmessage)) { callbackMode = CallbackMode.Continuation; // events are a lot like continuations return(null); } break; } } var next = PeekSent(false) as IMultiReplyMessage; if (next == null || next.Consume()) { return(base.ProcessReply(ref result, out callbackMode)); } // if we get here, we are dealing with a multi-reply message that is not yet satisfied; do nothing callbackMode = CallbackMode.SyncUnchecked; // won't actually be doing anything return(null); }
/// <summary> /// Invoked when the server is terminating /// </summary> protected override void ShuttingDown(Exception error) { base.ShuttingDown(error); RedisMessage message; RedisResult result = null; lock (sent) { if (sent.Count > 0) { result = RedisResult.Error( error == null ? "The server terminated before a reply was received" : ("Error processing data: " + error.Message)); } while (sent.Count > 0) { // notify clients of things that just didn't happen message = sent.Dequeue(); CompleteMessage(message, result); } } }
protected override bool GetValue(RedisResult result) { result.Assert(); return(true); }
protected override Dictionary <string, string> GetValue(RedisResult result) { return(result.ExtractStringPairs()); }
internal override void Complete(RedisResult result, bool includeDetail) { throw new NotSupportedException(); }
private void RaiseEvent(Action<string, byte[]> handler, string key, RedisResult value) { if (handler == null) return; foreach (Action<string, byte[]> child in handler.GetInvocationList()) { try { child(key, value.ValueBytes); } catch (Exception ex) { OnError("Subscriber callback", ex, false); } } }
private void OnMessageReceived(string subscriptionKey, string messageKey, RedisResult value) { ProcessNamedSubscription(subscriptionKey, messageKey, value); RaiseEvent(MessageReceived, messageKey, value); }
protected override double GetValue(RedisResult result) { return(result.ValueDouble); }
void IMessageResult.Complete(RedisResult result) { if (result.IsCancellation) { completion.SetCanceled(); } else if (result.IsError) { completion.SetException(result.Error()); } else { try { if (queued == null) throw new InvalidOperationException("Nothing was queued (null)!"); var items = result.ValueItems; if (items.Length != queued.Length) throw new InvalidOperationException(string.Format("{0} results expected, {1} received", queued.Length, items.Length)); for (int i = 0; i < items.Length; i++) { RedisResult reply = items[i]; var ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage); parent.ProcessCallbacks(ctx, reply); } completion.SetResult(true); } catch (Exception ex) { completion.SetException(ex); throw; } } }
internal override void Complete(RedisResult result) { // do nothing - this is just the WATCH; we'll spoof the reply manually from the multi-message reply }
internal virtual void Complete(RedisResult result) { #if VERBOSE Trace.WriteLine("< " + command); #endif var snapshot = Interlocked.Exchange(ref messageResult, null); // only run once ChangeState(MessageState.Sent, MessageState.Complete); if (snapshot != null) { snapshot.Complete(result); } }
internal override void Complete(RedisResult result, bool includeDetail) { received = DateTime.UtcNow; base.Complete(result.IsError ? result : new RedisResult.TimingRedisResult( sent - created, received - sent), includeDetail); }
protected override bool GetValue(RedisResult result) { var items = result.ValueItems; return(items != null); }
protected override long?GetValue(RedisResult result) { return(result.IsNil ? (long?)null : (long?)result.ValueInt64); }
protected abstract T GetValue(RedisResult result);
internal override object ProcessReply(ref RedisResult result) { return ProcessReply(ref result, null); }
protected override long GetValue(RedisResult result) { return(result.ValueInt64); }
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; } } }
internal override void ProcessCallbacks(object ctx, RedisResult result) { RedisResult[] subItems; if (!result.IsError && (subItems = result.ValueItems) != null) { switch (subItems.Length) { case 3: RedisResult msgType = subItems[0]; if (msgType.IsMatch(message)) { string key = subItems[1].ValueString; OnMessageReceived(key, key, subItems[2]); } else if (msgType.IsMatch(subscribe) || msgType.IsMatch(unsubscribe) || msgType.IsMatch(psubscribe) || msgType.IsMatch(punsubscribe)) { var newCount = (int) subItems[2].ValueInt64; Interlocked.Exchange(ref subscriptionCount, newCount); } break; case 4: if (subItems[0].IsMatch(pmessage)) { OnMessageReceived(subItems[1].ValueString, subItems[2].ValueString, subItems[3]); } break; } } }
public MultiRedisResult(RedisResult[] items) { this.items = items; }
internal override object ProcessReply(ref RedisResult result, RedisMessage message) { return null; }
internal override object ProcessReply(ref RedisResult result) { RedisMessage message; lock (sent) { int count = sent.Count; if (count == 0) throw new RedisException("Data received with no matching message"); message = sent.Dequeue(); if (count == 1) Monitor.Pulse(sent); // in case the outbound stream is closing and needs to know we're up-to-date } return ProcessReply(ref result, message); }
private void ProcessNamedSubscription(string subscriptionKey, string messageKey, RedisResult value) { if (string.IsNullOrEmpty(subscriptionKey)) return; Action<string, byte[]> handler; lock (subscriptions) { if (!subscriptions.TryGetValue(subscriptionKey, out handler)) handler = null; } RaiseEvent(handler, messageKey, value); }
internal static RedisResult Multi(RedisResult[] inner) { return new MultiRedisResult(inner); }
protected override Dictionary <string, byte[]> GetValue(RedisResult result) { return(result.ExtractHashPairs()); }
internal override void ProcessCallbacks(object ctx, RedisResult result) { CompleteMessage((RedisMessage)ctx, result); }
protected override KeyValuePair <string, double>[] GetValue(RedisResult result) { return(result.ExtractStringDoublePairs()); }
internal override object ProcessReply(ref RedisResult result, RedisMessage message) { byte[] expected; if (!result.IsError && (expected = message.Expected) != null) { result = result.IsMatch(expected) ? RedisResult.Pass : RedisResult.Error(result.ValueString); } if (result.IsError && message.MustSucceed) { throw new RedisException("A critical operation failed: " + message.ToString()); } return message; }
void IMessageResult.Complete(RedisResult result) { if (result.IsCancellation) { completion.SetCanceled(); SetInnerReplies(result); } else if (result.IsError) { completion.SetException(result.Error()); SetInnerReplies(result); } else { try { if (result.IsNil) { // aborted SetInnerReplies(RedisResult.Cancelled); completion.SetResult(false); } else { RedisResult[] 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)); for (int i = 0; i < items.Length; i++) { RedisResult reply = items[i]; object ctx = parent.ProcessReply(ref reply, queued[i].InnerMessage); parent.ProcessCallbacks(ctx, reply); } completion.SetResult(true); } } catch (Exception ex) { completion.SetException(ex); throw; } } }