Пример #1
0
        public void TestPrefetchAsyncBatch()
        {
            var pageSize     = 100;
            var buffer       = new PageBufferedLogSource(_taskScheduler, _source.Object, TimeSpan.Zero, pageSize: pageSize);
            var destination  = new LogBufferArray(4, new IColumnDescriptor[] { Core.Columns.Index, Core.Columns.RawContent });
            var queryOptions = new LogSourceQueryOptions(LogSourceQueryMode.FromCache | LogSourceQueryMode.FetchForLater);

            buffer.OnLogFileModified(_source.Object, LogSourceModification.Appended(0, 10));

            var section1ToQuery = new LogSourceSection(2, 4);

            buffer.GetEntries(section1ToQuery, destination, 0, queryOptions);
            _source.Verify(x => x.GetEntries(It.IsAny <IReadOnlyList <LogLineIndex> >(), It.IsAny <ILogBuffer>(), It.IsAny <int>(), It.IsAny <LogSourceQueryOptions>()),
                           Times.Never, "Because we didn't allow data to be retrieved on the calling thread");

            var section2ToQuery = new LogSourceSection(7, 3);

            buffer.GetEntries(section2ToQuery, destination, 0, queryOptions);
            _source.Verify(x => x.GetEntries(It.IsAny <IReadOnlyList <LogLineIndex> >(), It.IsAny <ILogBuffer>(), It.IsAny <int>(), It.IsAny <LogSourceQueryOptions>()),
                           Times.Never, "Because we didn't allow data to be retrieved on the calling thread");

            _taskScheduler.RunOnce();
            _source.Verify(x => x.GetEntries(new LogSourceSection(0, pageSize), It.IsAny <ILogBuffer>(), It.IsAny <int>(), It.IsAny <LogSourceQueryOptions>()),
                           Times.Once, "Because the buffer should avoid reading the same data for the same page multiple times in a row");
        }
Пример #2
0
        private void Append(LogSourceSection section)
        {
            var buffer = new LogBufferArray(section.Count, Core.Columns.Index, Core.Columns.Timestamp, Core.Columns.LogLevel);

            _source.GetEntries(section, buffer);

            lock (_syncRoot)
            {
                for (var i = 0; i < section.Count; ++i)
                {
                    var line = buffer[i];

                    if (_currentLogEntry.EntryIndex.IsInvalid ||
                        !AppendToCurrentLogEntry(line))
                    {
                        _currentLogEntry = _currentLogEntry.NextEntry(line.Index);
                    }

                    _indices.Add(_currentLogEntry);
                }
            }

            _currentSourceIndex += section.Count;
            _fullSourceSection   = new LogSourceSection(0, _currentSourceIndex.Value);
        }
Пример #3
0
 public ContiguousReadRequest(LogSourceSection sourceSection,
                              ILogBuffer destination,
                              int destinationIndex)
     : base(destination, destinationIndex)
 {
     _sourceSection = sourceSection;
 }
Пример #4
0
        public IReadOnlyList <MergedLogLineIndex> Get(LogSourceSection section)
        {
            var indices = new MergedLogLineIndex[section.Count];

            lock (_syncRoot)
            {
                if (section.Index.Value < _indices.Count)
                {
                    var count = Math.Min((section.Index + section.Count).Value, _indices.Count);
                    _indices.CopyTo(section.Index.Value, indices, 0, count);
                    for (var i = 0; i < section.Count - count; ++i)
                    {
                        indices[section.LastIndex + i] = MergedLogLineIndex.Invalid;
                    }
                }
                else
                {
                    for (var i = 0; i < section.Count; ++i)
                    {
                        indices[i] = MergedLogLineIndex.Invalid;
                    }
                }
            }

            return(indices);
        }
Пример #5
0
 private void AddToCache(ILogBuffer source, int destinationIndex, LogSourceSection contiguousSection)
 {
     lock (_syncRoot)
     {
         _buffer.TryAdd(contiguousSection, source, destinationIndex);
     }
 }
Пример #6
0
 protected override void OnSectionAppended(LogSourceSection section, IReadOnlyLogBuffer data, int totalLogEntryCount)
 {
     lock (_syncRoot)
     {
         _buffer.AddRange(data, section.Count);
     }
 }
Пример #7
0
        /// <summary>
        ///     Processes as many pending modifications as are available, removes existing indices if necessary and
        ///     establishes the boundaries of the source log file.
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private bool ProcessModifications(CancellationToken token)
        {
            bool performedWork = false;

            while (_pendingModifications.TryDequeue(out var modification) && !token.IsCancellationRequested)
            {
                if (modification.IsReset())
                {
                    Clear();
                    _lastLogBuffer.Clear();
                    _currentSourceIndex = 0;
                }
                else if (modification.IsRemoved(out var removedSection))
                {
                    LogLineIndex startIndex = removedSection.Index;
                    _fullSourceSection = new LogSourceSection(0, (int)startIndex);

                    if (_currentSourceIndex > _fullSourceSection.LastIndex)
                    {
                        _currentSourceIndex = (int)removedSection.Index;
                    }

                    RemoveFrom(_currentSourceIndex);
                    RemoveLinesFrom(_lastLogBuffer, _currentSourceIndex);
                }
                else if (modification.IsAppended(out var appendedSection))
                {
                    _fullSourceSection = LogSourceSection.MinimumBoundingLine(_fullSourceSection, appendedSection);
                }

                performedWork = true;
            }

            return(performedWork);
        }
Пример #8
0
        /// <summary>
        ///    Adds data from the given source to this cache.
        /// </summary>
        /// <param name="destinationSection">The destination indices of the log entries from the given source</param>
        /// <param name="source">The source from which to copy data to this buffer</param>
        /// <param name="sourceIndex">The index into the given source from which onwards log entries may be added to this cache.</param>
        public void TryAdd(LogSourceSection destinationSection, IReadOnlyLogBuffer source, int sourceIndex)
        {
            if (!CanCache(source))
            {
                return;
            }

            // We want to make sure to only read that data, which is actually covered by the log source.
            // This is because one thread might resize this buffer to a smaller size and then another thread
            // might try to add data which has been previously read, but is now no longer supposed to be part of the source.
            var sourceSectionEndIndex = Math.Min((int)(destinationSection.Index + destinationSection.Count), _sourceCount);

            for (LogLineIndex i = destinationSection.Index; i < sourceSectionEndIndex;)
            {
                var pageIndex = GetPageIndex(i);
                var page      = GetOrCreatePageByIndex(pageIndex);

                var remainingPageCount = (pageIndex + 1) * _pageSize - i;
                var count            = Math.Min(remainingPageCount, sourceSectionEndIndex - i);
                var sourceStartIndex = (i - destinationSection.Index) + sourceIndex;

                page.Add(sourceStartIndex, count, source, i);

                // We want the next copy operation to start at the beginning of the next page (it's a contiguous write after all)
                i += remainingPageCount;
            }
        }
Пример #9
0
        public void TestGetCount([Values(0, 1)] int count)
        {
            var section = new LogSourceSection(9001, count);

            section.Count.Should().Be(count);
            ((IReadOnlyList <LogLineIndex>)section).Count.Should().Be(count);
        }
Пример #10
0
        public void TestEnumerate([Range(0, 5)] int startIndex,
                                  [Range(0, 5)] int count)
        {
            var section  = new LogSourceSection(startIndex, count);
            var expected = Enumerable.Range(startIndex, count).Select(x => (LogLineIndex)x).ToArray();

            section.Should().Equal(expected);
        }
Пример #11
0
        /// <summary>
        ///    Processes all newly arrived log entries.
        /// </summary>
        /// <param name="token"></param>
        private void ProcessNewLogEntries(CancellationToken token)
        {
            if (!_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                int remaining   = _fullSourceSection.Index + _fullSourceSection.Count - _currentSourceIndex;
                int nextCount   = Math.Min(remaining, BatchSize);
                var nextSection = new LogSourceSection(_currentSourceIndex, nextCount);
                _source.GetEntries(nextSection, _array);

                for (int i = 0; i < nextCount; ++i)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    var logEntry = _array[i];
                    if (Log.IsDebugEnabled)
                    {
                        Log.DebugFormat("Processing: LineIndex={0}, OriginalLineIndex={1}, LogEntryIndex={2}, Message={3}",
                                        logEntry.Index,
                                        logEntry.OriginalIndex,
                                        logEntry.LogEntryIndex,
                                        logEntry.RawContent);
                    }

                    if (_lastLogBuffer.Count == 0 || _lastLogBuffer[0].LogEntryIndex == logEntry.LogEntryIndex)
                    {
                        TryAddLogLine(logEntry);
                    }
                    else if (logEntry.LogEntryIndex != _lastLogBuffer[0].LogEntryIndex)
                    {
                        TryAddLogEntry(_lastLogBuffer);
                        _lastLogBuffer.Clear();
                        TryAddLogLine(logEntry);
                    }
                }

                _currentSourceIndex += nextCount;
            }

            // Now that we've processes all newly added log entries, we can check if we're at the end just yet...
            if (_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                TryAddLogEntry(_lastLogBuffer);
                UpdateProperties();                 //< we need to update our own properties after we've added the last entry, but before we notify listeners...
                Listeners.OnRead(_indices.Count);

                if (_properties.GetValue(Core.Properties.PercentageProcessed) == Percentage.HundredPercent)
                {
                    Listeners.Flush();
                }
            }
            else
            {
                UpdateProperties();
            }
        }
Пример #12
0
        public void TestGetByIndex()
        {
            var section = new LogSourceSection(42, 10);

            for (int i = 0; i < 10; ++i)
            {
                section[i].Should().Be(new LogLineIndex(42 + i));
            }
        }
Пример #13
0
        public void TestGetColumn2()
        {
            var section = new LogSourceSection(42, 100);
            var buffer  = new string[100];
            var logFile = new LogSourceProxy(_taskScheduler, TimeSpan.Zero);

            logFile.GetColumn(section, Core.Columns.RawContent, buffer);
            buffer.Should().OnlyContain(x => ReferenceEquals(x, null));
        }
Пример #14
0
 /// <inheritdoc />
 public void GetEntries(LogSourceSection sourceSection, ILogBuffer destination, int destinationIndex, LogSourceQueryOptions queryOptions)
 {
     lock (_syncRoot)
     {
         foreach (var column in destination.Columns)
         {
             destination.CopyFrom(column, destinationIndex, _logBuffer, new Int32View(sourceSection));
         }
     }
 }
Пример #15
0
        private void AppendMatches(LogSourceSection section)
        {
            try
            {
                LogBufferArray lines;
                lock (_syncRoot)
                {
                    lines = _logLinesArray;
                    if (lines == null)
                    {
                        return;
                    }
                }

                // We've instructed the logfile to give us exactly up to
                // _logLinesBuffer.Length amount of entries in the ctor, hence the following
                // is correct:
                _logSource.GetEntries(section, lines);

                bool added = false;
                for (int i = 0; i < section.Count; ++i)
                {
                    var line = lines[i];

                    _filter.Match(line, _matchesBuffer);
                    if (_matchesBuffer.Count > 0)
                    {
                        lock (_syncRoot)
                        {
                            foreach (LogLineMatch logLineMatch in _matchesBuffer)
                            {
                                var match = new LogMatch(line.Index, logLineMatch);
                                _matches.Add(match);
                            }
                        }

                        _matchesBuffer.Clear();
                        added = true;
                    }
                }

                if (added)
                {
                    _listeners.EmitSearchChanged(_matches);
                }
            }
            catch (IndexOutOfRangeException e)
            {
                // This exception is usually thrown when we access a portion of the
                // log file that has already been reset. This means that a reset event is
                // either pending or soon to be. So not doing anything else to handle
                // this exception is fine.
                Log.DebugFormat("Caught exception while searching log file: {0}", e);
            }
        }
Пример #16
0
 private void Clear()
 {
     _fullSourceSection  = new LogSourceSection(0, 0);
     _currentSourceIndex = 0;
     _currentLogEntry    = new LogEntryInfo(-1, 0);
     lock (_syncRoot)
     {
         _indices.Clear();
     }
     Listeners.OnRead(-1);
 }
Пример #17
0
 private void Clear()
 {
     _fullSourceSection = new LogSourceSection();
     lock (_indices)
     {
         _indices.Clear();
         _logEntryIndices.Clear();
         _currentLogEntryIndex = 0;
     }
     Listeners.OnRead(-1);
 }
Пример #18
0
        public Page(int index, int pageSize, IReadOnlyList <IColumnDescriptor> columns, IReadOnlyList <IColumnDescriptor> copiedColumns)
        {
            _index          = index;
            _pageSize       = pageSize;
            _copiedColumns  = copiedColumns;
            _section        = new LogSourceSection(index * pageSize, pageSize);
            _buffer         = new LogBufferArray(pageSize, columns);
            _lastAccessTime = DateTime.MinValue;
            _numReads       = 0;

            _buffer.Fill(PageBufferedLogSource.RetrievalState, RetrievalState.NotInSource, 0, _pageSize);
        }
Пример #19
0
        private void Remove(LogSourceSection sectionToRemove)
        {
            var firstRemovedIndex   = LogLineIndex.Min(_fullSourceSection.LastIndex, sectionToRemove.Index);
            var lastRemovedIndex    = LogLineIndex.Min(_fullSourceSection.LastIndex, sectionToRemove.LastIndex);
            var removedCount        = lastRemovedIndex - firstRemovedIndex + 1;
            var previousSourceIndex = _currentSourceIndex;

            _fullSourceSection = new LogSourceSection(0, (int)firstRemovedIndex);
            if (_fullSourceSection.Count > 0)
            {
                // It's possible (likely) that we've received an invalidation for a region of the source
                // that we've already processed (i.e. created indices for). If that's the case, then we need
                // to rewind the index. Otherwise nothing needs to be done...
                var newIndex = _fullSourceSection.LastIndex + 1;
                if (newIndex < _currentSourceIndex)
                {
                    _currentSourceIndex = newIndex;
                }
            }
            else
            {
                _currentSourceIndex = 0;
            }

            lock (_syncRoot)
            {
                var toRemove = _indices.Count - lastRemovedIndex;
                if (toRemove > 0)
                {
                    _indices.RemoveRange((int)firstRemovedIndex, toRemove);
                    _currentLogEntry = new LogEntryInfo(firstRemovedIndex - 1, 0);
                }
                if (previousSourceIndex != _currentSourceIndex)
                {
                    _indices.RemoveRange((int)_currentSourceIndex, _indices.Count - _currentSourceIndex);
                }
            }

            if (_indices.Count != _currentSourceIndex)
            {
                Log.ErrorFormat("Inconsistency detected: We have {0} indices for {1} lines", _indices.Count,
                                _currentSourceIndex);
            }

            Listeners.Remove((int)firstRemovedIndex, removedCount);

            if (_fullSourceSection.Count > firstRemovedIndex)
            {
                _fullSourceSection = new LogSourceSection(0, firstRemovedIndex.Value);
            }
        }
Пример #20
0
        private void UpdateMaxWidth(LogSourceSection section, ILogSource logSource)
        {
            logSource.GetEntries(section, _buffer);
            for (int i = 0; i < section.Count; ++i)
            {
                var rawContent = _buffer[i].RawContent;
                if (rawContent == null)
                {
                    break;
                }

                _maxCharactersInLine = Math.Max(_maxCharactersInLine, rawContent.Length);
            }
        }
Пример #21
0
        public void Remove(int firstIndex, int count)
        {
            int lastIndex       = Math.Min(firstIndex + count, _lastNumberOfLines);
            int invalidateCount = lastIndex - firstIndex;

            // When the start index of the invalidation is greater than the last reported index
            // then this means that our listeners haven't even gotten the change yet and thus
            // they don't need to be notified of the invalidation either.
            if (invalidateCount > 0)
            {
                var section = new LogSourceSection(firstIndex, invalidateCount);
                _listener.OnLogFileModified(_logSource, LogSourceModification.Removed(section));
                _lastNumberOfLines = firstIndex;
            }
        }
Пример #22
0
        private void RemoveSection(LogSourceSection section)
        {
            _count = (int)section.Index;
            try
            {
                OnSectionRemoved(_count);
            }
            catch (Exception e)
            {
                Log.WarnFormat("Caught unexpected exception: {0}", e);
            }

            SynchronizeProperties();
            Listeners.Remove((int)section.Index, section.Count);
        }
Пример #23
0
        public void UpdateDataSources(IDataSource dataSource, LogSourceSection visibleSection, double yOffset)
        {
            _dataSource     = dataSource;
            _visibleSection = visibleSection;
            _yOffset        = yOffset;

            var multi = UnpackMultiDataSource(dataSource);

            if (multi != null)
            {
                var dataSources = multi.OriginalSources;
                var displayMode = DisplayMode;

                var maximumCharacterCount = GetMaximumCharacterCount(displayMode, dataSources);
                var texts = new FormattedText[dataSources.Count];
                for (int i = 0; i < dataSources.Count; ++i)
                {
                    var originalDataSource = dataSources[i];
                    texts[i] = CreateFormattedText(displayMode, GetDataSourceName(displayMode, originalDataSource));
                }

                _dataSourcesPerLogLine.Clear();
                var entries = new LogBufferArray(visibleSection.Count, new[] { Columns.SourceId });
                multi.FilteredLogSource.GetEntries(visibleSection, entries);
                foreach (var logEntry in entries)
                {
                    var dataSourceId = (int)logEntry.GetValue(Columns.SourceId);
                    if (dataSourceId >= 0 && dataSourceId < texts.Length)
                    {
                        var text = texts[dataSourceId];
                        _dataSourcesPerLogLine.Add(text);
                    }
                    else
                    {
                        _dataSourcesPerLogLine.Add(item: null);
                    }
                }

                Width = _textSettings.EstimateWidthUpperLimit(maximumCharacterCount);
            }
            else
            {
                _dataSourcesPerLogLine.Clear();
                Width = 0;
            }

            InvalidateVisual();
        }
Пример #24
0
        public void TestGetColumn1()
        {
            var section          = new LogSourceSection(42, 100);
            var buffer           = new string[142];
            var logFile          = new LogSourceProxy(_taskScheduler, TimeSpan.Zero, _logFile.Object);
            var destinationIndex = 42;
            var queryOptions     = new LogSourceQueryOptions(LogSourceQueryMode.FromCache);

            logFile.GetColumn(section, Core.Columns.RawContent, buffer, destinationIndex, queryOptions);
            _logFile.Verify(x => x.GetColumn(It.Is <LogSourceSection>(y => y == section),
                                             Core.Columns.RawContent,
                                             buffer,
                                             destinationIndex,
                                             queryOptions),
                            Times.Once);
        }
Пример #25
0
        private void AppendSection(LogSourceSection section)
        {
            _count = (int)(section.Index + section.Count);
            try
            {
                _source.GetEntries(section, _fetchBuffer);
                OnSectionAppended(section, _fetchBuffer, _count);
            }
            catch (Exception e)
            {
                Log.WarnFormat("Caught unexpected exception: {0}", e);
            }

            SynchronizeProperties();
            Listeners.OnRead(_count);
        }
Пример #26
0
        /// <inheritdoc />
        public void GetColumn <T>(LogSourceSection sourceSection, IColumnDescriptor <T> column, T[] destination, int destinationIndex, LogSourceQueryOptions queryOptions)
        {
            if (column == null)
            {
                throw new ArgumentNullException(nameof(column));
            }
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
            if (destinationIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(destinationIndex));
            }

            _logBuffer.CopyTo(column, (int)sourceSection.Index, destination, destinationIndex, sourceSection.Count);
        }
Пример #27
0
        private void Report(int numberOfLinesRead, DateTime now)
        {
            // We may never report all lines in one go if the listener specified
            // that he only wants to receive batches of N.
            // Therefore we invoke the listener multiple times.
            int count;

            while ((count = numberOfLinesRead - _lastNumberOfLines) > 0)
            {
                count = Math.Min(count, _maximumCount);
                var section = new LogSourceSection(_lastNumberOfLines, count);
                _listener.OnLogFileModified(_logSource, LogSourceModification.Appended(section));

                _lastNumberOfLines += count;
                _lastReportedTime   = now;
            }
        }
Пример #28
0
        public void TestGetEntries1()
        {
            _logFile.Setup(x => x.GetEntries(It.IsAny <LogSourceSection>(), It.IsAny <ILogBuffer>(), It.IsAny <int>(), It.IsAny <LogSourceQueryOptions>())).Throws <SystemException>();

            var section          = new LogSourceSection(42, 100);
            var buffer           = new Mock <ILogBuffer>().Object;
            var destinationIndex = 9001;
            var queryOptions     = new LogSourceQueryOptions(LogSourceQueryMode.FromCache);

            new Action(() => _proxy.GetEntries(section, buffer, destinationIndex, queryOptions)).Should().NotThrow();

            _logFile.Verify(x => x.GetEntries(It.Is <LogSourceSection>(y => y == section),
                                              It.Is <ILogBuffer>(y => ReferenceEquals(y, buffer)),
                                              destinationIndex,
                                              queryOptions),
                            Times.Once);
        }
Пример #29
0
        public void TestGetColumn1()
        {
            _logFile.Setup(x => x.GetColumn(It.IsAny <LogSourceSection>(), It.IsAny <IColumnDescriptor <string> >(), It.IsAny <string[]>(), It.IsAny <int>(), It.IsAny <LogSourceQueryOptions>())).Throws <SystemException>();

            var section          = new LogSourceSection(42, 100);
            var buffer           = new string[9101];
            var destinationIndex = 9001;
            var queryOptions     = new LogSourceQueryOptions(LogSourceQueryMode.FromCache);

            new Action(() => _proxy.GetColumn(section, Columns.RawContent, buffer, destinationIndex, queryOptions)).Should().NotThrow();

            _logFile.Verify(x => x.GetColumn(It.Is <LogSourceSection>(y => y == section),
                                             Columns.RawContent,
                                             buffer,
                                             destinationIndex,
                                             queryOptions),
                            Times.Once);
        }
Пример #30
0
        private bool TryGetEntriesContiguous(LogSourceSection sourceSection, ILogBuffer destination, int destinationIndex, out IReadOnlyList <LogSourceSection> accessedPageBoundaries)
        {
            bool fullyRead                 = true;
            var  sourceSectionEndIndex     = Math.Min((int)(sourceSection.Index + sourceSection.Count), _sourceCount);
            var  numEntriesRead            = 0;
            var  tmpAccessedPageBoundaries = new List <LogSourceSection>();

            for (LogLineIndex i = sourceSection.Index; i < sourceSectionEndIndex;)
            {
                var pageIndex          = GetPageIndex(i);
                var remainingPageCount = (pageIndex + 1) * _pageSize - i;
                var count = Math.Min(remainingPageCount, sourceSectionEndIndex - i);

                var page = TryGetPage(pageIndex);
                if (page != null)
                {
                    fullyRead &= page.TryRead(i, count, destination, destinationIndex + numEntriesRead, fullyRead);
                    tmpAccessedPageBoundaries.Add(page.Section);
                }
                else
                {
                    destination.FillDefault(destinationIndex + numEntriesRead, count);
                    if (destination.Contains(PageBufferedLogSource.RetrievalState))
                    {
                        destination.Fill(PageBufferedLogSource.RetrievalState, RetrievalState.NotCached, destinationIndex + numEntriesRead, count);
                    }
                    fullyRead = false;
                    tmpAccessedPageBoundaries.Add(GetSectionForPage(pageIndex));
                }

                numEntriesRead += count;
                i += count;
            }

            if (numEntriesRead < sourceSection.Count)
            {
                var start = destinationIndex + numEntriesRead;
                destination.FillDefault(start, sourceSection.Count - numEntriesRead);
                fullyRead = false;
            }

            accessedPageBoundaries = tmpAccessedPageBoundaries;
            return(fullyRead);
        }