public async static Task <NamespaceBlob> FetchForBlobAsync(CloudBlockBlob namespaceBlob) { var retval = new NamespaceBlob(namespaceBlob); await retval.RefreshAsync(); return(retval); }
public static async Task EnqueueBlobReplicationAsync(NamespaceBlob namespaceBlob, bool deleteReplica, bool saveNamespaceEntry = true) { if (!await namespaceBlob.ExistsAsync()) { return; } // Trim down the namespace replication list to the first 'master' item. This is sufficient to ensure that the // orphaned blobs are not effectively in the account. The master blob will be replicated over the top of the // orphaned blobs. string primaryAccount = namespaceBlob.PrimaryAccountName; if (namespaceBlob.IsReplicated) { namespaceBlob.PrimaryAccountName = primaryAccount; if (saveNamespaceEntry) { await namespaceBlob.SaveAsync(); } } // This rest of this method does not block. Enqueueing the replication is a completely async process var task = Task.Factory.StartNew(() => { var queue = new AzureMessageQueue(); var tasks = DashConfiguration.DataAccounts .Where(dataAccount => !dataAccount.Credentials.AccountName.Equals(primaryAccount, StringComparison.OrdinalIgnoreCase)) .Select(async dataAccount => await queue.EnqueueAsync(ConstructReplicationMessage(deleteReplica, primaryAccount, dataAccount.Credentials.AccountName, namespaceBlob.Container, namespaceBlob.BlobName, deleteReplica ? await GetBlobETagAsync(dataAccount, namespaceBlob.Container, namespaceBlob.BlobName) : null))) .ToArray(); Task.WhenAll(tasks) .ContinueWith(antecedent => { if (antecedent.Exception != null) { DashTrace.TraceWarning("Error queueing replication message for blob: {0}. Details: {1}", PathUtils.CombineContainerAndBlob(namespaceBlob.Container, namespaceBlob.BlobName), antecedent.Exception.Flatten()); } else { DashTrace.TraceInformation("Blob: {0} has been enqueued for replication.", PathUtils.CombineContainerAndBlob(namespaceBlob.Container, namespaceBlob.BlobName)); } }); }); }
public static async Task EnqueueBlobReplicationAsync(NamespaceBlob namespaceBlob, bool deleteReplica, bool saveNamespaceEntry = true) { if (!await namespaceBlob.ExistsAsync()) { return; } // Trim down the namespace replication list to the first 'master' item. This is sufficient to ensure that the // orphaned blobs are not effectively in the account. The master blob will be replicated over the top of the // orphaned blobs. string primaryAccount = namespaceBlob.PrimaryAccountName; if (namespaceBlob.IsReplicated) { namespaceBlob.PrimaryAccountName = primaryAccount; if (saveNamespaceEntry) { await namespaceBlob.SaveAsync(); } } // This rest of this method does not block. Enqueueing the replication is a completely async process var task = Task.Factory.StartNew(() => { var queue = new AzureMessageQueue(); var tasks = DashConfiguration.DataAccounts .Where(dataAccount => !dataAccount.Credentials.AccountName.Equals(primaryAccount, StringComparison.OrdinalIgnoreCase)) .Select(async dataAccount => await queue.EnqueueAsync(ConstructReplicationMessage(deleteReplica, primaryAccount, dataAccount.Credentials.AccountName, namespaceBlob.Container, namespaceBlob.BlobName, deleteReplica ? await GetBlobETagAsync(dataAccount, namespaceBlob.Container, namespaceBlob.BlobName) : null))); Task.WhenAll(tasks) .ContinueWith(antecedent => { if (antecedent.Exception != null) { DashTrace.TraceWarning("Error queueing replication message for blob: {0}. Details: {1}", PathUtils.CombineContainerAndBlob(namespaceBlob.Container, namespaceBlob.BlobName), antecedent.Exception.Flatten()); } else { DashTrace.TraceInformation("Blob: {0} has been enqueued for replication.", PathUtils.CombineContainerAndBlob(namespaceBlob.Container, namespaceBlob.BlobName)); } }); }); }
private async Task<HttpResponseMessage> ForwardRequestHandler(NamespaceBlob namespaceBlob, StorageOperationTypes operation) { // Clone the inbound request var sourceRequest = this.Request; // We always target the primary data account for forwarded messages. If the operation invalidates the replicas, then // separate logic will enqueue the new blob to be replicated. var clonedRequest = new HttpRequestMessage(sourceRequest.Method, ControllerOperations.GetRedirectUri(sourceRequest.RequestUri, sourceRequest.Method.Method, DashConfiguration.GetDataAccountByAccountName(namespaceBlob.PrimaryAccountName), namespaceBlob.Container, namespaceBlob.BlobName, false)); clonedRequest.Version = sourceRequest.Version; foreach (var property in sourceRequest.Properties) { clonedRequest.Properties.Add(property); } foreach (var header in sourceRequest.Headers) { if (!_noCopyHeaders.Contains(header.Key)) { clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value); } } // Depending on the operation, we have to do some fixup to unwind HttpRequestMessage a bit - we also have to fixup some responses switch (operation) { case StorageOperationTypes.GetBlob: case StorageOperationTypes.GetBlobMetadata: case StorageOperationTypes.GetBlobProperties: case StorageOperationTypes.GetBlockList: case StorageOperationTypes.GetPageRanges: case StorageOperationTypes.LeaseBlob: case StorageOperationTypes.SetBlobMetadata: case StorageOperationTypes.SetBlobProperties: case StorageOperationTypes.SnapshotBlob: // Push any headers that are assigned to Content onto the request itself as these operations do not have any body if (sourceRequest.Content != null) { foreach (var header in sourceRequest.Content.Headers) { clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value); } } break; default: clonedRequest.Content = sourceRequest.Content; break; } var client = new HttpClient(); var response = await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead); // Fixup response for HEAD requests switch (operation) { case StorageOperationTypes.GetBlobProperties: var content = response.Content; if (response.IsSuccessStatusCode && content != null) { string mediaType = null; string dummyContent = String.Empty; if (content.Headers.ContentType != null) { mediaType = content.Headers.ContentType.MediaType; } // For some reason, a HEAD request requires some content otherwise the Content-Length is set to 0 dummyContent = "A"; response.Content = new StringContent(dummyContent, null, mediaType); foreach (var header in content.Headers) { response.Content.Headers.TryAddWithoutValidation(header.Key, header.Value); } response.Content.Headers.ContentLength = content.Headers.ContentLength; content.Dispose(); } break; } return response; }
public static bool ShouldReplicateBlob(ILookup<string, string> headers, NamespaceBlob namespaceBlob) { return ShouldReplicateBlob(headers, namespaceBlob.Container, namespaceBlob.BlobName); }
static bool CleanupAbortedBlobReplication(NamespaceBlob namespaceBlob, ICloudBlob destBlob) { try { destBlob.DeleteIfExists(); } catch (Exception ex1) { DashTrace.TraceWarning("Error deleting aborted replication target [{0}][{1}]. Details: {2}", destBlob.ServiceClient.Credentials.AccountName, destBlob.Name, ex1); } return namespaceBlob.RemoveDataAccount(destBlob.ServiceClient.Credentials.AccountName); }
public async static Task<NamespaceBlob> FetchForBlobAsync(CloudBlockBlob namespaceBlob) { var retval = new NamespaceBlob(namespaceBlob); await retval.RefreshAsync(); return retval; }
public static async Task <NamespaceBlob> FetchNamespaceBlobAsync(string container, string blobName, string snapshot = null) { return(await NamespaceBlob.FetchForBlobAsync( (CloudBlockBlob)GetBlobByName(DashConfiguration.NamespaceAccount, container, blobName, snapshot))); }
public static bool ShouldReplicateBlob(ILookup <string, string> headers, NamespaceBlob namespaceBlob) { return(ShouldReplicateBlob(headers, namespaceBlob.Container, namespaceBlob.BlobName)); }