コード例 #1
0
        /// <summary>
        /// Writes an <see cref="IOperation" /> to the log.
        /// </summary>
        /// <param name="resource">The parent <see cref="ITransactedResource" /> responsible for serializing the operation.</param>
        /// <param name="operation">The operation to be written.</param>
        /// <remarks>
        /// <note>
        /// This property can only be called if the operation log is in <see cref="OperationLogMode.Undo" />
        /// mode.
        /// </note>
        /// </remarks>
        /// <exception cref="TransactionException">Thrown if the log isn't open or if the mode isn't <see cref="OperationLogMode.Undo" />.</exception>
        public void Write(ITransactedResource resource, IOperation operation)
        {
            long cbPos;
            long cb;

            using (TimedLock.Lock(this))
            {
                if (file == null)
                {
                    throw new TransactionException(ClosedMsg);
                }

                if (mode != OperationLogMode.Undo)
                {
                    throw new TransactionException("Write is available only when the log is in UNDO mode.");
                }

                file.WriteInt32(Magic);                     // Magic number
                cbPos = file.Position;                      // Length place holder
                file.WriteInt32(0);
                file.WriteString32(operation.Description);  // Description
                resource.WriteOperation(file, operation);   // Serialized operation

                cb = file.Position - cbPos - 4;
                if (cb < 0 || cb > int.MaxValue)
                {
                    throw new TransactionException("ITransactedResource.WriteOperation() returned with an unexpected stream position.");
                }

                file.Position = cbPos;
                file.WriteInt32((int)cb);
                file.Position = file.Length;
                file.Flush();
            }
        }
コード例 #2
0
        /// <summary>
        /// Rolls back the current transaction.
        /// </summary>
        /// <exception cref="TransactionException">Thrown if the stack is empty.</exception>
        internal void Rollback()
        {
            Transaction transaction;

            using (TimedLock.Lock(syncLock))
            {
                if (base.Count == 0)
                {
                    throw new TransactionException(EmptyMsg);
                }

                transaction = base.Pop();

                if (base.Count == 0)
                {
                    manager.Trace(0, "Begin rollback BASE", "ID=" + id.ToString());
                }
                else
                {
                    manager.Trace(0, string.Format("Begin rollback NESTED [{0}]", base.Count), "ID=" + id.ToString());
                }

                // Submit the operations being undone back to the
                // resource in the reverse order that they were
                // originally performed.

                ITransactedResource resource = manager.Resource;
                UpdateContext       context  = new UpdateContext(manager, false, false, true, ID);
                List <ILogPosition> positions;

                positions = operationLog.GetPositionsTo(transaction.Position);

                if (resource.BeginUndo(context))
                {
                    for (int i = 0; i < positions.Count; i++)
                    {
                        var operation = operationLog.Read(manager.Resource, positions[i]);

                        manager.Trace(0, "Undo: " + operation.Description, "ID=" + id.ToString());
                        resource.Undo(context, operation);
                    }
                }

                resource.EndUndo(context);

                if (base.Count == 0)
                {
                    manager.EndTransaction(this);
                    manager.Trace(0, "End rollback BASE", "ID=" + id.ToString());
                }
                else
                {
                    operationLog.Truncate(transaction.Position);
                    manager.Trace(0, string.Format("End rollback NESTED [{0}]", base.Count), "ID=" + id.ToString());
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Reads the operation from the specified position in the log.
        /// </summary>
        /// <param name="resource">The parent <see cref="ITransactedResource" /> responsible for deserializing the operation.</param>
        /// <param name="position">See the <see cref="ILogPosition" />.</param>
        /// <returns>The <see cref="IOperation" /> read from the log.</returns>
        /// <exception cref="TransactionException">Thrown if the log is not open.</exception>
        public IOperation Read(ITransactedResource resource, ILogPosition position)
        {
            using (TimedLock.Lock(syncLock))
            {
                if (!isOpen)
                {
                    throw new TransactionException(NotOpenMsg);
                }

                return(operations[((MemoryLogPosition)position).Index]);
            }
        }
コード例 #4
0
        /// <summary>
        /// Commits the current transaction.  If this is the base transaction then
        /// the operation will be commited to the <see cref="ITransactedResource" />.
        /// </summary>
        /// <exception cref="TransactionException">Thrown if the stack is empty.</exception>
        internal void Commit()
        {
            Transaction transaction;

            using (TimedLock.Lock(syncLock))
            {
                if (base.Count == 0)
                {
                    throw new TransactionException(EmptyMsg);
                }

                transaction = base.Pop();

                if (base.Count == 0)
                {
                    manager.Trace(0, "Begin commit BASE", "ID=" + id.ToString());

                    // We're committing the base transaction so play the redo log
                    // to the resource and then delete the log when we're finished.

                    ITransactedResource resource = manager.Resource;
                    UpdateContext       context  = new UpdateContext(manager, false, true, false, ID);
                    List <ILogPosition> positions;

                    positions = operationLog.GetPositions(false);

                    if (resource.BeginRedo(context))
                    {
                        for (int i = 0; i < positions.Count; i++)
                        {
                            var operation = operationLog.Read(manager.Resource, positions[i]);

                            manager.Trace(0, "Redo: " + operation.Description, "ID=" + id.ToString());
                            resource.Redo(context, operation);
                        }
                    }

                    resource.EndRedo(context);
                    manager.EndTransaction(this);

                    manager.Trace(0, "End commit BASE", "ID=" + id.ToString());
                }
                else
                {
                    manager.Trace(0, string.Format("Commit NESTED [{0}]", base.Count), "ID=" + id.ToString());
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Writes an <see cref="IOperation" /> to the log.
        /// </summary>
        /// <param name="resource">The parent <see cref="ITransactedResource" /> responsible for serializing the operation.</param>
        /// <param name="operation">The operation to be written.</param>
        /// <remarks>
        /// <note>
        /// This property can only be called if the operation log is in <see cref="OperationLogMode.Undo" />
        /// mode.
        /// </note>
        /// </remarks>
        /// <exception cref="TransactionException">Thrown if the log isn't open or if the mode isn't <see cref="OperationLogMode.Undo" />.</exception>
        public void Write(ITransactedResource resource, IOperation operation)
        {
            using (TimedLock.Lock(syncLock))
            {
                if (!isOpen)
                {
                    throw new TransactionException(NotOpenMsg);
                }

                if (mode != OperationLogMode.Undo)
                {
                    throw new TransactionException("Write is available only when the log is in UNDO mode.");
                }

                operations.Add(operation);
            }
        }
コード例 #6
0
        /// <summary>
        /// Starts the transaction manager.
        /// </summary>
        /// <param name="resource">The <see cref="ITransactedResource" /> to be managed.</param>
        /// <param name="log">The unopened <see cref="ITransactionLog" /> implementation to be used.</param>
        /// <param name="recoverCorrupt">Pass as <c>true</c> if recovery of corrupt transaction logs should be attempted.</param>
        public void Start(ITransactedResource resource, ITransactionLog log, bool recoverCorrupt)
        {
            using (TimedLock.Lock(this))
            {
                if (running)
                {
                    throw new TransactionException("Transaction manager has already started for [{0}].", resource.Name);
                }

                switch (log.Open(this))
                {
                case LogStatus.Ready:

                    break;

                case LogStatus.Recover:

                    this.resource = resource;
                    this.log      = log;

                    Recover();
                    break;

                case LogStatus.Corrupt:

                    if (!recoverCorrupt)
                    {
                        throw new TransactionException("Transaction log for [{0]] is corrupt.", resource.Name);
                    }

                    SysLog.LogWarning("Corrupt transaction log detected for [{0}]. Best efforts are being taken to recover.", resource.Name);
                    Recover();
                    break;
                }

                this.running        = true;
                this.resource       = resource;
                this.log            = log;
                this.transactions   = new Dictionary <Guid, BaseTransaction>();
                this.threadTransMap = new Dictionary <int, BaseTransaction>();
            }
        }
コード例 #7
0
        /// <summary>
        /// Reads the operation from the specified position in the log.
        /// </summary>
        /// <param name="resource">The parent <see cref="ITransactedResource" /> responsible for deserializing the operation.</param>
        /// <param name="position">See the <see cref="ILogPosition" />.</param>
        /// <returns>The <see cref="IOperation" /> read from the log.</returns>
        public IOperation Read(ITransactedResource resource, ILogPosition position)
        {
            int        cb;
            long       recEndPos;
            string     description;
            IOperation operation;

            using (TimedLock.Lock(this))
            {
                if (file == null)
                {
                    throw new TransactionException(ClosedMsg);
                }

                file.Position = ((FileLogPosition)position).Position;

                if (file.ReadInt32() != Magic)
                {
                    throw new TransactionException(CorruptMsg);
                }

                cb = file.ReadInt32();
                if (cb <= 0 || cb + file.Position > file.Length)
                {
                    throw new TransactionException(CorruptMsg);
                }

                recEndPos   = file.Position + cb;
                description = file.ReadString32();
                operation   = resource.ReadOperation(file);

                if (file.Position != recEndPos)
                {
                    SysLog.LogWarning("ITransactedResource.ReadOperation() returned with an unexpected stream position.");
                    file.Position = recEndPos;
                }

                return(operation);
            }
        }