/// <inheritdoc /> protected override TimeSpan RunOnce(CancellationToken token) { bool performedWork = false; LogFileSection section; while (_pendingModifications.TryDequeue(out section) && !token.IsCancellationRequested) { if (section.IsReset) { Clear(); _lastLogEntry.Clear(); _currentSourceIndex = 0; } else if (section.IsInvalidate) { LogLineIndex startIndex = section.Index; _fullSourceSection = new LogFileSection(0, (int)startIndex); if (_currentSourceIndex > _fullSourceSection.LastIndex) { _currentSourceIndex = (int)section.Index; } Invalidate(_currentSourceIndex); RemoveInvalidatedLines(_lastLogEntry, _currentSourceIndex); } else { _fullSourceSection = LogFileSection.MinimumBoundingLine(_fullSourceSection, section); } performedWork = true; } if (!_fullSourceSection.IsEndOfSection(_currentSourceIndex)) { int remaining = _fullSourceSection.Index + _fullSourceSection.Count - _currentSourceIndex; int nextCount = Math.Min(remaining, BatchSize); var nextSection = new LogFileSection(_currentSourceIndex, nextCount); _source.GetSection(nextSection, _buffer); for (int i = 0; i < nextCount; ++i) { if (token.IsCancellationRequested) { break; } LogLine line = _buffer[i]; if (_lastLogEntry.Count == 0 || _lastLogEntry[0].LogEntryIndex == line.LogEntryIndex) { TryAddLogLine(line); } else if (line.LogEntryIndex != _lastLogEntry[0].LogEntryIndex) { TryAddLogEntry(_lastLogEntry); _lastLogEntry.Clear(); TryAddLogLine(line); } } _currentSourceIndex += nextCount; } if (_fullSourceSection.IsEndOfSection(_currentSourceIndex)) { TryAddLogEntry(_lastLogEntry); Listeners.OnRead(_indices.Count); if (_source.EndOfSourceReached) { SetEndOfSourceReached(); } } if (performedWork) { return(TimeSpan.Zero); } return(_maximumWaitTime); }