Example #1
0
        /// <summary>
        /// Returns event records in the reverse sequence they were committed into TF.
        /// Positions is specified as post-positions (pointer after the end of record).
        /// </summary>
        public ReadAllResult ReadAllEventsBackward(TFPos pos, int maxCount, bool resolveLinks)
        {
            var records = new List <ResolvedEventRecord>();
            var nextPos = pos;
            // in case we are at position after which there is no commit at all, in that case we have to force
            // PreparePosition to 0, so if you decide to read backwards from PrevPos,
            // you will receive all prepares.
            var  prevPos     = new TFPos(pos.CommitPosition, 0);
            var  count       = 0;
            bool firstCommit = true;
            ITransactionFileSequentialReader seqReader = GetSeqReader();

            try
            {
                long nextCommitPostPos = pos.CommitPosition;
                while (count < maxCount)
                {
                    seqReader.Reposition(nextCommitPostPos);

                    SeqReadResult result;
                    do
                    {
                        result = seqReader.TryReadPrev();
                    }while (result.Success && result.LogRecord.RecordType != LogRecordType.Commit); // skip until commit

                    if (!result.Success)                                                            // no more records in TF
                    {
                        break;
                    }

                    var commitPostPos = result.RecordPostPosition;
                    nextCommitPostPos = result.RecordPrePosition;

                    var commit = (CommitLogRecord)result.LogRecord;
                    if (firstCommit)
                    {
                        firstCommit = false;
                        // for forward pass we allow read the same commit and as we have post-positions here
                        // we can put just prepare post-position as prepare pre-position for forward read
                        // so we put pre-position of commit and post-position of prepare
                        prevPos = new TFPos(commit.LogPosition, pos.PreparePosition);
                    }

                    // as we don't know exact position of the last record of transaction,
                    // we have to sequentially scan backwards, so no need to reposition
                    //seqReader.Reposition(commitLogRecord.TransactionPosition);
                    while (count < maxCount)
                    {
                        result = seqReader.TryReadPrev();
                        if (!result.Success) // no more records in TF
                        {
                            break;
                        }
                        // prepare with TransactionBegin could be scavenged already
                        // so we could reach beyond the start of transaction. In that case we have to stop.
                        if (result.LogRecord.Position < commit.TransactionPosition)
                        {
                            break;
                        }
                        if (result.LogRecord.RecordType != LogRecordType.Prepare)
                        {
                            continue;
                        }

                        var prepare = (PrepareLogRecord)result.LogRecord;
                        if (prepare.TransactionPosition != commit.TransactionPosition) // wrong prepare
                        {
                            continue;
                        }

                        if ((prepare.Flags & PrepareFlags.Data) != 0) // prepare with useful data
                        {
                            if (new TFPos(commitPostPos, result.RecordPostPosition) <= pos)
                            {
                                var eventRecord = new EventRecord(commit.EventNumber + prepare.TransactionOffset, prepare);

                                EventRecord linkToEvent = null;
                                if (resolveLinks)
                                {
                                    var resolved = ResolveLinkToEvent(eventRecord);
                                    if (resolved != null)
                                    {
                                        linkToEvent = eventRecord;
                                        eventRecord = resolved;
                                    }
                                }

                                records.Add(new ResolvedEventRecord(eventRecord, linkToEvent, commit.Position));
                                count++;

                                // for backward pass we allow read the same commit, but force to skip last read prepare
                                // so we put post-position of commit and pre-position of prepare
                                nextPos = new TFPos(commitPostPos, prepare.LogPosition);
                            }
                        }
                        if ((prepare.Flags & PrepareFlags.TransactionBegin) != 0)
                        {
                            break;
                        }
                    }
                }
            }
            finally
            {
                ReturnSeqReader(seqReader);
            }
            return(new ReadAllResult(records, maxCount, pos, nextPos, prevPos));
        }
Example #2
0
        /// <summary>
        /// Returns event records in the sequence they were committed into TF.
        /// Positions is specified as pre-positions (pointer at the beginning of the record).
        /// </summary>
        public ReadAllResult ReadAllEventsForward(TFPos pos, int maxCount, bool resolveLinks)
        {
            var records = new List <ResolvedEventRecord>();
            var nextPos = pos;
            // in case we are at position after which there is no commit at all, in that case we have to force
            // PreparePosition to int.MaxValue, so if you decide to read backwards from PrevPos,
            // you will receive all prepares.
            var  prevPos     = new TFPos(pos.CommitPosition, int.MaxValue);
            var  count       = 0;
            bool firstCommit = true;
            ITransactionFileSequentialReader seqReader = GetSeqReader();

            try
            {
                long nextCommitPos = pos.CommitPosition;
                while (count < maxCount)
                {
                    seqReader.Reposition(nextCommitPos);

                    SeqReadResult result;
                    do
                    {
                        result = seqReader.TryReadNext();
                    }while (result.Success && result.LogRecord.RecordType != LogRecordType.Commit); // skip until commit

                    if (!result.Success)                                                            // no more records in TF
                    {
                        break;
                    }

                    nextCommitPos = result.RecordPostPosition;

                    var commit = (CommitLogRecord)result.LogRecord;
                    if (firstCommit)
                    {
                        firstCommit = false;
                        // for backward pass we want to allow read the same commit and skip read prepares,
                        // so we put post-position of commit and post-position of prepare as TFPos for backward pass
                        prevPos = new TFPos(result.RecordPostPosition, pos.PreparePosition);
                    }

                    seqReader.Reposition(commit.TransactionPosition);
                    while (count < maxCount)
                    {
                        result = seqReader.TryReadNext();
                        if (!result.Success) // no more records in TF
                        {
                            break;
                        }
                        // prepare with TransactionEnd could be scavenged already
                        // so we could reach the same commit record. In that case have to stop
                        if (result.LogRecord.Position >= commit.Position)
                        {
                            break;
                        }
                        if (result.LogRecord.RecordType != LogRecordType.Prepare)
                        {
                            continue;
                        }

                        var prepare = (PrepareLogRecord)result.LogRecord;
                        if (prepare.TransactionPosition != commit.TransactionPosition) // wrong prepare
                        {
                            continue;
                        }

                        if ((prepare.Flags & PrepareFlags.Data) != 0) // prepare with useful data
                        {
                            if (new TFPos(commit.Position, prepare.LogPosition) >= pos)
                            {
                                var eventRecord = new EventRecord(commit.EventNumber + prepare.TransactionOffset, prepare);

                                EventRecord linkToEvent = null;
                                if (resolveLinks)
                                {
                                    var resolved = ResolveLinkToEvent(eventRecord);
                                    if (resolved != null)
                                    {
                                        linkToEvent = eventRecord;
                                        eventRecord = resolved;
                                    }
                                }

                                records.Add(new ResolvedEventRecord(eventRecord, linkToEvent, commit.Position));
                                count++;

                                // for forward pass position is inclusive,
                                // so we put pre-position of commit and post-position of prepare
                                nextPos = new TFPos(commit.LogPosition, result.RecordPostPosition);
                            }
                        }

                        if ((prepare.Flags & PrepareFlags.TransactionEnd) != 0)
                        {
                            break;
                        }
                    }
                }
            }
            finally
            {
                ReturnSeqReader(seqReader);
            }
            return(new ReadAllResult(records, maxCount, pos, nextPos, prevPos));
        }