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)); } }
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)); } }