private bool AcquireLeaseIfBlobExists(TimeSpan leaseDuration) { bool exists = true; StorageOperation.Try( () => { AcquireLeaseForExistingBlob(leaseDuration); }, catchHttp404: e => { exists = false; } ); return(exists); }
private void AcquireLeaseForExistingBlob(TimeSpan leaseDuration) { StorageOperation.Try( () => { lock (this.writeAccessCondition) { this.writeAccessCondition.LeaseId = this.backingBlob.AcquireLease(leaseDuration, proposedLeaseId: null); } }, catchHttp409: e => { throw new InvalidOperationException("The lease for this blob has been taken by another client", e); }); }
private void WriteLocalDataToCloudIfNeeded() { lock (this.syncRoot) { byte[] localContentHash; if (!Serialization.ModifiedSince( this.localObject, this.lastKnownBlobContentsHash, out localContentHash)) { return; } AccessCondition writeAccessConditionAtStartOfUpload = new AccessCondition(); lock (this.writeAccessCondition) { writeAccessConditionAtStartOfUpload.LeaseId = this.writeAccessCondition.LeaseId; } StorageOperation.Try( () => { OperationContext context = new OperationContext(); CloudBlobStream uploadStream = this.backingBlob.OpenWrite( accessCondition: writeAccessConditionAtStartOfUpload, operationContext: context); Serialization.SerializeIntoStream(this.localObject, uploadStream); uploadStream.Close(); this.readAccessCondition.IfNoneMatchETag = context.LastResult.Etag; this.lastKnownBlobContentsHash = localContentHash; }, catchHttp400: e => { // Can happen when two clients race to perform an upload to the same blob; one // client will get a HTTP 400 when committing their list of uploaded blocks. OnWriteToCloudFailure(e, writeAccessConditionAtStartOfUpload); }, catchHttp412: e => { // There is a lease in place that prevents this write. OnWriteToCloudFailure(e, writeAccessConditionAtStartOfUpload); }); } }
private bool TryRefreshDataFromCloudBlob() { bool exists = true; StorageOperation.Try( () => { T temp = default(T); OperationContext context = new OperationContext(); lock (this.syncRoot) { StorageOperation.Try( () => { Stream blobContentsStream = this.backingBlob.OpenRead( accessCondition: this.readAccessCondition, operationContext: context); exists = Serialization.DeserializeInto <T>( ref temp, blobContentsStream, out this.lastKnownBlobContentsHash); this.readAccessCondition.IfNoneMatchETag = context.LastResult.Etag; }, catchHttp404: e => { exists = false; }); this.localObject = temp; if (exists) { if (this.OnUpdate != null) { this.OnUpdate(this, EventArgs.Empty); } } } }, catchHttp304: e => { }, // TODO: Perf improvement; prevent throwing of exceptions in expected-case paths? catchHttp412: e => { }); return(exists); }
/// <summary> /// Starts a task that triggers a request to renew the lease on the backing blob MinimumLeaseInSeconds /// before it expires, and releases the lease when the task is aborted. /// </summary> private Task StartLeaseRenewer(TimeSpan leaseDuration) { return(Task.Run( () => { Stopwatch timer = Stopwatch.StartNew(); bool stop = false; while (!stop) { stop = stopLeaseRenewer.Wait(TimeSpan.FromTicks(timer.ElapsedTicks % (leaseDuration.Ticks / 2))); if (!stop) { StorageOperation.Try( () => { lock (this.writeAccessCondition) { this.backingBlob.RenewLease(this.writeAccessCondition); } }, catchHttp409: e => { // Lost our original lease (maybe due to this task sleeping for an extremely long time) AcquireLeaseForExistingBlob(leaseDuration); }); } } StorageOperation.Try( () => { lock (this.writeAccessCondition) { this.backingBlob.ReleaseLease(this.writeAccessCondition); } }, catchHttp409: e => { // Maybe we didn't have the lease anyway? Ooh well, we're shutting down anyway (absorb this error) }); })); }