Commit 795379da authored by Marc Gravell's avatar Marc Gravell

remove the concept of the unsent queue; the pipeline **is** that queue - no...

remove the concept of the unsent queue; the pipeline **is** that queue - no need to duplicate (and significantly simplifies); if you've successfully pushed a message to the bridge: *it is in the pipe*; also removes "ar", "wr", "wq", "qu" and "pending" counters
parent 60f90766
...@@ -18,18 +18,6 @@ public partial class ConnectionMultiplexer ...@@ -18,18 +18,6 @@ public partial class ConnectionMultiplexer
if (ownsSocketManager) socketManager?.Dispose(); if (ownsSocketManager) socketManager?.Dispose();
socketManager = null; socketManager = null;
} }
internal void RequestWrite(PhysicalBridge bridge, bool forced)
{
if (bridge == null) return;
var tmp = SocketManager;
if (tmp != null)
{
Trace("Requesting write: " + bridge.Name);
tmp.RequestWrite(bridge, forced);
}
}
partial void OnWriterCreated(); partial void OnWriterCreated();
} }
} }
...@@ -2007,10 +2007,6 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -2007,10 +2007,6 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
} }
else else
{ {
#if FEATURE_SOCKET_MODE_POLL
var mgrState = socketManager.State;
var lastError = socketManager.LastErrorTimeRelative();
#endif
var sb = new StringBuilder("Timeout performing ").Append(message.CommandAndKey); var sb = new StringBuilder("Timeout performing ").Append(message.CommandAndKey);
data = new List<Tuple<string, string>> { Tuple.Create("Message", message.CommandAndKey) }; data = new List<Tuple<string, string>> { Tuple.Create("Message", message.CommandAndKey) };
void add(string lk, string sk, string v) void add(string lk, string sk, string v)
...@@ -2019,20 +2015,12 @@ void add(string lk, string sk, string v) ...@@ -2019,20 +2015,12 @@ void add(string lk, string sk, string v)
sb.Append(", ").Append(sk).Append(": ").Append(v); sb.Append(", ").Append(sk).Append(": ").Append(v);
} }
int queue = server.GetOutstandingCount(message.Command, out int inst, out int qu, out int qs, out int qc, out int wr, out int wq, out int @in, out int ar); int queue = server.GetOutstandingCount(message.Command, out int inst, out int qs, out int qc, out int @in);
add("Instantaneous", "inst", inst.ToString()); add("Instantaneous", "inst", inst.ToString());
#if FEATURE_SOCKET_MODE_POLL
add("Manager-State", "mgr", mgrState.ToString());
add("Last-Error", "err", lastError);
#endif
add("Queue-Length", "queue", queue.ToString()); add("Queue-Length", "queue", queue.ToString());
add("Queue-Outstanding", "qu", qu.ToString());
add("Queue-Awaiting-Response", "qs", qs.ToString()); add("Queue-Awaiting-Response", "qs", qs.ToString());
add("Queue-Completion-Outstanding", "qc", qc.ToString()); add("Queue-Completion-Outstanding", "qc", qc.ToString());
add("Active-Writers", "wr", wr.ToString());
add("Write-Queue", "wq", wq.ToString());
add("Inbound-Bytes", "in", @in.ToString()); add("Inbound-Bytes", "in", @in.ToString());
add("Active-Readers", "ar", ar.ToString());
add("Client-Name", "clientName", ClientName); add("Client-Name", "clientName", ClientName);
add("Server-Endpoint", "serverEndpoint", server.EndPoint.ToString()); add("Server-Endpoint", "serverEndpoint", server.EndPoint.ToString());
......
...@@ -17,12 +17,6 @@ internal partial class ResultBox ...@@ -17,12 +17,6 @@ internal partial class ResultBox
public partial interface IServer public partial interface IServer
{ {
/// <summary>
/// Show what is in the pending (unsent) queue
/// </summary>
/// <param name="maxCount">The maximum count to list.</param>
string ListPending(int maxCount);
/// <summary> /// <summary>
/// Get the value of key. If the key does not exist the special value nil is returned. An error is returned if the value stored at key is not a string, because GET only handles string values. /// Get the value of key. If the key does not exist the special value nil is returned. An error is returned if the value stored at key is not a string, because GET only handles string values.
/// </summary> /// </summary>
...@@ -114,21 +108,11 @@ internal void SimulateConnectionFailure() ...@@ -114,21 +108,11 @@ internal void SimulateConnectionFailure()
interactive?.SimulateConnectionFailure(); interactive?.SimulateConnectionFailure();
subscription?.SimulateConnectionFailure(); subscription?.SimulateConnectionFailure();
} }
internal string ListPending(int maxCount)
{
var sb = new StringBuilder();
interactive?.ListPending(sb, maxCount);
subscription?.ListPending(sb, maxCount);
return sb.ToString();
}
} }
internal partial class RedisServer internal partial class RedisServer
{ {
void IServer.SimulateConnectionFailure() => server.SimulateConnectionFailure(); void IServer.SimulateConnectionFailure() => server.SimulateConnectionFailure();
string IServer.ListPending(int maxCount) => server.ListPending(maxCount);
void IServer.Crash() void IServer.Crash()
{ {
// using DB-0 because we also use "DEBUG OBJECT", which is db-centric // using DB-0 because we also use "DEBUG OBJECT", which is db-centric
...@@ -225,11 +209,6 @@ internal void SimulateConnectionFailure() ...@@ -225,11 +209,6 @@ internal void SimulateConnectionFailure()
} }
physical?.RecordConnectionFailed(ConnectionFailureType.SocketFailure); physical?.RecordConnectionFailed(ConnectionFailureType.SocketFailure);
} }
internal void ListPending(StringBuilder sb, int maxCount)
{
queue.ListPending(sb, maxCount);
}
} }
internal partial class PhysicalConnection internal partial class PhysicalConnection
......
...@@ -169,14 +169,14 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, ref Socket ...@@ -169,14 +169,14 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, ref Socket
// stop anything new coming in... // stop anything new coming in...
Bridge.Trace("Failed: " + failureType); Bridge.Trace("Failed: " + failureType);
int @in = -1, ar = -1; int @in = -1;
managerState = SocketManager.ManagerState.RecordConnectionFailed_OnDisconnected; managerState = SocketManager.ManagerState.RecordConnectionFailed_OnDisconnected;
Bridge.OnDisconnected(failureType, this, out bool isCurrent, out PhysicalBridge.State oldState); Bridge.OnDisconnected(failureType, this, out bool isCurrent, out PhysicalBridge.State oldState);
if (oldState == PhysicalBridge.State.ConnectedEstablished) if (oldState == PhysicalBridge.State.ConnectedEstablished)
{ {
try try
{ {
@in = GetAvailableInboundBytes(out ar); @in = GetAvailableInboundBytes();
} }
catch { /* best effort only */ } catch { /* best effort only */ }
} }
...@@ -211,23 +211,16 @@ void add(string lk, string sk, string v) ...@@ -211,23 +211,16 @@ void add(string lk, string sk, string v)
add("Last-Write", "last-write", (unchecked(now - lastWrite) / 1000) + "s ago"); add("Last-Write", "last-write", (unchecked(now - lastWrite) / 1000) + "s ago");
add("Unanswered-Write", "unanswered-write", (unchecked(now - unansweredRead) / 1000) + "s ago"); add("Unanswered-Write", "unanswered-write", (unchecked(now - unansweredRead) / 1000) + "s ago");
add("Keep-Alive", "keep-alive", Bridge.ServerEndPoint.WriteEverySeconds + "s"); add("Keep-Alive", "keep-alive", Bridge.ServerEndPoint.WriteEverySeconds + "s");
add("Pending", "pending", Bridge.GetPendingCount().ToString());
add("Previous-Physical-State", "state", oldState.ToString()); add("Previous-Physical-State", "state", oldState.ToString());
if (@in >= 0) if (@in >= 0)
{ {
add("Inbound-Bytes", "in", @in.ToString()); add("Inbound-Bytes", "in", @in.ToString());
add("Active-Readers", "ar", ar.ToString());
} }
add("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : ((unchecked(now - lastBeat) / 1000) + "s ago")) + (Bridge.IsBeating ? " (mid-beat)" : "")); add("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : ((unchecked(now - lastBeat) / 1000) + "s ago")) + (Bridge.IsBeating ? " (mid-beat)" : ""));
add("Last-Multiplexer-Heartbeat", "last-mbeat", Multiplexer.LastHeartbeatSecondsAgo + "s ago"); add("Last-Multiplexer-Heartbeat", "last-mbeat", Multiplexer.LastHeartbeatSecondsAgo + "s ago");
add("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago"); add("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago");
#if FEATURE_SOCKET_MODE_POLL
var mgr = Bridge.Multiplexer.SocketManager;
add("SocketManager-State", "mgr", mgr.State.ToString());
add("Last-Error", "err", mgr.LastErrorTimeRelative());
#endif
} }
var ex = innerException == null var ex = innerException == null
...@@ -592,6 +585,12 @@ private static int WriteRaw(Span<byte> span, long value, bool withLengthPrefix = ...@@ -592,6 +585,12 @@ private static int WriteRaw(Span<byte> span, long value, bool withLengthPrefix =
return WriteCrlf(span, offset); return WriteCrlf(span, offset);
} }
internal void WakeWriterAndCheckForThrottle()
{
var flush = _ioPipe.Output.FlushAsync();
if (!flush.IsCompletedSuccessfully) flush.AsTask().Wait();
}
static readonly byte[] NullBulkString = Encoding.ASCII.GetBytes("$-1\r\n"), EmptyBulkString = Encoding.ASCII.GetBytes("$0\r\n\r\n"); static readonly byte[] NullBulkString = Encoding.ASCII.GetBytes("$-1\r\n"), EmptyBulkString = Encoding.ASCII.GetBytes("$0\r\n\r\n");
private static void WriteUnified(PipeWriter writer, byte[] value) private static void WriteUnified(PipeWriter writer, byte[] value)
{ {
...@@ -802,14 +801,7 @@ private static void WriteUnified(PipeWriter writer, long value) ...@@ -802,14 +801,7 @@ private static void WriteUnified(PipeWriter writer, long value)
writer.Advance(bytes); writer.Advance(bytes);
} }
internal int GetAvailableInboundBytes() => socketToken.Available;
private int haveReader;
internal int GetAvailableInboundBytes(out int activeReaders)
{
activeReaders = Interlocked.CompareExchange(ref haveReader, 0, 0);
return socketToken.Available;
}
private static LocalCertificateSelectionCallback GetAmbientCertificateCallback() private static LocalCertificateSelectionCallback GetAmbientCertificateCallback()
{ {
......
...@@ -367,15 +367,15 @@ internal ServerCounters GetCounters() ...@@ -367,15 +367,15 @@ internal ServerCounters GetCounters()
return counters; return counters;
} }
internal int GetOutstandingCount(RedisCommand command, out int inst, out int qu, out int qs, out int qc, out int wr, out int wq, out int @in, out int ar) internal int GetOutstandingCount(RedisCommand command, out int inst, out int qs, out int qc, out int @in)
{ {
var bridge = GetBridge(command, false); var bridge = GetBridge(command, false);
if (bridge == null) if (bridge == null)
{ {
return inst = qu = qs = qc = wr = wq = @in = ar = 0; return inst = qs = qc = @in = 0;
} }
return bridge.GetOutstandingCount(out inst, out qu, out qs, out qc, out wr, out wq, out @in, out ar); return bridge.GetOutstandingCount(out inst, out qs, out qc, out @in);
} }
internal string GetProfile() internal string GetProfile()
......
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Net; using System.Net;
...@@ -13,9 +12,7 @@ namespace StackExchange.Redis ...@@ -13,9 +12,7 @@ namespace StackExchange.Redis
internal enum SocketMode internal enum SocketMode
{ {
Abort, Abort,
[Obsolete("just don't", error: true)] Async,
Poll,
Async
} }
/// <summary> /// <summary>
...@@ -109,10 +106,6 @@ internal enum ManagerState ...@@ -109,10 +106,6 @@ internal enum ManagerState
ProcessErrorQueue, ProcessErrorQueue,
} }
private readonly Queue<PhysicalBridge> writeQueue = new Queue<PhysicalBridge>();
private bool isDisposed;
private readonly bool useHighPrioritySocketThreads = true;
/// <summary> /// <summary>
/// Gets the name of this SocketManager instance /// Gets the name of this SocketManager instance
/// </summary> /// </summary>
...@@ -133,11 +126,6 @@ public SocketManager(string name, bool useHighPrioritySocketThreads) ...@@ -133,11 +126,6 @@ public SocketManager(string name, bool useHighPrioritySocketThreads)
{ {
if (string.IsNullOrWhiteSpace(name)) name = GetType().Name; if (string.IsNullOrWhiteSpace(name)) name = GetType().Name;
Name = name; Name = name;
this.useHighPrioritySocketThreads = useHighPrioritySocketThreads;
_writeOneQueueAsync = () => WriteOneQueueAsync();
Task.Run(() => WriteAllQueuesAsync());
const int Receive_PauseWriterThreshold = 1024 * 1024 * 1024; // let's give it up to 1GiB of buffer for now const int Receive_PauseWriterThreshold = 1024 * 1024 * 1024; // let's give it up to 1GiB of buffer for now
...@@ -159,9 +147,6 @@ public SocketManager(string name, bool useHighPrioritySocketThreads) ...@@ -159,9 +147,6 @@ public SocketManager(string name, bool useHighPrioritySocketThreads)
readonly DedicatedThreadPoolPipeScheduler _scheduler; readonly DedicatedThreadPoolPipeScheduler _scheduler;
internal readonly PipeOptions SendPipeOptions, ReceivePipeOptions; internal readonly PipeOptions SendPipeOptions, ReceivePipeOptions;
private readonly Func<Task> _writeOneQueueAsync;
private enum CallbackOperation private enum CallbackOperation
{ {
Read, Read,
...@@ -174,12 +159,6 @@ private enum CallbackOperation ...@@ -174,12 +159,6 @@ private enum CallbackOperation
public void Dispose() public void Dispose()
{ {
_scheduler?.Dispose(); _scheduler?.Dispose();
lock (writeQueue)
{
// make sure writer threads know to exit
isDisposed = true;
Monitor.PulseAll(writeQueue);
}
OnDispose(); OnDispose();
} }
internal SocketToken BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log) internal SocketToken BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log)
...@@ -247,27 +226,6 @@ void proxyCallback(IAsyncResult ar) ...@@ -247,27 +226,6 @@ void proxyCallback(IAsyncResult ar)
return token; return token;
} }
internal void RequestWrite(PhysicalBridge bridge, bool forced)
{
if (Interlocked.CompareExchange(ref bridge.inWriteQueue, 1, 0) == 0 || forced)
{
lock (writeQueue)
{
writeQueue.Enqueue(bridge);
if (writeQueue.Count == 1)
{
Monitor.PulseAll(writeQueue);
}
else if (writeQueue.Count >= 2)
{ // struggling are we? let's have some help dealing with the backlog
Task.Run(_writeOneQueueAsync);
}
}
}
}
internal void Shutdown(SocketToken token) internal void Shutdown(SocketToken token)
{ {
Shutdown(token.Socket); Shutdown(token.Socket);
...@@ -345,88 +303,5 @@ private void Shutdown(Socket socket) ...@@ -345,88 +303,5 @@ private void Shutdown(Socket socket)
try { socket.Dispose(); } catch { } try { socket.Dispose(); } catch { }
} }
} }
private async Task WriteAllQueuesAsync()
{
while (true)
{
PhysicalBridge bridge;
lock (writeQueue)
{
if (writeQueue.Count == 0)
{
if (isDisposed) break; // <========= exit point
Monitor.Wait(writeQueue);
if (isDisposed) break; // (woken by Dispose)
if (writeQueue.Count == 0) continue; // still nothing...
}
bridge = writeQueue.Dequeue();
}
switch (await bridge.WriteQueueAsync(200))
{
case WriteResult.MoreWork:
case WriteResult.QueueEmptyAfterWrite:
// back of the line!
lock (writeQueue)
{
writeQueue.Enqueue(bridge);
}
break;
case WriteResult.CompetingWriter:
break;
case WriteResult.NoConnection:
Interlocked.Exchange(ref bridge.inWriteQueue, 0);
break;
case WriteResult.NothingToDo:
if (!bridge.ConfirmRemoveFromWriteQueue())
{ // more snuck in; back of the line!
lock (writeQueue)
{
writeQueue.Enqueue(bridge);
}
}
break;
}
}
}
private Task WriteOneQueueAsync()
{
PhysicalBridge bridge;
lock (writeQueue)
{
bridge = writeQueue.Count == 0 ? null : writeQueue.Dequeue();
}
if (bridge == null) return Task.CompletedTask;
return WriteOneQueueAsyncImpl(bridge);
}
private async Task WriteOneQueueAsyncImpl(PhysicalBridge bridge)
{
bool keepGoing;
do
{
switch (await bridge.WriteQueueAsync(-1))
{
case WriteResult.MoreWork:
case WriteResult.QueueEmptyAfterWrite:
keepGoing = true;
break;
case WriteResult.NothingToDo:
keepGoing = !bridge.ConfirmRemoveFromWriteQueue();
break;
case WriteResult.CompetingWriter:
keepGoing = false;
break;
case WriteResult.NoConnection:
Interlocked.Exchange(ref bridge.inWriteQueue, 0);
keepGoing = false;
break;
default:
keepGoing = false;
break;
}
} while (keepGoing);
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment