diff --git a/src/all_logs_vtab.cc b/src/all_logs_vtab.cc index 34a30d19..69acf495 100644 --- a/src/all_logs_vtab.cc +++ b/src/all_logs_vtab.cc @@ -82,7 +82,7 @@ all_logs_vtab::extract(logfile* lf, logline_value_vector sub_values; this->vi_attrs.clear(); - sub_values.lvv_sbr = line; + sub_values.lvv_sbr = line.clone(); format->annotate(line_number, this->vi_attrs, sub_values, false); auto body = find_string_attr_range(this->vi_attrs, &SA_BODY); diff --git a/src/base/is_utf8.cc b/src/base/is_utf8.cc index f55dfe03..714d8c2f 100644 --- a/src/base/is_utf8.cc +++ b/src/base/is_utf8.cc @@ -64,7 +64,7 @@ is_utf8(string_fragment str, nonstd::optional terminator) { const auto* ustr = str.udata(); utf8_scan_result retval; - ssize_t i = 0; + ssize_t i = 0, valid_end = 0; while (i < str.length()) { if (ustr[i] == '\x1b') { @@ -72,9 +72,6 @@ is_utf8(string_fragment str, nonstd::optional terminator) } if (terminator && ustr[i] == terminator.value()) { - if (retval.usr_message == nullptr) { - retval.usr_valid_frag = str.sub_range(0, i); - } retval.usr_remaining = str.substr(i + 1); break; } @@ -84,7 +81,7 @@ is_utf8(string_fragment str, nonstd::optional terminator) continue; } - retval.usr_valid_frag = str.sub_range(0, i); + valid_end = i; if (ustr[i] <= 0x7F) /* 00..7F */ { i += 1; } else if (ustr[i] >= 0xC2 && ustr[i] <= 0xDF) /* C2..DF 80..BF */ { @@ -308,6 +305,8 @@ is_utf8(string_fragment str, nonstd::optional terminator) } if (retval.usr_message == nullptr) { retval.usr_valid_frag = str.sub_range(0, i); + } else { + retval.usr_valid_frag = str.sub_range(0, valid_end); } return retval; } diff --git a/src/data_scanner.hh b/src/data_scanner.hh index 793f33d5..5fa554ff 100644 --- a/src/data_scanner.hh +++ b/src/data_scanner.hh @@ -168,8 +168,9 @@ public: this->cleanup_end(); } - explicit data_scanner(shared_buffer_ref& line, size_t off, size_t end) - : ds_sbr(line), ds_input(line.to_string_fragment().sub_range(0, end)), + explicit data_scanner(const shared_buffer_ref& line, size_t off, size_t end) + : ds_sbr(line.clone()), + ds_input(line.to_string_fragment().sub_range(0, end)), ds_init_offset(off), ds_next_offset(off) { this->cleanup_end(); diff --git a/src/filter_observer.cc b/src/filter_observer.cc index cbe1c8fe..b8f15d93 100644 --- a/src/filter_observer.cc +++ b/src/filter_observer.cc @@ -48,7 +48,7 @@ line_filter_observer::logline_new_lines(const logfile& lf, } for (; ll_begin != ll_end; ++ll_begin) { - auto sbr_copy = sbr; + auto sbr_copy = sbr.clone(); if (lf.get_format() != nullptr) { lf.get_format()->get_subline(*ll_begin, sbr_copy); } diff --git a/src/gantt_source.cc b/src/gantt_source.cc index 4b34f316..628a9eb0 100644 --- a/src/gantt_source.cc +++ b/src/gantt_source.cc @@ -658,8 +658,8 @@ gantt_source::rebuild_indexes() if (!filt->is_enabled()) { continue; } - for (const auto& sbr : {sbr_opid, sbr_desc}) { - if (filt->matches(nonstd::nullopt, sbr)) { + for (const auto sbr : {&sbr_opid, &sbr_desc}) { + if (filt->matches(nonstd::nullopt, *sbr)) { this->gs_filter_hits[filt->get_index()] += 1; switch (filt->get_type()) { case text_filter::INCLUDE: diff --git a/src/line_buffer.hh b/src/line_buffer.hh index 9df74504..20a1759f 100644 --- a/src/line_buffer.hh +++ b/src/line_buffer.hh @@ -267,6 +267,8 @@ public: bool is_piper() const { return this->lb_piper_header_size > 0; } + size_t line_count_guess() const { return this->lb_line_starts.size(); } + static void cleanup_cache(); private: diff --git a/src/lnav.cc b/src/lnav.cc index 50a32adc..1eaf7dc8 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -1915,7 +1915,7 @@ looper() && lnav_data.ld_text_source.empty() && lnav_data.ld_log_source.text_line_count() > 0) { - textview_curses* tc_log = &lnav_data.ld_views[LNV_LOG]; + auto* tc_log = &lnav_data.ld_views[LNV_LOG]; lnav_data.ld_view_stack.pop_back(); lnav_data.ld_views[LNV_LOG].set_top( @@ -2022,6 +2022,7 @@ looper() } } session_stage += 1; + lnav_data.ld_exec_phase = lnav_exec_phase::INTERACTIVE; load_time_bookmarks(); } } diff --git a/src/lnav.hh b/src/lnav.hh index eedc651d..7ec18b20 100644 --- a/src/lnav.hh +++ b/src/lnav.hh @@ -146,6 +146,13 @@ struct key_repeat_history { }; }; +enum class lnav_exec_phase : int { + INIT, + PRELOAD, + LOADING, + INTERACTIVE, +}; + struct lnav_data_t { std::map> ld_session_id; time_t ld_session_time; @@ -246,6 +253,7 @@ struct lnav_data_t { bool ld_initial_build{false}; bool ld_show_help_view{false}; + lnav_exec_phase ld_exec_phase{lnav_exec_phase::INIT}; lnav::func::scoped_cb ld_status_refresher; diff --git a/src/lnav.indexing.cc b/src/lnav.indexing.cc index 849a2fa6..345d5df9 100644 --- a/src/lnav.indexing.cc +++ b/src/lnav.indexing.cc @@ -90,7 +90,7 @@ do_observer_update(const std::shared_ptr& lf) } lnav_data.ld_status_refresher(); if (lf && lnav_data.ld_mode == ln_mode_t::FILES - && !lnav_data.ld_initial_build) + && lnav_data.ld_exec_phase < lnav_exec_phase::INTERACTIVE) { auto& fc = lnav_data.ld_active_files; auto iter = std::find(fc.fc_files.begin(), fc.fc_files.end(), lf); diff --git a/src/log_format.cc b/src/log_format.cc index 8ddfd01b..05cd4c23 100644 --- a/src/log_format.cc +++ b/src/log_format.cc @@ -1581,7 +1581,7 @@ external_log_format::annotate(uint64_t line_number, values = this->jlf_line_values; sa = this->jlf_line_attrs; } else { - values.lvv_sbr = this->jlf_line_values.lvv_sbr; + values.lvv_sbr = this->jlf_line_values.lvv_sbr.clone(); for (const auto& llv : this->jlf_line_values.lvv_values) { if (this->jlf_cached_sub_range.contains(llv.lv_origin)) { values.lvv_values.emplace_back(llv); @@ -2025,7 +2025,7 @@ external_log_format::get_subline(const logline& ll, sbr.share(this->jlf_share_manager, &this->jlf_cached_line[0], this->jlf_cached_line.size()); - this->jlf_line_values.lvv_sbr = sbr; + this->jlf_line_values.lvv_sbr = sbr.clone(); this->jlf_line_attrs.emplace_back( line_range{0, -1}, SA_INVALID.value(fmt::format( @@ -2403,7 +2403,7 @@ external_log_format::get_subline(const logline& ll, sbr.get_metadata().m_has_ansi = ll.has_ansi(); this->jlf_cached_sub_range.lr_start = this_off; this->jlf_cached_sub_range.lr_end = next_off; - this->jlf_line_values.lvv_sbr = sbr; + this->jlf_line_values.lvv_sbr = sbr.clone(); } struct compiled_header_expr { @@ -3720,7 +3720,7 @@ public: intern_string_t mod_name; this->vi_attrs.clear(); - values.lvv_sbr = line; + values.lvv_sbr = line.clone(); format->annotate(cl, this->vi_attrs, values, false); this->elt_container_body = find_string_attr_range(this->vi_attrs, &SA_BODY); diff --git a/src/log_format.hh b/src/log_format.hh index d5c137ee..ac67434a 100644 --- a/src/log_format.hh +++ b/src/log_format.hh @@ -275,6 +275,23 @@ struct logline_value_vector { this->lvv_opid_value = nonstd::nullopt; } + logline_value_vector() {} + + logline_value_vector(const logline_value_vector& other) + : lvv_sbr(other.lvv_sbr.clone()), lvv_values(other.lvv_values), + lvv_opid_value(other.lvv_opid_value) + { + } + + logline_value_vector& operator=(const logline_value_vector& other) + { + this->lvv_sbr = other.lvv_sbr.clone(); + this->lvv_values = other.lvv_values; + this->lvv_opid_value = other.lvv_opid_value; + + return *this; + } + shared_buffer_ref lvv_sbr; std::vector lvv_values; nonstd::optional lvv_opid_value; diff --git a/src/shared_buffer.cc b/src/shared_buffer.cc index 39e21be5..01be2010 100644 --- a/src/shared_buffer.cc +++ b/src/shared_buffer.cc @@ -40,19 +40,15 @@ #include "base/ansi_scrubber.hh" #include "shared_buffer.hh" -static const bool DEBUG_TRACE = false; - void shared_buffer_ref::share(shared_buffer& sb, const char* data, size_t len) { -#ifdef HAVE_EXECINFO_H - if (DEBUG_TRACE) { - void* frames[128]; - int rc; +#if SHARED_BUFFER_TRACE + void* frames[128]; + int rc; - rc = backtrace(frames, 128); - this->sb_backtrace.reset(backtrace_symbols(frames, rc)); - } + rc = backtrace(frames, 128); + this->sb_backtrace.reset(backtrace_symbols(frames, rc)); #endif this->disown(); @@ -95,8 +91,36 @@ shared_buffer_ref::shared_buffer_ref(shared_buffer_ref&& other) noexcept this->sb_data = nullptr; this->sb_length = 0; } else if (other.sb_owner != nullptr) { - auto owner_ref_iter = std::find(other.sb_owner->sb_refs.begin(), - other.sb_owner->sb_refs.end(), + auto owner_ref_iter = std::find(other.sb_owner->sb_refs.rbegin(), + other.sb_owner->sb_refs.rend(), + &other); + *owner_ref_iter = this; + this->sb_owner = std::exchange(other.sb_owner, nullptr); + this->sb_data = std::exchange(other.sb_data, nullptr); + this->sb_length = std::exchange(other.sb_length, 0); + } else { + this->sb_owner = nullptr; + this->sb_data = other.sb_data; + this->sb_length = other.sb_length; + other.sb_data = nullptr; + other.sb_length = 0; + } + this->sb_metadata = other.sb_metadata; + other.sb_metadata = {}; +} + +shared_buffer_ref& +shared_buffer_ref::operator=(shared_buffer_ref&& other) +{ + this->disown(); + + if (other.sb_data == nullptr) { + this->sb_owner = nullptr; + this->sb_data = nullptr; + this->sb_length = 0; + } else if (other.sb_owner != nullptr) { + auto owner_ref_iter = std::find(other.sb_owner->sb_refs.rbegin(), + other.sb_owner->sb_refs.rend(), &other); *owner_ref_iter = this; this->sb_owner = std::exchange(other.sb_owner, nullptr); @@ -111,6 +135,8 @@ shared_buffer_ref::shared_buffer_ref(shared_buffer_ref&& other) noexcept } this->sb_metadata = other.sb_metadata; other.sb_metadata = {}; + + return *this; } bool diff --git a/src/shared_buffer.hh b/src/shared_buffer.hh index 2ee36d58..5fe26d0a 100644 --- a/src/shared_buffer.hh +++ b/src/shared_buffer.hh @@ -48,6 +48,8 @@ class shared_buffer; +#define SHARED_BUFFER_TRACE 0 + struct shared_buffer_ref { public: shared_buffer_ref(char* data = nullptr, size_t len = 0) @@ -57,28 +59,23 @@ public: ~shared_buffer_ref() { this->disown(); } - shared_buffer_ref(const shared_buffer_ref& other) - { - this->sb_owner = nullptr; - this->sb_data = nullptr; - this->sb_length = 0; - this->sb_metadata = file_range::metadata{}; - - this->copy_ref(other); - } + shared_buffer_ref(const shared_buffer_ref& other) = delete; shared_buffer_ref(shared_buffer_ref&& other) noexcept; - shared_buffer_ref& operator=(const shared_buffer_ref& other) + shared_buffer_ref& operator=(const shared_buffer_ref& other) = delete; + + shared_buffer_ref clone() const { - if (this != &other) { - this->disown(); - this->copy_ref(other); - } + shared_buffer_ref retval; - return *this; + retval.copy_ref(*this); + + return retval; } + shared_buffer_ref& operator=(shared_buffer_ref&& other); + bool empty() const { return this->sb_data == nullptr || this->sb_length == 0; @@ -165,7 +162,9 @@ public: private: void copy_ref(const shared_buffer_ref& other); +#if SHARED_BUFFER_TRACE auto_mem sb_backtrace; +#endif file_range::metadata sb_metadata; shared_buffer* sb_owner; const char* sb_data;