/// <summary>
        /// Private dispose method to release managed/unmanaged objects.
        /// If disposing = true clean up managed resources as well as unmanaged resources.
        /// If disposing = false only clean up unmanaged resources.
        /// </summary>
        /// <param name="disposing">Indicates whether or not to dispose managed resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (null != this.MemoryStream)
                {
                    this.MemoryStream.Dispose();
                    this.MemoryStream = null;
                }

                if (null != this.MemoryBuffer)
                {
                    this.MemoryManager.ReleaseBuffer(this.MemoryBuffer);
                    this.MemoryManager = null;
                }
            }
        }
        public TransferDownloadStream(
            MemoryManager memoryManager, 
            TransferDownloadBuffer firstBuffer, 
            int firstOffset, 
            int firstCount,
            TransferDownloadBuffer secondBuffer,
            int secondOffset,
            int secondCount)
        {
            this.memoryManager = memoryManager;
            this.firstBuffer = firstBuffer;
            this.firstOffset = firstOffset;
            this.firstStream = new MemoryStream(this.firstBuffer.MemoryBuffer, firstOffset, firstCount);

            if (null != secondBuffer)
            {
                this.secondBuffer = secondBuffer;
                this.secondOffset = secondOffset;
                this.secondStream = new MemoryStream(this.secondBuffer.MemoryBuffer, secondOffset, secondCount);
            }
        }
        /// <summary>
        /// Initializes a new instance of the 
        /// <see cref="TransferScheduler" /> class.
        /// </summary>
        /// <param name="options">BlobTransfer options.</param>
        public TransferScheduler(TransferConfigurations options)
        {
            // If no options specified create a default one.
            this.transferOptions = options ?? new TransferConfigurations();

            this.internalControllerQueue = new ConcurrentQueue<ITransferController>();
            this.controllerQueue = new BlockingCollection<ITransferController>(
                this.internalControllerQueue);
            this.memoryManager = new MemoryManager(
                this.transferOptions.MaximumCacheSize,
                this.transferOptions.BlockSize);

            this.randomGenerator = new Random();

            this.scheduleSemaphore = new SemaphoreSlim(
                this.transferOptions.ParallelOperations, 
                this.transferOptions.ParallelOperations);

            this.StartSchedule();
        }
        /// <summary>
        /// Private dispose method to release managed/unmanaged objects.
        /// If disposing is true clean up managed resources as well as 
        /// unmanaged resources.
        /// If disposing is false only clean up unmanaged resources.
        /// </summary>
        /// <param name="disposing">Indicates whether or not to dispose 
        /// managed resources.</param>
        private void Dispose(bool disposing)
        {
            if (!this.isDisposed)
            {
                lock (this.disposeLock)
                {
                    // We got the lock, isDisposed is true, means that the disposing has been finished.
                    if (this.isDisposed)
                    {
                        return;
                    }

                    this.isDisposed = true;

                    this.CancelWork();
                    this.WaitForCompletion();

                    if (disposing)
                    {
                        if (null != this.controllerQueue)
                        {
                            this.controllerQueue.Dispose();
                            this.controllerQueue = null;
                        }

                        if (null != this.cancellationTokenSource)
                        {
                            this.cancellationTokenSource.Dispose();
                            this.cancellationTokenSource = null;
                        }

                        if (null != this.controllerResetEvent)
                        {
                            this.controllerResetEvent.Dispose();
                            this.controllerResetEvent = null;
                        }

                        if (null != this.scheduleSemaphore)
                        {
                            this.scheduleSemaphore.Dispose();
                            this.scheduleSemaphore = null;
                        }

                        this.memoryManager = null;
                    }
                }
            }
            else
            {
                this.WaitForCompletion();
            }
        }
        public static byte[] RequireBuffer(MemoryManager memoryManager, Action checkCancellation)
        {
            byte[] buffer;
            buffer = memoryManager.RequireBuffer();

            if (null == buffer)
            {
                int retryCount = 0;
                int retryInterval = 100;
                while ((retryCount < RequireBufferMaxRetryCount)
                    && (null == buffer))
                {
                    checkCancellation();
                    retryInterval <<= 1;
                    Thread.Sleep(retryInterval);
                    buffer = memoryManager.RequireBuffer();
                    ++retryCount;
                }
            }

            if (null == buffer)
            {
                throw new TransferException(
                    TransferErrorCode.FailToAllocateMemory,
                    Resources.FailedToAllocateMemoryException);
            }

            return buffer;
        }
 public TransferDownloadStream(MemoryManager memoryManager, TransferDownloadBuffer buffer, int offset, int count)
     :this(memoryManager, buffer, offset, count, null, 0, 0)
 {
 }
 public TransferData(MemoryManager memoryManager)
 {
     this.memoryManager = memoryManager;
 }
        /// <summary>
        /// Calculate MD5 hash of transferred bytes.
        /// </summary>
        /// <param name="memoryManager">Reference to MemoryManager object to require buffer from.</param>
        /// <param name="checkCancellation">Action to check whether to cancel this calculation.</param>
        public void CalculateMd5(MemoryManager memoryManager, Action checkCancellation)
        {
            if (null == this.md5hash)
            {
                return;
            }

            byte[] buffer = null;

            try
            {
                buffer = Utils.RequireBuffer(memoryManager, checkCancellation);
            }
            catch (Exception)
            {
                lock (this.md5hash)
                {
                    this.finishedSeparateMd5Calculator = true;
                }

                throw;
            }

            long offset = 0;
            int readLength = 0;

            while (true)
            {
                lock (this.md5hash)
                {
                    if (offset >= this.md5hashOffset)
                    {
                        Debug.Assert(
                            offset == this.md5hashOffset,
                            "We should stop the separate calculator thread just at the transferred offset");

                        this.succeededSeparateMd5Calculator = true;
                        this.finishedSeparateMd5Calculator = true;
                        break;
                    }

                    readLength = (int)Math.Min(this.md5hashOffset - offset, buffer.Length);
                }

                try
                {
                    checkCancellation();
                    readLength = this.Read(offset, buffer, 0, readLength);

                    lock (this.md5hash)
                    {
                        this.md5hash.TransformBlock(buffer, 0, readLength, null, 0);
                    }
                }
                catch (Exception)
                {
                    lock (this.md5hash)
                    {
                        this.finishedSeparateMd5Calculator = true;
                    }

                    memoryManager.ReleaseBuffer(buffer);

                    throw;
                }

                offset += readLength;
            }

            memoryManager.ReleaseBuffer(buffer);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Calculate MD5 hash of transferred bytes.
        /// </summary>
        /// <param name="memoryManager">Reference to MemoryManager object to require buffer from.</param>
        /// <param name="checkCancellation">Action to check whether to cancel this calculation.</param>
        public void CalculateMd5(MemoryManager memoryManager, Action checkCancellation)
        {
            if (null == this.md5hash)
            {
                return;
            }

            byte[] buffer = null;

            try
            {
                buffer = Utils.RequireBuffer(memoryManager, checkCancellation);
            }
            catch (Exception)
            {
                lock (this.md5hash)
                {
                    this.finishedSeparateMd5Calculator = true;
                }

                throw;
            }

            long offset     = 0;
            int  readLength = 0;

            while (true)
            {
                lock (this.md5hash)
                {
                    if (offset >= this.md5hashOffset)
                    {
                        Debug.Assert(
                            offset == this.md5hashOffset,
                            "We should stop the separate calculator thread just at the transferred offset");

                        this.succeededSeparateMd5Calculator = true;
                        this.finishedSeparateMd5Calculator  = true;
                        break;
                    }

                    readLength = (int)Math.Min(this.md5hashOffset - offset, buffer.Length);
                }

                try
                {
                    checkCancellation();
                    readLength = this.Read(offset, buffer, 0, readLength);

                    lock (this.md5hash)
                    {
                        this.md5hash.UpdateHash(buffer, 0, readLength);
                    }
                }
                catch (Exception)
                {
                    lock (this.md5hash)
                    {
                        this.finishedSeparateMd5Calculator = true;
                    }

                    memoryManager.ReleaseBuffer(buffer);

                    throw;
                }

                offset += readLength;
            }

            memoryManager.ReleaseBuffer(buffer);
        }