/// <summary>
        /// Returns an enumerable collection of tables segmented implementation.
        /// </summary>
        /// <param name="prefix">The prefix.</param>
        /// <param name="continuationToken">The continuation token.</param>
        /// <param name="pagination">The pagination.</param>
        /// <param name="lastResult">The last result.</param>
        /// <param name="setResult">The set result.</param>
        /// <returns>A sequence of tasks to do the operation.</returns>
        private TaskSequence ListTablesSegmentedImplCore(
            string prefix,
            ResultContinuation continuationToken,
            ResultPagination pagination,
            ResultSegment <TableServiceTable> lastResult,
            Action <ResultSegment <string> > setResult)
        {
            CommonUtils.AssertContinuationType(continuationToken, ResultContinuation.ContinuationType.Table);

            InvokeTaskSequenceTask <ResultSegment <TableServiceTable> > listTablesSegmentedTask;

            if (lastResult == null)
            {
                var svc   = this.GetDataServiceContext();
                var query = from table in svc.CreateQuery <TableServiceTable>(Protocol.Constants.TableServiceTablesName)
                            select table;

                if (prefix != string.Empty)
                {
                    // Append Max char to end  '{' is 1 + 'z' in AsciiTable
                    string uppperBound = prefix + '{';

                    query = query.Where((table) => table.TableName.CompareTo(prefix) >= 0 && table.TableName.CompareTo(uppperBound) < 0);
                }

                if (pagination.IsPagingEnabled)
                {
                    query = query.Take(pagination.GetNextRequestPageSize().Value);
                }

                var listTablesQuery = query.AsTableServiceQuery();

                listTablesSegmentedTask = new InvokeTaskSequenceTask <ResultSegment <TableServiceTable> >(
                    (setResultInner) =>
                    listTablesQuery.ExecuteSegmentedImpl(continuationToken, setResultInner));
            }
            else
            {
                listTablesSegmentedTask = new InvokeTaskSequenceTask <ResultSegment <TableServiceTable> >(lastResult.GetNextImpl);
            }

            yield return(listTablesSegmentedTask);

            if (GetResultOrDefault <ResultSegment <TableServiceTable> >(listTablesSegmentedTask, out lastResult))
            {
                setResult(new ResultSegment <string>(
                              lastResult.Results.Select((table) => table.TableName),
                              lastResult.HasMoreResults,
                              (setResultInner) =>
                              this.ListTablesSegmentedImplCore(prefix, lastResult.ContinuationToken, pagination, lastResult, setResultInner),
                              RetryPolicy)
                {
                    ContinuationToken = lastResult.ContinuationToken
                });
            }
            else
            {
                setResult(new ResultSegment <string>(new List <string>(), false, null, RetryPolicy));
            }
        }
Exemple #2
0
        /// <summary>
        /// Generates a task sequence for getting the properties of the queue service.
        /// </summary>
        /// <param name="setResult">A delegate to receive the service properties.</param>
        /// <returns>A task sequence that gets the properties of the queue service.</returns>
        private TaskSequence GetServicePropertiesImpl(Action <ServiceProperties> setResult)
        {
            HttpWebRequest request = QueueRequest.GetServiceProperties(this.BaseUri, this.Timeout.RoundUpToSeconds());

            CommonUtils.ApplyRequestOptimizations(request, -1);
            this.Credentials.SignRequest(request);

            // Get the web response.
            Task <WebResponse> responseTask = request.GetResponseAsyncWithTimeout(this, this.Timeout);

            yield return(responseTask);

            using (HttpWebResponse response = responseTask.Result as HttpWebResponse)
                using (Stream responseStream = response.GetResponseStream())
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        // Download the service properties.
                        Task <NullTaskReturn> downloadTask = new InvokeTaskSequenceTask(() => { return(responseStream.WriteTo(memoryStream)); });
                        yield return(downloadTask);

                        // Materialize any exceptions.
                        NullTaskReturn scratch = downloadTask.Result;

                        // Get the result from the memory stream.
                        memoryStream.Seek(0, SeekOrigin.Begin);
                        setResult(QueueResponse.ReadServiceProperties(memoryStream));
                    }
        }
        /// <summary>
        /// Implements the flushing sequence.
        /// </summary>
        /// <returns>The sequence of events for a flush.</returns>
        private TaskSequence FlushInternal()
        {
            // If there's nothing to flush, just return;
            if (this.blockBuffer == null)
            {
                yield break;
            }

            // Rewind the stream before upload
            this.blockBuffer.Position = 0;

            InvokeTaskSequenceTask newTask;

            if (this.UseBlocks)
            {
                newTask = new InvokeTaskSequenceTask(this.UploadBlock);
            }
            else
            {
                newTask = new InvokeTaskSequenceTask(this.UploadBlob);
            }

            yield return(newTask);

            var result = newTask.Result; // Materialize the results to ensure exception propagation
        }
Exemple #4
0
        internal static IAsyncResult BeginImpl <T>(Func <Action <T>, TaskSequence> impl, AsyncCallback callback, object state)
        {
            CommonUtils.AssertNotNull("impl", impl);

            var invokerTask = new InvokeTaskSequenceTask <T>(impl);

            return(invokerTask.ToAsyncResult(callback, state));
        }
Exemple #5
0
        internal static T ExecuteImpl <T>(Func <Action <T>, TaskSequence> impl)
        {
            CommonUtils.AssertNotNull("impl", impl);

            var invokerTask = new InvokeTaskSequenceTask <T>(impl);

            return(invokerTask.ExecuteAndWait());
        }
Exemple #6
0
        internal static void ExecuteImpl(Func <TaskSequence> impl)
        {
            CommonUtils.AssertNotNull("impl", impl);

            InvokeTaskSequenceTask invokerTask = new InvokeTaskSequenceTask(impl);

            invokerTask.ExecuteAndWait();
        }
        /// <summary>
        /// Uploads the block list.
        /// </summary>
        /// <param name="blocks">The blocks to upload.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the block list.</returns>
        internal TaskSequence UploadBlockList(List <PutBlockListItem> blocks, BlobRequestOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException("modifers");
            }

            var request = ProtocolHelper.GetWebRequest(this.ServiceClient, options, (timeout) => BlobRequest.PutBlockList(this.TransformedAddress, timeout, this.Properties, null));

            options.AccessCondition.ApplyCondition(request);
            BlobRequest.AddMetadata(request, this.Metadata);

            using (var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize))
            {
                BlobRequest.WriteBlockListBody(blocks, memoryStream);

                CommonUtils.ApplyRequestOptimizations(request, memoryStream.Length);

                memoryStream.Seek(0, SeekOrigin.Begin);

                // Compute the MD5
                var md5 = System.Security.Cryptography.MD5.Create();

                request.Headers[HttpRequestHeader.ContentMd5] = Convert.ToBase64String(md5.ComputeHash(memoryStream));

                this.ServiceClient.Credentials.SignRequest(request);

                memoryStream.Seek(0, SeekOrigin.Begin);

                // Retrieve the stream
                var requestStreamTask = request.GetRequestStreamAsync();
                yield return(requestStreamTask);

                using (Stream requestStream = requestStreamTask.Result)
                {
                    // Copy the data
                    var copyTask = new InvokeTaskSequenceTask(() => { return(memoryStream.WriteTo(requestStream)); });
                    yield return(copyTask);

                    // Materialize any exceptions
                    var scratch = copyTask.Result;
                    Console.WriteLine(scratch);
                }
            }

            // Get the response
            var responseTask = request.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout);

            yield return(responseTask);

            using (var response = responseTask.Result as HttpWebResponse)
            {
                ParseSizeAndLastModified(response);
                this.Properties.Length = 0;
            }
        }
Exemple #8
0
        internal static Task <T> GetRetryableAsyncTask <T>(Func <Action <T>, TaskSequence> impl, RetryPolicy policy)
        {
            CommonUtils.AssertNotNull("impl", impl);
            CommonUtils.AssertNotNull("policy", policy);

            ShouldRetry oracle = policy();

            InvokeTaskSequenceTask <T> retryableTask = new InvokeTaskSequenceTask <T>(
                (setResult) => RequestWithRetry.RequestWithRetryImpl <T>(oracle, impl, setResult));

            return(retryableTask);
        }
        /// <summary>
        /// Creates the table if not exist implementation.
        /// </summary>
        /// <param name="tableName">The table name.</param>
        /// <param name="setResult">The set result.</param>
        /// <returns>A sequence of tasks to do the operation.</returns>
        private TaskSequence CreateTableIfNotExistImpl(string tableName, Action <bool> setResult)
        {
            CommonUtils.CheckStringParameter(tableName, false, "tableName", Protocol.Constants.TableServiceMaxStringPropertySizeInChars);
            TableServiceUtilities.CheckTableName(tableName, "tableName");

            var doesTableExistTask = new InvokeTaskSequenceTask <bool>((set) => this.DoesTableExistImpl(tableName, set));

            yield return(doesTableExistTask);

            if (doesTableExistTask.Result)
            {
                setResult(false);
            }
            else
            {
                var createTableTask = TaskImplHelper.GetRetryableAsyncTask <InvalidOperationException>((resultSetter) => this.CreateTableImpl(tableName, resultSetter), RetryPolicy);

                yield return(createTableTask);

                // wrap any exceptions
                try
                {
                    if (createTableTask.Result == null)
                    {
                        setResult(true);
                    }
                    else
                    {
                        StorageClientException exception = Utilities.TranslateDataServiceClientException(createTableTask.Result) as StorageClientException;
                        if (exception != null &&
                            exception.ErrorCode == StorageErrorCode.ResourceAlreadyExists &&
                            exception.ExtendedErrorInformation != null &&
                            exception.ExtendedErrorInformation.ErrorCode == TableErrorCodeStrings.TableAlreadyExists)
                        {
                            setResult(false);
                        }
                        else
                        {
                            throw createTableTask.Result;
                        }
                    }
                }
                catch (InvalidOperationException ex)
                {
                    throw Utilities.TranslateDataServiceClientException(ex);
                }
            }
        }
        /// <summary>
        /// Generates a task sequence for setting the properties of the queue service.
        /// </summary>
        /// <param name="properties">The queue service properties to set.</param>
        /// <returns>A task sequence that sets the properties of the queue service.</returns>
        private TaskSequence SetServicePropertiesImpl(ServiceProperties properties)
        {
            CommonUtils.AssertNotNull("properties", properties);

            HttpWebRequest request = QueueRequest.SetServiceProperties(this.BaseUri, this.Timeout.RoundUpToSeconds());

            using (MemoryStream memoryStream = new MemoryStream())
            {
                try
                {
                    QueueRequest.WriteServiceProperties(properties, memoryStream);
                }
                catch (InvalidOperationException invalidOpException)
                {
                    throw new ArgumentException(invalidOpException.Message, "properties");
                }

                memoryStream.Seek(0, SeekOrigin.Begin);
                CommonUtils.ApplyRequestOptimizations(request, memoryStream.Length);
                this.Credentials.SignRequest(request);

                // Get the request stream
                Task <Stream> getStreamTask = request.GetRequestStreamAsync();
                yield return(getStreamTask);

                using (Stream requestStream = getStreamTask.Result)
                {
                    // Upload the service properties.
                    Task <NullTaskReturn> uploadTask = new InvokeTaskSequenceTask(() => { return((memoryStream as Stream).WriteTo(requestStream)); });
                    yield return(uploadTask);

                    // Materialize any exceptions.
                    NullTaskReturn scratch = uploadTask.Result;
                    Console.WriteLine(scratch);
                }
            }

            // Get the web response.
            Task <WebResponse> responseTask = request.GetResponseAsyncWithTimeout(this, this.Timeout);

            yield return(responseTask);

            // Materialize any exceptions.
            using (HttpWebResponse response = responseTask.Result as HttpWebResponse)
            {
            }
        }
Exemple #11
0
        internal static Task <NullTaskReturn> GetRetryableAsyncTask(Func <TaskSequence> impl, RetryPolicy policy)
        {
            CommonUtils.AssertNotNull("impl", impl);
            CommonUtils.AssertNotNull("policy", policy);

            ShouldRetry oracle = policy();

            InvokeTaskSequenceTask retryableTask = new InvokeTaskSequenceTask(
                () => RequestWithRetry.RequestWithRetryImpl <NullTaskReturn>(
                    oracle,
                    (setResult) => impl(),
                    (scratch) =>
            {
            }));

            return(retryableTask);
        }
Exemple #12
0
        /// <summary>
        /// Commits the blob by uploading any remaining data and the blocklist asynchronously.
        /// </summary>
        /// <returns>A sequence of events required for commit.</returns>
        private TaskSequence CommitImpl()
        {
            this.CheckWriteState();

            if (this.blockBuffer != null && this.blockBuffer.Length != 0)
            {
                var task = new InvokeTaskSequenceTask(this.FlushInternal);
                yield return(task);

                var result = task.Result; // Materialize the errors
                Console.WriteLine(result);
            }

            // If all blocks are uploaded, commit
            if (this.UseBlocks)
            {
                this.SetBlobMD5();

                var task = TaskImplHelper.GetRetryableAsyncTask(
                    () =>
                {
                    // At the convenience layer we always upload uncommitted blocks
                    List <PutBlockListItem> putBlockList = new List <PutBlockListItem>();
                    foreach (var id in this.blockList)
                    {
                        putBlockList.Add(new PutBlockListItem(id, BlockSearchMode.Uncommitted));
                    }

                    return(this.Blob.ToBlockBlob.UploadBlockList(putBlockList, this.currentModifier));
                },
                    this.currentModifier.RetryPolicy);
                yield return(task);

                var result = task.Result;
                Console.WriteLine(result);
            }

            // Now we can set the full size.
            this.Blob.Properties.Length = this.Length;

            // Clear the internal state
            this.Abort();
        }
        /// <summary>
        /// Begins an asynchronous write operation.
        /// </summary>
        /// <param name="buffer">The buffer to write data from.</param>
        /// <param name="offset">The byte offset in buffer from which to begin writing.</param>
        /// <param name="count">The  number of bytes to write.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the write is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
        /// <returns>An IAsyncResult that represents the asynchronous write, which could still be pending.</returns>
        /// <exception cref="System.ArgumentNullException"><paramref name="buffer"/> is null.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">offset or count is negative.</exception>
        /// <exception cref="System.ObjectDisposedException">Thrown if blob is already committed/closed</exception>
        /// <remarks>The operation will be completed synchronously if the buffer is not filled</remarks>
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            this.CheckWriteState();
            StreamUtilities.CheckBufferArguments(buffer, offset, count);

            Task <NullTaskReturn> task = null;

            if (this.UseBlocks)
            {
                task = new InvokeTaskSequenceTask(() =>
                {
                    return(this.WriteBlockBlobImpl(buffer, offset, count));
                });
            }
            else
            {
                task = this.WriteNonBlockedBlobImpl(buffer, offset, count);
            }

            return(task.ToAsyncResult(callback, state));
        }
Exemple #14
0
        /// <summary>
        /// Implements the block writing task.
        /// </summary>
        /// <param name="buffer">The buffer to write data from.</param>
        /// <param name="offset">The byte offset in buffer from which to begin writing.</param>
        /// <param name="count">The  number of bytes to write.</param>
        /// <returns>The sequence representing the uploading of the blocks.</returns>
        private TaskSequence WriteBlockBlobImpl(byte[] buffer, int offset, int count)
        {
            if (this.blockList.Count + (count / this.blockSize) > Constants.MaxBlockNumber)
            {
                throw new ArgumentOutOfRangeException("count", String.Format(CultureInfo.CurrentCulture, SR.TooManyBlocksError, Constants.MaxBlockNumber));
            }

            while (count != 0)
            {
                // Create a buffer if we don't have one
                if (this.blockBuffer == null)
                {
                    this.CreateNewBlock();
                }

                // Copy enough data to fill the buffer.
                int numCopied = (int)Math.Min(count, this.blockSize - this.blockBuffer.Length);
                this.blockBuffer.Write(buffer, offset, numCopied);

                StreamUtilities.ComputeHash(buffer, offset, numCopied, this.blockHash);
                StreamUtilities.ComputeHash(buffer, offset, numCopied, this.blobHash);

                // Advance the location
                this.position += numCopied;
                offset        += numCopied;
                count         -= numCopied;

                // If buffer is full, flush
                if (this.blockBuffer.Length == this.blockSize)
                {
                    var newTask = new InvokeTaskSequenceTask(this.FlushInternal);
                    yield return(newTask);

                    // Make sure task completed successfully by materializing the exception
                    var result = newTask.Result;
                    Console.WriteLine(result);
                }
            }
        }
        /// <summary>
        /// Uploads the data into the web request.
        /// </summary>
        /// <param name="request">The request that is setup for a put.</param>
        /// <param name="source">The source of data.</param>
        /// <param name="result">The response from the server.</param>
        /// <returns>The sequence used for uploading data.</returns>
        internal TaskSequence UploadData(HttpWebRequest request, Stream source, Action<WebResponse> result)
        {
            // Retrieve the stream
            var requestStreamTask = request.GetRequestStreamAsync();
            yield return requestStreamTask;

            // Copy the data
            using (var outputStream = requestStreamTask.Result)
            {
                var copyTask = new InvokeTaskSequenceTask(() => { return source.WriteTo(outputStream); });
                yield return copyTask;

                // Materialize any exceptions
                var scratch = copyTask.Result;
            }

            // Get the response
            var responseTask = request.GetResponseAsyncWithTimeout(this.ServiceClient, this.ServiceClient.Timeout);
            yield return responseTask;

            // Return the response object
            var response = responseTask.Result;

            result(response);
        }
        /// <summary>
        /// Perform a parallel upload of blocks for a blob from a given stream.
        /// </summary>
        /// <param name="uploadFunc">The upload func.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the blob in parallel.</returns>
        /// <remarks>
        /// The operation is done as a series of alternate producer and consumer tasks. The producer tasks dispense out
        /// chunks of source stream as fixed size blocks. This is done in serial order on a thread using InvokeTaskSequence's
        /// serial execution. The consumer tasks upload each block in parallel on multiple thread. The producer thread waits
        /// for at least one consumer task to finish before adding more producer tasks. The producer thread quits when no
        /// more data can be read from the stream and no other pending consumer tasks.
        /// </remarks>
        internal TaskSequence ParallelExecute(
            Func <SmallBlockMemoryStream, string, string, BlobRequestOptions, Task <NullTaskReturn> > uploadFunc)
        {
            bool moreToUpload = true;
            List <IAsyncResult> asyncResults = new List <IAsyncResult>();

            Random rand = new Random();
            long   blockIdSequenceNumber = (long)rand.Next() << 32;

            blockIdSequenceNumber += rand.Next();

            do
            {
                int currentPendingTasks = asyncResults.Count;

                // Step 1
                // Create producer tasks in a serial order as stream can only be read sequentially
                for (int i = currentPendingTasks; i < this.parellelism && moreToUpload; i++)
                {
                    string blockId   = null;
                    string blockHash = null;
                    SmallBlockMemoryStream blockAsStream = null;
                    blockIdSequenceNumber++;

                    InvokeTaskSequenceTask producerTask = new InvokeTaskSequenceTask(() =>
                                                                                     this.DispenseBlockStream(
                                                                                         blockIdSequenceNumber,
                                                                                         (stream, id, hashVal) =>
                    {
                        blockAsStream = stream;
                        blockId       = id;
                        blockHash     = hashVal;
                    }));

                    yield return(producerTask);

                    this.producerTasksCreated++;

                    var scatch = producerTask.Result;
                    Console.WriteLine(scatch);

                    if (blockAsStream == null)
                    {
                        TraceHelper.WriteLine("No more upload tasks");
                        moreToUpload = false;
                    }
                    else
                    {
                        // Step 2
                        // Fire off consumer tasks that may finish on other threads;
                        var          task        = uploadFunc(blockAsStream, blockId, blockHash, this.options);
                        IAsyncResult asyncresult = task.ToAsyncResult(null, null);
                        this.consumerTasksCreated++;

                        asyncResults.Add(asyncresult);
                    }
                }

                // Step 3
                // Wait for 1 or more consumer tasks to finish inorder to bound set of parallel tasks
                if (asyncResults.Count > 0)
                {
                    int waitTimeout = GetWaitTimeout(this.options);

                    TraceHelper.WriteLine("Starting wait");

                    int waitResult = WaitHandle.WaitAny(asyncResults.Select(result => result.AsyncWaitHandle).ToArray(), waitTimeout);

                    TraceHelper.WriteLine("Ending wait");

                    if (waitResult == WaitHandle.WaitTimeout)
                    {
                        throw TimeoutHelper.ThrowTimeoutError(this.options.Timeout.Value);
                    }

                    CompleteAsyncresult(asyncResults, waitResult);

                    // Optimize away any other completed tasks
                    for (int index = 0; index < asyncResults.Count; index++)
                    {
                        IAsyncResult result = asyncResults[index];
                        if (result.IsCompleted)
                        {
                            CompleteAsyncresult(asyncResults, index);
                            index--;
                        }
                    }
                }
            }while (moreToUpload || asyncResults.Count != 0);

            TraceHelper.WriteLine(
                "Total producer tasks created {0}, consumer tasks created {1} ",
                this.producerTasksCreated,
                this.consumerTasksCreated);

            var commitTask = TaskImplHelper.GetRetryableAsyncTask(this.CommitBlob, this.options.RetryPolicy);

            yield return(commitTask);

            var commitTaskResult = commitTask.Result;

            Console.WriteLine(commitTaskResult);
        }
Exemple #17
0
        /// <summary>
        /// Implementation method for the WritePage methods.
        /// </summary>
        /// <param name="pageData">The page data.</param>
        /// <param name="startOffset">The start offset.</param>
        /// <param name="sourceStreamPosition">The beginning position of the source stream prior to execution, negative if stream is unseekable.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that writes the pages.</returns>
        private TaskSequence WritePageImpl(Stream pageData, long startOffset, long sourceStreamPosition, BlobRequestOptions options)
        {
            CommonUtils.AssertNotNull("options", options);

            long length = pageData.Length;

            // Logic to rewind stream on a retry
            // For non seekable streams we need a way to detect the retry iteration so as to only attempt to execute once.
            // The first attempt will have SourceStreamPosition = -1, which means the first iteration on a non seekable stream.
            // The second attempt will have SourceStreamPosition = -2, anything below -1 is considered an abort. Since the Impl method
            // does not have an execution context to be aware of what iteration is used the SourceStreamPosition is utilized as counter to
            // differentiate between the first attempt and a retry.
            if (sourceStreamPosition >= 0 && pageData.CanSeek)
            {
                if (sourceStreamPosition != pageData.Position)
                {
                    pageData.Seek(sourceStreamPosition, 0);
                }
            }
            else if (sourceStreamPosition < -1)
            {
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, SR.CannotRetryNonSeekableStreamError));
            }

            if (startOffset % Protocol.Constants.PageSize != 0)
            {
                CommonUtils.ArgumentOutOfRange("startOffset", startOffset);
            }

            long rangeStreamOffset = pageData.CanSeek ? pageData.Position : 0;

            PutPageProperties properties = new PutPageProperties()
            {
                Range     = new PageRange(startOffset, startOffset + length - rangeStreamOffset - 1),
                PageWrite = PageWrite.Update,
            };

            if ((1 + properties.Range.EndOffset - properties.Range.StartOffset) % Protocol.Constants.PageSize != 0 ||
                (1 + properties.Range.EndOffset - properties.Range.StartOffset) == 0)
            {
                CommonUtils.ArgumentOutOfRange("pageData", pageData);
            }

            var webRequest = ProtocolHelper.GetWebRequest(
                this.ServiceClient,
                options,
                (timeout) => BlobRequest.PutPage(this.TransformedAddress, timeout, properties, null));

            ////BlobRequest.AddMetadata(webRequest, this.Metadata);

            // Retrieve the stream
            var requestStreamTask = webRequest.GetRequestStreamAsync();

            yield return(requestStreamTask);

            // Copy the data
            using (var outputStream = requestStreamTask.Result)
            {
                var copyTask = new InvokeTaskSequenceTask(() => { return(pageData.WriteTo(outputStream)); });
                yield return(copyTask);

                // Materialize any exceptions
                var scratch = copyTask.Result;
            }

            // signing request needs Size to be set
            this.ServiceClient.Credentials.SignRequest(webRequest);

            // Get the response
            var responseTask = webRequest.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout);

            yield return(responseTask);

            // Parse the response
            using (HttpWebResponse webResponse = responseTask.Result as HttpWebResponse)
            {
                this.ParseSizeAndLastModified(webResponse);
            }
        }
Exemple #18
0
        /// <summary>
        /// Reads the data from the service starting at the specified location. Verifies the block's signature (if required) and adds it to the buffered data.
        /// </summary>
        /// <param name="startPosition">The starting position of the read-ahead.</param>
        /// <param name="length">The number of bytes to read ahead.</param>
        /// <returns> An TaskSequence that represents the asynchronous read action. </returns>
        private TaskSequence ReadAheadImpl(long startPosition, long length)
        {
            var webResponseTask = new InvokeTaskSequenceTask<Stream>((result) => { return this.Blob.GetStreamImpl(options, startPosition, length, result); });
            yield return webResponseTask;

            using (var stream = webResponseTask.Result)
            {
                this.LockToEtag();

                if (this.IntegrityControlVerificationEnabled && this.Blob.Properties.BlobType == BlobType.BlockBlob)
                {
                    long blockStartPosition = 0;
                    foreach (var block in this.blockList)
                    {
                        var blockSize = block.Size;

                        // Find the starting block
                        if (blockStartPosition < startPosition)
                        {
                            blockStartPosition += blockSize;
                            continue;
                        }

                        // Start creating blocks
                        var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize);
                        var md5Check = MD5.Create();
                        int totalCopied = 0, numRead = 0;
                        do
                        {
                            byte[] buffer = new byte[Constants.DefaultBufferSize];
                            var numToRead = (int)Math.Min(buffer.Length, blockSize - totalCopied);
                            var readTask = stream.ReadAsyncEx(buffer, 0, numToRead);
                            yield return readTask;

                            numRead = readTask.Result;

                            if (numRead != 0)
                            {
                                // Verify the content
                                StreamUtilities.ComputeHash(buffer, 0, numRead, md5Check);

                                var writeTask = memoryStream.WriteAsyncEx(buffer, 0, numRead);
                                yield return writeTask;
                                //var scratch = writeTask.Result; // Materialize any exceptions
                                totalCopied += numRead;
                            }
                        }
                        while (numRead != 0 && totalCopied < blockSize);

                        // If we read something, act on it
                        if (totalCopied != 0)
                        {
                            // Verify the hash
                            string blockNameMD5Value = Utilities.ExtractMD5ValueFromBlockID(block.Name);

                            if (blockNameMD5Value != StreamUtilities.GetHashValue(md5Check))
                            {
                                throw new InvalidDataException("Blob data corrupted (integrity check failed)");
                            }

                            memoryStream.Position = 0; // Rewind the stream to allow for reading

                            this.downloadedBlocksList.Add(new DownloadedBlock(startPosition, memoryStream));

                            startPosition += blockSize;
                            blockStartPosition += blockSize;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                else
                {
                    var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize);
                    var copyTask = new InvokeTaskSequenceTask(() => { return stream.WriteTo(memoryStream); });
                    yield return copyTask;

                    //var scratch = copyTask.Result; // Materialize any errors

                    memoryStream.Position = 0; // Rewind the stream to allow for reading
                    this.downloadedBlocksList.Add(new DownloadedBlock(startPosition, memoryStream));
                }
            }
        }
        /// <summary>
        /// Implementation method for the WritePage methods.
        /// </summary>
        /// <param name="pageData">The page data.</param>
        /// <param name="startOffset">The start offset.</param> 
        /// <param name="sourceStreamPosition">The beginning position of the source stream prior to execution, negative if stream is unseekable.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that writes the pages.</returns>
        private TaskSequence WritePageImpl(Stream pageData, long startOffset, long sourceStreamPosition, BlobRequestOptions options)
        {
            CommonUtils.AssertNotNull("options", options);

            long length = pageData.Length;

            // Logic to rewind stream on a retry
            // HACK : for non seekable streams we need a way to detect the retry iteration so as to only attempt to execute once.
            // The first attempt will have SourceStreamPosition = -1, which means the first iteration on a non seekable stream.
            // The second attempt will have SourceStreamPosition = -2, anything below -1 is considered an abort. Since the Impl method
            // does not have an executino context to be aware of what iteration is used the SourceStreamPosition is utilized as counter to
            // differentiate between the first attempt and a retry.
            if (sourceStreamPosition >= 0 && pageData.CanSeek)
            {
                if (sourceStreamPosition != pageData.Position)
                {
                    pageData.Seek(sourceStreamPosition, 0);
                }
            }
            else if (sourceStreamPosition < -1)
            {
                // TODO : Need to rewrite this to support buffering in XSCL2 so that retries can work on non seekable streams
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, SR.CannotRetryNonSeekableStreamError));
            }

            if (startOffset % Protocol.Constants.PageSize != 0)
            {
                CommonUtils.ArgumentOutOfRange("startOffset", startOffset);
            }

            // TODO should reuse sourceStreamPoisition when the HACK above is removed, for readability using a new local variable
            long rangeStreamOffset = pageData.CanSeek ? pageData.Position : 0;

            PutPageProperties properties = new PutPageProperties()
            {
                Range = new PageRange(startOffset, startOffset + length - rangeStreamOffset - 1),
                PageWrite = PageWrite.Update,
            };

            if ((1 + properties.Range.EndOffset - properties.Range.StartOffset) % Protocol.Constants.PageSize != 0 ||
                (1 + properties.Range.EndOffset - properties.Range.StartOffset) == 0)
            {
                CommonUtils.ArgumentOutOfRange("pageData", pageData);
            }

            var webRequest = ProtocolHelper.GetWebRequest(
                this.ServiceClient,
                options,
                (timeout) => BlobRequest.PutPage(this.TransformedAddress, timeout, properties, null));

            ////BlobRequest.AddMetadata(webRequest, this.Metadata);

            // Retrieve the stream
            var requestStreamTask = webRequest.GetRequestStreamAsync();
            yield return requestStreamTask;

            // Copy the data
            using (var outputStream = requestStreamTask.Result)
            {
                var copyTask = new InvokeTaskSequenceTask(() => { return pageData.WriteTo(outputStream); });
                yield return copyTask;

                // Materialize any exceptions
                var scratch = copyTask.Result;
            }

            // signing request needs Size to be set
            this.ServiceClient.Credentials.SignRequest(webRequest);

            // Get the response
            var responseTask = webRequest.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout);
            yield return responseTask;

            // Parse the response
            using (HttpWebResponse webResponse = responseTask.Result as HttpWebResponse)
            {
                this.ParseSizeAndLastModified(webResponse);
            }
        }
        /// <summary>
        /// Implements the flushing sequence.
        /// </summary>
        /// <returns>The sequence of events for a flush.</returns>
        private TaskSequence FlushInternal()
        {
            // If there's nothing to flush, just return;
            if (this.blockBuffer == null)
            {
                yield break;
            }

            // Rewind the stream before upload
            this.blockBuffer.Position = 0;

            InvokeTaskSequenceTask newTask;

            if (this.UseBlocks)
            {
                newTask = new InvokeTaskSequenceTask(this.UploadBlock);
            }
            else
            {
                newTask = new InvokeTaskSequenceTask(this.UploadBlob);
            }

            yield return newTask;
            var result = newTask.Result; // Materialize the results to ensure exception propagation
            Console.WriteLine(result);
        }
        /// <summary>
        /// Begins an asynchronous write operation.
        /// </summary>
        /// <param name="buffer">The buffer to write data from.</param>
        /// <param name="offset">The byte offset in buffer from which to begin writing.</param>
        /// <param name="count">The  number of bytes to write.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the write is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
        /// <returns>An IAsyncResult that represents the asynchronous write, which could still be pending.</returns>
        /// <exception cref="System.ArgumentNullException"><paramref name="buffer"/> is null.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">offset or count is negative.</exception>
        /// <exception cref="System.ObjectDisposedException">Thrown if blob is already committed/closed</exception>
        /// <remarks>The operation will be completed synchronously if the buffer is not filled</remarks>
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            this.CheckWriteState();
            StreamUtilities.CheckBufferArguments(buffer, offset, count);

            Task<NullTaskReturn> task = null;

            if (this.UseBlocks)
            {
                task = new InvokeTaskSequenceTask(() =>
                {
                    return this.WriteBlockBlobImpl(buffer, offset, count);
                });
            }
            else
            {
                task = this.WriteNonBlockedBlobImpl(buffer, offset, count);
            }

            return task.ToAsyncResult(callback, state);
        }
        /// <summary>
        /// Implementation for the DeleteIfExists method.
        /// </summary>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <param name="setResult">The set result.</param>
        /// <returns>A <see cref="TaskSequence"/> that deletes the blob if it exists.</returns>
        private TaskSequence DeleteBlobIfExistsImpl(BlobRequestOptions options, Action<bool> setResult)
        {
            CommonUtils.AssertNotNull("options", options);

            var task = new InvokeTaskSequenceTask(() => this.DeleteBlobImpl(options));

            yield return task;

            try
            {
                // Materialize exceptions
                var scratch = task.Result;

                setResult(true);
            }
            catch (StorageClientException e)
            {
                if (e.StatusCode == HttpStatusCode.NotFound)
                {
                    setResult(false);
                }
                else
                {
                    throw;
                }
            }
        }
        /// <summary>
        /// Implements the DownloadToStream method.
        /// </summary>
        /// <param name="target">The target stream.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that downloads the blob to the stream.</returns>
        internal TaskSequence DownloadToStreamImpl(Stream target, BlobRequestOptions options)
        {
            CommonUtils.AssertNotNull("options", options);

            var webResponseTask = new InvokeTaskSequenceTask<Stream>((result) => { return GetStreamImpl(options, result); });
            yield return webResponseTask;

            using (var responseStream = webResponseTask.Result)
            {
                var copyTask = new InvokeTaskSequenceTask(() => { return responseStream.WriteTo(target); });
                yield return copyTask;

                // Materialize any exceptions
                var scratch = copyTask.Result;
            }
        }
        /// <summary>
        /// Uploads the block.
        /// </summary>
        /// <param name="source">The source stream.</param>
        /// <param name="blockId">The block ID.</param>
        /// <param name="contentMD5">The content MD5.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the block.</returns>
        internal TaskSequence UploadBlock(Stream source, string blockId, string contentMD5, BlobRequestOptions options)
        {
            int id = Environment.TickCount;
            TraceHelper.WriteLine("Starting upload for id {0}", id);
            CommonUtils.AssertNotNull("options", options);

            var request = ProtocolHelper.GetWebRequest(this.ServiceClient, options, (timeout) => BlobRequest.PutBlock(this.TransformedAddress, timeout, blockId, null));
            options.AccessCondition.ApplyCondition(request);
            var length = source.Length - source.Position;
            CommonUtils.ApplyRequestOptimizations(request, length);

            if (!string.IsNullOrEmpty(contentMD5))
            {
                request.Headers.Set(HttpRequestHeader.ContentMd5, contentMD5);
            }

            this.ServiceClient.Credentials.SignRequest(request);

            var uploadTask = new InvokeTaskSequenceTask<WebResponse>((result) =>
            {
                return UploadData(request, source, result);
            });

            yield return uploadTask;

            uploadTask.Result.Close();

            TraceHelper.WriteLine("Ending upload for id {0}", id);
        }
Exemple #25
0
        /// <summary>
        /// Generates a task sequence for setting the properties of the blob service.
        /// </summary>
        /// <param name="properties">The blob service properties to set.</param>
        /// <returns>A task sequence that sets the properties of the blob service.</returns>
        private TaskSequence SetServicePropertiesImpl(ServiceProperties properties)
        {
            CommonUtils.AssertNotNull("properties", properties);

            HttpWebRequest request = BlobRequest.SetServiceProperties(this.BaseUri, this.Timeout.RoundUpToSeconds());
            using (MemoryStream memoryStream = new MemoryStream())
            {
                try
                {
                    BlobRequest.WriteServiceProperties(properties, memoryStream);
                }
                catch (InvalidOperationException invalidOpException)
                {
                    throw new ArgumentException(invalidOpException.Message, "properties");
                }

                memoryStream.Seek(0, SeekOrigin.Begin);
                CommonUtils.ApplyRequestOptimizations(request, memoryStream.Length);
                this.Credentials.SignRequest(request);

                // Get the request stream
				StorageTask<Stream> getStreamTask = request.GetRequestStreamAsyncEx();
                yield return getStreamTask;

                using (Stream requestStream = getStreamTask.Result)
                {
                    // Upload the service properties.
					StorageTask<NullTaskReturn> uploadTask = new InvokeTaskSequenceTask(() => { return (memoryStream as Stream).WriteTo(requestStream); });
                    yield return uploadTask;

                    // Materialize any exceptions.
                    NullTaskReturn scratch = uploadTask.Result;
					Console.WriteLine(scratch);
                }
            }

            // Get the web response.
			StorageTask<WebResponse> responseTask = request.GetResponseAsyncWithTimeout(this, this.Timeout);
            yield return responseTask;

            // Materialize any exceptions.
            using (HttpWebResponse response = responseTask.Result as HttpWebResponse)
            {
            }
        }
        /// <summary>
        /// Uploads the full blob.
        /// </summary>
        /// <param name="source">The source stream.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the blob.</returns>
        internal TaskSequence UploadFullBlobImpl(Stream source, BlobRequestOptions options)
        {
            CommonUtils.AssertNotNull("modifers", options);

            this.Properties.BlobType = BlobType.BlockBlob;
            var request = ProtocolHelper.GetWebRequest(
                this.ServiceClient,
                options,
                (timeout) => BlobRequest.Put(this.TransformedAddress, timeout, this.Properties, this.Properties.BlobType, null, 0));
            BlobRequest.AddMetadata(request, this.Metadata);
            var length = source.Length - source.Position;
            CommonUtils.ApplyRequestOptimizations(request, length);
            this.ServiceClient.Credentials.SignRequest(request);

            var uploadTask = new InvokeTaskSequenceTask<WebResponse>((result) =>
            {
                return UploadData(request, source, result);
            });
            yield return uploadTask;

            using (var response = uploadTask.Result as HttpWebResponse)
            {
                // Retrieve the ETag/LastModified
                this.ParseSizeAndLastModified(response);

                this.Properties.Length = length;
            }
        }
Exemple #27
0
        /// <summary>
        /// Generates a task sequence for getting the properties of the blob service.
        /// </summary>
        /// <param name="setResult">A delegate to receive the service properties.</param>
        /// <returns>A task sequence that gets the properties of the blob service.</returns>
        private TaskSequence GetServicePropertiesImpl(Action<ServiceProperties> setResult)
        {
            HttpWebRequest request = BlobRequest.GetServiceProperties(this.BaseUri, this.Timeout.RoundUpToSeconds());
            CommonUtils.ApplyRequestOptimizations(request, -1);
            this.Credentials.SignRequest(request);

            // Get the web response.
			StorageTask<WebResponse> responseTask = request.GetResponseAsyncWithTimeout(this, this.Timeout);
            yield return responseTask;

            using (HttpWebResponse response = responseTask.Result as HttpWebResponse)
            using (Stream responseStream = response.GetResponseStream())
            using (MemoryStream memoryStream = new MemoryStream())
            {
                // Download the service properties.
				StorageTask<NullTaskReturn> downloadTask = new InvokeTaskSequenceTask(() => { return responseStream.WriteTo(memoryStream); });
                yield return downloadTask;

                // Materialize any exceptions.
                NullTaskReturn scratch = downloadTask.Result;
				
   				Console.WriteLine(scratch);
				
				// Get the result from the memory stream.
                memoryStream.Seek(0, SeekOrigin.Begin);
                setResult(BlobResponse.ReadServiceProperties(memoryStream));
            }
        }
        /// <summary>
        /// Uploads the full blob with a retry sequence. The stream must be seekable.
        /// </summary>
        /// <param name="source">The source stream, which must be seekable.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the blob.</returns>
        private TaskSequence UploadFullBlobWithRetrySequenceImpl(Stream source, BlobRequestOptions options)
        {
            // Save the stream position
            long streamPos = source.Position;

            // Compute the MD5
            Task<string> md5Task = new InvokeTaskSequenceTask<string>(source.ComputeMD5);
            yield return md5Task;

            // Store the MD5 and rewind the stream
            this.Properties.ContentMD5 = md5Task.Result;
            source.Seek(streamPos, SeekOrigin.Begin);

            // Upload the blob
            Task<NullTaskReturn> uploadTask = this.UploadFullBlobWithRetryImpl(source, options);
            yield return uploadTask;

            // Materialize any exceptions
            NullTaskReturn scratch = uploadTask.Result;
        }
Exemple #29
0
        /// <summary>
        /// Reads the data from the service starting at the specified location. Verifies the block's signature (if required) and adds it to the buffered data.
        /// </summary>
        /// <param name="startPosition">The starting position of the read-ahead.</param>
        /// <param name="length">The number of bytes to read ahead.</param>
        /// <returns> An TaskSequence that represents the asynchronous read action. </returns>
        private TaskSequence ReadAheadImpl(long startPosition, long length)
        {
            var webResponseTask = new InvokeTaskSequenceTask <Stream>((result) => { return(this.Blob.GetStreamImpl(options, startPosition, length, result)); });

            yield return(webResponseTask);

            using (var stream = webResponseTask.Result)
            {
                this.LockToEtag();

                if (this.IntegrityControlVerificationEnabled && this.Blob.Properties.BlobType == BlobType.BlockBlob)
                {
                    long blockStartPosition = 0;
                    foreach (var block in this.blockList)
                    {
                        var blockSize = block.Size;

                        // Find the starting block
                        if (blockStartPosition < startPosition)
                        {
                            blockStartPosition += blockSize;
                            continue;
                        }

                        // Start creating blocks
                        var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize);
                        var md5Check = MD5.Create();
                        int totalCopied = 0, numRead = 0;
                        do
                        {
                            byte[] buffer    = new byte[Constants.DefaultBufferSize];
                            var    numToRead = (int)Math.Min(buffer.Length, blockSize - totalCopied);
                            var    readTask  = stream.ReadAsync(buffer, 0, numToRead);
                            yield return(readTask);

                            numRead = readTask.Result;

                            if (numRead != 0)
                            {
                                // Verify the content
                                StreamUtilities.ComputeHash(buffer, 0, numRead, md5Check);

                                var writeTask = memoryStream.WriteAsync(buffer, 0, numRead);
                                yield return(writeTask);

                                var scratch = writeTask.Result; // Materialize any exceptions
                                totalCopied += numRead;
                            }
                        }while (numRead != 0 && totalCopied < blockSize);

                        // If we read something, act on it
                        if (totalCopied != 0)
                        {
                            // Verify the hash
                            string blockNameMD5Value = Utilities.ExtractMD5ValueFromBlockID(block.Name);

                            if (blockNameMD5Value != StreamUtilities.GetHashValue(md5Check))
                            {
                                throw new InvalidDataException("Blob data corrupted (integrity check failed)");
                            }

                            memoryStream.Position = 0; // Rewind the stream to allow for reading

                            this.downloadedBlocksList.Add(new DownloadedBlock(startPosition, memoryStream));

                            startPosition      += blockSize;
                            blockStartPosition += blockSize;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                else
                {
                    var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize);
                    var copyTask     = new InvokeTaskSequenceTask(() => { return(stream.WriteTo(memoryStream)); });
                    yield return(copyTask);

                    var scratch = copyTask.Result; // Materialize any errors

                    memoryStream.Position = 0;     // Rewind the stream to allow for reading
                    this.downloadedBlocksList.Add(new DownloadedBlock(startPosition, memoryStream));
                }
            }
        }
        /// <summary>
        /// Commits the blob by uploading any remaining data and the blocklist asynchronously. 
        /// </summary>
        /// <returns>A sequence of events required for commit.</returns>
        private TaskSequence CommitImpl()
        {
            this.CheckWriteState();

            if (this.blockBuffer != null && this.blockBuffer.Length != 0)
            {
                var task = new InvokeTaskSequenceTask(this.FlushInternal);
                yield return task;
                var result = task.Result; // Materialize the errors
                Console.WriteLine(result);
            }

            // If all blocks are uploaded, commit
            if (this.UseBlocks)
            {
                this.SetBlobMD5();

                var task = TaskImplHelper.GetRetryableAsyncTask(
                   () =>
                   {
                       // At the convenience layer we always upload uncommitted blocks
                       List<PutBlockListItem> putBlockList = new List<PutBlockListItem>();
                       foreach (var id in this.blockList)
                       {
                           putBlockList.Add(new PutBlockListItem(id, BlockSearchMode.Uncommitted));
                       }

                       return this.Blob.ToBlockBlob.UploadBlockList(putBlockList, this.currentModifier);
                   },
                   this.currentModifier.RetryPolicy);
                yield return task;
                var result = task.Result;
                            Console.WriteLine(result);
            }

            // Now we can set the full size.
            this.Blob.Properties.Length = this.Length;

            // Clear the internal state
            this.Abort();
        }
        /// <summary>
        /// Implementation for the SetPermissions method.
        /// </summary>
        /// <param name="acl">The permissions to set.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that sets the permissions.</returns>
        private TaskSequence SetPermissionsImpl(BlobContainerPermissions acl, BlobRequestOptions options)
        {
            CommonUtils.AssertNotNull("options", options);

            var webRequest = ProtocolHelper.GetWebRequest(
                this.ServiceClient,
                options,
                (timeout) => ContainerRequest.SetAcl(this.TransformedAddress, timeout, acl.PublicAccess));

            using (var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize))
            {
                ContainerRequest.WriteSharedAccessIdentifiers(acl.SharedAccessPolicies, memoryStream);

                memoryStream.Seek(0, System.IO.SeekOrigin.Begin);

                CommonUtils.ApplyRequestOptimizations(webRequest, memoryStream.Length);

                this.ServiceClient.Credentials.SignRequest(webRequest);

                var requestStreamTask = webRequest.GetRequestStreamAsync();
                yield return requestStreamTask;

                using (var requestStream = requestStreamTask.Result)
                {
                    // Copy the data
                    var copyTask = new InvokeTaskSequenceTask(() => { return memoryStream.WriteTo(requestStream); });
                    yield return copyTask;

                    // Materialize any exceptions
                    var scratch = copyTask.Result;
                }
            }

            var task = webRequest.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout);
            yield return task;

            using (var webResponse = task.Result as HttpWebResponse)
            {
                this.ParseETagAndLastModified(webResponse);
            }
        }
        /// <summary>
        /// Implements the block writing task.
        /// </summary>
        /// <param name="buffer">The buffer to write data from.</param>
        /// <param name="offset">The byte offset in buffer from which to begin writing.</param>
        /// <param name="count">The  number of bytes to write.</param>
        /// <returns>The sequence representing the uploading of the blocks.</returns>
        private TaskSequence WriteBlockBlobImpl(byte[] buffer, int offset, int count)
        {
            if (this.blockList.Count + (count / this.blockSize) > Constants.MaxBlockNumber)
            {
                throw new ArgumentOutOfRangeException("count", String.Format(CultureInfo.CurrentCulture, SR.TooManyBlocksError, Constants.MaxBlockNumber));
            }

            while (count != 0)
            {
                // Create a buffer if we don't have one
                if (this.blockBuffer == null)
                {
                    this.CreateNewBlock();
                }

                // Copy enough data to fill the buffer.
                int numCopied = (int)Math.Min(count, this.blockSize - this.blockBuffer.Length);
                this.blockBuffer.Write(buffer, offset, numCopied);

                StreamUtilities.ComputeHash(buffer, offset, numCopied, this.blockHash);
                StreamUtilities.ComputeHash(buffer, offset, numCopied, this.blobHash);

                // Advance the location
                this.position += numCopied;
                offset += numCopied;
                count -= numCopied;

                // If buffer is full, flush
                if (this.blockBuffer.Length == this.blockSize)
                {
                    var newTask = new InvokeTaskSequenceTask(this.FlushInternal);
                    yield return newTask;

                    // Make sure task completed successfully by materializing the exception
                    var result = newTask.Result;
                    Console.WriteLine(result);
                }
            }
        }
        /// <summary>
        /// Implementation for the CreateIfNotExist method.
        /// </summary>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <param name="setResult">The set result.</param>
        /// <returns>A <see cref="TaskSequence"/> that creates the container if it does not exist.</returns>
        private TaskSequence CreateContainerIfNotExistImpl(BlobRequestOptions options, Action<bool> setResult)
        {
            CommonUtils.AssertNotNull("options", options);

            var task = new InvokeTaskSequenceTask(() => this.CreateContainerImpl(options));
            yield return task;

            try
            {
                // Materialize exceptions
                var scratch = task.Result;
                setResult(true);
            }
            catch (StorageClientException e)
            {
                if (e.StatusCode == HttpStatusCode.Conflict && e.ExtendedErrorInformation.ErrorCode == StorageErrorCodeStrings.ContainerAlreadyExists)
                {
                    setResult(false);
                }
                else
                {
                    throw;
                }
            }
        }
        /// <summary>
        /// Implementation of the *RequestWithRetry methods.
        /// </summary>
        /// <typeparam name="T">The result type of the task.</typeparam>
        /// <param name="retryOracle">The retry oracle.</param>
        /// <param name="impl">The task implementation.</param>
        /// <param name="setResult">The result report delegate.</param>
        /// <returns>A <see cref="TaskSequence"/> that performs the request with retries.</returns>
        internal static TaskSequence RequestWithRetryImpl <T>(ShouldRetry retryOracle, Func <Action <T>, TaskSequence> impl, Action <T> setResult)
        {
            int  retryCount  = 0;
            bool succeeded   = false;
            bool shouldRetry = false;

            do
            {
                var task = new InvokeTaskSequenceTask <T>(impl);
                yield return(task);

                TimeSpan delay = TimeSpan.FromMilliseconds(-1);

                try
                {
                    var result = task.Result;
                    succeeded = true;
                    setResult(result);
                }
                catch (TimeoutException e)
                {
                    shouldRetry = retryOracle != null?retryOracle(retryCount ++, e, out delay) : false;

                    // We should just throw out the exception if we are not retrying
                    if (!shouldRetry)
                    {
                        throw;
                    }
                }
                catch (StorageServerException e)
                {
                    if (e.StatusCode == HttpStatusCode.NotImplemented || e.StatusCode == HttpStatusCode.HttpVersionNotSupported)
                    {
                        throw;
                    }

                    shouldRetry = retryOracle != null?retryOracle(retryCount ++, e, out delay) : false;

                    // We should just throw out the exception if we are not retrying
                    if (!shouldRetry)
                    {
                        throw;
                    }
                }
                catch (InvalidOperationException e)
                {
                    //DataServiceClientException dsce = CommonUtils.FindInnerDataServiceClientException(e);

                    /*
                     * // rethrow 400 class errors immediately as they can't be retried
                     * // 501 (Not Implemented) and 505 (HTTP Version Not Supported) shouldn't be retried either.
                     * if (dsce != null &&
                     * ((dsce.StatusCode >= 400 && dsce.StatusCode < 500)
                     || dsce.StatusCode == (int)HttpStatusCode.NotImplemented
                     || dsce.StatusCode == (int)HttpStatusCode.HttpVersionNotSupported))
                     ||{
                     ||throw;
                     ||}*/

                    // If it is BlobTypeMismatchExceptionMessage, we should throw without retry
                    if (e.Message == SR.BlobTypeMismatchExceptionMessage)
                    {
                        throw;
                    }

                    shouldRetry = retryOracle != null?retryOracle(retryCount ++, e, out delay) : false;

                    // We should just throw out the exception if we are not retrying
                    if (!shouldRetry)
                    {
                        throw;
                    }
                }

                if (!succeeded && shouldRetry && delay > TimeSpan.Zero)
                {
                    using (DelayTask delayTask = new DelayTask(delay))
                    {
                        yield return(delayTask);

                        // Materialize exceptions
                        var scratch = delayTask.Result;
                        Console.WriteLine(scratch);
                    }
                }
            }while (!succeeded && shouldRetry);
        }
        /// <summary>
        /// Uploads the block list.
        /// </summary>
        /// <param name="blocks">The blocks to upload.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the block list.</returns>
        internal TaskSequence UploadBlockList(List<PutBlockListItem> blocks, BlobRequestOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException("modifers");
            }

            var request = ProtocolHelper.GetWebRequest(this.ServiceClient, options, (timeout) => BlobRequest.PutBlockList(this.TransformedAddress, timeout, this.Properties, null));

            options.AccessCondition.ApplyCondition(request);
            BlobRequest.AddMetadata(request, this.Metadata);

            using (var memoryStream = new SmallBlockMemoryStream(Constants.DefaultBufferSize))
            {
                BlobRequest.WriteBlockListBody(blocks, memoryStream);

                CommonUtils.ApplyRequestOptimizations(request, memoryStream.Length);

                memoryStream.Seek(0, SeekOrigin.Begin);

                // Compute the MD5
                var md5 = System.Security.Cryptography.MD5.Create();

                request.Headers[HttpRequestHeader.ContentMd5] = Convert.ToBase64String(md5.ComputeHash(memoryStream));

                this.ServiceClient.Credentials.SignRequest(request);

                memoryStream.Seek(0, SeekOrigin.Begin);

                // Retrieve the stream
                var requestStreamTask = request.GetRequestStreamAsync();
                yield return requestStreamTask;

                using (Stream requestStream = requestStreamTask.Result)
                {
                    // Copy the data
                    var copyTask = new InvokeTaskSequenceTask(() => { return memoryStream.WriteTo(requestStream); });
                    yield return copyTask;

                    // Materialize any exceptions
                    var scratch = copyTask.Result;
                    Console.WriteLine(scratch);
                }
            }

            // Get the response
            var responseTask = request.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout);
            yield return responseTask;

            using (var response = responseTask.Result as HttpWebResponse)
            {
                ParseSizeAndLastModified(response);
                this.Properties.Length = 0;
            }
        }
        /// <summary>
        /// Perform a parallel upload of blocks for a blob from a given stream.
        /// </summary>
        /// <param name="uploadFunc">The upload func.</param>
        /// <returns>A <see cref="TaskSequence"/> that uploads the blob in parallel.</returns>
        /// <remarks>
        /// The operation is done as a series of alternate producer and consumer tasks. The producer tasks dispense out
        /// chunks of source stream as fixed size blocks. This is done in serial order on a thread using InvokeTaskSequence's
        /// serial execution. The consumer tasks upload each block in parallel on multiple thread. The producer thread waits
        /// for at least one consumer task to finish before adding more producer tasks. The producer thread quits when no
        /// more data can be read from the stream and no other pending consumer tasks.
        /// </remarks>
        internal TaskSequence ParallelExecute(
            Func<SmallBlockMemoryStream, string, string, BlobRequestOptions, Task<NullTaskReturn>> uploadFunc)
        {
            bool moreToUpload = true;
            List<IAsyncResult> asyncResults = new List<IAsyncResult>();

            Random rand = new Random();
            long blockIdSequenceNumber = (long)rand.Next() << 32;
            blockIdSequenceNumber += rand.Next();

            do
            {
                int currentPendingTasks = asyncResults.Count;

                // Step 1
                // Create producer tasks in a serial order as stream can only be read sequentially
                for (int i = currentPendingTasks; i < this.parellelism && moreToUpload; i++)
                {
                    string blockId = null;
                    string blockHash = null;
                    SmallBlockMemoryStream blockAsStream = null;
                    blockIdSequenceNumber++;

                    InvokeTaskSequenceTask producerTask = new InvokeTaskSequenceTask(() =>
                        this.DispenseBlockStream(
                        blockIdSequenceNumber,
                            (stream, id, hashVal) =>
                            {
                                blockAsStream = stream;
                                blockId = id;
                                blockHash = hashVal;
                            }));

                    yield return producerTask;

                    this.producerTasksCreated++;

                    var scatch = producerTask.Result;

                    if (blockAsStream == null)
                    {
                        TraceHelper.WriteLine("No more upload tasks");
                        moreToUpload = false;
                    }
                    else
                    {
                        // Step 2
                        // Fire off consumer tasks that may finish on other threads;
                        var task = uploadFunc(blockAsStream, blockId, blockHash, this.options);
                        IAsyncResult asyncresult = task.ToAsyncResult(null, null);
                        this.consumerTasksCreated++;

                        asyncResults.Add(asyncresult);
                    }
                }

                // Step 3
                // Wait for 1 or more consumer tasks to finish inorder to bound set of parallel tasks
                if (asyncResults.Count > 0)
                {
                    int waitTimeout = GetWaitTimeout(this.options);

                    TraceHelper.WriteLine("Starting wait");

                    int waitResult = WaitHandle.WaitAny(asyncResults.Select(result => result.AsyncWaitHandle).ToArray(), waitTimeout);

                    TraceHelper.WriteLine("Ending wait");

                    if (waitResult == WaitHandle.WaitTimeout)
                    {
                        throw TimeoutHelper.ThrowTimeoutError(this.options.Timeout.Value);
                    }

                    CompleteAsyncresult(asyncResults, waitResult);

                    // Optimize away any other completed tasks
                    for (int index = 0; index < asyncResults.Count; index++)
                    {
                        IAsyncResult result = asyncResults[index];
                        if (result.IsCompleted)
                        {
                            CompleteAsyncresult(asyncResults, index);
                            index--;
                        }
                    }
                }
            }
            while (moreToUpload || asyncResults.Count != 0);

            TraceHelper.WriteLine(
                "Total producer tasks created {0}, consumer tasks created {1} ",
                this.producerTasksCreated,
                this.consumerTasksCreated);

            var commitTask = TaskImplHelper.GetRetryableAsyncTask(this.CommitBlob, this.options.RetryPolicy);

            yield return commitTask;
            var commitTaskResult = commitTask.Result;
        }
        /// <summary>Generates a task sequence for getting the properties of the queue service.</summary>
        /// <param name="setResult">A delegate to receive the service properties. </param>
        /// <returns>A task sequence that gets the properties of the queue service. </returns>
        private TaskSequence GetServicePropertiesImpl(Action<ServiceProperties> setResult)
        {
            var request = QueueRequest.GetServiceProperties(this.BaseUri, this.Timeout.RoundUpToSeconds());
            CommonUtils.ApplyRequestOptimizations(request, -1);
            this.Credentials.SignRequest(request);

            // Get the web response.
            var responseTask = request.GetResponseAsyncWithTimeout(this, this.Timeout);
            yield return responseTask;

            using (var response = responseTask.Result as HttpWebResponse)
            {
                Debug.Assert(response != null, "response != null");
                using (var responseStream = response.GetResponseStream())
                using (var memoryStream = new MemoryStream())
                {
                    // Download the service properties.
                    Task<NullTaskReturn> downloadTask =
                        new InvokeTaskSequenceTask(() => responseStream.WriteTo(memoryStream));
                    yield return downloadTask;

                    // Materialize any exceptions.
                    var scratch = downloadTask.Result;

                    // Get the result from the memory stream.
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    setResult(QueueResponse.ReadServiceProperties(memoryStream));
                }
            }
        }