private void EndConnect(IAsyncResult ar) { if (!ar.CompletedSynchronously) { ConnectionMultiplexer.TraceWithoutContext("EndConnect (async)"); EndConnectImpl(ar); } }
void IResultBox.ActivateContinuations() { lock (this) { // tell the waiting thread that we're done Monitor.PulseAll(this); } ConnectionMultiplexer.TraceWithoutContext("Pulsed", "Result"); }
bool IResultBox.TryComplete(bool isAsync) { lock (this) { // tell the waiting thread that we're done Monitor.PulseAll(this); } ConnectionMultiplexer.TraceWithoutContext("Pulsed", "Result"); return(true); }
/// <summary> /// Compare against a RedisValue for relative order /// </summary> public int CompareTo(RedisValue other) { try { long thisInt64, otherInt64; double thisDouble, otherDouble; CompareType thisType = this.ResolveType(out thisInt64, out thisDouble), otherType = other.ResolveType(out otherInt64, out otherDouble); if (thisType == CompareType.Null) { return(otherType == CompareType.Null ? 0 : -1); } if (otherType == CompareType.Null) { return(1); } if (thisType == CompareType.Int64) { if (otherType == CompareType.Int64) { return(thisInt64.CompareTo(otherInt64)); } if (otherType == CompareType.Double) { return(((double)thisInt64).CompareTo(otherDouble)); } } else if (thisType == CompareType.Double) { if (otherType == CompareType.Int64) { return(thisDouble.CompareTo((double)otherInt64)); } if (otherType == CompareType.Double) { return(thisDouble.CompareTo(otherDouble)); } } // otherwise, compare as strings #if !CORE_CLR return(StringComparer.InvariantCulture.Compare((string)this, (string)other)); #else var compareInfo = System.Globalization.CultureInfo.InvariantCulture.CompareInfo; return(compareInfo.Compare((string)this, (string)other, System.Globalization.CompareOptions.Ordinal)); #endif } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); } // if all else fails, consider equivalent return(0); }
private static void AnyOrderCompletionHandler(object state) { try { ConnectionMultiplexer.TraceWithoutContext("Completing async (any order): " + state); ((ICompletable)state).TryComplete(true); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext("Async completion error: " + ex.Message); } }
public bool TryComplete(bool isAsync) { if (resultBox != null) { return(resultBox.TryComplete(isAsync)); } else { ConnectionMultiplexer.TraceWithoutContext("No result-box to complete for " + Command, "Message"); return(true); } }
public override bool TryComplete(bool isAsync) { if (stateOrCompletionSource is TaskCompletionSource <T[]> tcs) { if (countNeeded != values.Count) { //true or false? return(true); } if (isAsync || (tcs.Task.CreationOptions & TaskCreationOptions.RunContinuationsAsynchronously) != 0) { // either on the async completion step, or the task is guarded // againsts thread-stealing; complete it directly // (note: RunContinuationsAsynchronously is only usable from NET46) UnwrapAndRecycle(this, true, out Dictionary <Message, T> values, out Exception ex); if (ex == null) { tcs.TrySetResult(values.Values.ToArray()); } else { if (ex is TaskCanceledException) { tcs.TrySetCanceled(); } else { tcs.TrySetException(ex); } // mark it as observed GC.KeepAlive(tcs.Task.Exception); GC.SuppressFinalize(tcs.Task); } return(true); } else { // could be thread-stealing continuations; push to async to preserve the reader thread return(false); } } else { lock (this) { // tell the waiting thread that we're done Monitor.PulseAll(this); } ConnectionMultiplexer.TraceWithoutContext("Pulsed", "Result"); return(true); } }
internal override bool TryValidate(RawResult result, out bool value) { bool parsed; if (ResultProcessor.DemandZeroOrOneProcessor.TryGet(result, out parsed)) { value = parsed == expectedResult; ConnectionMultiplexer.TraceWithoutContext("exists: " + parsed + "; expected: " + expectedResult + "; voting: " + value); return(true); } value = false; return(false); }
/// <summary> /// Compare against a RedisValue for relative order /// </summary> /// <param name="other">The other <see cref="RedisValue"/> to compare.</param> public int CompareTo(RedisValue other) { try { CompareType thisType = ResolveType(out long thisInt64, out double thisDouble), otherType = other.ResolveType(out long otherInt64, out double otherDouble); if (thisType == CompareType.Null) { return(otherType == CompareType.Null ? 0 : -1); } if (otherType == CompareType.Null) { return(1); } if (thisType == CompareType.Int64) { if (otherType == CompareType.Int64) { return(thisInt64.CompareTo(otherInt64)); } if (otherType == CompareType.Double) { return(((double)thisInt64).CompareTo(otherDouble)); } } else if (thisType == CompareType.Double) { if (otherType == CompareType.Int64) { return(thisDouble.CompareTo((double)otherInt64)); } if (otherType == CompareType.Double) { return(thisDouble.CompareTo(otherDouble)); } } // otherwise, compare as strings return(StringComparer.InvariantCulture.Compare((string)this, (string)other)); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); } // if all else fails, consider equivalent return(0); }
internal override bool TryValidate(RawResult result, out bool value) { switch (result.Type) { case ResultType.BulkString: case ResultType.SimpleString: case ResultType.Integer: var parsed = result.AsRedisValue(); value = parsed.IsInteger && (expectedLength.CompareTo((long)parsed) == compareToResult); ConnectionMultiplexer.TraceWithoutContext("actual: " + (string)parsed + "; expected: " + expectedLength + "; wanted: " + GetComparisonString() + "; voting: " + value); return(true); } value = false; return(false); }
internal override bool TryValidate(RawResult result, out bool value) { switch (result.Type) { case ResultType.BulkString: case ResultType.SimpleString: case ResultType.Integer: var parsed = result.AsRedisValue(); value = (parsed == expectedValue) == expectedEqual; ConnectionMultiplexer.TraceWithoutContext("actual: " + (string)parsed + "; expected: " + (string)expectedValue + "; wanted: " + (expectedEqual ? "==" : "!=") + "; voting: " + value); return(true); } value = false; return(false); }
public bool TryComplete(bool isAsync) { if (handler == null) { return(true); } if (isAsync) { ConnectionMultiplexer.TraceWithoutContext("Invoking...: " + (string)channel, "Subscription"); foreach (Action <RedisChannel, RedisValue> sub in handler.GetInvocationList()) { try { sub.Invoke(channel, message); } catch { } } ConnectionMultiplexer.TraceWithoutContext("Invoke complete", "Subscription"); return(true); } // needs to be called async (unless there is nothing to do!) return(false); }
public bool TryComplete(bool isAsync) { if (resultBox != null) { var ret = resultBox.TryComplete(isAsync); if (performance != null) { performance.SetCompleted(); } return(ret); } else { ConnectionMultiplexer.TraceWithoutContext("No result-box to complete for " + Command, "Message"); if (performance != null) { performance.SetCompleted(); } return(true); } }
public bool TryComplete(bool isAsync) { if (resultBox != null) { var ret = resultBox.TryComplete(isAsync); if (ret && isAsync) { resultBox = null; // in async mode TryComplete will have unwrapped and recycled resultBox; ensure we no longer reference it via this message } performance?.SetCompleted(); return(ret); } else { ConnectionMultiplexer.TraceWithoutContext("No result-box to complete for " + Command, "Message"); performance?.SetCompleted(); return(true); } }
internal override bool TryValidate(RawResult result, out bool value) { switch (type) { case RedisType.SortedSet: var parsedValue = result.AsRedisValue(); value = (parsedValue.IsNull != expectedResult); ConnectionMultiplexer.TraceWithoutContext("exists: " + parsedValue + "; expected: " + expectedResult + "; voting: " + value); return(true); default: bool parsed; if (ResultProcessor.DemandZeroOrOneProcessor.TryGet(result, out parsed)) { value = parsed == expectedResult; ConnectionMultiplexer.TraceWithoutContext("exists: " + parsed + "; expected: " + expectedResult + "; voting: " + value); return(true); } value = false; return(false); } }
private void EndConnectImpl(IAsyncResult ar, ConnectionMultiplexer multiplexer, TextWriter log, Tuple <Socket, ISocketCallback> tuple) { try { bool ignoreConnect = false; ShouldIgnoreConnect(tuple.Item2, ref ignoreConnect); if (ignoreConnect) { return; } var socket = tuple.Item1; var callback = tuple.Item2; #if CORE_CLR multiplexer.Wait((Task)ar); // make it explode if invalid (note: already complete at this point) #else socket.EndConnect(ar); #endif var netStream = new NetworkStream(socket, false); var socketMode = callback?.Connected(netStream, log) ?? SocketMode.Abort; switch (socketMode) { case SocketMode.Poll: multiplexer.LogLocked(log, "Starting poll"); OnAddRead(socket, callback); break; case SocketMode.Async: multiplexer.LogLocked(log, "Starting read"); try { callback.StartReading(); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); Shutdown(socket); } break; default: ConnectionMultiplexer.TraceWithoutContext("Aborting socket"); Shutdown(socket); break; } } catch (ObjectDisposedException) { multiplexer.LogLocked(log, "(socket shutdown)"); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } catch (Exception outer) { ConnectionMultiplexer.TraceWithoutContext(outer.Message); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } }
private void UnexpectedResponse(Message message, RawResult result) { ConnectionMultiplexer.TraceWithoutContext("From " + GetType().Name, "Unexpected Response"); ConnectionFail(message, ConnectionFailureType.ProtocolFailure, "Unexpected response to " + (message == null ? "n/a" : message.Command.ToString()) + ": " + result.ToString()); }
private void EndConnectImpl(IAsyncResult ar, ConnectionMultiplexer multiplexer, TextWriter log) { Tuple <Socket, ISocketCallback> tuple = null; try { tuple = (Tuple <Socket, ISocketCallback>)ar.AsyncState; bool ignoreConnect = false; ShouldIgnoreConnect(tuple.Item2, ref ignoreConnect); if (ignoreConnect) { return; } var socket = tuple.Item1; var callback = tuple.Item2; socket.EndConnect(ar); var netStream = new NetworkStream(socket, false); var socketMode = callback == null ? SocketMode.Abort : callback.Connected(netStream, log); switch (socketMode) { case SocketMode.Poll: multiplexer.LogLocked(log, "Starting poll"); OnAddRead(socket, callback); break; case SocketMode.Async: multiplexer.LogLocked(log, "Starting read"); try { callback.StartReading(); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); Shutdown(socket); } break; default: ConnectionMultiplexer.TraceWithoutContext("Aborting socket"); Shutdown(socket); break; } } catch (ObjectDisposedException) { multiplexer.LogLocked(log, "(socket shutdown)"); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } catch (Exception outer) { ConnectionMultiplexer.TraceWithoutContext(outer.Message); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } }
private void ReadImpl() { List <IntPtr> dead = null, active = new List <IntPtr>(); List <ISocketCallback> activeCallbacks = new List <ISocketCallback>(); IntPtr[] readSockets = EmptyPointers, errorSockets = EmptyPointers; long lastHeartbeat = Environment.TickCount; SocketPair[] allSocketPairs = null; while (true) { managerState = ManagerState.CheckForHeartbeat; active.Clear(); activeCallbacks.Clear(); if (dead != null) { dead.Clear(); } // this check is actually a pace-maker; sometimes the Timer callback stalls for // extended periods of time, which can cause socket disconnect long now = Environment.TickCount; if (unchecked (now - lastHeartbeat) >= 15000) { managerState = ManagerState.ExecuteHeartbeat; lastHeartbeat = now; lock (socketLookup) { if (allSocketPairs == null || allSocketPairs.Length != socketLookup.Count) { allSocketPairs = new SocketPair[socketLookup.Count]; } socketLookup.Values.CopyTo(allSocketPairs, 0); } foreach (var pair in allSocketPairs) { var callback = pair.Callback; if (callback != null) { try { callback.OnHeartbeat(); } catch { } } } } managerState = ManagerState.LocateActiveSockets; lock (socketLookup) { if (isDisposed) { return; } if (socketLookup.Count == 0) { // if empty, give it a few seconds chance before exiting managerState = ManagerState.NoSocketsPause; Monitor.Wait(socketLookup, TimeSpan.FromSeconds(20)); if (socketLookup.Count == 0) { return; // nothing new came in, so exit } } managerState = ManagerState.PrepareActiveSockets; foreach (var pair in socketLookup) { var socket = pair.Value.Socket; if (socket.Handle == pair.Key && socket.Connected) { if (pair.Value.Socket.Connected) { active.Add(pair.Key); activeCallbacks.Add(pair.Value.Callback); } else { (dead ?? (dead = new List <IntPtr>())).Add(pair.Key); } } } if (dead != null && dead.Count != 0) { managerState = ManagerState.CullDeadSockets; foreach (var socket in dead) { socketLookup.Remove(socket); } } } int pollingSockets = active.Count; if (pollingSockets == 0) { // nobody had actual sockets; just sleep managerState = ManagerState.NoActiveSocketsPause; Thread.Sleep(10); continue; } if (readSockets.Length < active.Count + 1) { managerState = ManagerState.GrowingSocketArray; ConnectionMultiplexer.TraceWithoutContext("Resizing socket array for " + active.Count + " sockets"); readSockets = new IntPtr[active.Count + 6]; // leave so space for growth errorSockets = new IntPtr[active.Count + 6]; } managerState = ManagerState.CopyingPointersForSelect; readSockets[0] = errorSockets[0] = (IntPtr)active.Count; active.CopyTo(readSockets, 1); active.CopyTo(errorSockets, 1); int ready; try { var timeout = new TimeValue(1000); managerState = ManagerState.ExecuteSelect; ready = select(0, readSockets, null, errorSockets, ref timeout); managerState = ManagerState.ExecuteSelectComplete; if (ready <= 0) // -ve typically means a socket was disposed just before; just retry { bool hasWorkToDo = false; if (ready == 0) { managerState = ManagerState.CheckForStaleConnections; foreach (var s in activeCallbacks) { if (s.IsDataAvailable) { hasWorkToDo = true; } else { #pragma warning disable 0420 s.CheckForStaleConnection(ref managerState); #pragma warning restore 0420 } } managerState = ManagerState.CheckForStaleConnectionsDone; } else { lastErrorTicks = Environment.TickCount; } if (!hasWorkToDo) { continue; } } ConnectionMultiplexer.TraceWithoutContext((int)readSockets[0] != 0, "Read sockets: " + (int)readSockets[0]); ConnectionMultiplexer.TraceWithoutContext((int)errorSockets[0] != 0, "Error sockets: " + (int)errorSockets[0]); } catch (Exception ex) { // this typically means a socket was disposed just before; just retry Trace.WriteLine(ex.Message); continue; } bool haveWork = false; int queueCount = (int)readSockets[0]; if (queueCount != 0) { managerState = ManagerState.EnqueueRead; lock (readQueue) { for (int i = 1; i <= queueCount; i++) { var callback = GetCallback(readSockets[i]); if (callback != null) { readQueue.Enqueue(callback); haveWork = true; } } } } queueCount = (int)errorSockets[0]; if (queueCount != 0) { managerState = ManagerState.EnqueueError; lock (errorQueue) { for (int i = 1; i <= queueCount; i++) { var callback = GetCallback(errorSockets[i]); if (callback != null) { errorQueue.Enqueue(callback); haveWork = true; } } } } if (!haveWork) { // edge case: select is returning 0, but data could still be available managerState = ManagerState.EnqueueReadFallback; lock (readQueue) { foreach (var callback in activeCallbacks) { if (callback.IsDataAvailable) { readQueue.Enqueue(callback); } } } } if (ready >= 5) // number of sockets we should attempt to process by ourself before asking for help { // seek help, work in parallel, then synchronize var obj = new QueueDrainSyncLock(this); lock (obj) { managerState = ManagerState.RequestAssistance; ThreadPool.QueueUserWorkItem(HelpProcessItems, obj); managerState = ManagerState.ProcessQueues; ProcessItems(true); if (!obj.Consume()) { // then our worker arrived and picked up work; we need // to let it finish; note that if it *didn't* get that far // yet, the Consume() call will mean that it never tries Monitor.Wait(obj); } } } else { // just do it ourself managerState = ManagerState.ProcessQueues; ProcessItems(true); } } }
private void ReadImpl() { List <IntPtr> dead = null, active = new List <IntPtr>(); IntPtr[] readSockets = EmptyPointers, errorSockets = EmptyPointers; long lastHeartbeat = Environment.TickCount; SocketPair[] allSocketPairs = null; while (true) { active.Clear(); if (dead != null) { dead.Clear(); } // this check is actually a pace-maker; sometimes the Timer callback stalls for // extended periods of time, which can cause socket disconnect long now = Environment.TickCount; if (unchecked (now - lastHeartbeat) >= 15000) { lastHeartbeat = now; lock (socketLookup) { if (allSocketPairs == null || allSocketPairs.Length != socketLookup.Count) { allSocketPairs = new SocketPair[socketLookup.Count]; } socketLookup.Values.CopyTo(allSocketPairs, 0); } foreach (var pair in allSocketPairs) { var callback = pair.Callback; if (callback != null) { try { callback.OnHeartbeat(); } catch { } } } } lock (socketLookup) { if (isDisposed) { return; } if (socketLookup.Count == 0) { // if empty, give it a few seconds chance before exiting Monitor.Wait(socketLookup, TimeSpan.FromSeconds(20)); if (socketLookup.Count == 0) { return; // nothing new came in, so exit } } foreach (var pair in socketLookup) { var socket = pair.Value.Socket; if (socket.Handle == pair.Key && socket.Connected) { if (pair.Value.Socket.Connected) { active.Add(pair.Key); } else { (dead ?? (dead = new List <IntPtr>())).Add(pair.Key); } } } if (dead != null && dead.Count != 0) { foreach (var socket in dead) { socketLookup.Remove(socket); } } } int pollingSockets = active.Count; if (pollingSockets == 0) { // nobody had actual sockets; just sleep Thread.Sleep(10); continue; } if (readSockets.Length < active.Count + 1) { ConnectionMultiplexer.TraceWithoutContext("Resizing socket array for " + active.Count + " sockets"); readSockets = new IntPtr[active.Count + 6]; // leave so space for growth errorSockets = new IntPtr[active.Count + 6]; } readSockets[0] = errorSockets[0] = (IntPtr)active.Count; active.CopyTo(readSockets, 1); active.CopyTo(errorSockets, 1); int ready; try { var timeout = new TimeValue(1000); ready = select(0, readSockets, null, errorSockets, ref timeout); if (ready <= 0) { continue; // -ve typically means a socket was disposed just before; just retry } ConnectionMultiplexer.TraceWithoutContext((int)readSockets[0] != 0, "Read sockets: " + (int)readSockets[0]); ConnectionMultiplexer.TraceWithoutContext((int)errorSockets[0] != 0, "Error sockets: " + (int)errorSockets[0]); } catch (Exception ex) { // this typically means a socket was disposed just before; just retry Trace.WriteLine(ex.Message); continue; } int queueCount = (int)readSockets[0]; lock (readQueue) { for (int i = 1; i <= queueCount; i++) { readQueue.Enqueue(readSockets[i]); } } queueCount = (int)errorSockets[0]; lock (errorQueue) { for (int i = 1; i <= queueCount; i++) { errorQueue.Enqueue(errorSockets[i]); } } if (ready >= 5) // number of sockets we should attempt to process by ourself before asking for help { // seek help, work in parallel, then synchronize var obj = new QueueDrainSyncLock(this); lock (obj) { ThreadPool.QueueUserWorkItem(HelpProcessItems, obj); ProcessItems(); if (!obj.Consume()) { // then our worker arrived and picked up work; we need // to let it finish; note that if it *didn't* get that far // yet, the Consume() call will mean that it never tries Monitor.Wait(obj); } } } else { // just do it ourself ProcessItems(); } } }