/// <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;
            }
        }
Beispiel #2
0
        public static SegmentMetadata Load(Stream stream)
        {
            BinaryReader    reader = new BinaryReader(stream);
            SegmentMetadata sh     = new SegmentMetadata
            {
                TransactionId = new Guid(reader.ReadBytes(16)),
                Position      = reader.ReadInt64(),
                Size          = reader.ReadInt32()
            };

            return(sh);
        }
        // Copies a section of data from master stream to the log stream
        void BackupData(long location, int size)
        {
            logStream.Seek(0, SeekOrigin.End);

            // Write segment header
            SegmentMetadata sh = new SegmentMetadata
            {
                TransactionId = logStreamHeader.TransactionId,
                Position      = location,
                Size          = size
            };
            long metadataPos = logStream.Position;

            sh.Save(logStream);

            // Copy data
            masterStream.Position = location;

            int bytesCopied = CopyData(masterStream, size, logStream);

            // If bytes copied differ from size in header, update the header
            if (bytesCopied != size)
            {
                logStream.Position = metadataPos;

                sh.Size = bytesCopied;
                sh.Save(logStream);
            }

            logStream.Flush();

            // Update log stream header
            logStreamHeader.SegmentCount++;
            logStreamHeader.Save(logStream);
            logStream.Flush();
        }