private void DoSequentialRead(
BlobTransferContext transferContext,
Stream stream,
byte[] streamBuffer = null,
KeyValuePair<long, int>? inputStartAndLength = null)
{
if (transferContext.CancellationToken.IsCancellationRequested)
{
return;
}
if (streamBuffer == null)
{
streamBuffer = transferContext.MemoryManager.RequireBuffer();
}
if (streamBuffer == null)
{
return;
}
KeyValuePair<long, int> startAndLength;
if (inputStartAndLength == null)
{
if (!transferContext.BlocksToTransfer.TryDequeue(out startAndLength))
{
transferContext.MemoryManager.ReleaseBuffer(streamBuffer);
return;
}
}
else
{
startAndLength = inputStartAndLength.Value;
}
// Catch any exceptions and cleanup the buffer. Otherwise uncleaned buffers will result in hang for future
// uploads as memorymanager is being shared.
// Also mark the transfer as complete and add exceptions to the transfercontext exception list.
try
{
if (!transferContext.PartialFileIOState.ContainsKey(startAndLength.Key))
{
transferContext.PartialFileIOState[startAndLength.Key] = 0;
}
transferContext.IsReadingOrWriting = true;
long beginFilePosition = startAndLength.Key;
long nextBeginFilePosition = startAndLength.Key + transferContext.BlockSize;
nextBeginFilePosition =
nextBeginFilePosition > transferContext.Length
? transferContext.Length
: nextBeginFilePosition;
beginFilePosition = beginFilePosition + transferContext.PartialFileIOState[startAndLength.Key];
int bytesToRead = (int)(nextBeginFilePosition - beginFilePosition);
stream.BeginRead(
streamBuffer,
transferContext.PartialFileIOState[startAndLength.Key],
bytesToRead,
result3 =>
{
int bytesRead;
SuccessfulOrRetryableResult wasReadSuccessful =
IsActionSuccessfulOrRetryable(transferContext, () => stream.EndRead(result3), out bytesRead);
if (!wasReadSuccessful.IsSuccessful)
{
transferContext.IsReadingOrWriting = false;
transferContext.MemoryManager.ReleaseBuffer(streamBuffer);
}
else if (bytesRead != bytesToRead)
{
transferContext.PartialFileIOState[startAndLength.Key] += bytesRead;
DoSequentialRead(transferContext, stream, streamBuffer, startAndLength);
}
else
{
transferContext.IsReadingOrWriting = false;
ApplyEncryptionTransform(
transferContext.FileEncryption,
Path.GetFileName(transferContext.LocalFilePath),
beginFilePosition,
streamBuffer,
bytesToRead);
transferContext.BlocksForFileIO[(int)(startAndLength.Key / transferContext.BlockSize)] = streamBuffer;
}
},
null);
}
catch (Exception ex)
{
transferContext.IsComplete = true;
transferContext.MemoryManager.ReleaseBuffer(streamBuffer);
transferContext.Exceptions.Add(ex);
}
}