Пример #1
0
        private async Task <OptimisticStoreWriteResult> SaveDataInternal(StoreLocation location, Metadata metadata, UpdateAuditInfo audit, Func <IWriteAsyncStream, Task <long?> > savingFunc, CancellationToken token, bool isOptimistic)
        {
            var blob = GetBlockBlob(location);

            // We always want to save the new audit information when saving!
            var currentMetadata = await GetBlobMetadata(blob).ConfigureAwait(false);

            var auditInfo = TransformAuditInformation(currentMetadata, audit);

            metadata       = metadata ?? new Metadata();
            metadata.Audit = auditInfo;

            var result = new OptimisticStoreWriteResult()
            {
                Result = true
            };

            try
            {
                // If the ETag value is empty then the store value must not exist yet...
                var condition = isOptimistic ?
                                (string.IsNullOrEmpty(metadata.ETag) ? AccessCondition.GenerateIfNoneMatchCondition("*") : AccessCondition.GenerateIfMatchCondition(metadata.ETag))
                    : null;

                // Copy the metadata across
                blob.Metadata.Clear();
                foreach (var m in metadata)
                {
                    blob.Metadata[m.Key] = m.Value;
                }

                // Always store the version - We use this to do more efficient things on read
                blob.Metadata[StoreVersionKey] = StoreVersionValue;

                long?length;
                using (var stream = new AzureWriteBlockBlobStream(blob, condition))
                {
                    length = await savingFunc(stream).ConfigureAwait(false);

                    await stream.Complete(token).ConfigureAwait(false);
                }

                if (length.HasValue && (metadata == null || !metadata.ContentLength.HasValue))
                {
                    blob.Metadata[MetadataConstants.ContentLengthMetadataKey] = length.Value.ToString(CultureInfo.InvariantCulture);

                    // Save the length straight away before the snapshot...
                    await blob.SetMetadataAsync(null, null, null, token).ConfigureAwait(false);
                }

                // Create a snapshot straight away on azure
                // Note: this shouldnt matter for cost as any blocks that are the same do not cost extra
                if (_enableSnapshots)
                {
                    var snapshotBlob = await blob.CreateSnapshotAsync(blob.Metadata, null, null, null, token).ConfigureAwait(false);

                    var snapshot = snapshotBlob.SnapshotTime.Value.UtcTicks.ToString(CultureInfo.InvariantCulture);

                    // Save the snapshot back to original blob...
                    blob.Metadata[InternalSnapshotKey] = snapshot;
                    await blob.SetMetadataAsync(null, null, null, token).ConfigureAwait(false);

                    LeoTrace.WriteLine("Created Snapshot: " + blob.Name);
                }

                result.Metadata = await GetActualMetadata(blob).ConfigureAwait(false);
            }
            catch (StorageException exc)
            {
                if (isOptimistic)
                {
                    // First condition occurrs when the eTags do not match
                    // Second condition when we specified no eTag (ie must be new blob)
                    if (exc.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed ||
                        (exc.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict && exc.RequestInformation.ExtendedErrorInformation.ErrorCode == "BlobAlreadyExists"))
                    {
                        result.Result = false;
                    }
                    else
                    {
                        // Might have been a different error?
                        throw exc.Wrap(blob.Name);
                    }
                }
                else
                {
                    if (exc.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict ||
                        exc.RequestInformation.ExtendedErrorInformation.ErrorCode == "LeaseIdMissing")
                    {
                        throw new LockException("The underlying storage is currently locked for save");
                    }

                    // Might have been a different error?
                    throw exc.Wrap(blob.Name);
                }
            }

            return(result);
        }
Пример #2
0
        private async Task<OptimisticStoreWriteResult> SaveDataInternal(StoreLocation location, Metadata metadata, UpdateAuditInfo audit, Func<IWriteAsyncStream, Task<long?>> savingFunc, CancellationToken token, bool isOptimistic)
        {
            var blob = GetBlockBlob(location);

            // We always want to save the new audit information when saving!
            var currentMetadata = await GetBlobMetadata(blob).ConfigureAwait(false);
            var auditInfo = TransformAuditInformation(currentMetadata, audit);
            metadata = metadata ?? new Metadata();
            metadata.Audit = auditInfo;

            var result = new OptimisticStoreWriteResult() { Result = true };
            try
            {
                // If the ETag value is empty then the store value must not exist yet...
                var condition = isOptimistic ? 
                    (string.IsNullOrEmpty(metadata.ETag) ? AccessCondition.GenerateIfNoneMatchCondition("*") : AccessCondition.GenerateIfMatchCondition(metadata.ETag)) 
                    : null;

                // Copy the metadata across
                blob.Metadata.Clear();
                foreach (var m in metadata)
                {
                    blob.Metadata[m.Key] = m.Value;
                }

                // Always store the version - We use this to do more efficient things on read
                blob.Metadata[StoreVersionKey] = StoreVersionValue;
                
                long? length;
                using (var stream = new AzureWriteBlockBlobStream(blob, condition))
                {
                    length = await savingFunc(stream).ConfigureAwait(false);
                    await stream.Complete(token).ConfigureAwait(false);
                }

                if (length.HasValue && (metadata == null || !metadata.ContentLength.HasValue))
                {
                    blob.Metadata[MetadataConstants.ContentLengthMetadataKey] = length.Value.ToString(CultureInfo.InvariantCulture);

                    // Save the length straight away before the snapshot...
                    await blob.SetMetadataAsync(token).ConfigureAwait(false);
                }

                // Create a snapshot straight away on azure
                // Note: this shouldnt matter for cost as any blocks that are the same do not cost extra
                if (_enableSnapshots)
                {
                    var snapshotBlob = await blob.CreateSnapshotAsync(token).ConfigureAwait(false);
                    var snapshot = snapshotBlob.SnapshotTime.Value.UtcTicks.ToString(CultureInfo.InvariantCulture);

                    // Save the snapshot back to original blob...
                    blob.Metadata[InternalSnapshotKey] = snapshot;
                    await blob.SetMetadataAsync(token).ConfigureAwait(false);

                    LeoTrace.WriteLine("Created Snapshot: " + blob.Name);
                }

                result.Metadata = await GetActualMetadata(blob).ConfigureAwait(false);
            }
            catch (StorageException exc)
            {
                if (isOptimistic)
                {
                    // First condition occurrs when the eTags do not match
                    // Second condition when we specified no eTag (ie must be new blob)
                    if (exc.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed
                        || (exc.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict && exc.RequestInformation.ExtendedErrorInformation.ErrorCode == "BlobAlreadyExists"))
                    {
                        result.Result = false;
                    }
                    else
                    {
                        // Might have been a different error?
                        throw exc.Wrap(blob.Name);
                    }
                }
                else
                {
                    if (exc.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict
                        || exc.RequestInformation.ExtendedErrorInformation.ErrorCode == "LeaseIdMissing")
                    {
                        throw new LockException("The underlying storage is currently locked for save");
                    }

                    // Might have been a different error?
                    throw exc.Wrap(blob.Name);
                }
            }

            return result;
        }
Пример #3
0
        private async Task <OptimisticStoreWriteResult> SaveDataInternal(StoreLocation location, Metadata metadata, UpdateAuditInfo audit, Func <IWriteAsyncStream, Task <long?> > savingFunc, CancellationToken token, bool isOptimistic)
        {
            var blob = GetBlockBlob(location);

            // We always want to save the new audit information when saving!
            var props = await GetBlobProperties(blob);

            var currentMetadata = await GetActualMetadata(blob, props, null);

            var auditInfo = TransformAuditInformation(currentMetadata, audit);

            metadata       = metadata ?? new Metadata();
            metadata.Audit = auditInfo;

            var result = new OptimisticStoreWriteResult()
            {
                Result = true
            };

            try
            {
                // If the ETag value is empty then the store value must not exist yet...
                var condition = isOptimistic ?
                                (string.IsNullOrEmpty(metadata.ETag) ? new BlobRequestConditions {
                    IfNoneMatch = ETag.All
                } : new BlobRequestConditions {
                    IfMatch = new ETag(metadata.ETag)
                })
                    : null;

                // Copy the metadata across
                var newMeta = new Dictionary <string, string>();
                foreach (var m in metadata)
                {
                    newMeta[m.Key] = AzureStoreMetadataEncoder.EncodeMetadata(m.Value);
                }

                // Always store the version - We use this to do more efficient things on read
                newMeta[StoreVersionKey] = StoreVersionValue;

                long?length;
                using (var stream = new AzureWriteBlockBlobStream(blob, condition, newMeta))
                {
                    length = await savingFunc(stream);

                    await stream.Complete(token);
                }

                if (length.HasValue && (metadata == null || !metadata.ContentLength.HasValue))
                {
                    newMeta[MetadataConstants.ContentLengthMetadataKey] = length.Value.ToString(CultureInfo.InvariantCulture);

                    // Save the length straight away before the snapshot...
                    await blob.SetMetadataAsync(newMeta, cancellationToken : token);
                }

                // Create a snapshot straight away on azure
                // Note: this shouldnt matter for cost as any blocks that are the same do not cost extra
                if (_enableSnapshots)
                {
                    var snapshotBlob = await blob.CreateSnapshotAsync(cancellationToken : token);

                    // Save the snapshot back to original blob...
                    newMeta[InternalSnapshotKey] = snapshotBlob.Value.Snapshot;
                    await blob.SetMetadataAsync(newMeta, cancellationToken : token);

                    LeoTrace.WriteLine("Created Snapshot: " + blob.Name);
                }

                var newProps = await blob.GetPropertiesAsync();

                result.Metadata = await GetActualMetadata(blob, newProps, null);
            }
            catch (RequestFailedException e)
            {
                if (isOptimistic)
                {
                    // First condition occurrs when the eTags do not match
                    // Second condition when we specified no eTag (ie must be new blob)
                    if (e.Status == (int)HttpStatusCode.PreconditionFailed ||
                        (e.Status == (int)HttpStatusCode.Conflict && e.ErrorCode == BlobErrorCode.BlobAlreadyExists))
                    {
                        result.Result = false;
                    }
                    else
                    {
                        // Might have been a different error?
                        throw;
                    }
                }
                else
                {
                    if (e.Status == (int)HttpStatusCode.Conflict || e.ErrorCode == BlobErrorCode.LeaseIdMissing)
                    {
                        throw new LockException("The underlying storage is currently locked for save");
                    }

                    // Might have been a different error?
                    throw;
                }
            }

            return(result);
        }