2022-04-30 20:05:42 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2022, Timothy Stack
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright notice, this
|
|
|
|
* list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
* * Neither the name of Timothy Stack nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "lnav.indexing.hh"
|
|
|
|
|
2023-08-05 07:51:19 +00:00
|
|
|
#include "bound_tags.hh"
|
2022-06-09 19:49:06 +00:00
|
|
|
#include "lnav.events.hh"
|
2022-04-30 20:05:42 +00:00
|
|
|
#include "lnav.hh"
|
|
|
|
#include "service_tags.hh"
|
|
|
|
#include "session_data.hh"
|
2023-08-05 07:51:19 +00:00
|
|
|
#include "sql_util.hh"
|
2022-04-30 20:05:42 +00:00
|
|
|
|
|
|
|
using namespace std::chrono_literals;
|
2023-08-26 04:03:00 +00:00
|
|
|
using namespace lnav::roles::literals;
|
2022-04-30 20:05:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Observer for loading progress that updates the bottom status bar.
|
|
|
|
*/
|
|
|
|
class loading_observer : public logfile_observer {
|
|
|
|
public:
|
|
|
|
loading_observer() : lo_last_offset(0){};
|
|
|
|
|
|
|
|
indexing_result logfile_indexing(const std::shared_ptr<logfile>& lf,
|
|
|
|
file_off_t off,
|
|
|
|
file_size_t total) override
|
|
|
|
{
|
|
|
|
static sig_atomic_t index_counter = 0;
|
|
|
|
|
|
|
|
if (lnav_data.ld_window == nullptr) {
|
|
|
|
return indexing_result::CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX require(off <= total); */
|
|
|
|
if (off > (off_t) total) {
|
|
|
|
off = total;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((((size_t) off == total) && (this->lo_last_offset != off))
|
|
|
|
|| ui_periodic_timer::singleton().time_to_update(index_counter))
|
|
|
|
{
|
2022-07-23 05:21:16 +00:00
|
|
|
if (off == total) {
|
|
|
|
lnav_data.ld_bottom_source.update_loading(0, 0);
|
|
|
|
} else {
|
|
|
|
lnav_data.ld_bottom_source.update_loading(off, total);
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
do_observer_update(lf);
|
|
|
|
this->lo_last_offset = off;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lnav_data.ld_looping) {
|
|
|
|
return indexing_result::BREAK;
|
|
|
|
}
|
|
|
|
return indexing_result::CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
off_t lo_last_offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
do_observer_update(const std::shared_ptr<logfile>& lf)
|
|
|
|
{
|
|
|
|
if (isendwin()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-09-22 01:54:45 +00:00
|
|
|
lnav_data.ld_status_refresher();
|
2022-04-30 20:05:42 +00:00
|
|
|
if (lf && lnav_data.ld_mode == ln_mode_t::FILES
|
2024-01-31 04:09:08 +00:00
|
|
|
&& lnav_data.ld_exec_phase < lnav_exec_phase::INTERACTIVE)
|
2022-08-04 06:01:38 +00:00
|
|
|
{
|
2022-04-30 20:05:42 +00:00
|
|
|
auto& fc = lnav_data.ld_active_files;
|
|
|
|
auto iter = std::find(fc.fc_files.begin(), fc.fc_files.end(), lf);
|
|
|
|
|
|
|
|
if (iter != fc.fc_files.end()) {
|
|
|
|
auto index = std::distance(fc.fc_files.begin(), iter);
|
|
|
|
lnav_data.ld_files_view.set_selection(
|
|
|
|
vis_line_t(fc.fc_other_files.size() + index));
|
|
|
|
lnav_data.ld_files_view.reload_data();
|
|
|
|
lnav_data.ld_files_view.do_update();
|
|
|
|
}
|
|
|
|
}
|
2022-08-11 18:16:49 +00:00
|
|
|
if (handle_winch()) {
|
|
|
|
layout_views();
|
|
|
|
lnav_data.ld_view_stack.do_update();
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rebuild_hist()
|
|
|
|
{
|
|
|
|
logfile_sub_source& lss = lnav_data.ld_log_source;
|
|
|
|
hist_source2& hs = lnav_data.ld_hist_source2;
|
|
|
|
int zoom = lnav_data.ld_zoom_level;
|
|
|
|
|
|
|
|
hs.set_time_slice(ZOOM_LEVELS[zoom]);
|
|
|
|
lss.reload_index_delegate();
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
class textfile_callback : public textfile_sub_source::scan_callback {
|
2022-04-30 20:05:42 +00:00
|
|
|
public:
|
2022-05-23 03:44:18 +00:00
|
|
|
void closed_files(
|
|
|
|
const std::vector<std::shared_ptr<logfile>>& files) override
|
2022-04-30 20:05:42 +00:00
|
|
|
{
|
|
|
|
for (const auto& lf : files) {
|
|
|
|
log_info("closed text files: %s", lf->get_filename().c_str());
|
|
|
|
}
|
|
|
|
lnav_data.ld_active_files.close_files(files);
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
void promote_file(const std::shared_ptr<logfile>& lf) override
|
2022-04-30 20:05:42 +00:00
|
|
|
{
|
2024-01-11 05:01:12 +00:00
|
|
|
auto& ftf = lnav_data.ld_files_to_front;
|
|
|
|
|
|
|
|
ftf.remove_if([&lf](const auto& elem) {
|
|
|
|
return elem.first == lf->get_filename()
|
|
|
|
|| elem.first == lf->get_open_options().loo_filename;
|
|
|
|
});
|
2022-04-30 20:05:42 +00:00
|
|
|
if (lnav_data.ld_log_source.insert_file(lf)) {
|
|
|
|
this->did_promotion = true;
|
|
|
|
log_info("promoting text file to log file: %s (%s)",
|
|
|
|
lf->get_filename().c_str(),
|
|
|
|
lf->get_content_id().c_str());
|
|
|
|
auto format = lf->get_format();
|
|
|
|
if (format->lf_is_self_describing) {
|
|
|
|
auto vt = format->get_vtab_impl();
|
|
|
|
|
|
|
|
if (vt != nullptr) {
|
|
|
|
lnav_data.ld_vtab_manager->register_vtab(vt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto iter = session_data.sd_file_states.find(lf->get_filename());
|
|
|
|
if (iter != session_data.sd_file_states.end()) {
|
2022-08-29 01:55:32 +00:00
|
|
|
log_info(" found visibility state for log file: %d",
|
|
|
|
iter->second.fs_is_visible);
|
2022-04-30 20:05:42 +00:00
|
|
|
|
|
|
|
lnav_data.ld_log_source.find_data(lf) | [&iter](auto ld) {
|
|
|
|
ld->set_visibility(iter->second.fs_is_visible);
|
|
|
|
};
|
|
|
|
}
|
2022-06-09 19:49:06 +00:00
|
|
|
|
|
|
|
lnav::events::publish(lnav_data.ld_db.in(),
|
|
|
|
lnav::events::file::format_detected{
|
|
|
|
lf->get_filename(),
|
|
|
|
lf->get_format_name().to_string(),
|
|
|
|
});
|
2022-04-30 20:05:42 +00:00
|
|
|
} else {
|
|
|
|
this->closed_files({lf});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-23 03:44:18 +00:00
|
|
|
void scanned_file(const std::shared_ptr<logfile>& lf) override
|
2022-04-30 20:05:42 +00:00
|
|
|
{
|
2023-07-19 05:14:45 +00:00
|
|
|
const auto& ftf = lnav_data.ld_files_to_front;
|
|
|
|
|
|
|
|
if (!ftf.empty()
|
|
|
|
&& (ftf.front().first == lf->get_filename()
|
|
|
|
|| ftf.front().first == lf->get_open_options().loo_filename))
|
2022-04-30 20:05:42 +00:00
|
|
|
{
|
|
|
|
this->front_file = lf;
|
|
|
|
this->front_top = lnav_data.ld_files_to_front.front().second;
|
|
|
|
|
|
|
|
lnav_data.ld_files_to_front.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-03 05:35:15 +00:00
|
|
|
void renamed_file(const std::shared_ptr<logfile>& lf) override
|
|
|
|
{
|
|
|
|
lnav_data.ld_active_files.regenerate_unique_file_names();
|
|
|
|
}
|
|
|
|
|
2022-04-30 20:05:42 +00:00
|
|
|
std::shared_ptr<logfile> front_file;
|
2022-08-29 01:55:32 +00:00
|
|
|
file_location_t front_top;
|
2022-04-30 20:05:42 +00:00
|
|
|
bool did_promotion{false};
|
|
|
|
};
|
|
|
|
|
2023-08-29 05:43:33 +00:00
|
|
|
rebuild_indexes_result_t
|
2022-04-30 20:05:42 +00:00
|
|
|
rebuild_indexes(nonstd::optional<ui_clock::time_point> deadline)
|
|
|
|
{
|
|
|
|
logfile_sub_source& lss = lnav_data.ld_log_source;
|
|
|
|
textview_curses& log_view = lnav_data.ld_views[LNV_LOG];
|
|
|
|
textview_curses& text_view = lnav_data.ld_views[LNV_TEXT];
|
|
|
|
bool scroll_downs[LNV__MAX];
|
2023-08-29 05:43:33 +00:00
|
|
|
rebuild_indexes_result_t retval;
|
2022-04-30 20:05:42 +00:00
|
|
|
|
2023-08-02 17:44:13 +00:00
|
|
|
for (auto lpc : {LNV_LOG, LNV_TEXT}) {
|
2023-06-16 04:52:33 +00:00
|
|
|
auto& view = lnav_data.ld_views[lpc];
|
|
|
|
|
|
|
|
if (view.is_selectable()) {
|
|
|
|
auto inner_height = view.get_inner_height();
|
|
|
|
|
|
|
|
if (inner_height > 0_vl) {
|
|
|
|
scroll_downs[lpc]
|
|
|
|
= (view.get_selection() == inner_height - 1_vl)
|
|
|
|
&& !(lnav_data.ld_flags & LNF_HEADLESS);
|
|
|
|
} else {
|
|
|
|
scroll_downs[lpc] = !(lnav_data.ld_flags & LNF_HEADLESS);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
scroll_downs[lpc] = (view.get_top() >= view.get_top_for_last_row())
|
|
|
|
&& !(lnav_data.ld_flags & LNF_HEADLESS);
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2022-06-09 19:49:06 +00:00
|
|
|
auto* tss = &lnav_data.ld_text_source;
|
2022-04-30 20:05:42 +00:00
|
|
|
textfile_callback cb;
|
|
|
|
|
2023-08-29 05:43:33 +00:00
|
|
|
auto rescan_res = tss->rescan_files(cb, deadline);
|
|
|
|
if (rescan_res.rr_new_data) {
|
2022-04-30 20:05:42 +00:00
|
|
|
text_view.reload_data();
|
2023-08-29 05:43:33 +00:00
|
|
|
retval.rir_changes += rescan_res.rr_new_data;
|
|
|
|
}
|
|
|
|
if (!rescan_res.rr_scan_completed) {
|
|
|
|
retval.rir_completed = false;
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cb.front_file != nullptr) {
|
|
|
|
ensure_view(&text_view);
|
|
|
|
|
|
|
|
if (tss->current_file() != cb.front_file) {
|
|
|
|
tss->to_front(cb.front_file);
|
|
|
|
}
|
|
|
|
|
2022-08-29 01:55:32 +00:00
|
|
|
nonstd::optional<vis_line_t> new_top_opt;
|
|
|
|
cb.front_top.match(
|
|
|
|
[&new_top_opt](vis_line_t vl) {
|
|
|
|
log_info("file open request to jump to line: %d", (int) vl);
|
|
|
|
if (vl < 0_vl) {
|
|
|
|
vl += lnav_data.ld_views[LNV_TEXT].get_inner_height();
|
|
|
|
}
|
|
|
|
if (vl < lnav_data.ld_views[LNV_TEXT].get_inner_height()) {
|
|
|
|
new_top_opt = vl;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[&new_top_opt](const std::string& loc) {
|
|
|
|
log_info("file open request to jump to anchor: %s",
|
|
|
|
loc.c_str());
|
|
|
|
auto* ta = dynamic_cast<text_anchors*>(
|
|
|
|
lnav_data.ld_views[LNV_TEXT].get_sub_source());
|
|
|
|
|
|
|
|
if (ta != nullptr) {
|
|
|
|
new_top_opt = ta->row_for_anchor(loc);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (new_top_opt) {
|
|
|
|
log_info(" setting requested top line: %d",
|
|
|
|
(int) new_top_opt.value());
|
2023-08-31 03:20:21 +00:00
|
|
|
text_view.set_selection(new_top_opt.value());
|
2022-08-29 01:55:32 +00:00
|
|
|
log_info(" actual top is now: %d", (int) text_view.get_top());
|
2023-08-31 03:20:21 +00:00
|
|
|
log_info(" actual selection is now: %d",
|
|
|
|
(int) text_view.get_selection());
|
2022-04-30 20:05:42 +00:00
|
|
|
scroll_downs[LNV_TEXT] = false;
|
2022-08-29 01:55:32 +00:00
|
|
|
} else {
|
|
|
|
log_warning("could not jump to requested line");
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cb.did_promotion && deadline) {
|
|
|
|
// If there's a new log file, extend the deadline so it can be
|
|
|
|
// indexed quickly.
|
|
|
|
deadline = deadline.value() + 500ms;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<logfile>> closed_files;
|
|
|
|
for (auto& lf : lnav_data.ld_active_files.fc_files) {
|
|
|
|
if ((!lf->exists() || lf->is_closed())) {
|
|
|
|
log_info("closed log file: %s", lf->get_filename().c_str());
|
|
|
|
lnav_data.ld_text_source.remove(lf);
|
|
|
|
lnav_data.ld_log_source.remove_file(lf);
|
|
|
|
closed_files.emplace_back(lf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!closed_files.empty()) {
|
|
|
|
lnav_data.ld_active_files.close_files(closed_files);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto result = lss.rebuild_index(deadline);
|
|
|
|
if (result != logfile_sub_source::rebuild_result::rr_no_change) {
|
|
|
|
size_t new_count = lss.text_line_count();
|
|
|
|
bool force
|
|
|
|
= result == logfile_sub_source::rebuild_result::rr_full_rebuild;
|
|
|
|
|
|
|
|
if ((!scroll_downs[LNV_LOG]
|
|
|
|
|| log_view.get_top() > vis_line_t(new_count))
|
|
|
|
&& force)
|
|
|
|
{
|
|
|
|
scroll_downs[LNV_LOG] = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::unordered_map<std::string, std::list<std::shared_ptr<logfile>>>
|
|
|
|
id_to_files;
|
|
|
|
bool reload = false;
|
|
|
|
|
|
|
|
for (const auto& lf : lnav_data.ld_active_files.fc_files) {
|
|
|
|
id_to_files[lf->get_content_id()].push_back(lf);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& pair : id_to_files) {
|
|
|
|
if (pair.second.size() == 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pair.second.sort([](const auto& left, const auto& right) {
|
|
|
|
return right->get_stat().st_size < left->get_stat().st_size;
|
|
|
|
});
|
|
|
|
|
|
|
|
auto dupe_name = pair.second.front()->get_unique_path();
|
|
|
|
pair.second.pop_front();
|
|
|
|
for_each(pair.second.begin(),
|
|
|
|
pair.second.end(),
|
|
|
|
[&dupe_name](auto& lf) {
|
2023-10-10 19:20:49 +00:00
|
|
|
if (lf->mark_as_duplicate(dupe_name)) {
|
|
|
|
log_info("Hiding duplicate file: %s",
|
|
|
|
lf->get_filename().c_str());
|
|
|
|
lnav_data.ld_log_source.find_data(lf) |
|
|
|
|
[](auto ld) { ld->set_visibility(false); };
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
});
|
|
|
|
reload = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reload) {
|
|
|
|
lss.text_filters_changed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-29 05:43:33 +00:00
|
|
|
retval.rir_changes += 1;
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
|
2023-08-02 17:44:13 +00:00
|
|
|
for (auto lpc : {LNV_LOG, LNV_TEXT}) {
|
2023-06-16 04:52:33 +00:00
|
|
|
auto& scroll_view = lnav_data.ld_views[lpc];
|
2022-04-30 20:05:42 +00:00
|
|
|
|
2023-06-24 06:03:23 +00:00
|
|
|
if (scroll_downs[lpc]) {
|
2023-06-16 04:52:33 +00:00
|
|
|
if (scroll_view.is_selectable()) {
|
|
|
|
auto inner_height = scroll_view.get_inner_height();
|
|
|
|
|
|
|
|
if (inner_height > 0_vl) {
|
|
|
|
scroll_view.set_selection(inner_height - 1_vl);
|
|
|
|
}
|
2023-06-24 06:03:23 +00:00
|
|
|
} else if (scroll_view.get_top_for_last_row()
|
|
|
|
> scroll_view.get_top())
|
|
|
|
{
|
2023-06-16 04:52:33 +00:00
|
|
|
scroll_view.set_top(scroll_view.get_top_for_last_row());
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-25 04:10:54 +00:00
|
|
|
lnav_data.ld_view_stack.top() | [&closed_files, &retval](auto tc) {
|
2023-08-06 14:19:48 +00:00
|
|
|
if (!closed_files.empty() && tc == &lnav_data.ld_views[LNV_GANTT]) {
|
|
|
|
auto* gantt_source = lnav_data.ld_views[LNV_GANTT].get_sub_source();
|
|
|
|
if (gantt_source != nullptr) {
|
|
|
|
gantt_source->text_filters_changed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-10 19:20:49 +00:00
|
|
|
auto* tss = tc->get_sub_source();
|
|
|
|
lnav_data.ld_filter_status_source.update_filtered(tss);
|
2023-08-29 05:43:33 +00:00
|
|
|
if (retval.rir_changes > 0) {
|
2023-08-25 04:10:54 +00:00
|
|
|
lnav_data.ld_scroll_broadcaster(tc);
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rebuild_indexes_repeatedly()
|
|
|
|
{
|
2023-08-29 05:43:33 +00:00
|
|
|
for (size_t attempt = 0; attempt < 10 && rebuild_indexes().rir_changes > 0;
|
|
|
|
attempt++)
|
|
|
|
{
|
2022-04-30 20:05:42 +00:00
|
|
|
log_info("continuing to rebuild indexes...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
update_active_files(file_collection& new_files)
|
|
|
|
{
|
|
|
|
static loading_observer obs;
|
|
|
|
|
|
|
|
if (lnav_data.ld_active_files.fc_invalidate_merge) {
|
|
|
|
lnav_data.ld_active_files.fc_invalidate_merge = false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-08-26 04:03:00 +00:00
|
|
|
bool was_below_open_file_limit
|
|
|
|
= lnav_data.ld_active_files.is_below_open_file_limit();
|
|
|
|
|
2022-04-30 20:05:42 +00:00
|
|
|
for (const auto& lf : new_files.fc_files) {
|
|
|
|
lf->set_logfile_observer(&obs);
|
|
|
|
lnav_data.ld_text_source.push_back(lf);
|
|
|
|
}
|
|
|
|
for (const auto& other_pair : new_files.fc_other_files) {
|
|
|
|
switch (other_pair.second.ofd_format) {
|
|
|
|
case file_format_t::SQLITE_DB:
|
|
|
|
attach_sqlite_db(lnav_data.ld_db.in(), other_pair.first);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lnav_data.ld_active_files.merge(new_files);
|
|
|
|
lnav_data.ld_child_pollers.insert(
|
|
|
|
lnav_data.ld_child_pollers.begin(),
|
|
|
|
std::make_move_iterator(
|
|
|
|
lnav_data.ld_active_files.fc_child_pollers.begin()),
|
|
|
|
std::make_move_iterator(
|
|
|
|
lnav_data.ld_active_files.fc_child_pollers.end()));
|
2022-08-29 01:55:32 +00:00
|
|
|
lnav_data.ld_active_files.fc_child_pollers.clear();
|
2022-04-30 20:05:42 +00:00
|
|
|
|
2022-06-09 19:49:06 +00:00
|
|
|
lnav::events::publish(
|
|
|
|
lnav_data.ld_db.in(), new_files.fc_files, [](const auto& lf) {
|
|
|
|
return lnav::events::file::open{
|
|
|
|
lf->get_filename(),
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2023-08-26 04:03:00 +00:00
|
|
|
if (was_below_open_file_limit
|
|
|
|
&& !lnav_data.ld_active_files.is_below_open_file_limit())
|
|
|
|
{
|
|
|
|
auto um
|
|
|
|
= lnav::console::user_message::error("Unable to open more files")
|
|
|
|
.with_reason(
|
|
|
|
attr_line_t("The file-descriptor limit of ")
|
|
|
|
.append(lnav::roles::number(fmt::to_string(
|
|
|
|
file_collection::get_limits().l_fds)))
|
|
|
|
.append(" is too low to support opening more files"))
|
|
|
|
.with_help(
|
|
|
|
attr_line_t("Use ")
|
|
|
|
.append("ulimit -n"_quoted_code)
|
|
|
|
.append(
|
|
|
|
" to increase the limit before running lnav"));
|
|
|
|
|
|
|
|
lnav_data.ld_exec_context.ec_error_callback_stack.back()(um);
|
|
|
|
}
|
|
|
|
|
2022-04-30 20:05:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
rescan_files(bool req)
|
|
|
|
{
|
|
|
|
auto& mlooper = injector::get<main_looper&, services::main_t>();
|
|
|
|
bool done = false;
|
|
|
|
auto delay = 0ms;
|
|
|
|
|
|
|
|
do {
|
|
|
|
auto fc = lnav_data.ld_active_files.rescan_files(req);
|
|
|
|
bool all_synced = true;
|
|
|
|
|
|
|
|
update_active_files(fc);
|
|
|
|
mlooper.get_port().process_for(delay);
|
2022-08-04 06:01:38 +00:00
|
|
|
for (const auto& pair : lnav_data.ld_active_files.fc_other_files) {
|
|
|
|
if (pair.second.ofd_format != file_format_t::REMOTE) {
|
|
|
|
continue;
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
2022-08-04 06:01:38 +00:00
|
|
|
|
2023-08-26 04:03:00 +00:00
|
|
|
if (lnav_data.ld_active_files.fc_name_to_errors->readAccess()
|
|
|
|
->count(pair.first))
|
|
|
|
{
|
2022-08-29 01:55:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-08-04 06:01:38 +00:00
|
|
|
if (lnav_data.ld_active_files.fc_synced_files.count(pair.first)
|
|
|
|
== 0)
|
|
|
|
{
|
|
|
|
all_synced = false;
|
2022-04-30 20:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
2023-08-26 04:03:00 +00:00
|
|
|
if (!lnav_data.ld_active_files.fc_name_to_errors->readAccess()->empty())
|
|
|
|
{
|
2022-08-29 01:55:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-08-04 06:01:38 +00:00
|
|
|
if (!all_synced) {
|
|
|
|
delay = 30ms;
|
|
|
|
}
|
2022-04-30 20:05:42 +00:00
|
|
|
done = fc.fc_file_names.empty() && all_synced;
|
2022-08-13 14:31:46 +00:00
|
|
|
if (!done && !(lnav_data.ld_flags & LNF_HEADLESS)) {
|
|
|
|
lnav_data.ld_files_view.set_needs_update();
|
|
|
|
lnav_data.ld_files_view.do_update();
|
2022-09-22 01:54:45 +00:00
|
|
|
lnav_data.ld_status_refresher();
|
2022-08-13 14:31:46 +00:00
|
|
|
}
|
2022-08-04 06:01:38 +00:00
|
|
|
} while (!done && lnav_data.ld_looping);
|
2022-04-30 20:05:42 +00:00
|
|
|
return true;
|
|
|
|
}
|