/// <summary> /// Begins an asynchronous read operation. /// </summary> /// <param name="buffer">The buffer to read the data into.</param> /// <param name="offset">The byte offset in buffer at which to begin writing /// data read from the stream.</param> /// <param name="count">The maximum number of bytes to read.</param> /// <param name="callback">An optional asynchronous callback, to be called when the read is complete.</param> /// <param name="state">A user-provided object that distinguishes this particular asynchronous read request from other requests.</param> /// <returns>An <c>IAsyncResult</c> that represents the asynchronous read, which could still be pending.</returns> public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { CommonUtils.AssertNotNull("buffer", buffer); CommonUtils.AssertInBounds("offset", offset, 0, buffer.Length); CommonUtils.AssertInBounds("count", count, 0, buffer.Length - offset); ChainedAsyncResult <int> chainedResult = new ChainedAsyncResult <int>(callback, state); if (this.lastException != null) { chainedResult.OnComplete(this.lastException); } else { if (!this.isLengthAvailable) { this.blob.BeginFetchAttributes( this.accessCondition, this.options, this.operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.blob.EndFetchAttributes(ar); } catch (Exception e) { this.lastException = e; chainedResult.OnComplete(this.lastException); return; } this.LockToETag(); this.isLengthAvailable = true; if (string.IsNullOrEmpty(this.blob.Properties.ContentMD5)) { this.blobMD5 = null; } this.DispatchRead(chainedResult, buffer, offset, count); }, null /* state */); } else { this.DispatchRead(chainedResult, buffer, offset, count); } } return(chainedResult); }
public ICancellableAsyncResult BeginListBlobsSegmented(string prefix, bool useFlatBlobListing, BlobListingDetails blobListingDetails, int?maxResults, BlobContinuationToken currentToken, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { string containerName; string listingPrefix; CloudBlobClient.ParseUserPrefix(prefix, out containerName, out listingPrefix); CloudBlobContainer container = this.GetContainerReference(containerName); ChainedAsyncResult <BlobResultSegment> result = new ChainedAsyncResult <BlobResultSegment>(callback, state); ICancellableAsyncResult asyncResult = container.BeginListBlobsSegmented( listingPrefix, useFlatBlobListing, blobListingDetails, maxResults, currentToken, options, operationContext, ar => { result.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { result.Result = container.EndListBlobsSegmented(ar); result.OnComplete(); } catch (Exception e) { result.OnComplete(e); } }, null /* state */); result.CancelDelegate = asyncResult.Cancel; return(result); }
public ICancellableAsyncResult BeginOpenWrite(long? size, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.PageBlob, this.ServiceClient); bool createNew = size.HasValue; ChainedAsyncResult<Stream> chainedResult = new ChainedAsyncResult<Stream>(callback, state); ICancellableAsyncResult result; if (createNew) { result = this.BeginCreate( size.Value, accessCondition, modifiedOptions, operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndCreate(ar); if (accessCondition != null) { accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId); } chainedResult.Result = new BlobWriteStream(this, size.Value, createNew, accessCondition, modifiedOptions, operationContext); chainedResult.OnComplete(); } catch (Exception e) { chainedResult.OnComplete(e); } }, null /* state */); } else { if (modifiedOptions.StoreBlobContentMD5.Value) { throw new ArgumentException(SR.MD5NotPossible); } result = this.BeginFetchAttributes( accessCondition, modifiedOptions, operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndFetchAttributes(ar); if (accessCondition != null) { accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId); } chainedResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext); chainedResult.OnComplete(); } catch (Exception e) { chainedResult.OnComplete(e); } }, null /* state */); } chainedResult.CancelDelegate = result.Cancel; return chainedResult; }
private void DeleteIfExistsHandler(DeleteSnapshotsOption deleteSnapshotsOption, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, ChainedAsyncResult<bool> chainedResult) { lock (chainedResult.CancellationLockerObject) { ICancellableAsyncResult savedExistsResult = this.BeginExists( options, operationContext, existsResult => { chainedResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously); lock (chainedResult.CancellationLockerObject) { chainedResult.CancelDelegate = null; try { bool exists = this.EndExists(existsResult); if (!exists) { chainedResult.Result = false; chainedResult.OnComplete(); return; } ICancellableAsyncResult savedDeleteResult = this.BeginDelete( deleteSnapshotsOption, accessCondition, options, operationContext, deleteResult => { chainedResult.UpdateCompletedSynchronously(deleteResult.CompletedSynchronously); chainedResult.CancelDelegate = null; try { this.EndDelete(deleteResult); chainedResult.Result = true; chainedResult.OnComplete(); } catch (StorageException e) { if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound) { chainedResult.Result = false; chainedResult.OnComplete(); } else { chainedResult.OnComplete(e); } } catch (Exception e) { chainedResult.OnComplete(e); } }, null /* state */); chainedResult.CancelDelegate = savedDeleteResult.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } catch (Exception e) { chainedResult.OnComplete(e); } } }, null /* state */); chainedResult.CancelDelegate = savedExistsResult.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } }
/// <summary> /// Begins an asynchronous read operation. /// </summary> /// <param name="buffer">The buffer to read the data into.</param> /// <param name="offset">The byte offset in buffer at which to begin writing /// data read from the stream.</param> /// <param name="count">The maximum number of bytes to read.</param> /// <param name="callback">An optional asynchronous callback, to be called when the read is complete.</param> /// <param name="state">A user-provided object that distinguishes this particular asynchronous read request from other requests.</param> /// <returns>An <c>IAsyncResult</c> that represents the asynchronous read, which could still be pending.</returns> public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { CommonUtils.AssertNotNull("buffer", buffer); CommonUtils.AssertInBounds("offset", offset, 0, buffer.Length); CommonUtils.AssertInBounds("count", count, 0, buffer.Length - offset); ChainedAsyncResult<int> chainedResult = new ChainedAsyncResult<int>(callback, state); if (this.lastException != null) { chainedResult.OnComplete(this.lastException); } else { if (!this.isLengthAvailable) { this.blob.BeginFetchAttributes( this.accessCondition, this.options, this.operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.blob.EndFetchAttributes(ar); } catch (Exception e) { this.lastException = e; chainedResult.OnComplete(this.lastException); return; } this.LockToETag(); this.isLengthAvailable = true; if (string.IsNullOrEmpty(this.blob.Properties.ContentMD5)) { this.blobMD5 = null; } this.DispatchRead(chainedResult, buffer, offset, count); }, null /* state */); } else { this.DispatchRead(chainedResult, buffer, offset, count); } } return chainedResult; }
/// <summary> /// Dispatches a read operation that either reads from the cache or makes a call to /// the server. /// </summary> /// <param name="chainedResult">The reference to the pending asynchronous request to finish.</param> /// <param name="buffer">The buffer to read the data into.</param> /// <param name="offset">The byte offset in buffer at which to begin writing /// data read from the stream.</param> /// <param name="count">The maximum number of bytes to read.</param> /// <remarks>Even though this code looks like it can run in parallel, the semaphore only allows /// 1 active read. This is required because of caching.</remarks> private void DispatchRead(ChainedAsyncResult<int> chainedResult, byte[] buffer, int offset, int count) { if ((this.currentOffset == this.Length) || (count == 0)) { chainedResult.Result = 0; chainedResult.OnComplete(); } else { this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { // If the buffer is already consumed, dispatch another read. if (this.buffer.Position == this.buffer.Length) { int readSize = (int)Math.Min(this.blob.StreamMinimumReadSizeInBytes, this.Length - this.currentOffset); if (this.options.UseTransactionalMD5.Value) { readSize = Math.Min(readSize, Constants.MaxBlockSize); } this.buffer.SetLength(0); this.blob.BeginDownloadRangeToStream( this.buffer, this.currentOffset, readSize, this.accessCondition, this.options, this.operationContext, ar => { try { this.blob.EndDownloadRangeToStream(ar); } catch (Exception e) { this.lastException = e; } if (this.lastException == null) { this.buffer.Seek(0, SeekOrigin.Begin); this.LockToETag(); // Read as much as we can from the buffer. int result = this.buffer.Read(buffer, offset, count); this.currentOffset += result; chainedResult.Result = result; this.VerifyBlobMD5(buffer, offset, result); } // Calling this here will make reentrancy safer, as the user // does not yet know the operation has completed. this.parallelOperationSemaphore.Release(); // End the async result chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); chainedResult.OnComplete(this.lastException); }, null /* state */); } else { // Read as much as we can from the buffer. int result = this.buffer.Read(buffer, offset, count); this.currentOffset += result; chainedResult.Result = result; this.VerifyBlobMD5(buffer, offset, result); // Calling this here will make reentrancy safer, as the user // does not yet know the operation has completed. this.parallelOperationSemaphore.Release(); // End the async result chainedResult.UpdateCompletedSynchronously(calledSynchronously); chainedResult.OnComplete(this.lastException); } } catch (Exception e) { this.lastException = e; // End the async result chainedResult.UpdateCompletedSynchronously(calledSynchronously); chainedResult.OnComplete(this.lastException); } }); } }
/// <summary> /// Starts an asynchronous WritePages operation as soon as the parallel /// operation semaphore becomes available. /// </summary> /// <param name="pageData">Data to be uploaded</param> /// <param name="offset">Offset within the page blob</param> /// <param name="contentMD5">MD5 hash of the data to be uploaded</param> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void WritePages(Stream pageData, long offset, string contentMD5, ChainedAsyncResult<NullType> asyncResult) { Interlocked.Increment(ref this.pendingWrites); this.noPendingWritesEvent.Reset(); bool completedSynchronously = this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); } try { this.pageBlob.BeginWritePages( pageData, offset, contentMD5, this.accessCondition, this.options, this.operationContext, ar => { try { this.pageBlob.EndWritePages(ar); } catch (Exception e) { this.lastException = e; } // This must be called before calling the user's callback // in case the callback is blocking. if (Interlocked.Decrement(ref this.pendingWrites) == 0) { this.noPendingWritesEvent.Set(); } this.parallelOperationSemaphore.Release(); // Do not try-catch this portion, as we are done anyway. // We should let the user handle the exception. if (!calledSynchronously && (asyncResult != null)) { // End the async result asyncResult.OnComplete(this.lastException); } }, null /* state */); } catch (Exception e) { this.lastException = e; // End the async result if (asyncResult != null) { asyncResult.OnComplete(e); } } }); if (completedSynchronously && (asyncResult != null)) { asyncResult.OnComplete(); } }
private void CreateIfNotExistsHandler(BlobRequestOptions options, OperationContext operationContext, ChainedAsyncResult<bool> chainedResult) { lock (chainedResult.CancellationLockerObject) { ICancellableAsyncResult savedExistsResult = this.BeginExists( options, operationContext, existsResult => { chainedResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously); lock (chainedResult.CancellationLockerObject) { chainedResult.CancelDelegate = null; try { bool exists = this.EndExists(existsResult); if (exists) { chainedResult.Result = false; chainedResult.OnComplete(); return; } ICancellableAsyncResult savedCreateResult = this.BeginCreate( options, operationContext, createResult => { chainedResult.UpdateCompletedSynchronously(createResult.CompletedSynchronously); chainedResult.CancelDelegate = null; try { this.EndCreate(createResult); chainedResult.Result = true; chainedResult.OnComplete(); } catch (StorageException e) { if ((e.RequestInformation.ExtendedErrorInformation != null) && (e.RequestInformation.ExtendedErrorInformation.ErrorCode == BlobErrorCodeStrings.ContainerAlreadyExists)) { chainedResult.Result = false; chainedResult.OnComplete(); } else { chainedResult.OnComplete(e); } } catch (Exception e) { chainedResult.OnComplete(e); } }, null /* state */); chainedResult.CancelDelegate = savedCreateResult.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } catch (Exception e) { chainedResult.OnComplete(e); } } }, null /* state */); chainedResult.CancelDelegate = savedExistsResult.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } }
public ICancellableAsyncResult BeginUploadFromStream(Stream source, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { CommonUtils.AssertNotNull("source", source); this.attributes.AssertNoSnapshot(); if (!source.CanSeek) { throw new InvalidOperationException(); } long size = source.Length - source.Position; if ((size % Constants.PageSize) != 0) { throw new ArgumentException(SR.InvalidPageSize, "source"); } BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.PageBlob, this.ServiceClient); DateTime? expiryTime = modifiedOptions.MaximumExecutionTime.HasValue ? DateTime.Now + modifiedOptions.MaximumExecutionTime.Value : (DateTime?)null; OperationContext tempOperationContext = new OperationContext(); ExecutionState<NullType> executionState = new ExecutionState<NullType>(null /* cmd */, modifiedOptions.RetryPolicy, tempOperationContext); ChainedAsyncResult<NullType> chainedResult = new ChainedAsyncResult<NullType>(callback, state); lock (chainedResult.CancellationLockerObject) { ICancellableAsyncResult result = this.BeginOpenWrite( size, accessCondition, modifiedOptions, operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); lock (chainedResult.CancellationLockerObject) { chainedResult.CancelDelegate = null; try { Stream blobStream = this.EndOpenWrite(ar); source.WriteToAsync( blobStream, null /* maxLength */, expiryTime, false, executionState, tempOperationContext, null /* streamCopyState */, completedState => { chainedResult.UpdateCompletedSynchronously(executionState.CompletedSynchronously); try { blobStream.Close(); chainedResult.OnComplete(executionState.ExceptionRef); } catch (Exception e) { chainedResult.OnComplete(e); } }); chainedResult.CancelDelegate = executionState.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } catch (Exception e) { chainedResult.OnComplete(e); } } }, null /* state */); chainedResult.CancelDelegate = result.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } return chainedResult; }
/// <summary> /// Begins an asynchronous operation to open a stream for writing to the blob. /// </summary> /// <param name="accessCondition">An <see cref="AccessCondition"/> object that represents the access conditions for the blob. If <c>null</c>, no condition is used.</param> /// <param name="options">A <see cref="BlobRequestOptions"/> object that specifies any additional options for the request.</param> /// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param> /// <param name="callback">The callback delegate that will receive notification when the asynchronous operation completes.</param> /// <param name="state">A user-defined object that will be passed to the callback delegate.</param> /// <returns>An <see cref="ICancellableAsyncResult"/> that references the asynchronous operation.</returns> public ICancellableAsyncResult BeginOpenWrite(AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient); ChainedAsyncResult<Stream> chainedResult = new ChainedAsyncResult<Stream>(callback, state); if ((accessCondition != null) && accessCondition.IsConditional) { ICancellableAsyncResult result = this.BeginFetchAttributes( accessCondition, modifiedOptions, operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndFetchAttributes(ar); } catch (StorageException e) { if ((e.RequestInformation != null) && (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound) && string.IsNullOrEmpty(accessCondition.IfMatchETag)) { // If we got a 404 and the condition was not an If-Match, // we should continue with the operation. } else { chainedResult.OnComplete(e); } } catch (Exception e) { chainedResult.OnComplete(e); } chainedResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext); chainedResult.OnComplete(); }, null /* state */); chainedResult.CancelDelegate = result.Cancel; } else { chainedResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext); chainedResult.OnComplete(); } return chainedResult; }
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { ChainedAsyncResult<NullType> result = new ChainedAsyncResult<NullType>(callback, state); if (this.completeSynchronously) { result.UpdateCompletedSynchronously(this.completeSynchronously); try { this.Write(buffer, offset, count); result.OnComplete(); } catch (Exception e) { result.OnComplete(e); } } else { ThreadPool.QueueUserWorkItem(_ => { result.UpdateCompletedSynchronously(this.completeSynchronously); try { this.Write(buffer, offset, count); result.OnComplete(); } catch (Exception e) { result.OnComplete(e); } }, null); } return result; }
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { ChainedAsyncResult<int> result = new ChainedAsyncResult<int>(callback, state); if (this.completeSynchronously) { result.UpdateCompletedSynchronously(this.completeSynchronously); result.Result = this.Read(buffer, offset, count); result.OnComplete(); } else { ThreadPool.QueueUserWorkItem(_ => { result.UpdateCompletedSynchronously(this.completeSynchronously); result.Result = this.Read(buffer, offset, count); result.OnComplete(); }, null); } return result; }
/// <summary> /// Dispatches a read operation that either reads from the cache or makes a call to /// the server. /// </summary> /// <param name="chainedResult">The reference to the pending asynchronous request to finish.</param> /// <param name="buffer">The buffer to read the data into.</param> /// <param name="offset">The byte offset in buffer at which to begin writing /// data read from the stream.</param> /// <param name="count">The maximum number of bytes to read.</param> /// <remarks>Even though this code looks like it can run in parallel, the semaphore only allows /// 1 active read. This is required because of caching.</remarks> private void DispatchRead(ChainedAsyncResult <int> chainedResult, byte[] buffer, int offset, int count) { if ((this.currentOffset == this.Length) || (count == 0)) { chainedResult.Result = 0; chainedResult.OnComplete(); } else { this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { // If the buffer is already consumed, dispatch another read. if (this.buffer.Position == this.buffer.Length) { int readSize = (int)Math.Min(this.blob.StreamMinimumReadSizeInBytes, this.Length - this.currentOffset); if (this.options.UseTransactionalMD5.Value) { readSize = Math.Min(readSize, Constants.MaxBlockSize); } this.buffer.SetLength(0); this.blob.BeginDownloadRangeToStream( this.buffer, this.currentOffset, readSize, this.accessCondition, this.options, this.operationContext, ar => { try { this.blob.EndDownloadRangeToStream(ar); } catch (Exception e) { this.lastException = e; } if (this.lastException == null) { this.buffer.Seek(0, SeekOrigin.Begin); this.LockToETag(); // Read as much as we can from the buffer. int result = this.buffer.Read(buffer, offset, count); this.currentOffset += result; chainedResult.Result = result; this.VerifyBlobMD5(buffer, offset, result); } // Calling this here will make reentrancy safer, as the user // does not yet know the operation has completed. this.parallelOperationSemaphore.Release(); // End the async result chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); chainedResult.OnComplete(this.lastException); }, null /* state */); } else { // Read as much as we can from the buffer. int result = this.buffer.Read(buffer, offset, count); this.currentOffset += result; chainedResult.Result = result; this.VerifyBlobMD5(buffer, offset, result); // Calling this here will make reentrancy safer, as the user // does not yet know the operation has completed. this.parallelOperationSemaphore.Release(); // End the async result chainedResult.UpdateCompletedSynchronously(calledSynchronously); chainedResult.OnComplete(this.lastException); } } catch (Exception e) { this.lastException = e; // End the async result chainedResult.UpdateCompletedSynchronously(calledSynchronously); chainedResult.OnComplete(this.lastException); } }); } }
public ICancellableAsyncResult BeginWritePages(Stream pageData, long startOffset, string contentMD5, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.PageBlob, this.ServiceClient); bool requiresContentMD5 = (contentMD5 == null) && modifiedOptions.UseTransactionalMD5.Value; operationContext = operationContext ?? new OperationContext(); ChainedAsyncResult<NullType> chainedResult = new ChainedAsyncResult<NullType>(callback, state); if (pageData.CanSeek && !requiresContentMD5) { this.WritePagesHandler(pageData, startOffset, contentMD5, accessCondition, modifiedOptions, operationContext, chainedResult); } else { DateTime? expiryTime = modifiedOptions.MaximumExecutionTime.HasValue ? DateTime.Now + modifiedOptions.MaximumExecutionTime.Value : (DateTime?)null; OperationContext tempOperationContext = new OperationContext(); ExecutionState<NullType> executionState = new ExecutionState<NullType>(null /* cmd */, modifiedOptions.RetryPolicy, tempOperationContext); chainedResult.CancelDelegate = executionState.Cancel; Stream seekableStream; Stream writeToStream; if (pageData.CanSeek) { seekableStream = pageData; writeToStream = Stream.Null; } else { seekableStream = new MemoryStream(); writeToStream = seekableStream; } long startPosition = seekableStream.Position; StreamDescriptor streamCopyState = new StreamDescriptor(); pageData.WriteToAsync( writeToStream, Constants.MaxBlockSize, expiryTime, requiresContentMD5, executionState, tempOperationContext, streamCopyState, _ => { chainedResult.UpdateCompletedSynchronously(executionState.CompletedSynchronously); if (executionState.ExceptionRef != null) { chainedResult.OnComplete(executionState.ExceptionRef); } else { try { if (requiresContentMD5) { contentMD5 = streamCopyState.Md5; } seekableStream.Position = startPosition; this.WritePagesHandler(seekableStream, startOffset, contentMD5, accessCondition, modifiedOptions, operationContext, chainedResult); } catch (Exception e) { chainedResult.OnComplete(e); } } }); } return chainedResult; }
public ICancellableAsyncResult BeginUploadFromStream(Stream source, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { CommonUtils.AssertNotNull("source", source); this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient); DateTime? expiryTime = modifiedOptions.MaximumExecutionTime.HasValue ? DateTime.Now + modifiedOptions.MaximumExecutionTime.Value : (DateTime?)null; OperationContext tempOperationContext = new OperationContext(); ExecutionState<NullType> executionState = new ExecutionState<NullType>(null /* cmd */, modifiedOptions.RetryPolicy, tempOperationContext); ChainedAsyncResult<NullType> chainedResult = new ChainedAsyncResult<NullType>(callback, state) { CancelDelegate = executionState.Cancel, }; if ((this.ServiceClient.ParallelOperationThreadCount == 1) && source.CanSeek && ((source.Length - source.Position) <= this.ServiceClient.SingleBlobUploadThresholdInBytes)) { if (modifiedOptions.StoreBlobContentMD5.Value) { long startPosition = source.Position; StreamDescriptor streamCopyState = new StreamDescriptor(); source.WriteToAsync( Stream.Null, null /* maxLength */, expiryTime, true, executionState, tempOperationContext, streamCopyState, completedState => { chainedResult.UpdateCompletedSynchronously(executionState.CompletedSynchronously); try { lock (chainedResult.CancellationLockerObject) { chainedResult.CancelDelegate = null; if (completedState.ExceptionRef != null) { chainedResult.OnComplete(completedState.ExceptionRef); } else { source.Position = startPosition; UploadFromStreamHandler(source, streamCopyState.Md5, accessCondition, operationContext, modifiedOptions, chainedResult); } } } catch (Exception e) { chainedResult.OnComplete(e); } }); } else { this.UploadFromStreamHandler(source, null /* contentMD5 */, accessCondition, operationContext, modifiedOptions, chainedResult); } } else { Stream blobStream = this.OpenWrite(accessCondition, modifiedOptions, operationContext); source.WriteToAsync( blobStream, null /* maxLength */, expiryTime, false, executionState, tempOperationContext, null /* streamCopyState */, completedState => { chainedResult.UpdateCompletedSynchronously(executionState.CompletedSynchronously); try { blobStream.Close(); chainedResult.OnComplete(executionState.ExceptionRef); } catch (Exception e) { chainedResult.OnComplete(e); } }); } return chainedResult; }
private void WritePagesHandler(Stream pageData, long startOffset, string contentMD5, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, ChainedAsyncResult<NullType> chainedResult) { lock (chainedResult.CancellationLockerObject) { ICancellableAsyncResult result = Executor.BeginExecuteAsync( this.PutPageImpl(pageData, startOffset, contentMD5, accessCondition, options), options.RetryPolicy, operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { Executor.EndExecuteAsync<NullType>(ar); chainedResult.OnComplete(); } catch (Exception e) { chainedResult.OnComplete(e); } }, null /* asyncState */); chainedResult.CancelDelegate = result.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } } }
private void UploadFromStreamHandler(Stream source, string contentMD5, AccessCondition accessCondition, OperationContext operationContext, BlobRequestOptions options, ChainedAsyncResult<NullType> chainedResult) { ICancellableAsyncResult result = Executor.BeginExecuteAsync( this.PutBlobImpl(source, contentMD5, accessCondition, options), options.RetryPolicy, operationContext, ar => { chainedResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { Executor.EndExecuteAsync<NullType>(ar); chainedResult.OnComplete(); } catch (Exception e) { chainedResult.OnComplete(e); } }, null /* asyncState */); chainedResult.CancelDelegate = result.Cancel; if (chainedResult.CancelRequested) { chainedResult.Cancel(); } }
public ICancellableAsyncResult BeginListBlobsSegmented(string prefix, bool useFlatBlobListing, BlobListingDetails blobListingDetails, int? maxResults, BlobContinuationToken currentToken, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { string containerName; string listingPrefix; CloudBlobClient.ParseUserPrefix(prefix, out containerName, out listingPrefix); CloudBlobContainer container = this.GetContainerReference(containerName); ChainedAsyncResult<BlobResultSegment> result = new ChainedAsyncResult<BlobResultSegment>(callback, state); ICancellableAsyncResult asyncResult = container.BeginListBlobsSegmented( listingPrefix, useFlatBlobListing, blobListingDetails, maxResults, currentToken, options, operationContext, ar => { result.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { result.Result = container.EndListBlobsSegmented(ar); result.OnComplete(); } catch (Exception e) { result.OnComplete(e); } }, null /* state */); result.CancelDelegate = asyncResult.Cancel; return result; }
/// <summary> /// Starts an asynchronous WritePages operation as soon as the parallel /// operation semaphore becomes available. /// </summary> /// <param name="pageData">Data to be uploaded</param> /// <param name="offset">Offset within the page blob</param> /// <param name="contentMD5">MD5 hash of the data to be uploaded</param> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void WritePages(Stream pageData, long offset, string contentMD5, ChainedAsyncResult <NullType> asyncResult) { Interlocked.Increment(ref this.pendingWrites); this.noPendingWritesEvent.Reset(); bool completedSynchronously = this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); } try { this.pageBlob.BeginWritePages( pageData, offset, contentMD5, this.accessCondition, this.options, this.operationContext, ar => { try { this.pageBlob.EndWritePages(ar); } catch (Exception e) { this.lastException = e; } // This must be called before calling the user's callback // in case the callback is blocking. if (Interlocked.Decrement(ref this.pendingWrites) == 0) { this.noPendingWritesEvent.Set(); } this.parallelOperationSemaphore.Release(); // Do not try-catch this portion, as we are done anyway. // We should let the user handle the exception. if (!calledSynchronously && (asyncResult != null)) { // End the async result asyncResult.OnComplete(this.lastException); } }, null /* state */); } catch (Exception e) { this.lastException = e; // End the async result if (asyncResult != null) { asyncResult.OnComplete(e); } } }); if (completedSynchronously && (asyncResult != null)) { asyncResult.OnComplete(); } }