wasLastBlock adjustments

This commit is contained in:
Ben Adams 2016-11-19 04:32:42 +00:00
parent 7ab4442392
commit 5041d6c291
2 changed files with 103 additions and 96 deletions

View File

@ -14,8 +14,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
public static readonly int? ECONNRESET = GetECONNRESET();
public static readonly int? EADDRINUSE = GetEADDRINUSE();
public static readonly Encoding UTF8 = Encoding.UTF8;
/// <summary>
/// Prefix of host name used to specify Unix sockets in the configuration.
/// </summary>

View File

@ -44,14 +44,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (_block == null)
var block = _block;
if (block == null)
{
return true;
}
else if (_index < _block.End)
else if (_index < block.End)
{
return false;
}
else if (block.Next == null)
{
return true;
}
else
{
return IsEndMultiBlock();
@ -63,14 +68,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
private bool IsEndMultiBlock()
{
var block = _block.Next;
while (block != null)
do
{
if (block.Start < block.End)
{
return false; // subsequent block has data - IsEnd is false
}
block = block.Next;
}
} while (block != null);
return true;
}
@ -88,6 +94,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
}
var index = _index;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
if (index < block.End)
{
@ -95,28 +103,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
return block.Array[index];
}
return TakeMultiBlock();
return wasLastBlock ? -1 : TakeMultiBlock();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private int TakeMultiBlock()
{
var block = _block;
var wasLastBlock = block.Next == null;
do
{
int index;
if (wasLastBlock)
{
return -1;
}
else
{
block = block.Next;
index = block.Start;
}
block = block.Next;
var index = block.Start;
wasLastBlock = block.Next == null;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
if (index < block.End)
{
@ -124,18 +124,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
_index = index + 1;
return block.Array[index];
}
if (wasLastBlock)
{
return -1;
}
} while (true);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Skip(int bytesToSkip)
{
if (_block == null)
var block = _block;
if (block == null)
{
return;
}
var following = _block.End - _index;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
var following = block.End - _index;
if (following >= bytesToSkip)
{
@ -143,29 +151,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
return;
}
if (wasLastBlock)
{
ThrowInvalidOperationException_SkipMoreThanAvailable();
}
SkipMultiBlock(bytesToSkip, following);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void SkipMultiBlock(int bytesToSkip, int following)
{
var wasLastBlock = _block.Next == null;
var block = _block;
while (true)
do
{
int index;
if (wasLastBlock)
{
throw new InvalidOperationException("Attempted to skip more bytes than available.");
}
else
{
bytesToSkip -= following;
block = block.Next;
index = block.Start;
}
bytesToSkip -= following;
block = block.Next;
var index = block.Start;
wasLastBlock = block.Next == null;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
following = block.End - index;
if (following >= bytesToSkip)
@ -174,7 +179,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
_index = index + bytesToSkip;
return;
}
}
if (wasLastBlock)
{
ThrowInvalidOperationException_SkipMoreThanAvailable();
}
} while (true);
}
private static void ThrowInvalidOperationException_SkipMoreThanAvailable()
{
throw new InvalidOperationException("Attempted to skip more bytes than available.");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -188,38 +203,36 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
var index = _index;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
if (index < block.End)
{
return block.Array[index];
}
return PeekMultiBlock();
return wasLastBlock ? -1 : PeekMultiBlock();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private int PeekMultiBlock()
{
var block = _block;
var wasLastBlock = block.Next == null;
do
{
int index;
if (wasLastBlock)
{
return -1;
}
else
{
block = block.Next;
index = block.Start;
}
block = block.Next;
var index = block.Start;
wasLastBlock = block.Next == null;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
if (index < block.End)
{
return block.Array[index];
}
if (wasLastBlock)
{
return -1;
}
} while (true);
}
@ -229,60 +242,57 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
{
longValue = 0;
if (_block == null)
var block = _block;
if (block == null)
{
return false;
}
var blockBytes = _block.End - _index;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
var blockBytes = block.End - _index;
if (blockBytes >= sizeof(ulong))
{
longValue = *(ulong*)(_block.DataFixedPtr + _index);
longValue = *(ulong*)(block.DataFixedPtr + _index);
return true;
}
return TryPeekLongMultiBlock(ref longValue, blockBytes);
// wasLastBlock ? false : TryPeekLongMultiBlock(ref longValue, blockBytes);
return !wasLastBlock && TryPeekLongMultiBlock(ref longValue, blockBytes);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private unsafe bool TryPeekLongMultiBlock(ref ulong longValue, int blockBytes)
{
var wasLastBlock = _block.Next == null;
if (wasLastBlock)
// Each block will be filled with at least 2048 bytes before the Next pointer is set, so a long
// will cross at most one block boundary assuming there are at least 8 bytes following the iterator.
var nextBytes = sizeof(ulong) - blockBytes;
var block = _block;
if (block.Next.End - block.Next.Start < nextBytes)
{
return false;
}
var nextLong = *(ulong*)(block.Next.DataFixedPtr + block.Next.Start);
if (blockBytes == 0)
{
// This case can not fall through to the else block since that would cause a 64-bit right shift
// on blockLong which is equivalent to no shift at all instead of shifting in all zeros.
// https://msdn.microsoft.com/en-us/library/xt18et0d.aspx
longValue = nextLong;
}
else
{
// Each block will be filled with at least 2048 bytes before the Next pointer is set, so a long
// will cross at most one block boundary assuming there are at least 8 bytes following the iterator.
var nextBytes = sizeof(ulong) - blockBytes;
var blockLong = *(ulong*)(block.DataFixedPtr + block.End - sizeof(ulong));
if (_block.Next.End - _block.Next.Start < nextBytes)
{
return false;
}
var nextLong = *(ulong*)(_block.Next.DataFixedPtr + _block.Next.Start);
if (blockBytes == 0)
{
// This case can not fall through to the else block since that would cause a 64-bit right shift
// on blockLong which is equivalent to no shift at all instead of shifting in all zeros.
// https://msdn.microsoft.com/en-us/library/xt18et0d.aspx
longValue = nextLong;
}
else
{
var blockLong = *(ulong*)(_block.DataFixedPtr + _block.End - sizeof(ulong));
// Ensure that the right shift has a ulong operand so a logical shift is performed.
longValue = (blockLong >> nextBytes * 8) | (nextLong << blockBytes * 8);
}
return true;
// Ensure that the right shift has a ulong operand so a logical shift is performed.
longValue = (blockLong >> nextBytes * 8) | (nextLong << blockBytes * 8);
}
return true;
}
public int Seek(byte byte0)
@ -799,6 +809,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
var block = _block;
var index = _index;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
if (index < block.End)
{
_index = index + 1;
@ -806,28 +818,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
return true;
}
return PutMultiBlock(data);
// wasLastBlock ? false : PutMultiBlock(data);
return !wasLastBlock && PutMultiBlock(data);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private bool PutMultiBlock(byte data)
{
var block = _block;
var wasLastBlock = block.Next == null;
do
{
int index;
if (wasLastBlock)
{
return false;
}
else
{
block = block.Next;
index = block.Start;
}
block = block.Next;
var index = block.Start;
wasLastBlock = block.Next == null;
// Always set wasLastBlock before checking .End to avoid race which may cause data loss
var wasLastBlock = block.Next == null;
if (index < block.End)
{
@ -836,6 +841,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
block.Array[index] = data;
break;
}
if (wasLastBlock)
{
return false;
}
} while (true);
return true;
@ -1123,10 +1132,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
}
if (end.Block == Block)
{
return Constants.UTF8.GetString(Block.Array, Index, end.Index - Index);
return Encoding.UTF8.GetString(Block.Array, Index, end.Index - Index);
}
var decoder = Constants.UTF8.GetDecoder();
var decoder = Encoding.UTF8.GetDecoder();
var length = GetLength(end);
var charLength = length;