Beispiel #1
0
        /// <summary>
        /// Downloads the next block.
        /// </summary>
        private async Task DownloadBlock(bool async, CancellationToken cancellationToken)
        {
            Response <BlobDownloadStreamingResult> response;
            HttpRange range = new HttpRange(_offset, _blockSize);

            response = async
                ? await _blobClient.DownloadStreamingAsync(range, cancellationToken : cancellationToken).ConfigureAwait(false)
                : _blobClient.DownloadStreaming(range, cancellationToken: cancellationToken);

            _stream            = response.Value.Content;
            _offset           += response.Value.Details.ContentLength;
            _lastDownloadBytes = response.Value.Details.ContentLength;
            _blobLength        = GetBlobLength(response);
        }
Beispiel #2
0
        public async Task UploadBlobFromStream()
        {
            string data = "hello world";

            BlobContainerClient containerClient = new BlobContainerClient(ConnectionString, Randomize("sample-container"));

            try
            {
                await containerClient.CreateAsync();

                string blobName = Randomize("sample-blob");

                string     localFilePath = this.CreateTempPath();
                FileStream fs            = File.OpenWrite(localFilePath);
                var        bytes         = Encoding.UTF8.GetBytes(data);
                await fs.WriteAsync(bytes, 0, bytes.Length);

                await fs.FlushAsync();

                fs.Close();

                #region Snippet:SampleSnippetsBlobMigration_UploadBlobFromStream
                BlobClient blobClient = containerClient.GetBlobClient(blobName);
                using Stream stream = File.OpenRead(localFilePath);
                await blobClient.UploadAsync(stream, overwrite : true);

                #endregion

                Stream downloadStream = (await blobClient.DownloadStreamingAsync()).Value.Content;
                string downloadedData = await new StreamReader(downloadStream).ReadToEndAsync();
                downloadStream.Close();

                Assert.AreEqual(data, downloadedData);
            }
            finally
            {
                await containerClient.DeleteIfExistsAsync();
            }
        }
Beispiel #3
0
        public async Task ExpectedDownloadStreamingStreamTypeReturned(TransactionalHashAlgorithm algorithm, bool isBuffered)
        {
            await using var test = await GetDisposingContainerAsync();

            // Arrange
            var        data = GetRandomBuffer(Constants.KB);
            BlobClient blob = InstrumentClient(test.Container.GetBlobClient(GetNewResourceName()));

            using (var stream = new MemoryStream(data))
            {
                await blob.UploadAsync(stream);
            }
            // don't make options instance at all for no hash request
            DownloadTransactionalHashingOptions hashingOptions = algorithm == TransactionalHashAlgorithm.None
                ? default
                : new DownloadTransactionalHashingOptions {
                Algorithm = algorithm
            };

            // Act
            Response <BlobDownloadStreamingResult> response = await blob.DownloadStreamingAsync(new BlobDownloadOptions
            {
                TransactionalHashingOptions = hashingOptions,
                Range = new HttpRange(length: data.Length)
            });

            // Assert
            if (isBuffered)
            {
                Assert.AreEqual(typeof(MemoryStream), response.Value.Content.GetType());
            }
            // actual unbuffered stream type is private; just check we didn't get back a buffered stream
            else
            {
                Assert.AreNotEqual(typeof(MemoryStream), response.Value.Content.GetType());
            }
        }
#pragma warning disable CA1822 // Does not acces instance data can be marked static.
        public virtual async Task <Segment> BuildSegment(
#pragma warning restore CA1822 // Can't mock static methods in MOQ.
            bool async,
            string manifestPath,
            SegmentCursor cursor = default)
        {
            // Models we need for later
            List <Shard>   shards   = new List <Shard>();
            DateTimeOffset dateTime = BlobChangeFeedExtensions.ToDateTimeOffset(manifestPath).Value;

            // Download segment manifest
            BlobClient blobClient = _containerClient.GetBlobClient(manifestPath);
            BlobDownloadStreamingResult blobDownloadStreamingResult;

            if (async)
            {
                blobDownloadStreamingResult = await blobClient.DownloadStreamingAsync().ConfigureAwait(false);
            }
            else
            {
                blobDownloadStreamingResult = blobClient.DownloadStreaming();
            }

            // Parse segment manifest
            JsonDocument jsonManifest;

            if (async)
            {
                jsonManifest = await JsonDocument.ParseAsync(blobDownloadStreamingResult.Content).ConfigureAwait(false);
            }
            else
            {
                jsonManifest = JsonDocument.Parse(blobDownloadStreamingResult.Content);
            }

            foreach (JsonElement shardJsonElement in jsonManifest.RootElement.GetProperty("chunkFilePaths").EnumerateArray())
            {
                string shardPath   = shardJsonElement.ToString().Substring("$blobchangefeed/".Length);
                var    shardCursor = cursor?.ShardCursors?.Find(x => x.CurrentChunkPath.StartsWith(shardPath, StringComparison.InvariantCulture));
                Shard  shard       = await _shardFactory.BuildShard(
                    async,
                    shardPath,
                    shardCursor)
                                     .ConfigureAwait(false);

                if (shard.HasNext())
                {
                    shards.Add(shard);
                }
            }

            int    shardIndex       = 0;
            string currentShardPath = cursor?.CurrentShardPath;

            if (!string.IsNullOrWhiteSpace(currentShardPath))
            {
                shardIndex = shards.FindIndex(s => s.ShardPath == currentShardPath);
                if (shardIndex < 0)
                {
                    // Either shard doesn't exist or cursor is pointing to end of shard. So start from beginning.
                    shardIndex = 0;
                }
            }
            return(new Segment(
                       shards,
                       shardIndex,
                       dateTime,
                       manifestPath));
        }
Beispiel #5
0
        public async Task <ChangeFeed> BuildChangeFeed(
            DateTimeOffset?startTime,
            DateTimeOffset?endTime,
            string continuation,
            bool async,
            CancellationToken cancellationToken)
        {
            DateTimeOffset   lastConsumable;
            Queue <string>   years    = new Queue <string>();
            Queue <string>   segments = new Queue <string>();
            ChangeFeedCursor cursor   = null;

            // Create cursor
            if (continuation != null)
            {
                cursor = JsonSerializer.Deserialize <ChangeFeedCursor>(continuation);
                ValidateCursor(_containerClient, cursor);
                startTime = BlobChangeFeedExtensions.ToDateTimeOffset(cursor.CurrentSegmentCursor.SegmentPath).Value;
                endTime   = cursor.EndTime;
            }
            // Round start and end time if we are not using the cursor.
            else
            {
                startTime = startTime.RoundDownToNearestHour();
                endTime   = endTime.RoundUpToNearestHour();
            }

            // Check if Change Feed has been abled for this account.
            bool changeFeedContainerExists;

            if (async)
            {
                changeFeedContainerExists = await _containerClient.ExistsAsync(cancellationToken : cancellationToken).ConfigureAwait(false);
            }
            else
            {
                changeFeedContainerExists = _containerClient.Exists(cancellationToken: cancellationToken);
            }

            if (!changeFeedContainerExists)
            {
                throw new ArgumentException("Change Feed hasn't been enabled on this account, or is currently being enabled.");
            }

            // Get last consumable
            BlobClient blobClient = _containerClient.GetBlobClient(Constants.ChangeFeed.MetaSegmentsPath);
            BlobDownloadStreamingResult blobDownloadInfo;

            try
            {
                if (async)
                {
                    blobDownloadInfo = await blobClient.DownloadStreamingAsync(cancellationToken : cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    blobDownloadInfo = blobClient.DownloadStreaming(cancellationToken: cancellationToken);
                }
            }
            catch (RequestFailedException e) when(e.ErrorCode == BlobErrorCode.BlobNotFound)
            {
                return(ChangeFeed.Empty());
            }

            JsonDocument jsonMetaSegment;

            if (async)
            {
                jsonMetaSegment = await JsonDocument.ParseAsync(
                    blobDownloadInfo.Content,
                    cancellationToken : cancellationToken
                    ).ConfigureAwait(false);
            }
            else
            {
                jsonMetaSegment = JsonDocument.Parse(blobDownloadInfo.Content);
            }

            lastConsumable = jsonMetaSegment.RootElement.GetProperty("lastConsumable").GetDateTimeOffset();

            // Get year paths
            years = await GetYearPathsInternal(
                async,
                cancellationToken).ConfigureAwait(false);

            // Dequeue any years that occur before start time
            if (startTime.HasValue)
            {
                while (years.Count > 0 &&
                       BlobChangeFeedExtensions.ToDateTimeOffset(years.Peek()) < startTime.RoundDownToNearestYear())
                {
                    years.Dequeue();
                }
            }

            // There are no years.
            if (years.Count == 0)
            {
                return(ChangeFeed.Empty());
            }

            while (segments.Count == 0 && years.Count > 0)
            {
                // Get Segments for year
                segments = await BlobChangeFeedExtensions.GetSegmentsInYearInternal(
                    containerClient : _containerClient,
                    yearPath : years.Dequeue(),
                    startTime : startTime,
                    endTime : BlobChangeFeedExtensions.MinDateTime(lastConsumable, endTime),
                    async : async,
                    cancellationToken : cancellationToken)
                           .ConfigureAwait(false);
            }

            // We were on the last year, and there were no more segments.
            if (segments.Count == 0)
            {
                return(ChangeFeed.Empty());
            }

            Segment currentSegment = await _segmentFactory.BuildSegment(
                async,
                segments.Dequeue(),
                cursor?.CurrentSegmentCursor)
                                     .ConfigureAwait(false);

            return(new ChangeFeed(
                       _containerClient,
                       _segmentFactory,
                       years,
                       segments,
                       currentSegment,
                       lastConsumable,
                       startTime,
                       endTime));
        }
Beispiel #6
0
        public async Task <string> PublishFileAsync(FileMapping fileMap, CancellationToken ct)
        {
            Uri      result      = null;
            int      retriesLeft = MaxFullLoopRetries;
            TimeSpan loopDelay   = FullLoopRetryDelay;
            bool     completed   = false;

            do
            {
                _logger.LogInformation($"Attempting to publish {fileMap.RelativeOutputPath}, {retriesLeft} tries left.");
                try
                {
                    BlobContainerClient client = await GetClient(ct);

                    if (client == null)
                    {
                        // client creation failed, return
                        return(null);
                    }

                    using var srcStream = new FileStream(fileMap.LocalSourcePath, FileMode.Open, FileAccess.Read);

                    BlobClient blobClient = client.GetBlobClient(GetBlobName(_releaseName, fileMap.RelativeOutputPath));

                    await blobClient.UploadAsync(srcStream, overwrite : true, ct);

                    BlobSasBuilder sasBuilder = new BlobSasBuilder()
                    {
                        BlobContainerName = client.Name,
                        BlobName          = blobClient.Name,
                        Identifier        = AccessPolicyDownloadId,
                        Protocol          = SasProtocol.Https
                    };
                    Uri accessUri = blobClient.GenerateSasUri(sasBuilder);

                    using BlobDownloadStreamingResult blobStream = (await blobClient.DownloadStreamingAsync(cancellationToken: ct)).Value;
                    srcStream.Position = 0;
                    completed          = await VerifyFileStreamsMatchAsync(srcStream, blobStream, ct);

                    result = accessUri;
                }
                catch (IOException ioEx) when(!(ioEx is PathTooLongException))
                {
                    _logger.LogWarning(ioEx, $"Failed to publish {fileMap.LocalSourcePath}, retries remaining: {retriesLeft}.");

                    /* Retry IO exceptions */
                    retriesLeft--;
                    loopDelay *= 2;

                    if (retriesLeft > 0)
                    {
                        await Task.Delay(loopDelay, ct);
                    }
                }
                catch (Exception ex)
                {
                    // Azure errors have their own built-in retry logic, so just abort if we got an AzureResponseException
                    _logger.LogWarning(ex, $"Failed to publish {fileMap.LocalSourcePath}, unexpected error, aborting.");
                    return(null);
                }
            } while (retriesLeft > 0 && !completed);

            return(result?.OriginalString);
        }