private IReadOnlyList <LogSourceModification> Process(IReadOnlyList <MergedLogSourceSection> pendingModifications) { // This method keeps track of the changes made // to the index structure in this object and then returns // the list once it is done. // It will try to compress the changes to the bare minimum // (which it can do if given more pending modifications at once). lock (_syncRoot) { var stopwatch = Stopwatch.StartNew(); var changes = new MergedLogSourceChanges(_indices.Count); ProcessResetsNoLock(pendingModifications, changes); ProcessInvalidationsNoLock(pendingModifications, changes); ProcessAppendsNoLock(pendingModifications, changes); UpdateLogEntryIndicesNoLock(changes); stopwatch.Stop(); if (Log.IsDebugEnabled) { int lineCount = pendingModifications.Sum(x => x.Modification.IsAppended(out var appendedSection) ? appendedSection.Count : 0); Log.DebugFormat("MergedLogFileIndex::Process(#{0} modifications, #{1} lines): {2}ms", pendingModifications.Count, lineCount, stopwatch.ElapsedMilliseconds); } return(changes.Sections); } }
private void UpdateLogEntryIndicesNoLock(MergedLogSourceChanges changes) { // DO NOT CALL EXTERNAL / VIRTUAL METHODS OF ANY KIND HERE // We only need to re-calculate those indices if there was an invalidation or a portion // of this index. If there wasn't, then ProcessAppendsNoLock() already does its job as required... if (changes.TryGetFirstRemovedIndex(out var firstRemovedIndex)) { for (int i = firstRemovedIndex.Value; i < _indices.Count; ++i) { var index = _indices[i]; index.MergedLogEntryIndex = (int)CalculateLogEntryIndexFor(i, index); _indices[i] = index; } } }
private void ProcessAppendsNoLock(IReadOnlyList <MergedLogSourceSection> pendingModifications, MergedLogSourceChanges changes) { // DO NOT CALL EXTERNAL / VIRTUAL METHODS OF ANY KIND HERE var indices = CreateIndices(pendingModifications); var removed = false; var appendStartingIndex = _indices.Count; foreach (var index in indices) { var insertionIndex = FindInsertionIndexNoLock(index); if (insertionIndex < _indices.Count) { if (!removed) { // Here's the awesome thing: We're inserting a "pre-sorted" list of indices // into our index buffer. Therefore, the very first index which requires an invalidation // is also the LOWEST POSSIBLE index which could require an invalidation and therefore // there can only ever be one invalidation while this method is executing. // We do need to take into account that even though we're invalidating a region, // that doesn't mean we also didn't append something previously.... var appendCount = _indices.Count - appendStartingIndex; if (appendCount > 0) { changes.Append(appendStartingIndex, appendCount); } changes.RemoveFrom(insertionIndex); removed = true; } } var actualIndex = index; actualIndex.MergedLogEntryIndex = (int)CalculateLogEntryIndexFor(insertionIndex, index); _indices.Insert(insertionIndex, actualIndex); } var appendCount2 = _indices.Count - appendStartingIndex; if (appendCount2 > 0) { changes.Append(appendStartingIndex, appendCount2); } }
private void ProcessInvalidationsNoLock(IReadOnlyList <MergedLogSourceSection> pendingModifications, MergedLogSourceChanges changes) { // DO NOT CALL EXTERNAL / VIRTUAL METHODS OF ANY KIND HERE foreach (var pendingModification in pendingModifications) { if (pendingModification.Modification.IsRemoved(out var removedSection)) { var logFileIndex = GetLogFileIndex(pendingModification.LogSource); bool Predicate(MergedLogLineIndex x) => x.SourceId == logFileIndex && x.SourceLineIndex >= removedSection.Index; var firstIndex = _indices.FindIndex(Predicate); if (firstIndex >= 0) { _indices.RemoveAll(Predicate); if (_indices.Count == 0) { changes.Reset(); } else { changes.RemoveFrom(firstIndex); var appendCount = _indices.Count - firstIndex; if (appendCount > 0) { changes.Append(firstIndex, appendCount); } } } } } }