Ejemplo n.º 1
0
        private async Task <List <Task> > Dispatch(FilePartSource partSource, string chunkUploadUrl, string fileName, CancellationToken cancellationToken = default(CancellationToken))
        {
            var  incrementLock   = new object();
            long currentPartSize = partConfig.InitialPartSize;
            var  partSizeCalc    = new PartSizeCalculator(concurrentWorkers, partConfig);

            Func <FilePart, Task> attemptPartUpload = async part =>
            {
                IStopwatch timer = Stopwatch.StartNew();
                try
                {
                    await UploadPart(chunkUploadUrl, part, fileName, cancellationToken).ConfigureAwait(false);
                }
                finally
                {
                    timer.Stop();
                }
                lock (incrementLock)
                {
                    currentPartSize = partSizeCalc.NextPartSize(currentPartSize, part.Bytes.Length, timer.Elapsed);
                }
            };

            var workerTasks = new List <Task>();

            try
            {
                var  activeWorkers = new AsyncSemaphore(concurrentWorkers);
                bool giveUp        = false;
                while (!giveUp && partSource.HasMore)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        throw new UploadException(
                                  "Upload was cancelled",
                                  UploadStatusCode.Cancelled,
                                  new ActiveUploadState(UploadSpecification, LastConsecutiveByteUploaded));
                    }
                    await activeWorkers.WaitAsync().ConfigureAwait(false);

                    if (giveUp)
                    {
                        return(workerTasks);
                    }

                    var part = await partSource.GetNextPart(Interlocked.Read(ref currentPartSize)).ConfigureAwait(false);

                    var task = Task.Run(async() =>
                    {
                        try
                        {
                            await AttemptPartUploadWithRetry(attemptPartUpload, part, partConfig.PartRetryCount).ConfigureAwait(false);
                        }
                        catch
                        {
                            giveUp = true;
                            throw;
                        }
                        finally
                        {
                            activeWorkers.Release();
                            part.Bytes.Dispose();
                        }
                    });
                    workerTasks.Add(task);
                }
                return(workerTasks);
            }
            catch
            {
                ObserveExceptions(workerTasks);
                throw;
            }
        }