From 4d7d1a7965879016290481235d6d088b4aab3b0a Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Tue, 19 Mar 2019 14:38:57 +0100 Subject: [PATCH] windows powerfail signal: stop indexing only on resume and topdirs change --- src/common/rclinit.cpp | 12 ++++--- src/common/rclinit.h | 8 +++++ src/index/fsindexer.cpp | 15 --------- src/index/recollindex.cpp | 67 ++++++++++++++++++++++++++++----------- src/utils/rclutil.cpp | 15 +++++++++ src/utils/rclutil.h | 2 ++ 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/common/rclinit.cpp b/src/common/rclinit.cpp index 3311e68d..52415cda 100644 --- a/src/common/rclinit.cpp +++ b/src/common/rclinit.cpp @@ -168,12 +168,14 @@ LRESULT CALLBACK MainWndProc(HWND hwnd , UINT msg , WPARAM wParam, case WM_POWERBROADCAST: { LOGDEB("MainWndProc: got powerbroadcast message\n"); - // We always try to end an indexing operation, independantly - // of the kind of event. Mounted volumes may have changed - // etc. Using SIGTERM just to have something different from - // the other messages + // This gets specific processing because we want to check the + // state of topdirs on resuming indexing (in case a mounted + // volume went away). if (l_sigcleanup) { - l_sigcleanup(SIGTERM); + if (wParam == PBT_APMRESUMEAUTOMATIC || + wParam == PBT_APMRESUMESUSPEND) { + l_sigcleanup(RCLSIG_RESUME); + } } } break; diff --git a/src/common/rclinit.h b/src/common/rclinit.h index f370bb60..fad43786 100644 --- a/src/common/rclinit.h +++ b/src/common/rclinit.h @@ -41,6 +41,14 @@ class RclConfig; */ enum RclInitFlags {RCLINIT_NONE = 0, RCLINIT_DAEMON = 1, RCLINIT_IDX = 2, RCLINIT_PYTHON = 4}; +// Kinds of termination requests, in addition to the normal signal +// values. Passed as type int to sigcleanup() when it is not invoked +// directly as a sig handler. Note that because of the existence of +// sigset_t, we are pretty sure that no signals can have a high value +enum RclSigKind { + // System resume from sleep + RCLSIG_RESUME = 1002}; + extern RclConfig *recollinit(int flags, void (*cleanup)(void), void (*sigcleanup)(int), std::string& reason, const std::string *argcnf = 0); diff --git a/src/index/fsindexer.cpp b/src/index/fsindexer.cpp index d0e03045..6509d68f 100644 --- a/src/index/fsindexer.cpp +++ b/src/index/fsindexer.cpp @@ -172,21 +172,6 @@ bool FsIndexer::init() return true; } -// Check if path is either non-existing or an empty directory. -static bool path_empty(const string& path) -{ - if (path_isdir(path)) { - string reason; - std::set entries; - if (!readdir(path, reason, entries) || entries.empty()) { - return true; - } - return false; - } else { - return !path_exists(path); - } -} - // Recursively index each directory in the topdirs: bool FsIndexer::index(int flags) { diff --git a/src/index/recollindex.cpp b/src/index/recollindex.cpp index 5ad7d9c7..eded1bea 100644 --- a/src/index/recollindex.cpp +++ b/src/index/recollindex.cpp @@ -174,12 +174,43 @@ private: }; static MyUpdater *updater; +// This holds the state of topdirs (exist+nonempty) on indexing +// startup. If it changes after a resume from sleep we interrupt the +// indexing (the assumption being that a volume has been mounted or +// unmounted while we slept). This is not foolproof as the user can +// always pull out a removable volume while we work. It just avoids a +// harmful purge in a common case. +static vector o_topdirs; +static vector o_topdirs_emptiness; + +bool topdirs_state(vector tdlstate) +{ + tdlstate.clear(); + for (const auto& dir : o_topdirs) { + tdlstate.push_back(path_empty(dir)); + } +} + static void sigcleanup(int sig) { - cerr << "Recollindex: got signal " << sig << ", registering stop request\n"; - LOGDEB("Got signal " << sig << ", registering stop request\n"); - CancelCheck::instance().setCancel(); - stopindexing = 1; + if (sig == RCLSIG_RESUME) { + vector emptiness; + topdirs_state(emptiness); + if (emptiness != o_topdirs_emptiness) { + string msg = "Recollindex: resume: topdirs state changed while " + "we were sleeping\n"; + cerr << msg; + LOGDEB(msg); + CancelCheck::instance().setCancel(); + stopindexing = 1; + } + } else { + cerr << "Recollindex: got signal " << sig << + ", registering stop request\n"; + LOGDEB("Got signal " << sig << ", registering stop request\n"); + CancelCheck::instance().setCancel(); + stopindexing = 1; + } } static void makeIndexerOrExit(RclConfig *config, bool inPlaceReset) @@ -330,8 +361,7 @@ static bool createstemdb(RclConfig *config, const string &lang) // match existing files or directories. Warn if they don't static bool checktopdirs(RclConfig *config, vector& nonexist) { - vector tdl; - if (!config->getConfParam("topdirs", &tdl)) { + if (!config->getConfParam("topdirs", &o_topdirs)) { cerr << "No 'topdirs' parameter in configuration\n"; LOGERR("recollindex:No 'topdirs' parameter in configuration\n"); return false; @@ -343,7 +373,7 @@ static bool checktopdirs(RclConfig *config, vector& nonexist) if (config->getConfParam("monitordirs", &mondirs)) { for (const auto& sub : mondirs) { bool found{false}; - for (const auto& top : tdl) { + for (const auto& top : o_topdirs) { if (path_isdesc(top, sub)) { found = true; break; @@ -358,24 +388,24 @@ static bool checktopdirs(RclConfig *config, vector& nonexist) } } } - - for (vector::iterator it = tdl.begin(); it != tdl.end(); it++) { - *it = path_tildexpand(*it); - if (!it->size() || !path_isabsolute(*it)) { - if ((*it)[0] == '~') { - cerr << "Tilde expansion failed: " << *it << endl; - LOGERR("recollindex: tilde expansion failed: " << *it << "\n"); + for (auto& dir : o_topdirs) { + dir = path_tildexpand(dir); + if (!dir.size() || !path_isabsolute(dir)) { + if (dir[0] == '~') { + cerr << "Tilde expansion failed: " << dir << endl; + LOGERR("recollindex: tilde expansion failed: " << dir << "\n"); } else { - cerr << "Not an absolute path: " << *it << endl; - LOGERR("recollindex: not an absolute path: " << *it << "\n"); + cerr << "Not an absolute path: " << dir << endl; + LOGERR("recollindex: not an absolute path: " << dir << "\n"); } return false; } - if (!path_exists(*it)) { - nonexist.push_back(*it); + if (!path_exists(dir)) { + nonexist.push_back(dir); } } + topdirs_state(o_topdirs_emptiness); // We'd like to check skippedPaths too, but these are wildcard // exprs, so reasonably can't @@ -895,4 +925,3 @@ int main(int argc, char **argv) return !status; } } - diff --git a/src/utils/rclutil.cpp b/src/utils/rclutil.cpp index 67703fba..653cdae2 100644 --- a/src/utils/rclutil.cpp +++ b/src/utils/rclutil.cpp @@ -132,6 +132,21 @@ string path_wingettempfilename(TCHAR *pref) #endif // _WIN32 +// Check if path is either non-existing or an empty directory. +bool path_empty(const string& path) +{ + if (path_isdir(path)) { + string reason; + std::set entries; + if (!readdir(path, reason, entries) || entries.empty()) { + return true; + } + return false; + } else { + return !path_exists(path); + } +} + string path_defaultrecollconfsubdir() { #ifdef _WIN32 diff --git a/src/utils/rclutil.h b/src/utils/rclutil.h index 955bb07b..f4cb93b5 100644 --- a/src/utils/rclutil.h +++ b/src/utils/rclutil.h @@ -30,6 +30,8 @@ extern void rclutil_init_mt(); /// Sub-directory for default recoll config (e.g: .recoll) extern std::string path_defaultrecollconfsubdir(); +// Check if path is either non-existing or an empty directory. +extern bool path_empty(const std::string& path); /// e.g. /usr/share/recoll. Depends on OS and config extern const std::string& path_pkgdatadir();