[files_vtab] add a vtable for opened files

Defect Number:
    Reviewed By:
   Testing Done:
This commit is contained in:
Timothy Stack 2017-03-08 13:51:07 -08:00
parent 9e7c30f00a
commit 32c9dacd0a
10 changed files with 359 additions and 38 deletions

View File

@ -10,6 +10,7 @@ set(diag_STAT_SRCS
environ_vtab.cc
extension-functions.c
field_overlay_source.cc
file_vtab.cc
fs-extension-functions.cc
grep_proc.cc
hist_source.cc
@ -92,6 +93,7 @@ set(diag_STAT_SRCS
curl_looper.hh
elem_to_json.hh
field_overlay_source.hh
file_vtab.hh
filter_observer.hh
format-text-files.hh
grep_highlighter.hh

View File

@ -139,6 +139,7 @@ noinst_HEADERS = \
elem_to_json.hh \
environ_vtab.hh \
field_overlay_source.hh \
file_vtab.hh \
filter_observer.hh \
format-text-files.hh \
grep_highlighter.hh \
@ -241,6 +242,7 @@ libdiag_a_SOURCES = \
environ_vtab.cc \
extension-functions.c \
field_overlay_source.cc \
file_vtab.cc \
fs-extension-functions.cc \
grep_proc.cc \
hist_source.cc \

View File

@ -258,7 +258,6 @@ string execute_sql(exec_context &ec, const string &sql, string &alt_msg)
}
if (retcode == SQLITE_DONE) {
lnav_data.ld_views[LNV_LOG].reload_data();
lnav_data.ld_views[LNV_DB].reload_data();
lnav_data.ld_views[LNV_DB].set_left(0);
@ -319,7 +318,6 @@ string execute_sql(exec_context &ec, const string &sql, string &alt_msg)
lnav_data.ld_status[LNS_BOTTOM].do_update();
redo_search(LNV_DB);
}
lnav_data.ld_views[LNV_LOG].reload_data();
return retval;
}
@ -347,7 +345,7 @@ static string execute_file_contents(exec_context &ec, const string &path, bool m
char mode = '\0';
pair<string, string> dir_and_base = split_path(path);
ec.ec_path_stack.push(dir_and_base.first);
ec.ec_path_stack.push_back(dir_and_base.first);
while ((line_size = getline(&line, &line_max_size, file)) != -1) {
line_number += 1;
@ -394,7 +392,7 @@ static string execute_file_contents(exec_context &ec, const string &path, bool m
} else {
fclose(file);
}
ec.ec_path_stack.pop();
ec.ec_path_stack.pop_back();
return retval;
}
@ -454,7 +452,7 @@ string execute_file(exec_context &ec, const string &path_and_args, bool multilin
open_error = strerror(errno);
}
else {
string local_path = ec.ec_path_stack.top() + "/" + script_name;
string local_path = ec.ec_path_stack.back() + "/" + script_name;
if (access(local_path.c_str(), R_OK) == 0) {
struct script_metadata meta;

View File

@ -50,7 +50,7 @@ struct exec_context {
ec_sql_callback(sql_callback),
ec_pipe_callback(pipe_callback) {
this->ec_local_vars.push(std::map<std::string, std::string>());
this->ec_path_stack.push(".");
this->ec_path_stack.push_back(".");
}
vis_line_t ec_top_line;
@ -59,7 +59,7 @@ struct exec_context {
std::vector<logline_value> *ec_line_values;
std::stack<std::map<std::string, std::string> > ec_local_vars;
std::map<std::string, std::string> ec_global_vars;
std::stack<std::string> ec_path_stack;
std::vector<std::string> ec_path_stack;
std::string ec_accumulator;

269
src/file_vtab.cc Normal file
View File

@ -0,0 +1,269 @@
/**
* Copyright (c) 2017, 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 "config.h"
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "lnav.hh"
#include "auto_mem.hh"
#include "lnav_log.hh"
#include "sql_util.hh"
#include "file_vtab.hh"
using namespace std;
const char *LNAV_FILE_CREATE_STMT = "\
-- Access lnav's open file list through this table.\n\
CREATE TABLE lnav_file (\n\
device integer,\n\
inode integer,\n\
filepath text,\n\
format text,\n\
lines integer\n\
);\n\
";
struct vtab {
sqlite3_vtab base;
sqlite3 * db;
};
struct vtab_cursor {
sqlite3_vtab_cursor base;
int vc_index;
};
static int vt_destructor(sqlite3_vtab *p_svt);
static int vt_create(sqlite3 *db,
void *pAux,
int argc, const char *const *argv,
sqlite3_vtab **pp_vt,
char **pzErr)
{
vtab *p_vt;
/* Allocate the sqlite3_vtab/vtab structure itself */
p_vt = (vtab *)sqlite3_malloc(sizeof(*p_vt));
if (p_vt == NULL) {
return SQLITE_NOMEM;
}
memset(&p_vt->base, 0, sizeof(sqlite3_vtab));
p_vt->db = db;
*pp_vt = &p_vt->base;
int rc = sqlite3_declare_vtab(db, LNAV_FILE_CREATE_STMT);
return rc;
}
static int vt_destructor(sqlite3_vtab *p_svt)
{
vtab *p_vt = (vtab *)p_svt;
/* Free the SQLite structure */
sqlite3_free(p_vt);
return SQLITE_OK;
}
static int vt_connect(sqlite3 *db, void *p_aux,
int argc, const char *const *argv,
sqlite3_vtab **pp_vt, char **pzErr)
{
return vt_create(db, p_aux, argc, argv, pp_vt, pzErr);
}
static int vt_disconnect(sqlite3_vtab *pVtab)
{
return vt_destructor(pVtab);
}
static int vt_destroy(sqlite3_vtab *p_vt)
{
return vt_destructor(p_vt);
}
static int vt_next(sqlite3_vtab_cursor *cur);
static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
{
vtab *p_vt = (vtab *)p_svt;
p_vt->base.zErrMsg = NULL;
vtab_cursor *p_cur = (vtab_cursor *)new vtab_cursor();
if (p_cur == NULL) {
return SQLITE_NOMEM;
} else {
*pp_cursor = (sqlite3_vtab_cursor *)p_cur;
p_cur->base.pVtab = p_svt;
p_cur->vc_index = 0;
}
return SQLITE_OK;
}
static int vt_close(sqlite3_vtab_cursor *cur)
{
vtab_cursor *p_cur = (vtab_cursor *)cur;
/* Free cursor struct. */
delete p_cur;
return SQLITE_OK;
}
static int vt_eof(sqlite3_vtab_cursor *cur)
{
vtab_cursor *vc = (vtab_cursor *)cur;
return vc->vc_index >= lnav_data.ld_files.size();
}
static int vt_next(sqlite3_vtab_cursor *cur)
{
vtab_cursor *vc = (vtab_cursor *)cur;
if (vc->vc_index < lnav_data.ld_files.size()) {
vc->vc_index += 1;
}
return SQLITE_OK;
}
static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
{
vtab_cursor *vc = (vtab_cursor *)cur;
logfile *lf = lnav_data.ld_files[vc->vc_index];
const struct stat &st = lf->get_stat();
const string &name = lf->get_filename();
log_format *format = lf->get_format();
const char *format_name = format != NULL ? format->get_name().get() : NULL;
switch (col) {
case 0:
sqlite3_result_int(ctx, st.st_dev);
break;
case 1:
sqlite3_result_int(ctx, st.st_ino);
break;
case 2:
sqlite3_result_text(ctx, name.c_str(), name.size(), SQLITE_TRANSIENT);
break;
case 3:
if (format_name != NULL) {
sqlite3_result_text(ctx, format_name, -1, SQLITE_STATIC);
} else {
sqlite3_result_null(ctx);
}
break;
case 4:
sqlite3_result_int(ctx, lf->size());
break;
}
return SQLITE_OK;
}
static int vt_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
vtab_cursor *p_cur = (vtab_cursor *)cur;
*p_rowid = (int64_t) p_cur->vc_index;
return SQLITE_OK;
}
static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
{
return SQLITE_OK;
}
static int vt_filter(sqlite3_vtab_cursor *p_vtc,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv)
{
return SQLITE_OK;
}
static int vt_update(sqlite3_vtab *tab,
int argc,
sqlite3_value **argv,
sqlite_int64 *rowid)
{
return SQLITE_ERROR;
}
static sqlite3_module vtab_module = {
0, /* iVersion */
vt_create, /* xCreate - create a vtable */
vt_connect, /* xConnect - associate a vtable with a connection */
vt_best_index, /* xBestIndex - best index */
vt_disconnect, /* xDisconnect - disassociate a vtable with a connection */
vt_destroy, /* xDestroy - destroy a vtable */
vt_open, /* xOpen - open a cursor */
vt_close, /* xClose - close a cursor */
vt_filter, /* xFilter - configure scan constraints */
vt_next, /* xNext - advance a cursor */
vt_eof, /* xEof - inidicate end of result set*/
vt_column, /* xColumn - read data */
vt_rowid, /* xRowid - read data */
vt_update, /* xUpdate - write data */
NULL, /* xBegin - begin transaction */
NULL, /* xSync - sync transaction */
NULL, /* xCommit - commit transaction */
NULL, /* xRollback - rollback transaction */
NULL, /* xFindFunction - function overloading */
};
int register_file_vtab(sqlite3 *db)
{
auto_mem<char, sqlite3_free> errmsg;
int rc;
rc = sqlite3_create_module(db, "lnav_file_vtab_impl", &vtab_module, NULL);
assert(rc == SQLITE_OK);
if ((rc = sqlite3_exec(db,
"CREATE VIRTUAL TABLE lnav_file USING lnav_file_vtab_impl()",
NULL, NULL, errmsg.out())) != SQLITE_OK) {
fprintf(stderr, "unable to create lnav_file table %s\n", errmsg.in());
}
return rc;
}

39
src/file_vtab.hh Normal file
View File

@ -0,0 +1,39 @@
/**
* Copyright (c) 2017, 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.
*/
#ifndef __file_vtab_hh
#define __file_vtab_hh
#include <sqlite3.h>
int register_file_vtab(sqlite3 *db);
extern const char *LNAV_FILE_CREATE_STMT;
#endif

View File

@ -119,6 +119,7 @@
#include "views_vtab.hh"
#include "pretty_printer.hh"
#include "all_logs_vtab.hh"
#include "file_vtab.hh"
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
@ -278,8 +279,11 @@ bool setup_logline_table()
textview_curses &log_view = lnav_data.ld_views[LNV_LOG];
bool retval = false;
bool update_possibilities = (
lnav_data.ld_rl_view != NULL &&
lnav_data.ld_exec_context.ec_local_vars.size() == 1);
if (lnav_data.ld_rl_view != NULL) {
if (update_possibilities) {
lnav_data.ld_rl_view->clear_possibilities(LNM_SQL, "*");
add_view_text_possibilities(LNM_SQL, "*", &log_view);
}
@ -292,7 +296,7 @@ bool setup_logline_table()
lnav_data.ld_vtab_manager->unregister_vtab(logline);
lnav_data.ld_vtab_manager->register_vtab(new log_data_table(cl, logline));
if (lnav_data.ld_rl_view != NULL) {
if (update_possibilities) {
log_data_helper ldh(lnav_data.ld_log_source);
ldh.parse_line(cl);
@ -311,9 +315,11 @@ bool setup_logline_table()
retval = true;
}
lnav_data.ld_db_key_names.clear();
auto &db_key_names = lnav_data.ld_db_key_names;
if (lnav_data.ld_rl_view != NULL) {
db_key_names.clear();
if (update_possibilities) {
add_env_possibilities(LNM_SQL);
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", sql_keywords);
@ -349,11 +355,13 @@ bool setup_logline_table()
walk_sqlite_metadata(lnav_data.ld_db.in(), lnav_sql_meta_callbacks);
for (const auto &iter : *lnav_data.ld_vtab_manager) {
iter.second->get_foreign_keys(lnav_data.ld_db_key_names);
iter.second->get_foreign_keys(db_key_names);
}
stable_sort(lnav_data.ld_db_key_names.begin(),
lnav_data.ld_db_key_names.end());
db_key_names.push_back("device");
db_key_names.push_back("inode");
stable_sort(db_key_names.begin(), db_key_names.end());
return retval;
}
@ -472,7 +480,10 @@ public:
if (!lf->is_valid_filename()) {
lnav_data.ld_file_names.erase(lf->get_filename());
}
lnav_data.ld_files.remove(lf);
auto file_iter = find(lnav_data.ld_files.begin(),
lnav_data.ld_files.end(),
lf);
lnav_data.ld_files.erase(file_iter);
delete lf;
};
@ -570,8 +581,7 @@ void rebuild_indexes(bool force)
old_count = 0;
}
list<logfile *>::iterator file_iter;
for (file_iter = lnav_data.ld_files.begin();
for (auto file_iter = lnav_data.ld_files.begin();
file_iter != lnav_data.ld_files.end(); ) {
logfile *lf = *file_iter;
@ -717,6 +727,7 @@ static void open_schema_view(void)
schema += ENVIRON_CREATE_STMT;
schema += LNAV_VIEWS_CREATE_STMT;
schema += LNAV_VIEW_STACK_CREATE_STMT;
schema += LNAV_FILE_CREATE_STMT;
for (log_vtab_manager::iterator vtab_iter =
lnav_data.ld_vtab_manager->begin();
vtab_iter != lnav_data.ld_vtab_manager->end();
@ -809,6 +820,7 @@ static void open_pretty_view(void)
format->annotate(sbr, sa, values);
exec_context ec(&values, pretty_sql_callback, pretty_pipe_callback);
ec.ec_top_line = vl;
add_ansi_vars(ec.ec_global_vars);
add_global_vars(ec);
format->rewrite(ec, sbr, sa, rewritten_line);
@ -1277,7 +1289,6 @@ struct same_file {
static bool watch_logfile(string filename, logfile_open_options &loo, bool required)
{
static loading_observer obs;
list<logfile *>::iterator file_iter;
struct stat st;
int rc;
bool retval = false;
@ -1313,9 +1324,9 @@ static bool watch_logfile(string filename, logfile_open_options &loo, bool requi
}
}
file_iter = find_if(lnav_data.ld_files.begin(),
lnav_data.ld_files.end(),
same_file(st));
auto file_iter = find_if(lnav_data.ld_files.begin(),
lnav_data.ld_files.end(),
same_file(st));
if (file_iter == lnav_data.ld_files.end()) {
if (find(lnav_data.ld_other_files.begin(),
@ -1404,7 +1415,6 @@ static void expand_filename(string path, bool required)
bool rescan_files(bool required)
{
map<string, logfile_open_options>::iterator iter;
list<logfile *>::iterator file_iter;
bool retval = false;
for (iter = lnav_data.ld_file_names.begin();
@ -1423,7 +1433,7 @@ bool rescan_files(bool required)
}
}
for (file_iter = lnav_data.ld_files.begin();
for (auto file_iter = lnav_data.ld_files.begin();
file_iter != lnav_data.ld_files.end(); ) {
logfile *lf = *file_iter;
@ -2846,6 +2856,7 @@ int main(int argc, char *argv[])
register_environ_vtab(lnav_data.ld_db.in());
register_views_vtab(lnav_data.ld_db.in());
register_file_vtab(lnav_data.ld_db.in());
lnav_data.ld_vtab_manager =
new log_vtab_manager(lnav_data.ld_db,
@ -3047,9 +3058,9 @@ int main(int argc, char *argv[])
if (lnav_data.ld_flags & LNF_CHECK_CONFIG) {
rescan_files(true);
for (list<logfile *>::iterator file_iter = lnav_data.ld_files.begin();
file_iter != lnav_data.ld_files.end();
++file_iter) {
for (auto file_iter = lnav_data.ld_files.begin();
file_iter != lnav_data.ld_files.end();
++file_iter) {
logfile *lf = (*file_iter);
lf->rebuild_index();
@ -3298,13 +3309,12 @@ int main(int argc, char *argv[])
if (stdin_out_fd != -1 &&
!(lnav_data.ld_flags & LNF_QUIET) &&
!(lnav_data.ld_flags & LNF_HEADLESS)) {
list<logfile *>::iterator file_iter;
struct stat st;
fstat(stdin_out_fd, &st);
file_iter = find_if(lnav_data.ld_files.begin(),
lnav_data.ld_files.end(),
same_file(st));
auto file_iter = find_if(lnav_data.ld_files.begin(),
lnav_data.ld_files.end(),
same_file(st));
if (file_iter != lnav_data.ld_files.end()) {
logfile::iterator line_iter;
logfile *lf = *file_iter;

View File

@ -223,7 +223,7 @@ struct _lnav_data {
bool ld_cmd_init_done;
std::vector<std::string> ld_config_paths;
std::map<std::string, logfile_open_options> ld_file_names;
std::list<logfile *> ld_files;
std::vector<logfile *> ld_files;
std::list<std::string> ld_other_files;
std::set<std::string> ld_closed_files;
std::list<std::pair<std::string, int> > ld_files_to_front;

View File

@ -84,7 +84,7 @@ static string refresh_pt_search()
}
#ifdef HAVE_LIBCURL
for (list<logfile *>::iterator iter = lnav_data.ld_files.begin();
for (auto iter = lnav_data.ld_files.begin();
iter != lnav_data.ld_files.end();
++iter) {
logfile *lf = *iter;
@ -709,7 +709,7 @@ static string com_pipe_to(exec_context &ec, string cmdline, vector<string> &args
const char *args[] = {
"sh", "-c", cmd.c_str(), NULL,
};
vector<std::string> path_v;
vector<std::string> path_v = ec.ec_path_stack;
string path;
dup2(STDOUT_FILENO, STDERR_FILENO);
@ -798,6 +798,8 @@ static string com_pipe_to(exec_context &ec, string cmdline, vector<string> &args
}
}
in_pipe.write_end().reset();
if (reader.valid()) {
retval = reader.get();
}
@ -1328,7 +1330,6 @@ static string com_open(exec_context &ec, string cmdline, vector<string> &args)
}
vector<string> word_exp;
list<logfile *>::iterator file_iter;
size_t colon_index;
int top = 0;
string pat;
@ -1363,9 +1364,8 @@ static string com_open(exec_context &ec, string cmdline, vector<string> &args)
}
}
for (file_iter = lnav_data.ld_files.begin();
file_iter != lnav_data.ld_files.end();
++file_iter) {
auto file_iter = lnav_data.ld_files.begin();
for (; file_iter != lnav_data.ld_files.end(); ++file_iter) {
logfile *lf = *file_iter;
if (lf->get_filename() == fn) {

View File

@ -497,7 +497,7 @@ EOF
schema_dump() {
${lnav_test} -n -c ';.schema' ${test_dir}/logfile_access_log.0 | head -n10
${lnav_test} -n -c ';.schema' ${test_dir}/logfile_access_log.0 | head -n11
}
run_test schema_dump
@ -507,6 +507,7 @@ ATTACH DATABASE '' AS 'main';
CREATE VIRTUAL TABLE environ USING environ_vtab_impl();
CREATE VIRTUAL TABLE lnav_views USING views_vtab_impl();
CREATE VIRTUAL TABLE lnav_view_stack USING view_stack_vtab_impl();
CREATE VIRTUAL TABLE lnav_file USING lnav_file_vtab_impl();
CREATE TABLE http_status_codes (
status integer PRIMARY KEY,
message text,