예제 #1
0
        protected override async Task <SelectedSnapshot> LoadAsync(string persistenceId,
                                                                   SnapshotSelectionCriteria criteria)
        {
            var requestOptions        = GenerateOptions();
            BlobResultSegment results = null;

            using (var cts = new CancellationTokenSource(_settings.RequestTimeout))
            {
                results = await Container.ListBlobsSegmentedAsync(SeqNoHelper.ToSnapshotSearchQuery(persistenceId),
                                                                  true,
                                                                  BlobListingDetails.Metadata, null, null, requestOptions, new OperationContext(), cts.Token);
            }

            // if we made it down here, the initial request succeeded.

            async Task <SelectedSnapshot> FilterAndFetch(BlobResultSegment segment)
            {
                // apply filter criteria
                var filtered = segment.Results
                               .Where(x => x is CloudBlockBlob)
                               .Cast <CloudBlockBlob>()
                               .Where(x => FilterBlobSeqNo(criteria, x))
                               .Where(x => FilterBlobTimestamp(criteria, x))
                               .OrderByDescending(x => FetchBlobSeqNo(x)) // ordering matters - get highest seqNo item
                               .ThenByDescending(x =>
                                                 FetchBlobTimestamp(
                                                     x)) // if there are multiple snapshots taken at same SeqNo, need latest timestamp
                               .FirstOrDefault();

                // couldn't find what we were looking for. Onto the next part of the query
                // or return null to sender possibly.
                if (filtered == null)
                {
                    return(null);
                }

                using (var cts = new CancellationTokenSource(_settings.RequestTimeout))
                    using (var memoryStream = new MemoryStream())
                    {
                        await filtered.DownloadToStreamAsync(memoryStream, AccessCondition.GenerateIfExistsCondition(),
                                                             GenerateOptions(), new OperationContext(), cts.Token);

                        var snapshot = _serialization.SnapshotFromBytes(memoryStream.ToArray());
                        return(new SelectedSnapshot(new SnapshotMetadata(persistenceId, FetchBlobSeqNo(filtered)),
                                                    snapshot.Data));
                    }
            }

            // TODO: see if there's ever a scenario where the most recent snapshots aren't in the beginning of the pagination list.
            var result = await FilterAndFetch(results);

            return(result);
        }
        protected override async Task <SelectedSnapshot> LoadAsync(string persistenceId,
                                                                   SnapshotSelectionCriteria criteria)
        {
            using var cts = new CancellationTokenSource(_settings.RequestTimeout);
            {
                var results = Container.GetBlobsAsync(
                    prefix: SeqNoHelper.ToSnapshotSearchQuery(persistenceId),
                    traits: BlobTraits.Metadata,
                    cancellationToken: cts.Token);

                var pageEnumerator = results.AsPages().GetAsyncEnumerator(cts.Token);

                if (!await pageEnumerator.MoveNextAsync())
                {
                    return(null);
                }

                // TODO: see if there's ever a scenario where the most recent snapshots aren't in the first page of the pagination list.
                // apply filter criteria
                var filtered = pageEnumerator.Current.Values
                               .Where(x => FilterBlobSeqNo(criteria, x))
                               .Where(x => FilterBlobTimestamp(criteria, x))
                               .OrderByDescending(FetchBlobSeqNo)    // ordering matters - get highest seqNo item
                               .ThenByDescending(FetchBlobTimestamp) // if there are multiple snapshots taken at same SeqNo, need latest timestamp
                               .FirstOrDefault();

                // couldn't find what we were looking for. Onto the next part of the query
                // or return null to sender possibly.
                if (filtered == null)
                {
                    return(null);
                }

                using var memoryStream = new MemoryStream();
                var blobClient   = Container.GetBlockBlobClient(filtered.Name);
                var downloadInfo = await blobClient.DownloadAsync(cts.Token);

                await downloadInfo.Value.Content.CopyToAsync(memoryStream);

                var snapshot = _serialization.SnapshotFromBytes(memoryStream.ToArray());

                var result =
                    new SelectedSnapshot(
                        new SnapshotMetadata(
                            persistenceId,
                            FetchBlobSeqNo(filtered),
                            new DateTime(FetchBlobTimestamp(filtered))),
                        snapshot.Data);

                return(result);
            }
        }
        protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria)
        {
            using var cts = new CancellationTokenSource(_settings.RequestTimeout);
            var items = Container.GetBlobsAsync(
                prefix: SeqNoHelper.ToSnapshotSearchQuery(persistenceId),
                traits: BlobTraits.Metadata,
                cancellationToken: cts.Token);

            var filtered = items
                           .Where(x => FilterBlobSeqNo(criteria, x))
                           .Where(x => FilterBlobTimestamp(criteria, x));

            var deleteTasks = new List <Task>();

            await foreach (var blob in filtered.WithCancellation(cts.Token))
            {
                var blobClient = Container.GetBlobClient(blob.Name);
                deleteTasks.Add(blobClient.DeleteIfExistsAsync(cancellationToken: cts.Token));
            }

            await Task.WhenAll(deleteTasks);
        }
예제 #4
0
        protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria)
        {
            var requestOptions        = GenerateOptions();
            BlobResultSegment results = null;

            using (var cts = new CancellationTokenSource(_settings.RequestTimeout))
            {
                /*
                 * Query only the metadata - don't need to stream the entire blob back to us
                 * in order to delete it from storage in the next request.
                 */
                results = await Container.ListBlobsSegmentedAsync(SeqNoHelper.ToSnapshotSearchQuery(persistenceId),
                                                                  true,
                                                                  BlobListingDetails.Metadata, null, null, requestOptions, new OperationContext(), cts.Token);
            }

            // if we made it down here, the initial request succeeded.

            async Task FilterAndDelete(BlobResultSegment segment)
            {
                // apply filter criteria
                var filtered = segment.Results.Where(x => x is CloudBlockBlob)
                               .Cast <CloudBlockBlob>()
                               .Where(x => FilterBlobSeqNo(criteria, x))
                               .Where(x => FilterBlobTimestamp(criteria, x));

                var deleteTasks = new List <Task>();

                using (var cts = new CancellationTokenSource(_settings.RequestTimeout))
                {
                    foreach (var blob in filtered)
                    {
                        deleteTasks.Add(blob.DeleteIfExistsAsync(DeleteSnapshotsOption.None,
                                                                 AccessCondition.GenerateIfExistsCondition(),
                                                                 GenerateOptions(), new OperationContext(), cts.Token));
                    }

                    await Task.WhenAll(deleteTasks);
                }
            }

            var continuationToken = results.ContinuationToken;
            var deleteTask        = FilterAndDelete(results);

            while (continuationToken != null)
            {
                // get the next round of results in parallel with the deletion of the previous
                var nextResults = await Container.ListBlobsSegmentedAsync(continuationToken);

                // finish our previous delete tasks
                await deleteTask;

                // start next round of deletes
                deleteTask = FilterAndDelete(nextResults);

                // move the loop forward if there are more results to be processed still
                continuationToken = nextResults.ContinuationToken;
            }

            // wait for the final delete operation to complete
            await deleteTask;
        }