예제 #1
0
 IndexReadEventResult IIndexReader.ReadEvent(string streamId, int eventNumber)
 {
     Ensure.NotNullOrEmpty(streamId, "streamId");
     if (eventNumber < -1)
     {
         throw new ArgumentOutOfRangeException("eventNumber");
     }
     using (var reader = _cache.BorrowReader())
     {
         return(ReadEventInternal(reader, streamId, eventNumber));
     }
 }
예제 #2
0
        public IndexReadAllResult ReadAllEventsForward(TFPos pos, int maxCount)
        {
            var records = new List <CommitEventRecord>();
            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 long.MaxValue, so if you decide to read backwards from PrevPos,
            // you will receive all prepares.
            var  prevPos     = new TFPos(pos.CommitPosition, long.MaxValue);
            long count       = 0;
            bool firstCommit = true;

            using (var reader = _cache.BorrowReader())
            {
                long nextCommitPos = pos.CommitPosition;
                while (count < maxCount)
                {
                    reader.Reposition(nextCommitPos);

                    SeqReadResult result;
                    while ((result = reader.TryReadNext()).Success && !IsCommitAlike(result.LogRecord))
                    {
                        // skip until commit
                    }

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

                    nextCommitPos = result.RecordPostPosition;

                    switch (result.LogRecord.RecordType)
                    {
                    case LogRecordType.Prepare:
                    {
                        var prepare = (PrepareLogRecord)result.LogRecord;
                        if (firstCommit)
                        {
                            firstCommit = false;
                            prevPos     = new TFPos(result.RecordPrePosition, result.RecordPrePosition);
                        }
                        if (prepare.Flags.HasAnyOf(PrepareFlags.Data | PrepareFlags.StreamDelete) &&
                            new TFPos(prepare.LogPosition, prepare.LogPosition) >= pos)
                        {
                            var eventRecord = new EventRecord(prepare.ExpectedVersion + 1 /* EventNumber */, prepare);
                            records.Add(new CommitEventRecord(eventRecord, prepare.LogPosition));
                            count++;
                            nextPos = new TFPos(result.RecordPostPosition, result.RecordPostPosition);
                        }
                        break;
                    }

                    case LogRecordType.Commit:
                    {
                        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);
                        }
                        reader.Reposition(commit.TransactionPosition);
                        while (count < maxCount)
                        {
                            result = reader.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.LogPosition >= commit.LogPosition)
                            {
                                break;
                            }
                            if (result.LogRecord.RecordType != LogRecordType.Prepare)
                            {
                                continue;
                            }

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

                            // prepare with useful data or delete tombstone
                            if (prepare.Flags.HasAnyOf(PrepareFlags.Data | PrepareFlags.StreamDelete) &&
                                new TFPos(commit.LogPosition, prepare.LogPosition) >= pos)
                            {
                                var eventRecord = new EventRecord(commit.FirstEventNumber + prepare.TransactionOffset, prepare);
                                records.Add(new CommitEventRecord(eventRecord, commit.LogPosition));
                                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.HasAnyOf(PrepareFlags.TransactionEnd))
                            {
                                break;
                            }
                        }
                        break;
                    }

                    default:
                        throw new Exception(string.Format("Unexpected log record type: {0}.", result.LogRecord.RecordType));
                    }
                }
                return(new IndexReadAllResult(records, pos, nextPos, prevPos));
            }
        }