Remove count parameter from ISocketOutput.ProducingComplete

- This makes the calling code cleaner with a (hopefully) minimal pref impact
This commit is contained in:
Stephen Halter 2015-12-01 11:47:39 -08:00
parent dff3a4f231
commit d0dca75241
9 changed files with 144 additions and 151 deletions

View File

@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Filter
return new MemoryPoolIterator2(_producingBlock);
}
public void ProducingComplete(MemoryPoolIterator2 end, int count)
public void ProducingComplete(MemoryPoolIterator2 end)
{
var block = _producingBlock;
while (block != end.Block)

View File

@ -674,12 +674,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
}
count += end.CopyFrom(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0);
count += end.CopyFrom(statusBytes);
count += _responseHeaders.CopyTo(ref end);
count += end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length);
end.CopyFrom(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0);
end.CopyFrom(statusBytes);
_responseHeaders.CopyTo(ref end);
end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length);
SocketOutput.ProducingComplete(end, count);
SocketOutput.ProducingComplete(end);
if (immediate)
{

View File

@ -7821,16 +7821,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
((ICollection<KeyValuePair<string, StringValues>>)MaybeUnknown)?.CopyTo(array, arrayIndex);
}
protected int CopyToFast(ref MemoryPoolIterator2 output)
protected void CopyToFast(ref MemoryPoolIterator2 output)
{
var count = 0;
if (((_bits & 1L) != 0))
{
foreach(var value in _CacheControl)
{
count += output.CopyFrom(_headerBytes, 0, 17);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 0, 17);
output.CopyFromAscii(value);
}
}
@ -7838,12 +7837,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
if (_rawConnection != null)
{
count += output.CopyFrom(_rawConnection, 0, _rawConnection.Length);
output.CopyFrom(_rawConnection, 0, _rawConnection.Length);
} else
foreach(var value in _Connection)
{
count += output.CopyFrom(_headerBytes, 17, 14);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 17, 14);
output.CopyFromAscii(value);
}
}
@ -7851,12 +7850,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
if (_rawDate != null)
{
count += output.CopyFrom(_rawDate, 0, _rawDate.Length);
output.CopyFrom(_rawDate, 0, _rawDate.Length);
} else
foreach(var value in _Date)
{
count += output.CopyFrom(_headerBytes, 31, 8);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 31, 8);
output.CopyFromAscii(value);
}
}
@ -7864,8 +7863,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _KeepAlive)
{
count += output.CopyFrom(_headerBytes, 39, 14);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 39, 14);
output.CopyFromAscii(value);
}
}
@ -7873,8 +7872,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Pragma)
{
count += output.CopyFrom(_headerBytes, 53, 10);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 53, 10);
output.CopyFromAscii(value);
}
}
@ -7882,8 +7881,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Trailer)
{
count += output.CopyFrom(_headerBytes, 63, 11);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 63, 11);
output.CopyFromAscii(value);
}
}
@ -7891,12 +7890,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
if (_rawTransferEncoding != null)
{
count += output.CopyFrom(_rawTransferEncoding, 0, _rawTransferEncoding.Length);
output.CopyFrom(_rawTransferEncoding, 0, _rawTransferEncoding.Length);
} else
foreach(var value in _TransferEncoding)
{
count += output.CopyFrom(_headerBytes, 74, 21);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 74, 21);
output.CopyFromAscii(value);
}
}
@ -7904,8 +7903,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Upgrade)
{
count += output.CopyFrom(_headerBytes, 95, 11);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 95, 11);
output.CopyFromAscii(value);
}
}
@ -7913,8 +7912,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Via)
{
count += output.CopyFrom(_headerBytes, 106, 7);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 106, 7);
output.CopyFromAscii(value);
}
}
@ -7922,8 +7921,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Warning)
{
count += output.CopyFrom(_headerBytes, 113, 11);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 113, 11);
output.CopyFromAscii(value);
}
}
@ -7931,8 +7930,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Allow)
{
count += output.CopyFrom(_headerBytes, 124, 9);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 124, 9);
output.CopyFromAscii(value);
}
}
@ -7940,12 +7939,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
if (_rawContentLength != null)
{
count += output.CopyFrom(_rawContentLength, 0, _rawContentLength.Length);
output.CopyFrom(_rawContentLength, 0, _rawContentLength.Length);
} else
foreach(var value in _ContentLength)
{
count += output.CopyFrom(_headerBytes, 133, 18);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 133, 18);
output.CopyFromAscii(value);
}
}
@ -7953,8 +7952,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ContentType)
{
count += output.CopyFrom(_headerBytes, 151, 16);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 151, 16);
output.CopyFromAscii(value);
}
}
@ -7962,8 +7961,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ContentEncoding)
{
count += output.CopyFrom(_headerBytes, 167, 20);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 167, 20);
output.CopyFromAscii(value);
}
}
@ -7971,8 +7970,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ContentLanguage)
{
count += output.CopyFrom(_headerBytes, 187, 20);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 187, 20);
output.CopyFromAscii(value);
}
}
@ -7980,8 +7979,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ContentLocation)
{
count += output.CopyFrom(_headerBytes, 207, 20);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 207, 20);
output.CopyFromAscii(value);
}
}
@ -7989,8 +7988,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ContentMD5)
{
count += output.CopyFrom(_headerBytes, 227, 15);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 227, 15);
output.CopyFromAscii(value);
}
}
@ -7998,8 +7997,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ContentRange)
{
count += output.CopyFrom(_headerBytes, 242, 17);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 242, 17);
output.CopyFromAscii(value);
}
}
@ -8007,8 +8006,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Expires)
{
count += output.CopyFrom(_headerBytes, 259, 11);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 259, 11);
output.CopyFromAscii(value);
}
}
@ -8016,8 +8015,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _LastModified)
{
count += output.CopyFrom(_headerBytes, 270, 17);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 270, 17);
output.CopyFromAscii(value);
}
}
@ -8025,8 +8024,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _AcceptRanges)
{
count += output.CopyFrom(_headerBytes, 287, 17);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 287, 17);
output.CopyFromAscii(value);
}
}
@ -8034,8 +8033,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Age)
{
count += output.CopyFrom(_headerBytes, 304, 7);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 304, 7);
output.CopyFromAscii(value);
}
}
@ -8043,8 +8042,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ETag)
{
count += output.CopyFrom(_headerBytes, 311, 8);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 311, 8);
output.CopyFromAscii(value);
}
}
@ -8052,8 +8051,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Location)
{
count += output.CopyFrom(_headerBytes, 319, 12);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 319, 12);
output.CopyFromAscii(value);
}
}
@ -8061,8 +8060,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _ProxyAutheticate)
{
count += output.CopyFrom(_headerBytes, 331, 21);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 331, 21);
output.CopyFromAscii(value);
}
}
@ -8070,8 +8069,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _RetryAfter)
{
count += output.CopyFrom(_headerBytes, 352, 15);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 352, 15);
output.CopyFromAscii(value);
}
}
@ -8079,12 +8078,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
if (_rawServer != null)
{
count += output.CopyFrom(_rawServer, 0, _rawServer.Length);
output.CopyFrom(_rawServer, 0, _rawServer.Length);
} else
foreach(var value in _Server)
{
count += output.CopyFrom(_headerBytes, 367, 10);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 367, 10);
output.CopyFromAscii(value);
}
}
@ -8092,8 +8091,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _SetCookie)
{
count += output.CopyFrom(_headerBytes, 377, 14);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 377, 14);
output.CopyFromAscii(value);
}
}
@ -8101,8 +8100,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _Vary)
{
count += output.CopyFrom(_headerBytes, 391, 8);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 391, 8);
output.CopyFromAscii(value);
}
}
@ -8110,12 +8109,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
foreach(var value in _WWWAuthenticate)
{
count += output.CopyFrom(_headerBytes, 399, 20);
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, 399, 20);
output.CopyFromAscii(value);
}
}
return count;
}
public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value)
{

View File

@ -30,23 +30,22 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return GetEnumerator();
}
public int CopyTo(ref MemoryPoolIterator2 output)
public void CopyTo(ref MemoryPoolIterator2 output)
{
var count = CopyToFast(ref output);
CopyToFast(ref output);
if (MaybeUnknown != null)
{
foreach (var kv in MaybeUnknown)
{
foreach (var value in kv.Value)
{
count += output.CopyFrom(_CrLf, 0, 2);
count += output.CopyFromAscii(kv.Key);
count += output.CopyFrom(_colonSpace, 0, 2);
count += output.CopyFromAscii(value);
output.CopyFrom(_CrLf, 0, 2);
output.CopyFromAscii(kv.Key);
output.CopyFrom(_colonSpace, 0, 2);
output.CopyFromAscii(value);
}
}
}
return count;
}
public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>

View File

@ -30,7 +30,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// or <see cref="WriteAsync(ArraySegment{byte}, bool, CancellationToken)"/> is called afterwards.
/// </summary>
/// <param name="end">Points to the end of the committed data.</param>
/// <param name="count">The number of bytes added to the response.</param>
void ProducingComplete(MemoryPoolIterator2 end, int count);
void ProducingComplete(MemoryPoolIterator2 end);
}
}

View File

@ -19,6 +19,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private const int _initialTaskQueues = 64;
private static WaitCallback _returnBlocks = (state) => ReturnBlocks((MemoryPoolBlock2)state);
private static MemoryPoolIterator2 _defaultIterator;
private readonly KestrelThread _thread;
private readonly UvStreamHandle _socket;
@ -34,8 +35,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private MemoryPoolBlock2 _head;
private MemoryPoolBlock2 _tail;
private bool _isProducing;
private MemoryPoolBlock2 _returnFromOnProducingComplete;
private MemoryPoolIterator2 _lastStart;
// This locks access to to all of the below fields
private readonly object _contextLock = new object();
@ -83,7 +83,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
var tail = ProducingStart();
tail.CopyFrom(buffer);
// We do our own accounting below
ProducingComplete(tail, count: 0);
ProducingCompleteNoPreComplete(tail);
}
TaskCompletionSource<object> tcs = null;
@ -165,54 +165,57 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
lock (_returnLock)
{
Debug.Assert(!_isProducing);
_isProducing = true;
Debug.Assert(_lastStart.IsDefault);
if (_tail == null)
{
throw new IOException("The socket has been closed.");
}
return new MemoryPoolIterator2(_tail, _tail.End);
_lastStart = new MemoryPoolIterator2(_tail, _tail.End);
return _lastStart;
}
}
public void ProducingComplete(MemoryPoolIterator2 end, int count)
public void ProducingComplete(MemoryPoolIterator2 end)
{
Debug.Assert(!_lastStart.IsDefault);
int bytesProduced, buffersIncluded;
BytesBetween(_lastStart, end, out bytesProduced, out buffersIncluded);
lock (_contextLock)
{
_numBytesPreCompleted += bytesProduced;
}
ProducingCompleteNoPreComplete(end);
}
private void ProducingCompleteNoPreComplete(MemoryPoolIterator2 end)
{
var decreasePreCompleted = false;
MemoryPoolBlock2 blockToReturn = null;
lock (_returnLock)
{
Debug.Assert(_isProducing);
_isProducing = false;
Debug.Assert(!_lastStart.IsDefault);
if (_returnFromOnProducingComplete == null)
// If the socket has been closed, return the produced blocks
// instead of advancing the now non-existent tail.
if (_tail != null)
{
_tail = end.Block;
_tail.End = end.Index;
if (count != 0)
{
decreasePreCompleted = true;
}
}
else
{
blockToReturn = _returnFromOnProducingComplete;
_returnFromOnProducingComplete = null;
blockToReturn = _lastStart.Block;
}
}
if (decreasePreCompleted)
{
lock (_contextLock)
{
_numBytesPreCompleted += count;
}
_lastStart = _defaultIterator;
}
if (blockToReturn != null)
{
ThreadPool.QueueUserWorkItem(_returnBlocks, blockToReturn);
@ -354,11 +357,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
returnBlock.Pool?.Return(returnBlock);
}
if (_isProducing)
{
_returnFromOnProducingComplete = _tail;
}
else
// Only return the _tail if we aren't between ProducingStart/Complete calls
if (_lastStart.IsDefault)
{
_tail.Pool?.Return(_tail);
}
@ -387,6 +387,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return WriteAsync(buffer, immediate);
}
private static void BytesBetween(MemoryPoolIterator2 start, MemoryPoolIterator2 end, out int bytes, out int buffers)
{
if (start.Block == end.Block)
{
bytes = end.Index - start.Index;
buffers = 1;
return;
}
bytes = start.Block.Data.Offset + start.Block.Data.Count - start.Index;
buffers = 1;
for (var block = start.Block.Next; block != end.Block; block = block.Next)
{
bytes += block.Data.Count;
buffers++;
}
bytes += end.Index - end.Block.Data.Offset;
buffers++;
}
private class WriteContext
{
private static WaitCallback _returnWrittenBlocks = (state) => ReturnWrittenBlocks((MemoryPoolBlock2)state);
@ -535,24 +557,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_lockedStart = new MemoryPoolIterator2(head, head.Start);
_lockedEnd = new MemoryPoolIterator2(tail, tail.End);
if (_lockedStart.Block == _lockedEnd.Block)
{
_byteCount = _lockedEnd.Index - _lockedStart.Index;
_bufferCount = 1;
return;
}
_byteCount = _lockedStart.Block.Data.Offset + _lockedStart.Block.Data.Count - _lockedStart.Index;
_bufferCount = 1;
for (var block = _lockedStart.Block.Next; block != _lockedEnd.Block; block = block.Next)
{
_byteCount += block.Data.Count;
_bufferCount++;
}
_byteCount += _lockedEnd.Index - _lockedEnd.Block.Data.Offset;
_bufferCount++;
BytesBetween(_lockedStart, _lockedEnd, out _byteCount, out _bufferCount);
}
}
}

View File

@ -532,17 +532,17 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
}
}
public int CopyFrom(byte[] data)
public void CopyFrom(byte[] data)
{
return CopyFrom(new ArraySegment<byte>(data));
CopyFrom(new ArraySegment<byte>(data));
}
public int CopyFrom(byte[] data, int offset, int count)
public void CopyFrom(byte[] data, int offset, int count)
{
return CopyFrom(new ArraySegment<byte>(data, offset, count));
CopyFrom(new ArraySegment<byte>(data, offset, count));
}
public int CopyFrom(ArraySegment<byte> buffer)
public void CopyFrom(ArraySegment<byte> buffer)
{
Debug.Assert(_block != null);
Debug.Assert(_block.Pool != null);
@ -582,11 +582,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
_block = block;
_index = blockIndex;
return buffer.Count;
}
public unsafe int CopyFromAscii(string data)
public unsafe void CopyFromAscii(string data)
{
Debug.Assert(_block != null);
Debug.Assert(_block.Pool != null);
@ -649,8 +647,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
_block = block;
_index = blockIndex;
return length;
}
}
}

View File

@ -309,17 +309,15 @@ namespace Microsoft.AspNet.Server.KestrelTests
// block 1
var start = socketOutput.ProducingStart();
start.Block.End = start.Block.Data.Offset + start.Block.Data.Count;
var totalBytes = start.Block.Data.Count;
// block 2
var block2 = memory.Lease();
block2.End = block2.Data.Offset + block2.Data.Count;
start.Block.Next = block2;
totalBytes += block2.Data.Count;
var end = new MemoryPoolIterator2(block2, block2.End);
socketOutput.ProducingComplete(end, totalBytes);
socketOutput.ProducingComplete(end);
// A call to Write is required to ensure a write is scheduled
socketOutput.WriteAsync(default(ArraySegment<byte>));

View File

@ -380,24 +380,22 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
((ICollection<KeyValuePair<string, StringValues>>)MaybeUnknown)?.CopyTo(array, arrayIndex);
}}
{(loop.ClassName == "FrameResponseHeaders" ? $@"
protected int CopyToFast(ref MemoryPoolIterator2 output)
protected void CopyToFast(ref MemoryPoolIterator2 output)
{{
var count = 0;
{Each(loop.Headers, header => $@"
if ({header.TestBit()})
{{ {(header.EnhancedSetter == false ? "" : $@"
if (_raw{header.Identifier} != null)
{{
count += output.CopyFrom(_raw{header.Identifier}, 0, _raw{header.Identifier}.Length);
output.CopyFrom(_raw{header.Identifier}, 0, _raw{header.Identifier}.Length);
}} else ")}
foreach(var value in _{header.Identifier})
{{
count += output.CopyFrom(_headerBytes, {header.BytesOffset}, {header.BytesCount});
count += output.CopyFromAscii(value);
output.CopyFrom(_headerBytes, {header.BytesOffset}, {header.BytesCount});
output.CopyFromAscii(value);
}}
}}
")}
return count;
}}" : "")}
public unsafe void Append(byte[] keyBytes, int keyOffset, int keyLength, string value)
{{