// in v2 this checks if the first character is '$' // system streams can be created dynamically at runtime // e.g. "$persistentsubscription-" + _eventStreamId + "::" + _groupName + "-parked" // so we can either allocate a range of numbers (how many?) for them, or look up the name and see if it begins with $. // for now do the latter because (1) allocating a range of numbers will probably get fiddly // and (2) i expect we will find that at the point we are trying to determine if a stream is a system stream then // we will have already looked up its info in the stream index, so this call will become trivial or unnecessary. public bool IsSystemStream(StreamId streamId) { if (IsVirtualStream(streamId) || _metastreams.IsMetaStream(streamId) || streamId == NoSystemStream) { return(true); } if (streamId == NoUserStream) { return(false); } var streamName = _streamNames.LookupName(streamId); return(SystemStreams.IsSystemStream(streamName)); }
private IndexReadAllResult ReadAllEventsForwardInternal(TFPos pos, int maxCount, int maxSearchWindow, IEventFilter eventFilter) { 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); var consideredEventsCount = 0L; var firstCommit = true; var reachedEndOfStream = false; using (var reader = _backend.BorrowReader()) { long nextCommitPos = pos.CommitPosition; while (records.Count < maxCount && consideredEventsCount < maxSearchWindow) { if (nextCommitPos > _indexCommitter.LastIndexedPosition) { reachedEndOfStream = true; break; } 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: case LogRecordType.Stream: { var prepare = (IPrepareLogRecord <TStreamId>)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 streamName = _streamNames.LookupName(prepare.EventStreamId); var eventRecord = new EventRecord(eventNumber: prepare.ExpectedVersion + 1, prepare, streamName); consideredEventsCount++; if (eventFilter.IsEventAllowed(eventRecord)) { records.Add(new CommitEventRecord(eventRecord, prepare.LogPosition)); } nextPos = new TFPos(result.RecordPostPosition, 0); } 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 (consideredEventsCount < 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 = (IPrepareLogRecord <TStreamId>)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 streamName = _streamNames.LookupName(prepare.EventStreamId); var eventRecord = new EventRecord(commit.FirstEventNumber + prepare.TransactionOffset, prepare, streamName); consideredEventsCount++; if (eventFilter.IsEventAllowed(eventRecord)) { records.Add(new CommitEventRecord(eventRecord, commit.LogPosition)); } // 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, reachedEndOfStream, consideredEventsCount)); } }
string IReadIndex <TStreamId> .GetStreamName(TStreamId streamId) { return(_streamNames.LookupName(streamId)); }