From 2c6b023a8859f562b16adaef6a7c2753458c7844 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Tue, 6 Mar 2012 09:35:21 +0100 Subject: [PATCH] real time indexer: monitor the configuration for changes and reexecute when needed --- src/common/rclconfig.cpp | 15 +++++++++++++++ src/common/rclconfig.h | 4 ++++ src/index/rclmon.h | 3 ++- src/index/rclmonprc.cpp | 10 ++++++++-- src/index/recollindex.cpp | 16 ++++++++++++++-- src/index/recollindex.h | 3 +++ src/utils/conftree.cpp | 28 +++++++++++++++++++++++++--- src/utils/conftree.h | 16 ++++++++++++++++ 8 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/common/rclconfig.cpp b/src/common/rclconfig.cpp index c9da7487..58941c74 100644 --- a/src/common/rclconfig.cpp +++ b/src/common/rclconfig.cpp @@ -893,6 +893,21 @@ string RclConfig::getDbDir() return path_canon(dbdir); } +bool RclConfig::sourceChanged() +{ + if (m_conf && m_conf->sourceChanged()) + return true; + if (mimemap && mimemap->sourceChanged()) + return true; + if (mimeconf && mimeconf->sourceChanged()) + return true; + if (mimeview && mimeview->sourceChanged()) + return true; + if (m_fields && m_fields->sourceChanged()) + return true; + return false; +} + string RclConfig::getStopfile() { return path_cat(getConfDir(), "stoplist.txt"); diff --git a/src/common/rclconfig.h b/src/common/rclconfig.h index bf2ea680..6d524fd7 100644 --- a/src/common/rclconfig.h +++ b/src/common/rclconfig.h @@ -88,6 +88,10 @@ class RclConfig { * constructor it it is the default one (~/.recoll) and it did * not exist yet. */ string getConfDir() {return m_confdir;} + + /** Check if the config files were modified since we read them */ + bool sourceChanged(); + /** Returns true if this is ~/.recoll */ bool isDefaultConfig(); /** Get the local value for /usr/local/share/recoll/ */ diff --git a/src/index/rclmon.h b/src/index/rclmon.h index bdb9aa18..4604f620 100644 --- a/src/index/rclmon.h +++ b/src/index/rclmon.h @@ -65,7 +65,8 @@ class RclMonEvent { int evflags() {return m_etyp & 0xf0;} }; -enum RclMonitorOption {RCLMON_NONE=0, RCLMON_NOFORK=1, RCLMON_NOX11=2}; +enum RclMonitorOption {RCLMON_NONE=0, RCLMON_NOFORK=1, RCLMON_NOX11=2, + RCLMON_NOCONFCHECK=4}; /** * Monitoring event queue. This is the shared object between the main thread diff --git a/src/index/rclmonprc.cpp b/src/index/rclmonprc.cpp index 50f9418b..70fd82c5 100644 --- a/src/index/rclmonprc.cpp +++ b/src/index/rclmonprc.cpp @@ -39,6 +39,7 @@ #include "debuglog.h" #include "rclmon.h" #include "debuglog.h" +#include "execmd.h" #include "recollindex.h" #include "pathut.h" #include "x11mon.h" @@ -485,11 +486,11 @@ bool startMonitor(RclConfig *conf, int opts) switch (ev.evtype()) { case RclMonEvent::RCLEVT_MODIFY: case RclMonEvent::RCLEVT_DIRCREATE: - LOGDEB(("Monitor: Modify/Check on %s\n", ev.m_path.c_str())); + LOGDEB0(("Monitor: Modify/Check on %s\n", ev.m_path.c_str())); modified.push_back(ev.m_path); break; case RclMonEvent::RCLEVT_DELETE: - LOGDEB(("Monitor: Delete on %s\n", ev.m_path.c_str())); + LOGDEB0(("Monitor: Delete on %s\n", ev.m_path.c_str())); // If this is for a directory (which the caller should // tell us because he knows), we should purge the db // of all the subtree, because on a directory rename, @@ -552,6 +553,11 @@ bool startMonitor(RclConfig *conf, int opts) } } + // Check for a config change + if (!(opts & RCLMON_NOCONFCHECK) && o_reexec && conf->sourceChanged()) { + LOGDEB(("Rclmonprc: config changed, reexecuting myself\n")); + o_reexec->reexec(); + } // Lock queue before waiting again rclEQ.lock(); } diff --git a/src/index/recollindex.cpp b/src/index/recollindex.cpp index 90fc91eb..e86b65f7 100644 --- a/src/index/recollindex.cpp +++ b/src/index/recollindex.cpp @@ -45,6 +45,7 @@ using namespace std; #include "recollindex.h" #include "fsindexer.h" #include "rclionice.h" +#include "execmd.h" // Command line options static int op_flags; @@ -63,6 +64,9 @@ static int op_flags; #define OPT_l 0x1000 #define OPT_b 0x2000 #define OPT_f 0x4000 +#define OPT_C 0x8000 + +ReExec *o_reexec; // Globals for atexit cleanup static ConfIndexer *confindexer; @@ -224,9 +228,10 @@ static const char usage [] = " Index everything according to configuration file\n" " -z : reset database before starting indexing\n" #ifdef RCL_MONITOR -"recollindex -m [-w ] -x [-D]\n" +"recollindex -m [-w ] -x [-D] [-C]\n" " Perform real time indexing. Don't become a daemon if -D is set.\n" " -w sets number of seconds to wait before starting.\n" +" -C disables monitoring config for changes/reexecuting.\n" #ifndef DISABLE_X11MON " -x disables exit on end of x11 session\n" #endif /* DISABLE_X11MON */ @@ -271,10 +276,12 @@ void lockorexit(Pidfile *pidfile) } } -int main(int argc, const char **argv) +int main(int argc, char **argv) { string a_config; int sleepsecs = 60; + o_reexec = new ReExec; + o_reexec->init(argc, argv); thisprog = argv[0]; argc--; argv++; @@ -290,6 +297,7 @@ int main(int argc, const char **argv) a_config = *(++argv); argc--; goto b1; #ifdef RCL_MONITOR + case 'C': op_flags |= OPT_C; break; case 'D': op_flags |= OPT_D; break; #endif case 'e': op_flags |= OPT_e; break; @@ -333,6 +341,8 @@ int main(int argc, const char **argv) cerr << "Configuration problem: " << reason << endl; exit(1); } + o_reexec->atexit(cleanup); + bool rezero(op_flags & OPT_z); Pidfile pidfile(config->getPidfile()); updater = new MyUpdater(config); @@ -433,6 +443,8 @@ int main(int argc, const char **argv) int opts = RCLMON_NONE; if (op_flags & OPT_D) opts |= RCLMON_NOFORK; + if (op_flags & OPT_C) + opts |= RCLMON_NOCONFCHECK; if (op_flags & OPT_x) opts |= RCLMON_NOX11; bool monret = startMonitor(config, opts); diff --git a/src/index/recollindex.h b/src/index/recollindex.h index fe201a81..b1439746 100644 --- a/src/index/recollindex.h +++ b/src/index/recollindex.h @@ -25,4 +25,7 @@ extern bool createAuxDbs(RclConfig *config); extern int stopindexing; +class ReExec; +extern ReExec *o_reexec; + #endif /* _recollindex_h_included_ */ diff --git a/src/utils/conftree.cpp b/src/utils/conftree.cpp index 1c31b0a0..7cf0edb3 100644 --- a/src/utils/conftree.cpp +++ b/src/utils/conftree.cpp @@ -23,6 +23,7 @@ #include // for access(2) #include #include +#include #include #include @@ -145,13 +146,13 @@ void ConfSimple::parseinput(istream &input) ConfSimple::ConfSimple(int readonly, bool tildexp) - : dotildexpand(tildexp), m_holdWrites(false) + : dotildexpand(tildexp), m_fmtime(0), m_holdWrites(false) { status = readonly ? STATUS_RO : STATUS_RW; } ConfSimple::ConfSimple(const string& d, int readonly, bool tildexp) - : dotildexpand(tildexp), m_holdWrites(false) + : dotildexpand(tildexp), m_fmtime(0), m_holdWrites(false) { status = readonly ? STATUS_RO : STATUS_RW; @@ -160,7 +161,7 @@ ConfSimple::ConfSimple(const string& d, int readonly, bool tildexp) } ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp) - : dotildexpand(tildexp), m_filename(fname), m_holdWrites(false) + : dotildexpand(tildexp), m_filename(fname), m_fmtime(0), m_holdWrites(false) { status = readonly ? STATUS_RO : STATUS_RW; @@ -193,6 +194,7 @@ ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp) } parseinput(input); + i_changed(true); } ConfSimple::StatusCode ConfSimple::getStatus() const @@ -204,6 +206,26 @@ ConfSimple::StatusCode ConfSimple::getStatus() const } } +bool ConfSimple::sourceChanged() +{ + return i_changed(false); +} + +bool ConfSimple::i_changed(bool upd) +{ + if (!m_filename.empty()) { + struct stat st; + if (stat(m_filename.c_str(), &st) == 0) { + if (m_fmtime != st.st_mtime) { + if (upd) + m_fmtime = st.st_mtime; + return true; + } + } + } + return false; +} + int ConfSimple::get(const string &nm, string &value, const string &sk) const { if (!ok()) diff --git a/src/utils/conftree.h b/src/utils/conftree.h index 243406f2..843e3efc 100644 --- a/src/utils/conftree.h +++ b/src/utils/conftree.h @@ -107,6 +107,7 @@ public: virtual list getSubKeys() = 0; virtual list getSubKeys(bool) = 0; virtual bool holdWrites(bool) = 0; + virtual bool sourceChanged() = 0; }; /** @@ -140,6 +141,9 @@ public: virtual ~ConfSimple() {}; + /** Origin file changed. Only makes sense if we read the data from a file */ + virtual bool sourceChanged(); + /** * Decide if we actually rewrite the backing-store after modifying the * tree. @@ -252,6 +256,7 @@ protected: private: // Set if we're working with a file string m_filename; + time_t m_fmtime; // Configuration data submaps (one per subkey, the main data has a // null subkey) map > m_submaps; @@ -267,6 +272,7 @@ private: // Internal version of set: no RW checking virtual int i_set(const string &nm, const string &val, const string &sk, bool init = false); + bool i_changed(bool upd); }; /** @@ -366,6 +372,16 @@ public: return *this; } + virtual bool sourceChanged() + { + typename list::const_iterator it; + for (it = m_confs.begin();it != m_confs.end();it++) { + if ((*it)->sourceChanged()) + return true; + } + return false; + } + virtual int get(const string &name, string &value, const string &sk) const { typename list::const_iterator it;