/// <summary>
        /// Rolls back transaction by copying all backed up data bask to master stream and closes the transaction.
        /// </summary>
        public void RollbackTransaction()
        {
            if (logStreamHeader != null)
            {
                if (logStreamHeader.TransactionCompleted)
                {
                    throw new InvalidOperationException("Can't rollback completed transaction");
                }
                logStream.Position = TransactionLogStreamMetadata.StructureSize;

                // Copy segments from log stream back to stream
                for (int i = 0; i < logStreamHeader.SegmentCount; i++)
                {
                    SegmentMetadata sh = SegmentMetadata.Load(logStream);
                    if (!sh.TransactionId.Equals(logStreamHeader.TransactionId))
                    {
                        throw new InvalidOperationException("Wrong segment found in transaction log");
                    }
                    masterStream.Position = sh.Position;
                    CopyData(logStream, sh.Size, masterStream);
                }

                // Set back original stream length
                if (logStreamHeader.StreamLength < masterStream.Length)
                {
                    masterStream.SetLength(logStreamHeader.StreamLength);
                }

                masterStream.Flush();
                logStream.SetLength(0);
                logStream.Flush();
                logStreamHeader = null;
                rollbackNeeded  = false;
            }
        }
        /// <summary>
        /// Marks in the log file that transaction has ended
        /// </summary>
        public void EndTransaction()
        {
            CheckState();
            if (logStreamHeader != null)
            {
                masterStream.Flush();

                logStreamHeader.TransactionCompleted = true;
                logStreamHeader.Save(logStream);
                logStream.Flush();

                logStreamHeader = null;

                CheckSegments();
            }
        }
        /// <summary>
        /// Start transaction
        /// </summary>
        /// <param name="initialSegments">Areas in master stream which don't require backing up. Can be null.</param>
        public Guid BeginTransaction(IEnumerable <Segment> initialSegments = null)
        {
            CheckState();
            if (logStream == null)
            {
                throw new InvalidOperationException("Log stream not specified");
            }
            if (logStreamHeader != null)
            {
                throw new InvalidOperationException("Unable to start new transaction while existing transaction is in progress");
            }

            // Add custom segments that will not be backed up
            segments.Clear();
            if (initialSegments != null)
            {
                // <源码修改>
                //IOrderedEnumerable<Segment> orderedList = initialSegments.OrderBy(x => x.Location);
                var orderedList = new List <Segment>(initialSegments);
                orderedList.Sort(SegmentComparer.Instance);
                // </源码修改>
                foreach (var segment in orderedList)
                {
                    segments.AddLast(segment);
                }
            }
            // Add unallocated space after the end of stream
            segments.AddLast(new Segment(masterStream.Length, long.MaxValue - masterStream.Length));
            CheckSegments();

            // Truncate transaction log
            logStream.SetLength(0);
            logStream.Flush();

            // Initialize transaction log
            logStreamHeader = new TransactionLogStreamMetadata
            {
                TransactionId        = Guid.NewGuid(),
                StreamLength         = masterStream.Length,
                SegmentCount         = 0,
                TransactionCompleted = false
            };
            logStreamHeader.Save(logStream);
            logStream.Flush();

            return(logStreamHeader.TransactionId);
        }
        /// <summary>
        /// Consrtructs a transaction stream on top of the specified master stream
        /// </summary>
        /// <param name="masterStream">Stream for which backup si performed</param>
        /// <param name="logStream">Stream where backed up data is stored</param>
        /// <param name="blockSize">Size of the minimum block size that will be backed up</param>
        public TransactionStream(Stream masterStream, Stream logStream, long blockSize)
        {
            this.masterStream = masterStream;
            this.logStream    = logStream;
            this.blockSize    = blockSize;

            // Check if previous transaction has completed
            if (logStream != null && logStream.Length > TransactionLogStreamMetadata.StructureSize)
            {
                logStreamHeader = TransactionLogStreamMetadata.Load(logStream);
                rollbackNeeded  = !logStreamHeader.TransactionCompleted;
                if (logStreamHeader.SegmentCount == 0 || logStreamHeader.TransactionCompleted)
                {
                    logStreamHeader = null;
                }
            }
        }