Beispiel #1
0
        /// <summary>
        /// Asynchronously walks a stream, calling back into supplied delegates at a block level
        /// </summary>
        /// <param name="stream">The stream to read bytes from.  The caller is responsible for correctly setting the stream's starting positon.</param>
        /// <param name="blockActionSemaphore">Optional: If non-null, a SemaphoreSlim to bound the number of callbacks in flight.  This can be used to bound the number of block-sized that are allocated at any one time.</param>
        /// <param name="multipleBlocksInParallel">Only affects multi-block blobs.  Determines if multiBlockCallback delegates are called in parallel (True) or serial (False).</param>
        /// <param name="singleBlockCallback">Only will be called if the blob is composed of a single block. Is called with the byte buffer for the block, the length of block (possibly less than buffer's length), and the hash of the block.</param>
        /// <param name="multipleBlockCallback">Only will be called if the blob is composed of a multiple blocks. Is called with the byte buffer for the block, the length of block (possibly less than buffer's length), the index of this block, the hash of the block, and whether or not this is the final block.</param>
        /// <param name="multipleBlockSealCallback">Only will be called if the blob is composed of a multiple blocks. Is called after all multiBlockCallback delegates have returned.</param>
        /// <param name="bytesToReadFromStream">Number of bytes to read from the stream. Specify -1 to read to the end of the stream.</param>
        public static async Task WalkBlocksAsync(
            Stream stream,
            SemaphoreSlim?blockActionSemaphore,
            bool multipleBlocksInParallel,
            SingleBlockBlobCallbackAsync singleBlockCallback,
            MultipleBlockBlobCallbackAsync multipleBlockCallback,
            MultipleBlockBlobSealCallbackAsync multipleBlockSealCallback,
            long bytesToReadFromStream = -1)
        {
            bytesToReadFromStream = (bytesToReadFromStream >= 0) ? bytesToReadFromStream : (stream.Length - stream.Position);
            bool isSingleBlockBlob = bytesToReadFromStream <= BlockSize;

            if (isSingleBlockBlob)
            {
                await WalkSingleBlockBlobAsync(stream, blockActionSemaphore, singleBlockCallback, bytesToReadFromStream).ConfigureAwait(false);
            }
            else
            {
                await WalkMultiBlockBlobAsync(stream, blockActionSemaphore, multipleBlocksInParallel, multipleBlockCallback, multipleBlockSealCallback, bytesToReadFromStream).ConfigureAwait(false);
            }
        }
Beispiel #2
0
        public static async Task <BlobIdentifierWithBlocks> WalkAllBlobBlocksAsync(
            Stream stream,
            SemaphoreSlim blockActionSemaphore,
            bool multipleBlocksInParallel,
            MultipleBlockBlobCallbackAsync multipleBlockCallback,
            long?bytesToReadFromStream = null)
        {
            bytesToReadFromStream = bytesToReadFromStream ?? (stream.Length - stream.Position);
            BlobIdentifierWithBlocks?blobIdWithBlocks = null;

            await WalkMultiBlockBlobAsync(
                stream,
                blockActionSemaphore,
                multipleBlocksInParallel,
                multipleBlockCallback,
                computedBlobIdWithBlocks =>
            {
                blobIdWithBlocks = computedBlobIdWithBlocks;
                return(Task.FromResult(0));
            },
                bytesToReadFromStream.GetValueOrDefault()).ConfigureAwait(false);

            return(blobIdWithBlocks !);
        }
Beispiel #3
0
        private static async Task WalkMultiBlockBlobAsync(
            Stream stream,
            SemaphoreSlim?blockActionSemaphore,
            bool multiBlocksInParallel,
            MultipleBlockBlobCallbackAsync multipleBlockCallback,
            MultipleBlockBlobSealCallbackAsync multipleBlockSealCallback,
            long bytesLeftInBlob)
        {
            var rollingId = new RollingBlobIdentifierWithBlocks();
            BlobIdentifierWithBlocks?blobIdentifierWithBlocks = null;

            var tasks = new List <Task>();

            do
            {
                await ReadBlockAsync(
                    stream,
                    blockActionSemaphore,
                    bytesLeftInBlob,
                    async (blockBufferHandle, blockLength, blockHash) =>
                {
                    bytesLeftInBlob  -= blockLength;
                    bool isFinalBlock = bytesLeftInBlob == 0;

                    try
                    {
                        if (isFinalBlock)
                        {
                            blobIdentifierWithBlocks = rollingId.Finalize(blockHash);
                        }
                        else
                        {
                            rollingId.Update(blockHash);
                        }
                    }
                    catch
                    {
                        CleanupBufferAndSemaphore(blockBufferHandle, blockActionSemaphore);
                        throw;
                    }

                    Task multiBlockTask = Task.Run(async() =>
                    {
                        try
                        {
                            await multipleBlockCallback(blockBufferHandle.Value, blockLength, blockHash, isFinalBlock).ConfigureAwait(false);
                        }
                        finally
                        {
                            CleanupBufferAndSemaphore(blockBufferHandle, blockActionSemaphore);
                        }
                    });
                    tasks.Add(multiBlockTask);

                    if (!multiBlocksInParallel)
                    {
                        await multiBlockTask.ConfigureAwait(false);
                    }
                }).ConfigureAwait(false);
            }while (bytesLeftInBlob > 0);

            await Task.WhenAll(tasks).ConfigureAwait(false);

            await multipleBlockSealCallback(blobIdentifierWithBlocks).ConfigureAwait(false);
        }