public ICancellableAsyncResult BeginOpenRead(AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { StorageAsyncResult<Stream> storageAsyncResult = new StorageAsyncResult<Stream>(callback, state); ICancellableAsyncResult result = this.BeginFetchAttributes( accessCondition, options, operationContext, ar => { try { this.EndFetchAttributes(ar); storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); AccessCondition streamAccessCondition = AccessCondition.CloneConditionWithETag(accessCondition, this.Properties.ETag); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false); storageAsyncResult.Result = new BlobReadStream(this, streamAccessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); storageAsyncResult.CancelDelegate = result.Cancel; return storageAsyncResult; }
/// <summary> /// Dispatches a write operation. /// </summary> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void DispatchWrite(StorageAsyncResult <NullType> asyncResult) { if (this.internalBuffer.Length == 0) { if (asyncResult != null) { asyncResult.OnComplete(this.lastException); } return; } MultiBufferMemoryStream bufferToUpload = this.internalBuffer; this.internalBuffer = new MultiBufferMemoryStream(this.Blob.ServiceClient.BufferManager); bufferToUpload.Seek(0, SeekOrigin.Begin); string bufferMD5 = null; if (this.blockMD5 != null) { bufferMD5 = this.blockMD5.ComputeHash(); this.blockMD5.Dispose(); this.blockMD5 = new MD5Wrapper(); } if (this.blockBlob != null) { string blockId = this.GetCurrentBlockId(); this.blockList.Add(blockId); this.WriteBlock(bufferToUpload, blockId, bufferMD5, asyncResult); } else { if ((bufferToUpload.Length % Constants.PageSize) != 0) { this.lastException = new IOException(SR.InvalidPageSize); throw this.lastException; } long offset = this.currentPageOffset; this.currentPageOffset += bufferToUpload.Length; this.WritePages(bufferToUpload, offset, bufferMD5, asyncResult); } }
/// <summary> /// Starts an asynchronous AppendBlock operation as soon as the parallel /// operation semaphore becomes available. Since parallelism is always set /// to 1 for append blobs, appendblock operations are called serially. /// </summary> /// <param name="blockData">Data to be uploaded.</param> /// <param name="offset">Offset within the append blob to be used to set the append offset conditional header.</param> /// <param name="blockMD5">MD5 hash of the data to be uploaded.</param> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void WriteAppendBlock(Stream blockData, long offset, string blockMD5, StorageAsyncResult <NullType> asyncResult) { this.noPendingWritesEvent.Increment(); this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { this.accessCondition.IfAppendPositionEqual = offset; int previousResultsCount = this.operationContext.RequestResults.Count; ICancellableAsyncResult result = this.appendBlob.BeginAppendBlock( blockData, blockMD5, this.accessCondition, this.options, this.operationContext, this.AppendBlockCallback, previousResultsCount /* state */); if (asyncResult != null) { // We do not need to do this inside a lock, as asyncResult is // not returned to the user yet. asyncResult.CancelDelegate = result.Cancel; } } catch (Exception e) { this.lastException = e; this.noPendingWritesEvent.Decrement(); this.parallelOperationSemaphore.Release(); } finally { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); asyncResult.OnComplete(this.lastException); } } }); }
private void WriteStreamCallback(IAsyncResult ar) { StorageAsyncResult <NullType> storageAsyncResult = (StorageAsyncResult <NullType>)ar.AsyncState; storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); Exception endException = null; try { this.wrappedStream.EndWrite(ar); this.position += (int)storageAsyncResult.OperationState; } catch (Exception e) { endException = e; } storageAsyncResult.OnComplete(endException); }
private void WriteRange(Stream rangeData, long offset, string contentMD5, StorageAsyncResult <NullType> asyncResult) { this.noPendingWritesEvent.Increment(); this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { ICancellableAsyncResult result = this.file.BeginWriteRange( rangeData, offset, contentMD5, this.accessCondition, this.options, this.operationContext, this.WriteRangeCallback, null /* state */); if (asyncResult != null) { // We do not need to do this inside a lock, as asyncResult is // not returned to the user yet. asyncResult.CancelDelegate = result.Cancel; } } catch (Exception e) { this.lastException = e; this.noPendingWritesEvent.Decrement(); this.parallelOperationSemaphore.Release(); } finally { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); asyncResult.OnComplete(this.lastException); } } }); }
private void DownloadRangeToStreamCallback(IAsyncResult ar) { StorageAsyncResult <int> storageAsyncResult = (StorageAsyncResult <int>)ar.AsyncState; storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.blob.EndDownloadRangeToStream(ar); ArraySegment <byte> bufferSegment = (ArraySegment <byte>)storageAsyncResult.OperationState; this.internalBuffer.Seek(0, SeekOrigin.Begin); storageAsyncResult.Result = this.ConsumeBuffer(bufferSegment.Array, bufferSegment.Offset, bufferSegment.Count); } catch (Exception e) { this.lastException = e; } storageAsyncResult.OnComplete(this.lastException); }
private void WriteBlock(Stream blockData, string blockId, string blockMD5, StorageAsyncResult <NullType> asyncResult) { this.noPendingWritesEvent.Increment(); this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { ICancellableAsyncResult result = this.blockBlob.BeginPutBlock( blockId, blockData, blockMD5, this.accessCondition, this.options, this.operationContext, this.PutBlockCallback, null /* state */); if (asyncResult != null) { // We do not need to do this inside a lock, as asyncResult is // not returned to the user yet. asyncResult.CancelDelegate = result.Cancel; } } catch (Exception e) { this.lastException = e; } finally { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); asyncResult.OnComplete(this.lastException); } } }); }
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { // Keep buffering until we have 16 bytes of IV. if (this.bufferIV && this.position < 16) { int bytesToCopy = 16 - (int)this.position; bytesToCopy = count > bytesToCopy ? bytesToCopy : count; Array.Copy(buffer, offset, this.iv, (int)this.position, bytesToCopy); this.position += bytesToCopy; offset += bytesToCopy; count -= bytesToCopy; } // Wrap user stream with LengthLimitingStream. This stream will be used to discard the extra bytes we downloaded in order to deal with AES block size. // Create crypto stream around the length limiting stream once per download and start writing to it. During retries, the state is maintained and // new crypto streams will not be created each time. if (this.cryptoStream == null) { LengthLimitingStream lengthLimitingStream = new LengthLimitingStream(this.userStream, this.discardFirst, this.userProvidedLength); this.cryptoStream = this.encryptionPolicy.DecryptBlob(lengthLimitingStream, this.metadata, out this.transform, this.requireEncryption, iv: !this.bufferIV ? null : this.iv, noPadding: this.noPadding); } StorageAsyncResult <NullType> storageAsyncResult = new StorageAsyncResult <NullType>(callback, state); if (count <= 0) { storageAsyncResult.OnComplete(); } else { // Route the remaining data through the crypto stream. storageAsyncResult.OperationState = count; this.cryptoStream.BeginWrite(buffer, offset, count, this.WriteStreamCallback, storageAsyncResult); } return(storageAsyncResult); }
private void DeleteIfExistsHandler(DeleteSnapshotsOption deleteSnapshotsOption, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult) { lock (storageAsyncResult.CancellationLockerObject) { ICancellableAsyncResult savedExistsResult = this.BeginExists( options, operationContext, existsResult => { storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously); lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { bool exists = this.EndExists(existsResult); if (!exists) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); return; } ICancellableAsyncResult savedDeleteResult = this.BeginDelete( deleteSnapshotsOption, accessCondition, options, operationContext, deleteResult => { storageAsyncResult.UpdateCompletedSynchronously(deleteResult.CompletedSynchronously); storageAsyncResult.CancelDelegate = null; try { this.EndDelete(deleteResult); storageAsyncResult.Result = true; storageAsyncResult.OnComplete(); } catch (StorageException e) { if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound) { if ((e.RequestInformation.ExtendedErrorInformation == null) || (e.RequestInformation.ExtendedErrorInformation.ErrorCode == BlobErrorCodeStrings.BlobNotFound)) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); } else { storageAsyncResult.OnComplete(e); } } else { storageAsyncResult.OnComplete(e); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); storageAsyncResult.CancelDelegate = savedDeleteResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }, null /* state */); storageAsyncResult.CancelDelegate = savedExistsResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } }
internal ICancellableAsyncResult BeginUploadFromStreamHelper(Stream source, long? length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("source", source); if (!source.CanSeek) { throw new InvalidOperationException(); } if (length.HasValue) { CommonUtility.AssertInBounds("length", (long)length, 1, source.Length - source.Position); } else { length = source.Length - source.Position; } if ((length % Constants.PageSize) != 0) { throw new ArgumentException(SR.InvalidPageSize, "source"); } this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.PageBlob, this.ServiceClient); ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions); StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); ICancellableAsyncResult result = this.BeginOpenWrite( length, accessCondition, modifiedOptions, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { CloudBlobStream blobStream = this.EndOpenWrite(ar); storageAsyncResult.OperationState = blobStream; source.WriteToAsync( blobStream, length, null /* maxLength */, false, tempExecutionState, null /* streamCopyState */, completedState => { storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously); if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { try { lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; ICancellableAsyncResult commitResult = blobStream.BeginCommit( CloudBlob.BlobOutputStreamCommitCallback, storageAsyncResult); storageAsyncResult.CancelDelegate = commitResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }); storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }, null /* state */); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = result.Cancel; return storageAsyncResult; }
internal ICancellableAsyncResult BeginUploadFromStreamHelper(Stream source, long? length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("source", source); if (length.HasValue) { CommonUtility.AssertInBounds("length", length.Value, 1); if (source.CanSeek && length > source.Length - source.Position) { throw new ArgumentOutOfRangeException("length", SR.StreamLengthShortError); } } this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient); ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions); StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); bool lessThanSingleBlobThreshold = CloudBlockBlob.IsLessThanSingleBlobThreshold(source, length, modifiedOptions, false); modifiedOptions.AssertPolicyIfRequired(); if (modifiedOptions.ParallelOperationThreadCount.Value == 1 && lessThanSingleBlobThreshold) { // Because we may or may not want to calculate the MD5, and we may or may not want to encrypt, rather than have four branching code // paths, here we have an action that we will run, which continually gets added to, depending on which operations we need to do. // The confusing part is that we have to build it from the bottom up. string md5 = null; Stream sourceStream = source; Action actionToRun = null; Action uploadAction = () => { if (md5 == null && modifiedOptions.UseTransactionalMD5.Value) { throw new ArgumentException(SR.PutBlobNeedsStoreBlobContentMD5, "options"); } this.UploadFromStreamHandler( sourceStream, length, md5, accessCondition, operationContext, modifiedOptions, storageAsyncResult); }; actionToRun = uploadAction; if (modifiedOptions.StoreBlobContentMD5.Value) { Action<Action> calculateMD5 = (continuation) => { long startPosition = sourceStream.Position; StreamDescriptor streamCopyState = new StreamDescriptor(); sourceStream.WriteToAsync( Stream.Null, length, null /* maxLength */, true, tempExecutionState, streamCopyState, completedState => { ContinueAsyncOperation(storageAsyncResult, completedState, () => { if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { sourceStream.Position = startPosition; md5 = streamCopyState.Md5; continuation(); } }); }); storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } }; Action oldActionToRun = actionToRun; actionToRun = () => calculateMD5(oldActionToRun); } if (modifiedOptions.EncryptionPolicy != null) { Action<Action> encryptStream = continuation => { SyncMemoryStream syncMemoryStream = new SyncMemoryStream(); options.AssertPolicyIfRequired(); sourceStream = syncMemoryStream; if (modifiedOptions.EncryptionPolicy.EncryptionMode != BlobEncryptionMode.FullBlob) { throw new InvalidOperationException(SR.InvalidEncryptionMode, null); } ICryptoTransform transform = options.EncryptionPolicy.CreateAndSetEncryptionContext(this.Metadata, false /* noPadding */); CryptoStream cryptoStream = new CryptoStream(syncMemoryStream, transform, CryptoStreamMode.Write); StreamDescriptor streamCopyState = new StreamDescriptor(); source.WriteToAsync(cryptoStream, length, null, false, tempExecutionState, streamCopyState, completedState => { ContinueAsyncOperation(storageAsyncResult, completedState, () => { if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { // Flush the CryptoStream in order to make sure that the last block of data is flushed. This call is a sync call // but it is ok to have it because we're just writing to a memory stream. cryptoStream.FlushFinalBlock(); // After the tempStream has been written to, we need to seek back to the beginning, so that it can be read from. sourceStream.Seek(0, SeekOrigin.Begin); length = syncMemoryStream.Length; continuation(); } }); }); storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } }; Action oldActionToRun = actionToRun; actionToRun = () => encryptStream(oldActionToRun); } actionToRun(); } else { ICancellableAsyncResult result = this.BeginOpenWrite( accessCondition, modifiedOptions, operationContext, ar => { ContinueAsyncOperation(storageAsyncResult, ar, () => { CloudBlobStream blobStream = this.EndOpenWrite(ar); storageAsyncResult.OperationState = blobStream; source.WriteToAsync( blobStream, length, null /* maxLength */, false, tempExecutionState, null /* streamCopyState */, completedState => { ContinueAsyncOperation(storageAsyncResult, completedState, () => { if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { ICancellableAsyncResult commitResult = blobStream.BeginCommit( CloudBlob.BlobOutputStreamCommitCallback, storageAsyncResult); storageAsyncResult.CancelDelegate = commitResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } }); }); storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } }); }, null /* state */); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = result.Cancel; } return storageAsyncResult; }
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { StorageAsyncResult<NullType> result = new StorageAsyncResult<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; }
private void WriteRange(Stream rangeData, long offset, string contentMD5, StorageAsyncResult<NullType> asyncResult) { this.noPendingWritesEvent.Increment(); this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { ICancellableAsyncResult result = this.file.BeginWriteRange( rangeData, offset, contentMD5, this.accessCondition, this.options, this.operationContext, this.WriteRangeCallback, null /* state */); if (asyncResult != null) { // We do not need to do this inside a lock, as asyncResult is // not returned to the user yet. asyncResult.CancelDelegate = result.Cancel; } } catch (Exception e) { this.lastException = e; } finally { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); asyncResult.OnComplete(this.lastException); } } }); }
public override ICancellableAsyncResult BeginFlush(AsyncCallback callback, object state) { if (this.committed) { throw new InvalidOperationException(SR.FileStreamAlreadyCommitted); } if (this.flushPending) { // We cannot allow more than one BeginFlush at a time, because // RegisterWaitForSingleObject would need duplicated handles // of noPendingWritesEvent for each call. throw new InvalidOperationException(SR.FileStreamFlushPending); } try { this.flushPending = true; this.DispatchWrite(null /* asyncResult */); StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); if ((this.lastException != null) || this.noPendingWritesEvent.Wait(0)) { storageAsyncResult.OnComplete(this.lastException); } else { RegisteredWaitHandle waitHandle = ThreadPool.RegisterWaitForSingleObject( this.noPendingWritesEvent.WaitHandle, this.WaitForPendingWritesCallback, storageAsyncResult, -1, true); storageAsyncResult.OperationState = waitHandle; storageAsyncResult.CancelDelegate = () => { waitHandle.Unregister(null /* waitObject */); storageAsyncResult.OnComplete(this.lastException); }; } return storageAsyncResult; } catch (Exception) { this.flushPending = false; throw; } }
/// <summary> /// Dispatches a write operation. /// </summary> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void DispatchWrite(StorageAsyncResult<NullType> asyncResult) { if (this.internalBuffer.Length == 0) { if (asyncResult != null) { asyncResult.OnComplete(this.lastException); } return; } MultiBufferMemoryStream bufferToUpload = this.internalBuffer; this.internalBuffer = new MultiBufferMemoryStream(this.Blob.ServiceClient.BufferManager); bufferToUpload.Seek(0, SeekOrigin.Begin); string bufferMD5 = null; if (this.blockMD5 != null) { bufferMD5 = this.blockMD5.ComputeHash(); this.blockMD5.Dispose(); this.blockMD5 = new MD5Wrapper(); } if (this.blockBlob != null) { string blockId = this.GetCurrentBlockId(); this.blockList.Add(blockId); this.WriteBlock(bufferToUpload, blockId, bufferMD5, asyncResult); } else { if ((bufferToUpload.Length % Constants.PageSize) != 0) { this.lastException = new IOException(SR.InvalidPageSize); throw this.lastException; } long offset = this.currentPageOffset; this.currentPageOffset += bufferToUpload.Length; this.WritePages(bufferToUpload, offset, bufferMD5, asyncResult); } }
private void DeleteIfExistsHandler(AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult) { ICancellableAsyncResult savedExistsResult = this.BeginExists( options, operationContext, existsResult => { storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously); lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { bool exists = this.EndExists(existsResult); if (!exists) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); return; } } catch (Exception e) { storageAsyncResult.OnComplete(e); return; } ICancellableAsyncResult savedDeleteResult = this.BeginDelete( accessCondition, options, operationContext, deleteResult => { storageAsyncResult.UpdateCompletedSynchronously(deleteResult.CompletedSynchronously); storageAsyncResult.CancelDelegate = null; try { this.EndDelete(deleteResult); storageAsyncResult.Result = true; storageAsyncResult.OnComplete(); } catch (StorageException e) { if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); } else { storageAsyncResult.OnComplete(e); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null); storageAsyncResult.CancelDelegate = savedDeleteResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } }, null); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = savedExistsResult.Cancel; }
private void CreateIfNotExistsHandler(FileRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult) { ICancellableAsyncResult savedExistsResult = this.BeginExists( options, operationContext, existsResult => { storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously); lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { bool exists = this.EndExists(existsResult); if (exists) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); return; } } catch (Exception e) { storageAsyncResult.OnComplete(e); return; } ICancellableAsyncResult savedCreateResult = this.BeginCreate( options, operationContext, createResult => { storageAsyncResult.UpdateCompletedSynchronously(createResult.CompletedSynchronously); storageAsyncResult.CancelDelegate = null; try { this.EndCreate(createResult); storageAsyncResult.Result = true; storageAsyncResult.OnComplete(); } catch (StorageException e) { if ((e.RequestInformation.ExtendedErrorInformation != null) && (e.RequestInformation.ExtendedErrorInformation.ErrorCode == FileErrorCodeStrings.ResourceAlreadyExists)) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); } else { storageAsyncResult.OnComplete(e); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null); storageAsyncResult.CancelDelegate = savedCreateResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } }, null); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = savedExistsResult.Cancel; }
/// <summary> /// Begins an asynchronous read operation. /// </summary> /// <param name="buffer">When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param> /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param> /// <param name="count">The maximum number of bytes to be 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 IAsyncResult 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) { if (count < 0) { throw new ArgumentOutOfRangeException("count"); } long remainingBytes = this.Length > this.Position ? this.Length - this.Position : 0; if (count > remainingBytes) { count = (int)remainingBytes; } StorageAsyncResult<int> storageAsyncResult = new StorageAsyncResult<int>(callback, state); if (count == 0) { storageAsyncResult.Result = 0; storageAsyncResult.OnComplete(); return storageAsyncResult; } else { return this.wrappedStream.BeginRead(buffer, offset, count, callback, state); } }
private void PutBlockHandler(string blockId, Stream blockData, string contentMD5, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, StorageAsyncResult<NullType> storageAsyncResult) { lock (storageAsyncResult.CancellationLockerObject) { ICancellableAsyncResult result = Executor.BeginExecuteAsync( this.PutBlockImpl(blockData, blockId, contentMD5, accessCondition, options), options.RetryPolicy, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { Executor.EndExecuteAsync<NullType>(ar); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* asyncState */); storageAsyncResult.CancelDelegate = result.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } }
/// <summary> /// Begins an asynchronous write operation. /// </summary> /// <param name="buffer">An array of bytes. This method copies count bytes from /// buffer to the current stream. </param> /// <param name="offset">The zero-based byte offset in buffer at which to begin /// copying bytes to the current stream.</param> /// <param name="count">The number of bytes to be written to the current stream.</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 <c>IAsyncResult</c> that represents the asynchronous write, which could still be pending.</returns> public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("buffer", buffer); CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length); CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset); if (this.committed) { throw new InvalidOperationException(SR.BlobStreamAlreadyCommitted); } StorageAsyncResult <NullType> storageAsyncResult = new StorageAsyncResult <NullType>(callback, state); StorageAsyncResult <NullType> currentAsyncResult = storageAsyncResult; this.currentOffset += count; int initialOffset = offset; int initialCount = count; bool dispatched = false; if (this.lastException == null) { while (count > 0) { int maxBytesToWrite = this.streamWriteSizeInBytes - (int)this.internalBuffer.Length; int bytesToWrite = Math.Min(count, maxBytesToWrite); this.internalBuffer.Write(buffer, offset, bytesToWrite); if (this.blockMD5 != null) { this.blockMD5.UpdateHash(buffer, offset, bytesToWrite); } count -= bytesToWrite; offset += bytesToWrite; if (bytesToWrite == maxBytesToWrite) { this.DispatchWrite(currentAsyncResult); dispatched = true; // Do not use the IAsyncResult we are going to return more // than once, as otherwise its callback will be called more // than once. currentAsyncResult = null; } } } // Update transactional, then update full blob, in that order. // This way, if there's any bit corruption that happens in between the two, we detect it at PutBlock on the service, // rather than GetBlob + validate on the client if (this.blobMD5 != null) { this.blobMD5.UpdateHash(buffer, initialOffset, initialCount); } if (!dispatched) { storageAsyncResult.OnComplete(this.lastException); } return(storageAsyncResult); }
/// <summary> /// Begins an asynchronous write operation. /// </summary> /// <param name="buffer">The buffer to write data from.</param> /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</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> public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("buffer", buffer); CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length); CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset); StorageAsyncResult<NullType> result = new StorageAsyncResult<NullType>(callback, state); try { this.Write(buffer, offset, count); result.OnComplete(); } catch (Exception e) { result.OnComplete(e); } return result; }
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); StorageAsyncResult<BlobResultSegment> result = new StorageAsyncResult<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> /// Initiates a write operation for the next buffer in line. /// </summary> /// <param name="result">Internal StorageAsyncResult that represents the asynchronous copy.</param> private void FastCopyToInternal(StorageAsyncResult<NullType> result) { CopyState copyState = (CopyState)result.OperationState; // Maximum amount you can read is from current spot to the end. long leftToRead = this.Length - this.Position; try { while (leftToRead != 0) { if (copyState.ExpiryTime.HasValue && DateTime.Now.CompareTo(copyState.ExpiryTime.Value) > 0) { throw new TimeoutException(); } ArraySegment<byte> currentBlock = this.GetCurrentBlock(); int blockReadLength = (int)Math.Min(leftToRead, currentBlock.Count); this.AdvancePosition(ref leftToRead, blockReadLength); IAsyncResult asyncResult = copyState.Destination.BeginWrite(currentBlock.Array, currentBlock.Offset, blockReadLength, this.FastCopyToCallback, result); if (!asyncResult.CompletedSynchronously) { return; } copyState.Destination.EndWrite(asyncResult); } result.OnComplete(); } catch (Exception e) { if (copyState.ExpiryTime.HasValue && DateTime.Now.CompareTo(copyState.ExpiryTime.Value) > 0) { result.OnComplete(new TimeoutException()); } else { result.OnComplete(e); } } }
/// <summary> /// Dispatches a write operation. /// </summary> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void DispatchWrite(StorageAsyncResult<NullType> asyncResult) { if (this.internalBuffer.Length == 0) { if (asyncResult != null) { asyncResult.OnComplete(this.lastException); } return; } MultiBufferMemoryStream bufferToUpload = this.internalBuffer; this.internalBuffer = new MultiBufferMemoryStream(this.file.ServiceClient.BufferManager); bufferToUpload.Seek(0, SeekOrigin.Begin); string bufferMD5 = null; if (this.rangeMD5 != null) { bufferMD5 = this.rangeMD5.ComputeHash(); this.rangeMD5.Dispose(); this.rangeMD5 = new MD5Wrapper(); } long offset = this.currentFileOffset; this.currentFileOffset += bufferToUpload.Length; this.WriteRange(bufferToUpload, offset, bufferMD5, asyncResult); }
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { // Discard bytes at the beginning if required. if (this.position < this.startOffset) { int discardBytes = (int)Math.Min(this.startOffset - this.position, count); offset += discardBytes; count -= discardBytes; this.position += discardBytes; } // Discard bytes at the end if required. if (this.endOffset.HasValue) { count = (int)Math.Min(this.endOffset.Value + 1 - this.position, count); } StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); if (count <= 0) { storageAsyncResult.OnComplete(); } else { // If there are any bytes in the buffer left to be written, write to the underlying stream and update position. storageAsyncResult.OperationState = count; this.wrappedStream.BeginWrite(buffer, offset, count, this.WriteStreamCallback, storageAsyncResult); } return storageAsyncResult; }
/// <summary> /// Begins an asynchronous write operation. /// </summary> /// <param name="buffer">An array of bytes. This method copies count bytes from /// buffer to the current stream. </param> /// <param name="offset">The zero-based byte offset in buffer at which to begin /// copying bytes to the current stream.</param> /// <param name="count">The number of bytes to be written to the current stream.</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 <c>IAsyncResult</c> that represents the asynchronous write, which could still be pending.</returns> public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("buffer", buffer); CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length); CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset); if (this.committed) { throw new InvalidOperationException(SR.FileStreamAlreadyCommitted); } if (this.fileMD5 != null) { this.fileMD5.UpdateHash(buffer, offset, count); } StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); StorageAsyncResult<NullType> currentChainedResult = storageAsyncResult; this.currentOffset += count; bool dispatched = false; if (this.lastException == null) { while (count > 0) { int maxBytesToWrite = this.streamWriteSizeInBytes - (int)this.internalBuffer.Length; int bytesToWrite = Math.Min(count, maxBytesToWrite); this.internalBuffer.Write(buffer, offset, bytesToWrite); if (this.rangeMD5 != null) { this.rangeMD5.UpdateHash(buffer, offset, bytesToWrite); } count -= bytesToWrite; offset += bytesToWrite; if (bytesToWrite == maxBytesToWrite) { this.DispatchWrite(currentChainedResult); dispatched = true; // Do not use the IAsyncResult we are going to return more // than once, as otherwise its callback will be called more // than once. currentChainedResult = null; } } } if (!dispatched) { storageAsyncResult.OnComplete(this.lastException); } return storageAsyncResult; }
public ICancellableAsyncResult BeginOpenWrite(long? size, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { this.attributes.AssertNoSnapshot(); bool createNew = size.HasValue; BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false); StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state); ICancellableAsyncResult result; if (createNew) { result = this.BeginCreate( size.Value, accessCondition, options, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndCreate(ar); if (accessCondition != null) { accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId); } storageAsyncResult.Result = new BlobWriteStream(this, size.Value, createNew, accessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); } else { if (modifiedOptions.StoreBlobContentMD5.Value) { throw new ArgumentException(SR.MD5NotPossible); } result = this.BeginFetchAttributes( accessCondition, options, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndFetchAttributes(ar); if (accessCondition != null) { accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId); } storageAsyncResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); } storageAsyncResult.CancelDelegate = result.Cancel; return storageAsyncResult; }
private static void ContinueAsyncOperation(StorageAsyncResult<NullType> storageAsyncResult, IAsyncResult result, Action actionToTakeInTheLock) { storageAsyncResult.UpdateCompletedSynchronously(result.CompletedSynchronously); try { lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; actionToTakeInTheLock(); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } }
/// <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) { CommonUtility.AssertNotNull("buffer", buffer); CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length); CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset); if (this.readPending) { throw new InvalidOperationException(SR.BlobStreamReadPending); } try { this.readPending = true; StorageAsyncResult<int> storageAsyncResult = new StorageAsyncResult<int>(callback, state); if (this.lastException != null) { storageAsyncResult.OnComplete(this.lastException); return storageAsyncResult; } if ((this.currentOffset == this.Length) || (count == 0)) { storageAsyncResult.Result = 0; storageAsyncResult.OnComplete(); return storageAsyncResult; } int readCount = this.ConsumeBuffer(buffer, offset, count); if (readCount > 0) { storageAsyncResult.Result = readCount; storageAsyncResult.OnComplete(); return storageAsyncResult; } this.DispatchReadAsync(storageAsyncResult, buffer, offset, count); return storageAsyncResult; } catch (Exception) { this.readPending = false; throw; } }
public ICancellableAsyncResult BeginOpenWrite(long? size, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { this.attributes.AssertNoSnapshot(); bool createNew = size.HasValue; BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false); StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state); ICancellableAsyncResult result; modifiedOptions.AssertPolicyIfRequired(); if (createNew) { #if !(WINDOWS_RT || ASPNET_K || PORTABLE) ICryptoTransform transform = null; if (options != null && options.EncryptionPolicy != null) { #if WINDOWS_PHONE throw new InvalidOperationException(SR.EncryptionNotSupportedForPageBlobsOnPhone); #else transform = options.EncryptionPolicy.CreateAndSetEncryptionContext(this.Metadata, true /* noPadding */); #endif } #endif result = this.BeginCreate( size.Value, accessCondition, options, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndCreate(ar); if (accessCondition != null) { accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId); } #if !(WINDOWS_RT || ASPNET_K || PORTABLE) if (modifiedOptions.EncryptionPolicy != null) { storageAsyncResult.Result = new BlobEncryptedWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext, transform); } else #endif { storageAsyncResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext); } storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); } else { if (modifiedOptions.StoreBlobContentMD5.Value) { throw new ArgumentException(SR.MD5NotPossible); } #if !(WINDOWS_RT || ASPNET_K || PORTABLE) if (modifiedOptions.EncryptionPolicy != null) { throw new ArgumentException(SR.EncryptionNotSupportedForExistingBlobs); } #endif result = this.BeginFetchAttributes( accessCondition, options, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndFetchAttributes(ar); if (accessCondition != null) { accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId); } storageAsyncResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); } storageAsyncResult.CancelDelegate = result.Cancel; return storageAsyncResult; }
private void CommitFlushCallback(IAsyncResult ar) { StorageAsyncResult <NullType> storageAsyncResult = (StorageAsyncResult <NullType>)ar.AsyncState; storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); this.committed = true; lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { this.EndFlush(ar); if (this.blockBlob != null) { if (this.blobMD5 != null) { this.blockBlob.Properties.ContentMD5 = this.blobMD5.ComputeHash(); } ICancellableAsyncResult result = this.blockBlob.BeginPutBlockList( this.blockList, this.accessCondition, this.options, this.operationContext, this.PutBlockListCallback, storageAsyncResult); storageAsyncResult.CancelDelegate = result.Cancel; } else { if (this.blobMD5 != null) { this.Blob.Properties.ContentMD5 = this.blobMD5.ComputeHash(); ICancellableAsyncResult result = this.Blob.BeginSetProperties( this.accessCondition, this.options, this.operationContext, this.SetPropertiesCallback, storageAsyncResult); storageAsyncResult.CancelDelegate = result.Cancel; } else { storageAsyncResult.OnComplete(); } } if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } catch (Exception e) { this.lastException = e; storageAsyncResult.OnComplete(e); } } }
/// <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(); StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false); if ((accessCondition != null) && accessCondition.IsConditional) { ICancellableAsyncResult result = this.BeginFetchAttributes( accessCondition, options, operationContext, ar => { storageAsyncResult.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 { storageAsyncResult.OnComplete(e); return; } } catch (Exception e) { storageAsyncResult.OnComplete(e); return; } storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); }, null /* state */); storageAsyncResult.CancelDelegate = result.Cancel; } else { storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); } return storageAsyncResult; }
private void UploadFromStreamHandler(Stream source, long? length, string contentMD5, AccessCondition accessCondition, OperationContext operationContext, BlobRequestOptions options, StorageAsyncResult<NullType> storageAsyncResult) { ICancellableAsyncResult result = Executor.BeginExecuteAsync( this.PutBlobImpl(source, length, contentMD5, accessCondition, options), options.RetryPolicy, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { Executor.EndExecuteAsync<NullType>(ar); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* asyncState */); storageAsyncResult.CancelDelegate = result.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } }
public ICancellableAsyncResult BeginPutBlock(string blockId, Stream blockData, string contentMD5, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("blockData", blockData); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient); bool requiresContentMD5 = (contentMD5 == null) && modifiedOptions.UseTransactionalMD5.Value; operationContext = operationContext ?? new OperationContext(); StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); if (blockData.CanSeek && !requiresContentMD5) { this.PutBlockHandler(blockId, blockData, contentMD5, accessCondition, modifiedOptions, operationContext, storageAsyncResult); } else { ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions); storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; Stream seekableStream; Stream writeToStream; if (blockData.CanSeek) { seekableStream = blockData; writeToStream = Stream.Null; } else { seekableStream = new MultiBufferMemoryStream(this.ServiceClient.BufferManager); writeToStream = seekableStream; } long startPosition = seekableStream.Position; StreamDescriptor streamCopyState = new StreamDescriptor(); blockData.WriteToAsync( writeToStream, null /* copyLength */, Constants.MaxBlockSize, requiresContentMD5, tempExecutionState, streamCopyState, completedState => { storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously); if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { try { if (requiresContentMD5) { contentMD5 = streamCopyState.Md5; } seekableStream.Position = startPosition; this.PutBlockHandler(blockId, seekableStream, contentMD5, accessCondition, modifiedOptions, operationContext, storageAsyncResult); } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }); } return storageAsyncResult; }
/// <summary> /// Starts an asynchronous AppendBlock operation as soon as the parallel /// operation semaphore becomes available. Since parallelism is always set /// to 1 for append blobs, appendblock operations are called serially. /// </summary> /// <param name="blockData">Data to be uploaded.</param> /// <param name="offset">Offset within the append blob to be used to set the append offset conditional header.</param> /// <param name="blockMD5">MD5 hash of the data to be uploaded.</param> /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param> private void WriteAppendBlock(Stream blockData, long offset, string blockMD5, StorageAsyncResult<NullType> asyncResult) { this.noPendingWritesEvent.Increment(); this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { this.accessCondition.IfAppendPositionEqual = offset; int previousResultsCount = this.operationContext.RequestResults.Count; ICancellableAsyncResult result = this.appendBlob.BeginAppendBlock( blockData, blockMD5, this.accessCondition, this.options, this.operationContext, this.AppendBlockCallback, previousResultsCount /* state */); if (asyncResult != null) { // We do not need to do this inside a lock, as asyncResult is // not returned to the user yet. asyncResult.CancelDelegate = result.Cancel; } } catch (Exception e) { this.lastException = e; this.noPendingWritesEvent.Decrement(); this.parallelOperationSemaphore.Release(); } finally { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); asyncResult.OnComplete(this.lastException); } } }); }
internal ICancellableAsyncResult BeginUploadFromStreamHelper(Stream source, long? length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { CommonUtility.AssertNotNull("source", source); if (length.HasValue) { CommonUtility.AssertInBounds("length", length.Value, 1); if (source.CanSeek && length > source.Length - source.Position) { throw new ArgumentOutOfRangeException("length", SR.StreamLengthShortError); } } this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient); ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions); StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state); bool lessThanSingleBlobThreshold = source.CanSeek && (length ?? source.Length - source.Position) <= this.ServiceClient.SingleBlobUploadThresholdInBytes; if (this.ServiceClient.ParallelOperationThreadCount == 1 && lessThanSingleBlobThreshold) { if (modifiedOptions.StoreBlobContentMD5.Value) { long startPosition = source.Position; StreamDescriptor streamCopyState = new StreamDescriptor(); source.WriteToAsync( Stream.Null, length, null /* maxLength */, true, tempExecutionState, streamCopyState, completedState => { storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously); try { lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { source.Position = startPosition; this.UploadFromStreamHandler( source, length, streamCopyState.Md5, accessCondition, operationContext, modifiedOptions, storageAsyncResult); } } } catch (Exception e) { storageAsyncResult.OnComplete(e); } }); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; } else { if (modifiedOptions.UseTransactionalMD5.Value) { throw new ArgumentException(SR.PutBlobNeedsStoreBlobContentMD5, "options"); } this.UploadFromStreamHandler( source, length, null /* contentMD5 */, accessCondition, operationContext, modifiedOptions, storageAsyncResult); } } else { ICancellableAsyncResult result = this.BeginOpenWrite( accessCondition, modifiedOptions, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { CloudBlobStream blobStream = this.EndOpenWrite(ar); storageAsyncResult.OperationState = blobStream; source.WriteToAsync( blobStream, length, null /* maxLength */, false, tempExecutionState, null /* streamCopyState */, completedState => { storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously); if (completedState.ExceptionRef != null) { storageAsyncResult.OnComplete(completedState.ExceptionRef); } else { try { lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; ICancellableAsyncResult commitResult = blobStream.BeginCommit( CloudBlobSharedImpl.BlobOutputStreamCommitCallback, storageAsyncResult); storageAsyncResult.CancelDelegate = commitResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }); storageAsyncResult.CancelDelegate = tempExecutionState.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }, null /* state */); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = result.Cancel; } return storageAsyncResult; }
private void CreateIfNotExistsHandler(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult) { ICancellableAsyncResult savedExistsResult = this.BeginExists( true, options, operationContext, existsResult => { storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously); lock (storageAsyncResult.CancellationLockerObject) { storageAsyncResult.CancelDelegate = null; try { bool exists = this.EndExists(existsResult); if (exists) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); return; } ICancellableAsyncResult savedCreateResult = this.BeginCreate( accessType, options, operationContext, createResult => { storageAsyncResult.UpdateCompletedSynchronously(createResult.CompletedSynchronously); storageAsyncResult.CancelDelegate = null; try { this.EndCreate(createResult); storageAsyncResult.Result = true; storageAsyncResult.OnComplete(); } catch (StorageException e) { if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict) { if ((e.RequestInformation.ExtendedErrorInformation == null) || (e.RequestInformation.ExtendedErrorInformation.ErrorCode == BlobErrorCodeStrings.ContainerAlreadyExists)) { storageAsyncResult.Result = false; storageAsyncResult.OnComplete(); } else { storageAsyncResult.OnComplete(e); } } else { storageAsyncResult.OnComplete(e); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); storageAsyncResult.CancelDelegate = savedCreateResult.Cancel; if (storageAsyncResult.CancelRequested) { storageAsyncResult.Cancel(); } } catch (Exception e) { storageAsyncResult.OnComplete(e); } } }, null /* state */); // We do not need to do this inside a lock, as storageAsyncResult is // not returned to the user yet. storageAsyncResult.CancelDelegate = savedExistsResult.Cancel; }
public virtual ICancellableAsyncResult BeginOpenWrite(bool createNew, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state) { this.attributes.AssertNoSnapshot(); BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false); StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state); ICancellableAsyncResult result; #if !(WINDOWS_RT || ASPNET_K || PORTABLE) ICryptoTransform transform = null; #endif if (createNew) { #if !(WINDOWS_RT || ASPNET_K || PORTABLE) if (options != null && options.EncryptionPolicy != null) { transform = options.EncryptionPolicy.CreateAndSetEncryptionContext(this.Metadata, false /* noPadding */); } #endif result = this.BeginCreateOrReplace( accessCondition, options, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndCreateOrReplace(ar); if (accessCondition != null) { accessCondition = new AccessCondition() { LeaseId = accessCondition.LeaseId, IfAppendPositionEqual = accessCondition.IfAppendPositionEqual, IfMaxSizeLessThanOrEqual = accessCondition.IfMaxSizeLessThanOrEqual }; } #if !(WINDOWS_RT || ASPNET_K || PORTABLE) if (modifiedOptions.EncryptionPolicy != null) { storageAsyncResult.Result = new BlobEncryptedWriteStream(this, accessCondition, modifiedOptions, operationContext, transform); } else #endif { storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext); } storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); } else { if (modifiedOptions.StoreBlobContentMD5.Value) { throw new ArgumentException(SR.MD5NotPossible); } #if !(WINDOWS_RT || ASPNET_K || PORTABLE) if (modifiedOptions.EncryptionPolicy != null) { throw new ArgumentException(SR.EncryptionNotSupportedForExistingBlobs); } #endif // Although we don't need any properties from the service, we should make this call in order to honor the user specified conditional headers // while opening an existing stream and to get the append position for an existing blob if user didn't specify one. result = this.BeginFetchAttributes( accessCondition, options, operationContext, ar => { storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously); try { this.EndFetchAttributes(ar); if (accessCondition != null) { accessCondition = new AccessCondition() { LeaseId = accessCondition.LeaseId, IfAppendPositionEqual = accessCondition.IfAppendPositionEqual }; } storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext); storageAsyncResult.OnComplete(); } catch (Exception e) { storageAsyncResult.OnComplete(e); } }, null /* state */); } storageAsyncResult.CancelDelegate = result.Cancel; return storageAsyncResult; }
private void WriteBlock(Stream blockData, string blockId, string blockMD5, StorageAsyncResult<NullType> asyncResult) { this.noPendingWritesEvent.Increment(); this.parallelOperationSemaphore.WaitAsync(calledSynchronously => { try { ICancellableAsyncResult result = this.blockBlob.BeginPutBlock( blockId, blockData, blockMD5, this.accessCondition, this.options, this.operationContext, this.PutBlockCallback, null /* state */); if (asyncResult != null) { // We do not need to do this inside a lock, as asyncResult is // not returned to the user yet. asyncResult.CancelDelegate = result.Cancel; } } catch (Exception e) { this.lastException = e; this.noPendingWritesEvent.Decrement(); this.parallelOperationSemaphore.Release(); } finally { if (asyncResult != null) { asyncResult.UpdateCompletedSynchronously(calledSynchronously); asyncResult.OnComplete(this.lastException); } } }); }