Esempio n. 1
0
        protected override async Task <List <Utils.Range> > DoGetRangesAsync(Utils.RangesSpan rangesSpan)
        {
            AccessCondition accessCondition = Utils.GenerateIfMatchConditionWithCustomerCondition(
                this.sourceLocation.Blob.Properties.ETag,
                this.sourceLocation.AccessCondition);

            List <Utils.Range> rangeList = new List <Utils.Range>();

            foreach (var pageRange in await this.pageBlob.GetPageRangesAsync(
                         rangesSpan.StartOffset,
                         rangesSpan.EndOffset - rangesSpan.StartOffset + 1,
                         accessCondition,
                         Utils.GenerateBlobRequestOptions(this.sourceLocation.BlobRequestOptions),
                         Utils.GenerateOperationContext(this.Controller.TransferContext),
                         this.CancellationToken))
            {
                rangeList.Add(new Utils.Range()
                {
                    StartOffset = pageRange.StartOffset,
                    EndOffset   = pageRange.EndOffset,
                    HasData     = true
                });
            }

            return(rangeList);
        }
Esempio n. 2
0
        protected override async Task <List <Utils.Range> > DoGetRangesAsync(Utils.RangesSpan rangesSpan)
        {
            List <Utils.Range> rangeList = new List <Utils.Range>();

            foreach (var fileRange in await this.cloudFile.ListRangesAsync(
                         rangesSpan.StartOffset,
                         rangesSpan.EndOffset - rangesSpan.StartOffset + 1,
                         null,
                         Utils.GenerateFileRequestOptions(this.sourceLocation.FileRequestOptions),
                         Utils.GenerateOperationContext(this.Controller.TransferContext),
                         this.CancellationToken))
            {
                rangeList.Add(new Utils.Range()
                {
                    StartOffset = fileRange.StartOffset,
                    EndOffset   = fileRange.EndOffset,
                    HasData     = true
                });
            }

            return(rangeList);
        }
Esempio n. 3
0
 protected abstract Task <List <Utils.Range> > DoGetRangesAsync(Utils.RangesSpan rangesSpan);
Esempio n. 4
0
        /// <summary>
        /// It might fail to get large ranges list from storage. This method is to split the whole file to spans of 148MB to get ranges.
        /// In restartable, we only need to get ranges for chunks in TransferWindow and after TransferEntryOffset in check point.
        /// In TransferWindow, there might be some chunks adjacent to TransferEntryOffset, so this method will first merge these chunks into TransferEntryOffset;
        /// Then in remained chunks in the TransferWindow, it's very possible that ranges of several chunks can be got in one 148MB span.
        /// To avoid sending too many get ranges requests, this method will merge the chunks to 148MB spans.
        /// </summary>
        private void PrepareToGetRanges()
        {
            this.getRangesSpanIndex = -1;
            this.rangesSpanList     = new List <Utils.RangesSpan>();
            this.rangeList          = new List <Utils.Range>();

            this.nextDownloadIndex = 0;

            SingleObjectCheckpoint checkpoint = this.transferJob.CheckPoint;
            int blockSize = this.SharedTransferData.BlockSize;

            Utils.RangesSpan rangesSpan = null;

            if ((null != checkpoint.TransferWindow) &&
                (checkpoint.TransferWindow.Any()))
            {
                checkpoint.TransferWindow.Sort();

                long lastOffset = 0;
                if (checkpoint.EntryTransferOffset == this.SharedTransferData.TotalLength)
                {
                    long lengthBeforeLastChunk = checkpoint.EntryTransferOffset % blockSize;
                    lastOffset = 0 == lengthBeforeLastChunk ?
                                 checkpoint.EntryTransferOffset - blockSize :
                                 checkpoint.EntryTransferOffset - lengthBeforeLastChunk;
                }
                else
                {
                    lastOffset = checkpoint.EntryTransferOffset - blockSize;
                }

                for (int i = checkpoint.TransferWindow.Count - 1; i >= 0; i--)
                {
                    if (lastOffset == checkpoint.TransferWindow[i])
                    {
                        checkpoint.TransferWindow.RemoveAt(i);
                        checkpoint.EntryTransferOffset = lastOffset;
                    }
                    else if (lastOffset < checkpoint.TransferWindow[i])
                    {
                        throw new FormatException(Resources.RestartableInfoCorruptedException);
                    }
                    else
                    {
                        break;
                    }

                    lastOffset = checkpoint.EntryTransferOffset - blockSize;
                }

                if (this.transferJob.CheckPoint.TransferWindow.Any())
                {
                    rangesSpan             = new Utils.RangesSpan();
                    rangesSpan.StartOffset = checkpoint.TransferWindow[0];
                    rangesSpan.EndOffset   = Math.Min(rangesSpan.StartOffset + Constants.PageRangesSpanSize, this.SharedTransferData.TotalLength) - 1;

                    for (int i = 1; i < checkpoint.TransferWindow.Count; ++i)
                    {
                        if (checkpoint.TransferWindow[i] + blockSize > rangesSpan.EndOffset)
                        {
                            long lastEndOffset = rangesSpan.EndOffset;
                            this.rangesSpanList.Add(rangesSpan);
                            rangesSpan             = new Utils.RangesSpan();
                            rangesSpan.StartOffset = checkpoint.TransferWindow[i] > lastEndOffset ? checkpoint.TransferWindow[i] : lastEndOffset + 1;
                            rangesSpan.EndOffset   = Math.Min(rangesSpan.StartOffset + Constants.PageRangesSpanSize, this.SharedTransferData.TotalLength) - 1;
                        }
                    }

                    this.rangesSpanList.Add(rangesSpan);
                }
            }

            long offset = null != rangesSpan ?
                          rangesSpan.EndOffset > checkpoint.EntryTransferOffset ?
                          rangesSpan.EndOffset + 1 :
                          checkpoint.EntryTransferOffset :
                          checkpoint.EntryTransferOffset;

            while (offset < this.SharedTransferData.TotalLength)
            {
                rangesSpan = new Utils.RangesSpan()
                {
                    StartOffset = offset,
                    EndOffset   = Math.Min(offset + Constants.PageRangesSpanSize, this.SharedTransferData.TotalLength) - 1
                };

                this.rangesSpanList.Add(rangesSpan);
                offset = rangesSpan.EndOffset + 1;
            }

            if (!this.rangesSpanList.Any())
            {
                return;
            }
            else if (this.rangesSpanList.Count == 1)
            {
                if (this.rangesSpanList[0].EndOffset - this.rangesSpanList[0].StartOffset < blockSize)
                {
                    this.rangeList.Add(new Utils.Range()
                    {
                        StartOffset = this.rangesSpanList[0].StartOffset,
                        EndOffset   = this.rangesSpanList[0].EndOffset,
                        HasData     = true
                    });

                    this.rangesSpanList.Clear();
                    return;
                }
            }

            this.getRangesCountDownEvent = new CountdownEvent(this.rangesSpanList.Count);
        }
Esempio n. 5
0
        private async Task GetRangesAsync()
        {
            Debug.Assert(
                (this.state == State.GetRanges) || (this.state == State.Error),
                "GetRangesAsync called, but state isn't GetRanges or Error");

            this.hasWork = false;

            this.lastTransferOffset = this.SharedTransferData.TransferJob.CheckPoint.EntryTransferOffset;

            int spanIndex = Interlocked.Increment(ref this.getRangesSpanIndex);

            this.hasWork = spanIndex < (this.rangesSpanList.Count - 1);

            Utils.RangesSpan rangesSpan = this.rangesSpanList[spanIndex];

            rangesSpan.Ranges = await this.DoGetRangesAsync(rangesSpan);

            List <Utils.Range> ranges = new List <Utils.Range>();

            Utils.Range currentRange       = null;
            long        currentStartOffset = rangesSpan.StartOffset;

            foreach (var range in rangesSpan.Ranges)
            {
                long emptySize = range.StartOffset - currentStartOffset;
                if (emptySize > 0 && emptySize < MinimumNoDataRangeSize)
                {
                    // There is empty range which size is smaller than MinimumNoDataRangeSize
                    // merge it to the adjacent data range.
                    if (null == currentRange)
                    {
                        currentRange = new Utils.Range()
                        {
                            StartOffset = currentStartOffset,
                            EndOffset   = range.EndOffset,
                            HasData     = range.HasData
                        };
                    }
                    else
                    {
                        currentRange.EndOffset = range.EndOffset;
                    }
                }
                else
                {
                    // Empty range size is larger than MinimumNoDataRangeSize
                    // put current data range in list and start to deal with the next data range.
                    if (null != currentRange)
                    {
                        ranges.Add(currentRange);
                    }

                    currentRange = new Utils.Range
                    {
                        StartOffset = range.StartOffset,
                        EndOffset   = range.EndOffset,
                        HasData     = range.HasData
                    };
                }

                currentStartOffset = range.EndOffset + 1;
            }

            if (null != currentRange)
            {
                ranges.Add(currentRange);
            }

            rangesSpan.Ranges = ranges;

            if (this.getRangesCountDownEvent.Signal())
            {
                this.ArrangeRanges();

                // Don't call CallFinish here, InitDownloadInfo will call it.
                this.InitDownloadInfo();
            }
        }