public void ReadToEnd(IEventStoreObserver observer)
{
var overflowWriter = default(ByteBufferWriter);
var bufferBlock = new byte[FirstReadAhead + MaxBlockSize];
var bufferStartPosition = NextReadPosition & SectorMask;
var bufferFullLength = 0;
var bufferReadOffset = (int)(NextReadPosition - bufferStartPosition);
var currentReadAhead = FirstReadAhead;
var buf = ByteBuffer.NewSync(bufferBlock, bufferFullLength, currentReadAhead);
var bufReadLength = (int)File.Read(buf, bufferStartPosition);
bufferFullLength += bufReadLength;
while (true)
{
if (bufferStartPosition + (ulong)bufferReadOffset + HeaderSize > File.MaxFileSize)
{
KnownAsFinished = true;
return;
}
if (bufferReadOffset == bufferFullLength)
{
break;
}
if (bufferReadOffset + HeaderSize > bufferFullLength)
{
for (var i = bufferReadOffset; i < bufferFullLength; i++)
{
if (bufferBlock[i] != 0)
{
SetCorrupted();
return;
}
}
break;
}
var blockCheckSum = PackUnpack.UnpackUInt32LE(bufferBlock, bufferReadOffset);
bufferReadOffset += 4;
var blockLen = PackUnpack.UnpackUInt32LE(bufferBlock, bufferReadOffset);
if (blockCheckSum == 0 && blockLen == 0)
{
bufferReadOffset -= 4;
break;
}
var blockType = (BlockType)(blockLen & 0xff);
blockLen >>= 8;
if (blockType == BlockType.LastBlock && blockLen == 0)
{
if (Checksum.CalcFletcher32(bufferBlock, (uint)bufferReadOffset, 4) != blockCheckSum)
{
SetCorrupted();
return;
}
KnownAsFinished = true;
return;
}
if (blockLen == 0 && blockType != (BlockType.FirstBlock | BlockType.LastBlock))
{
SetCorrupted();
return;
}
if (blockLen + HeaderSize > MaxBlockSize)
{
SetCorrupted();
return;
}
bufferReadOffset += 4;
var bufferLenToFill = (uint)(bufferReadOffset + (int)blockLen + FirstReadAhead) & SectorMaskUInt;
if (bufferLenToFill > bufferBlock.Length) bufferLenToFill = (uint)bufferBlock.Length;
buf = ByteBuffer.NewSync(bufferBlock, bufferFullLength, (int)(bufferLenToFill - bufferFullLength));
if (buf.Length > 0)
{
bufferLenToFill = (uint)(bufferReadOffset + (int)blockLen + currentReadAhead) & SectorMaskUInt;
if (bufferLenToFill > bufferBlock.Length) bufferLenToFill = (uint)bufferBlock.Length;
if (bufferStartPosition + bufferLenToFill > File.MaxFileSize)
{
bufferLenToFill = (uint)(File.MaxFileSize - bufferStartPosition);
}
buf = ByteBuffer.NewSync(bufferBlock, bufferFullLength, (int)(bufferLenToFill - bufferFullLength));
if (buf.Length > 0) {
if (currentReadAhead * 4 < MaxBlockSize)
{
currentReadAhead = currentReadAhead * 2;
}
bufReadLength = (int)File.Read(buf, bufferStartPosition + (ulong)bufferFullLength);
bufferFullLength += bufReadLength;
}
}
if (bufferReadOffset + (int)blockLen > bufferFullLength)
{
SetCorrupted();
return;
}
if (Checksum.CalcFletcher32(bufferBlock, (uint)bufferReadOffset - 4, blockLen + 4) != blockCheckSum)
{
SetCorrupted();
return;
}
var blockTypeBlock = blockType & (BlockType.FirstBlock | BlockType.MiddleBlock | BlockType.LastBlock);
var stopReadingRequested = false;
if (blockTypeBlock == (BlockType.FirstBlock | BlockType.LastBlock))
{
stopReadingRequested = Process(blockType, ByteBuffer.NewSync(bufferBlock, bufferReadOffset, (int)blockLen), observer);
}
else
{
if (blockTypeBlock == BlockType.FirstBlock)
{
overflowWriter = new ByteBufferWriter();
}
else if (blockTypeBlock == BlockType.MiddleBlock || blockTypeBlock == BlockType.LastBlock)
{
if (overflowWriter == null)
{
SetCorrupted();
return;
}
}
else
{
SetCorrupted();
return;
}
overflowWriter.WriteBlock(ByteBuffer.NewSync(bufferBlock, bufferReadOffset, (int)blockLen));
if (blockTypeBlock == BlockType.LastBlock)
{
stopReadingRequested = Process(blockType, overflowWriter.Data, observer);
overflowWriter = null;
}
}
bufferReadOffset += (int)blockLen;
if (overflowWriter == null)
NextReadPosition = bufferStartPosition + (ulong)bufferReadOffset;
if (stopReadingRequested)
{
return;
}
var nextBufferStartPosition = (bufferStartPosition + (ulong)bufferReadOffset) & SectorMask;
var bufferMoveDistance = (int)(nextBufferStartPosition - bufferStartPosition);
if (bufferMoveDistance <= 0) continue;
Array.Copy(bufferBlock, bufferMoveDistance, bufferBlock, 0, bufferFullLength - bufferMoveDistance);
bufferStartPosition = nextBufferStartPosition;
bufferFullLength -= bufferMoveDistance;
bufferReadOffset -= bufferMoveDistance;
}
if (overflowWriter != null)
{
// It is not corrupted here just unfinished, but definitely not appendable
EndBufferPosition = ulong.MaxValue;
return;
}
EndBufferLen = (uint)(bufferReadOffset - (bufferReadOffset & SectorMaskUInt));
EndBufferPosition = bufferStartPosition + (ulong)bufferReadOffset - EndBufferLen;
Array.Copy(bufferBlock, bufferReadOffset - EndBufferLen, EndBuffer, 0, EndBufferLen);
}