Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit d2e8052

Browse files
committed
Don't use QueueUserWorkItem to trigger write callbacks immediately
- In this case we are off the event loop, so we can invoke the callback directly. - Increase _maxBytesBufferedBeforeThrottling
1 parent 174e794 commit d2e8052

File tree

1 file changed

+37
-47
lines changed

1 file changed

+37
-47
lines changed

src/Microsoft.AspNet.Server.Kestrel/Http/SocketOutput.cs

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
1212
public class SocketOutput : ISocketOutput
1313
{
1414
private const int _maxPendingWrites = 3;
15-
private const int _maxBytesBufferedBeforeThrottling = 65536 / 8;
15+
private const int _maxBytesBufferedBeforeThrottling = 65536;
1616

1717
private readonly KestrelThread _thread;
1818
private readonly UvStreamHandle _socket;
1919

20-
// This locks all access to to all the below
20+
// This locks access to to all of the below fields
2121
private readonly object _lockObj = new object();
2222

2323
// The number of write operations that have been scheduled so far
@@ -45,17 +45,7 @@ public void Write(ArraySegment<byte> buffer, Action<Exception, object> callback,
4545

4646
KestrelTrace.Log.ConnectionWrite(0, buffer.Count);
4747

48-
var writeOp = new WriteOperation
49-
{
50-
Buffer = buffer
51-
};
52-
53-
var callbackContext = new CallbackContext
54-
{
55-
Callback = callback,
56-
State = state,
57-
BytesToWrite = buffer.Count
58-
};
48+
bool triggerCallbackNow = false;
5949

6050
lock (_lockObj)
6151
{
@@ -64,20 +54,22 @@ public void Write(ArraySegment<byte> buffer, Action<Exception, object> callback,
6454
_nextWriteContext = new WriteContext(this);
6555
}
6656

67-
_nextWriteContext.Operations.Enqueue(writeOp);
57+
_nextWriteContext.Buffers.Enqueue(buffer);
6858
_numBytesBuffered += buffer.Count;
6959

7060
// Complete the write task immediately if all previous write tasks have been completed,
7161
// the buffers haven't grown too large, and the last write to the socket succeeded.
72-
if (_lastWriteError == null &&
73-
_callbacksPending.Count == 0 &&
74-
_numBytesBuffered < _maxBytesBufferedBeforeThrottling)
62+
triggerCallbackNow = _lastWriteError == null &&
63+
_callbacksPending.Count == 0 &&
64+
_numBytesBuffered <= _maxBytesBufferedBeforeThrottling;
65+
if (!triggerCallbackNow)
7566
{
76-
TriggerCallback(callbackContext);
77-
}
78-
else
79-
{
80-
_callbacksPending.Enqueue(callbackContext);
67+
_callbacksPending.Enqueue(new CallbackContext
68+
{
69+
Callback = callback,
70+
State = state,
71+
BytesToWrite = buffer.Count
72+
});
8173
}
8274

8375
if (_writesPending < _maxPendingWrites)
@@ -86,6 +78,11 @@ public void Write(ArraySegment<byte> buffer, Action<Exception, object> callback,
8678
_writesPending++;
8779
}
8880
}
81+
82+
if (triggerCallbackNow)
83+
{
84+
callback(null, state);
85+
}
8986
}
9087

9188
private void ScheduleWrite()
@@ -118,19 +115,21 @@ private void WriteAllPending()
118115

119116
try
120117
{
121-
var buffers = new ArraySegment<byte>[writingContext.Operations.Count];
118+
var buffers = new ArraySegment<byte>[writingContext.Buffers.Count];
122119

123120
var i = 0;
124-
foreach (var writeOp in writingContext.Operations)
121+
foreach (var buffer in writingContext.Buffers)
125122
{
126-
buffers[i] = writeOp.Buffer;
127-
i++;
123+
buffers[i++] = buffer;
128124
}
129125

130-
writingContext.WriteReq.Write(_socket, new ArraySegment<ArraySegment<byte>>(buffers), (r, status, error, state) =>
126+
var writeReq = new UvWriteReq();
127+
writeReq.Init(_thread.Loop);
128+
129+
writeReq.Write(_socket, new ArraySegment<ArraySegment<byte>>(buffers), (r, status, error, state) =>
131130
{
132131
var writtenContext = (WriteContext)state;
133-
writtenContext.Self.OnWriteCompleted(writtenContext.Operations, r, status, error);
132+
writtenContext.Self.OnWriteCompleted(writtenContext.Buffers, r, status, error);
134133
}, writingContext);
135134
}
136135
catch
@@ -147,8 +146,10 @@ private void WriteAllPending()
147146
}
148147

149148
// This is called on the libuv event loop
150-
private void OnWriteCompleted(Queue<WriteOperation> completedWrites, UvWriteReq req, int status, Exception error)
149+
private void OnWriteCompleted(Queue<ArraySegment<byte>> writtenBuffers, UvWriteReq req, int status, Exception error)
151150
{
151+
KestrelTrace.Log.ConnectionWriteCallback(0, status);
152+
152153
lock (_lockObj)
153154
{
154155
_lastWriteError = error;
@@ -162,16 +163,16 @@ private void OnWriteCompleted(Queue<WriteOperation> completedWrites, UvWriteReq
162163
_writesPending--;
163164
}
164165

165-
foreach (var writeOp in completedWrites)
166+
foreach (var writeBuffer in writtenBuffers)
166167
{
167-
_numBytesBuffered -= writeOp.Buffer.Count;
168+
_numBytesBuffered -= writeBuffer.Count;
168169
}
169170

170171
var bytesLeftToBuffer = _maxBytesBufferedBeforeThrottling - _numBytesBuffered;
171-
while (_callbacksPending.Count > 0 && _callbacksPending.Peek().BytesToWrite < bytesLeftToBuffer)
172+
while (_callbacksPending.Count > 0 &&
173+
_callbacksPending.Peek().BytesToWrite <= bytesLeftToBuffer)
172174
{
173-
var context = _callbacksPending.Dequeue();
174-
TriggerCallback(context);
175+
TriggerCallback(_callbacksPending.Dequeue());
175176
}
176177
}
177178

@@ -196,27 +197,16 @@ private class CallbackContext
196197
public int BytesToWrite;
197198
}
198199

199-
private class WriteOperation
200-
{
201-
public ArraySegment<byte> Buffer;
202-
}
203-
204200
private class WriteContext
205201
{
206202
public WriteContext(SocketOutput self)
207203
{
208204
Self = self;
209-
210-
WriteReq = new UvWriteReq();
211-
WriteReq.Init(self._thread.Loop);
212-
213-
Operations = new Queue<WriteOperation>();
205+
Buffers = new Queue<ArraySegment<byte>>();
214206
}
215207

216208
public SocketOutput Self;
217-
218-
public UvWriteReq WriteReq;
219-
public Queue<WriteOperation> Operations;
209+
public Queue<ArraySegment<byte>> Buffers;
220210
}
221211
}
222212
}

0 commit comments

Comments
 (0)