merge preamble-output, socket-output

This commit is contained in:
Ben Adams 2015-11-20 21:27:59 +00:00
parent a3173c487a
commit feb40402de
9 changed files with 173 additions and 201 deletions

View File

@ -68,13 +68,29 @@ namespace Microsoft.AspNet.Server.Kestrel.Filter
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
var segment = new ArraySegment<byte>(buffer, offset, count); ArraySegment<byte> segment;
if (buffer != null)
{
segment = new ArraySegment<byte>(buffer, offset, count);
}
else
{
segment = default(ArraySegment<byte>);
}
_output.Write(segment); _output.Write(segment);
} }
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token) public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
{ {
var segment = new ArraySegment<byte>(buffer, offset, count); ArraySegment<byte> segment;
if (buffer != null)
{
segment = new ArraySegment<byte>(buffer, offset, count);
}
else
{
segment = default(ArraySegment<byte>);
}
return _output.WriteAsync(segment, cancellationToken: token); return _output.WriteAsync(segment, cancellationToken: token);
} }

View File

@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Filter
returnBlock.Pool?.Return(returnBlock); returnBlock.Pool?.Return(returnBlock);
} }
_outputStream.Write(end.Block.Array, end.Block.Data.Offset, end.Index); _outputStream.Write(end.Block.Array, end.Block.Data.Offset, end.Index - end.Block.Data.Offset);
end.Block.Pool?.Return(end.Block); end.Block.Pool?.Return(end.Block);
} }
} }

View File

@ -623,8 +623,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
bool appCompleted, bool appCompleted,
bool immediate) bool immediate)
{ {
var memoryBlock = Memory2.Lease(); var begin = SocketOutput.ProducingStart();
var begin = memoryBlock.GetIterator(); var count = 0;
var end = begin; var end = begin;
if (_keepAlive) if (_keepAlive)
{ {
@ -673,48 +673,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive); _responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
} }
end.CopyFrom(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0); count += end.CopyFrom(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0);
end.CopyFrom(statusBytes); count += end.CopyFrom(statusBytes);
_responseHeaders.CopyTo(ref end); count += _responseHeaders.CopyTo(ref end);
end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length); count += end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length);
// TODO: change this to SocketOutput.ProduceStart/ProduceComplete once that change is made SocketOutput.ProducingComplete(end, count);
var scan = begin.Block;
while (scan.Next != null)
{
if (scan.Start != scan.End)
{
SocketOutput.WriteAsync(
new ArraySegment<byte>(scan.Array, scan.Start, scan.End - scan.Start),
false);
}
var next = scan.Next;
Memory2.Return(scan);
scan = next;
}
var writeTask = SocketOutput.WriteAsync(
new ArraySegment<byte>(scan.Array, scan.Start, scan.End - scan.Start),
immediate);
if (writeTask.IsCompleted) if (immediate)
{ {
Memory2.Return(scan); return SocketOutput.WriteAsync(default(ArraySegment<byte>), immediate: true);
return TaskUtilities.CompletedTask;
} }
else else
{ {
return writeTask.ContinueWith( return TaskUtilities.CompletedTask;
(t, o) =>
{
var mb = (MemoryPoolBlock2)o;
mb.Pool.Return(mb);
if (t.IsFaulted)
{
throw t.Exception;
}
},
scan);
} }
} }

View File

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

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public partial class FrameResponseHeaders : FrameHeaders public partial class FrameResponseHeaders : FrameHeaders
{ {
private static byte[] _CRLF = new[] { (byte)'\r', (byte)'\n' }; private static byte[] _CrLf = new[] { (byte)'\r', (byte)'\n' };
private static byte[] _colonSpace = new[] { (byte)':', (byte)' ' }; private static byte[] _colonSpace = new[] { (byte)':', (byte)' ' };
public bool HasConnection => HeaderConnection.Count != 0; public bool HasConnection => HeaderConnection.Count != 0;
@ -30,22 +30,23 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return GetEnumerator(); return GetEnumerator();
} }
public void CopyTo(ref MemoryPoolIterator2 output) public int CopyTo(ref MemoryPoolIterator2 output)
{ {
CopyToFast(ref output); var count = CopyToFast(ref output);
if (MaybeUnknown != null) if (MaybeUnknown != null)
{ {
foreach (var kv in MaybeUnknown) foreach (var kv in MaybeUnknown)
{ {
foreach (var value in kv.Value) foreach (var value in kv.Value)
{ {
output.CopyFrom(_CRLF, 0, 2); count += output.CopyFrom(_CrLf, 0, 2);
output.CopyFromAscii(kv.Key); count += output.CopyFromAscii(kv.Key);
output.CopyFrom(_colonSpace, 0, 2); count += output.CopyFrom(_colonSpace, 0, 2);
output.CopyFromAscii(value); count += output.CopyFromAscii(value);
} }
} }
} }
return count;
} }
public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>> public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>

View File

@ -70,11 +70,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
bool socketShutdownSend = false, bool socketShutdownSend = false,
bool socketDisconnect = false) bool socketDisconnect = false)
{ {
var tail = ProducingStart(); if (buffer.Count > 0)
tail = tail.CopyFrom(buffer); {
// We do our own accounting below var tail = ProducingStart();
ProducingComplete(tail, count: 0); tail.CopyFrom(buffer);
// We do our own accounting below
ProducingComplete(tail, count: 0);
}
TaskCompletionSource<object> tcs = null; TaskCompletionSource<object> tcs = null;
lock (_contextLock) lock (_contextLock)

View File

@ -532,7 +532,17 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
} }
} }
public MemoryPoolIterator2 CopyFrom(ArraySegment<byte> buffer) public int CopyFrom(byte[] data)
{
return CopyFrom(new ArraySegment<byte>(data));
}
public int CopyFrom(byte[] data, int offset, int count)
{
return CopyFrom(new ArraySegment<byte>(data, offset, count));
}
public int CopyFrom(ArraySegment<byte> buffer)
{ {
Debug.Assert(_block != null); Debug.Assert(_block != null);
Debug.Assert(_block.Pool != null); Debug.Assert(_block.Pool != null);
@ -545,11 +555,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
var bufferIndex = buffer.Offset; var bufferIndex = buffer.Offset;
var remaining = buffer.Count; var remaining = buffer.Count;
var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex;
while (remaining > 0) while (remaining > 0)
{ {
var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex;
if (bytesLeftInBlock == 0) if (bytesLeftInBlock == 0)
{ {
var nextBlock = pool.Lease(); var nextBlock = pool.Lease();
@ -560,93 +569,55 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
bytesLeftInBlock = block.Data.Count; bytesLeftInBlock = block.Data.Count;
} }
var bytesToCopy = Math.Min(remaining, bytesLeftInBlock); var bytesToCopy = remaining < bytesLeftInBlock ? remaining : bytesLeftInBlock;
Buffer.BlockCopy(buffer.Array, bufferIndex, block.Array, blockIndex, bytesToCopy); Buffer.BlockCopy(buffer.Array, bufferIndex, block.Array, blockIndex, bytesToCopy);
blockIndex += bytesToCopy; blockIndex += bytesToCopy;
bufferIndex += bytesToCopy; bufferIndex += bytesToCopy;
remaining -= bytesToCopy; remaining -= bytesToCopy;
bytesLeftInBlock -= bytesToCopy;
block.End = blockIndex; block.End = blockIndex;
} }
return new MemoryPoolIterator2(block, blockIndex); _block = block;
_index = blockIndex;
return buffer.Count;
} }
public void CopyFrom(byte[] data) public unsafe int CopyFromAscii(string data)
{
CopyFrom(data, 0, data.Length);
}
public void CopyFrom(byte[] data, int offset, int count)
{ {
Debug.Assert(_block != null);
Debug.Assert(_block.Pool != null);
Debug.Assert(_block.Next == null); Debug.Assert(_block.Next == null);
Debug.Assert(_block.End == _index); Debug.Assert(_block.End == _index);
var pool = _block.Pool;
var block = _block; var block = _block;
var blockIndex = _index;
var length = data.Length;
var sourceData = data; var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex;
var sourceStart = offset; var bytesLeftInBlockMinusSpan = bytesLeftInBlock - 3;
var sourceEnd = offset + count;
var targetData = block.Array;
var targetStart = block.End;
var targetEnd = block.Data.Offset + block.Data.Count;
while (true)
{
// actual count to copy is remaining data, or unused trailing space in the current block, whichever is smaller
var copyCount = Math.Min(sourceEnd - sourceStart, targetEnd - targetStart);
Buffer.BlockCopy(sourceData, sourceStart, targetData, targetStart, copyCount);
sourceStart += copyCount;
targetStart += copyCount;
// if this means all source data has been copied
if (sourceStart == sourceEnd)
{
// increase occupied space in the block, and adjust iterator at start of unused trailing space
block.End = targetStart;
_block = block;
_index = targetStart;
return;
}
// otherwise another block needs to be allocated to follow this one
block.Next = block.Pool.Lease();
block = block.Next;
targetData = block.Array;
targetStart = block.End;
targetEnd = block.Data.Offset + block.Data.Count;
}
}
public unsafe void CopyFromAscii(string data)
{
Debug.Assert(_block.Next == null);
Debug.Assert(_block.End == _index);
var block = _block;
var inputLength = data.Length;
var inputLengthMinusSpan = inputLength - 3;
fixed (char* pData = data) fixed (char* pData = data)
{ {
var input = pData; var input = pData;
var inputEnd = pData + data.Length; var inputEnd = pData + length;
var blockRemaining = block.Data.Offset + block.Data.Count - block.End; var inputEndMinusSpan = inputEnd - 3;
var blockRemainingMinusSpan = blockRemaining - 3;
while (input < inputEnd) while (input < inputEnd)
{ {
if (blockRemaining == 0) if (bytesLeftInBlock == 0)
{ {
block.Next = block.Pool.Lease(); var nextBlock = pool.Lease();
block = block.Next; block.Next = nextBlock;
blockRemaining = block.Data.Count; block = nextBlock;
blockRemainingMinusSpan = blockRemaining - 3;
blockIndex = block.Data.Offset;
bytesLeftInBlock = block.Data.Count;
bytesLeftInBlockMinusSpan = bytesLeftInBlock - 3;
} }
fixed (byte* pOutput = block.Data.Array) fixed (byte* pOutput = block.Data.Array)
@ -654,7 +625,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
var output = pOutput + block.End; var output = pOutput + block.End;
var copied = 0; var copied = 0;
for (; copied < inputLengthMinusSpan && copied < blockRemainingMinusSpan; copied += 4) for (; input < inputEndMinusSpan && copied < bytesLeftInBlockMinusSpan; copied += 4)
{ {
*(output) = (byte)*(input); *(output) = (byte)*(input);
*(output + 1) = (byte)*(input + 1); *(output + 1) = (byte)*(input + 1);
@ -662,19 +633,24 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
*(output + 3) = (byte)*(input + 3); *(output + 3) = (byte)*(input + 3);
output += 4; output += 4;
input += 4; input += 4;
blockRemainingMinusSpan -= 4;
} }
for (; copied < inputLength && copied < blockRemaining; copied++) for (; input < inputEnd && copied < bytesLeftInBlock; copied++)
{ {
*(output++) = (byte)*(input++); *(output++) = (byte)*(input++);
blockRemaining--;
} }
block.End += copied;
_block = block; blockIndex += copied;
_index = block.End; bytesLeftInBlockMinusSpan -= copied;
bytesLeftInBlock -= copied;
} }
block.End = blockIndex;
} }
} }
_block = block;
_index = blockIndex;
return length;
} }
} }
} }

View File

@ -159,7 +159,8 @@ namespace Microsoft.AspNet.Server.KestrelTests
using (var pool = new MemoryPool2()) using (var pool = new MemoryPool2())
{ {
var block1 = pool.Lease(128); var block1 = pool.Lease(128);
var iterator = block1.GetIterator(); var start = block1.GetIterator();
var end = start;
var bufferSize = block1.Data.Count * 3; var bufferSize = block1.Data.Count * 3;
var buffer = new byte[bufferSize]; var buffer = new byte[bufferSize];
@ -170,18 +171,18 @@ namespace Microsoft.AspNet.Server.KestrelTests
Assert.Null(block1.Next); Assert.Null(block1.Next);
var end = iterator.CopyFrom(new ArraySegment<byte>(buffer)); end.CopyFrom(new ArraySegment<byte>(buffer));
Assert.NotNull(block1.Next); Assert.NotNull(block1.Next);
for (int i = 0; i < bufferSize; i++) for (int i = 0; i < bufferSize; i++)
{ {
Assert.Equal(i % 73, iterator.Take()); Assert.Equal(i % 73, start.Take());
} }
Assert.Equal(-1, iterator.Take()); Assert.Equal(-1, start.Take());
Assert.Equal(iterator.Block, end.Block); Assert.Equal(start.Block, end.Block);
Assert.Equal(iterator.Index, end.Index); Assert.Equal(start.Index, end.Index);
} }
} }

View File

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