Example #1
0
        /// <summary>
        /// Updates the line index centred around 'filepos'.
        /// If 'filepos' is within the current byte range of 'm_line_index' then an incremental search
        /// for lines is done in the direction needed to re-centre the line list around 'filepos'.
        /// If 'reload' is true a full rebuild of the cache is done</summary>
        public void Build(long filepos, bool reload, IList <IFilter> filters)
        {
            // Incremental updates cannot interrupt full reloads
            if (m_reload_in_progress && reload == false)
            {
                return;
            }
            m_reload_in_progress = reload;

            // Increment the build issue number to cancel any previous builds
            Interlocked.Increment(ref m_issue);
            var issue = m_issue;

            // Make a copy of the current state
            var state = m_state;

            // The index that 'filepos' would have in 'm_line_index'.
            // -1 if 'filepos' is before the current cached range,
            // or 'm_line_index.Count' if after
            state.m_index_centre = FindIndex(m_line_index, filepos);
            state.m_index_count  = m_line_index.Count;

            // Make a copy of the filters
            state.m_filters = new List <IFilter>(filters);

            // Start a build in a worker thread
            ThreadPool.QueueUserWorkItem(BuildWorker);
            void BuildWorker(object _)
            {
                try
                {
                    // Open a new stream to the log data
                    using (var src = Src.OpenStream())
                    {
                        // Determine new state properties of the file
                        state.m_fileend = src.Length;
                        state.m_filepos = Math_.Clamp(filepos, 0, state.m_fileend);

                        // Do the update
                        var lines = BuildAsync(ref state, src, reload, Progress);

                        // Add the lines to the line index
                        m_dispatcher.BeginInvoke(new Action(() =>
                        {
                            MergeResults(state, lines, reload, Progress);
                        }));
                    }
                }
                catch (Exception ex)
                {
                    m_dispatcher.BeginInvoke(new Action(() =>
                    {
                        BuildError?.Invoke(this, new BuildErrorEventArgs(ex));
                    }));
                }
                finally
                {
                    m_dispatcher.BeginInvoke(new Action(() =>
                    {
                        if (!Progress(1, 1))
                        {
                            return;
                        }
                        m_reload_in_progress = false;
                    }));
                }
            }

            bool Progress(long scanned, long length)
            {
                m_dispatcher.BeginInvoke(new Action(() =>
                {
                    if (IsBuildCancelled(issue))
                    {
                        return;
                    }
                    BuildProgress?.Invoke(this, new BuildProgressEventArgs(scanned, length));
                }));
                return(!IsBuildCancelled(issue));
            }
        }