From fccc0ac09c183c52a7a379ff9643165c8cd5c847 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Tue, 7 Feb 2012 17:07:07 +0100 Subject: [PATCH] Get rid of the GUI indexing thread. All indexing now done by recollindex, with start/stop from the GUI --- src/index/fsindexer.cpp | 1 + src/index/indexer.cpp | 24 ++-- src/index/indexer.h | 21 ++- src/index/recollindex.cpp | 6 + src/qtgui/confgui/confguiindex.cpp | 5 - src/qtgui/idxthread.cpp | 190 ------------------------- src/qtgui/idxthread.h | 45 ------ src/qtgui/main.cpp | 5 - src/qtgui/rclmain_w.cpp | 218 +++++++++++++++++++---------- src/qtgui/rclmain_w.h | 8 +- src/qtgui/recoll.h | 2 - src/qtgui/recoll.pro.in | 1 - src/utils/execmd.cpp | 53 ++++++- src/utils/execmd.h | 8 +- 14 files changed, 237 insertions(+), 350 deletions(-) delete mode 100644 src/qtgui/idxthread.cpp delete mode 100644 src/qtgui/idxthread.h diff --git a/src/index/fsindexer.cpp b/src/index/fsindexer.cpp index 0c1118eb..af238cb9 100644 --- a/src/index/fsindexer.cpp +++ b/src/index/fsindexer.cpp @@ -349,6 +349,7 @@ FsIndexer::processone(const std::string &fn, const struct stat *stp, if (m_updater) { // Status bar update, abort request etc. m_updater->status.fn = fn; + ++(m_updater->status.filesdone); if (!m_updater->update()) { return FsTreeWalker::FtwStop; } diff --git a/src/index/indexer.cpp b/src/index/indexer.cpp index 0b072c9c..b7a9fb59 100644 --- a/src/index/indexer.cpp +++ b/src/index/indexer.cpp @@ -107,7 +107,7 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun) return true; } -bool ConfIndexer::indexFiles(std::list& ifiles, IxFlag flag) +bool ConfIndexer::indexFiles(list& ifiles, IxFlag flag) { list myfiles; for (list::const_iterator it = ifiles.begin(); @@ -151,11 +151,8 @@ bool ConfIndexer::indexFiles(std::list& ifiles, IxFlag flag) return ret; } -// Update index for specific documents. The docs come from an index -// query, so the udi, backend etc. fields are filled. -bool ConfIndexer::updateDocs(std::vector &docs, IxFlag flag) +bool ConfIndexer::docsToPaths(vector &docs, vector &paths) { - list files; for (vector::iterator it = docs.begin(); it != docs.end(); it++) { Rcl::Doc &idoc = *it; string backend; @@ -168,15 +165,24 @@ bool ConfIndexer::updateDocs(std::vector &docs, IxFlag flag) if (!backend.empty() && backend.compare("FS")) continue; - // Filesystem document. Intern from file. - // The url has to be like file:// + // Filesystem document. The url has to be like file:// if (idoc.url.find(cstr_fileu) != 0) { - LOGERR(("idx::updateDocs: FS backend and non fs url: [%s]\n", + LOGERR(("idx::docsToPaths: FS backend and non fs url: [%s]\n", idoc.url.c_str())); continue; } - files.push_back(idoc.url.substr(7, string::npos)); + paths.push_back(idoc.url.substr(7, string::npos)); } + return true; +} + +// Update index for specific documents. The docs come from an index +// query, so the udi, backend etc. fields are filled. +bool ConfIndexer::updateDocs(std::vector &docs, IxFlag flag) +{ + vector paths; + docsToPaths(docs, paths); + list files(paths.begin(), paths.end()); if (!files.empty()) { return indexFiles(files, flag); } diff --git a/src/index/indexer.h b/src/index/indexer.h index deee8877..feb81fb5 100644 --- a/src/index/indexer.h +++ b/src/index/indexer.h @@ -20,11 +20,13 @@ #include #include #include +#include #ifndef NO_NAMESPACES using std::string; using std::list; using std::map; +using std::vector; #endif #include "rclconfig.h" @@ -38,12 +40,19 @@ class DbIxStatus { public: enum Phase {DBIXS_NONE, DBIXS_FILES, DBIXS_PURGE, DBIXS_STEMDB, DBIXS_CLOSING, + DBIXS_MONITOR, DBIXS_DONE}; Phase phase; string fn; // Last file processed - int docsdone; // Documents processed + int docsdone; // Documents actually updated + int filesdone; // Files tested (updated or not) int dbtotdocs; // Doc count in index at start - void reset() {phase = DBIXS_FILES;fn.erase();docsdone=dbtotdocs=0;} + void reset() + { + phase = DBIXS_FILES; + fn.erase(); + docsdone = filesdone = dbtotdocs = 0; + } DbIxStatus() {reset();} }; @@ -101,14 +110,14 @@ class ConfIndexer { static list getStemmerNames(); /** Index a list of files. No db cleaning or stemdb updating */ - bool indexFiles(std::list &files, IxFlag f = IxFNone); + bool indexFiles(list &files, IxFlag f = IxFNone); /** Update index for list of documents given as list of docs (out of query) */ - bool updateDocs(std::vector &docs, IxFlag f = IxFNone); - + bool updateDocs(vector &docs, IxFlag f = IxFNone); + static bool docsToPaths(vector &docs, vector &paths); /** Purge a list of files. */ - bool purgeFiles(std::list &files); + bool purgeFiles(list &files); private: RclConfig *m_config; diff --git a/src/index/recollindex.cpp b/src/index/recollindex.cpp index c5dd5757..90fc91eb 100644 --- a/src/index/recollindex.cpp +++ b/src/index/recollindex.cpp @@ -103,6 +103,7 @@ class MyUpdater : public DbIxStatusUpdater { FILE *fp = fdopen(fd1, "w"); fprintf(fp, "phase = %d\n", int(status.phase)); fprintf(fp, "docsdone = %d\n", status.docsdone); + fprintf(fp, "filesdone = %d\n", status.filesdone); fprintf(fp, "dbtotdocs = %d\n", status.dbtotdocs); fprintf(fp, "fn = %s\n", status.fn.c_str()); ftruncate(m_fd, off_t(ftell(fp))); @@ -423,6 +424,11 @@ int main(int argc, const char **argv) LOGERR(("recollindex, initial indexing pass failed, not going into monitor mode\n")); exit(1); } + if (updater) { + updater->status.phase = DbIxStatus::DBIXS_MONITOR; + updater->status.fn.clear(); + updater->update(); + } deleteZ(confindexer); int opts = RCLMON_NONE; if (op_flags & OPT_D) diff --git a/src/qtgui/confgui/confguiindex.cpp b/src/qtgui/confgui/confguiindex.cpp index 580ab176..e0bcfc15 100644 --- a/src/qtgui/confgui/confguiindex.cpp +++ b/src/qtgui/confgui/confguiindex.cpp @@ -33,7 +33,6 @@ using std::list; #include "confgui.h" #include "recoll.h" -#include "idxthread.h" #include "confguiindex.h" #include "smallut.h" #include "debuglog.h" @@ -85,10 +84,6 @@ void ConfIndexW::acceptChanges() m_rclconf->updateMainConfig(); snapshotConfig(); - if (startIndexingAfterConfig) { - startIndexingAfterConfig = 0; - start_indexing(true); - } hide(); } diff --git a/src/qtgui/idxthread.cpp b/src/qtgui/idxthread.cpp deleted file mode 100644 index f81313ce..00000000 --- a/src/qtgui/idxthread.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include - -#include -#include -#include - -#include "indexer.h" -#include "debuglog.h" -#include "idxthread.h" -#include "smallut.h" -#include "rclinit.h" -#include "pathut.h" -#include "recoll.h" - -static int stopindexing; -static int startindexing; -static bool rezero; -static vector idxdocs; // Docs to update. Update all if empty - -static IdxThreadStatus indexingstatus = IDXTS_OK; -static string indexingReason; -static int stopidxthread; - -static QMutex curfile_mutex; -static QMutex action_mutex; -static QWaitCondition action_wait; - -class IdxThread : public QThread , public DbIxStatusUpdater { - virtual void run(); - public: - // This gets called at intervals by the file system walker to check for - // a requested interrupt and update the current status. - virtual bool update() { - QMutexLocker locker(&curfile_mutex); - m_statusSnap = status; - LOGDEB1(("IdxThread::update: indexing %s\n", m_statusSnap.fn.c_str())); - if (stopindexing) { - stopindexing = 0; - m_interrupted = true; - return false; - } - return true; - } - // Maintain a copy/snapshot of idx status - DbIxStatus m_statusSnap; - bool m_interrupted; -}; - -void IdxThread::run() -{ - recoll_threadinit(); - action_mutex.lock(); - for (;;) { - if (startindexing) { - startindexing = 0; - action_mutex.unlock(); - - m_interrupted = false; - indexingstatus = IDXTS_NULL; - // We make a private snapshot of the config: setKeydir changes - // it during indexing and it may be updated by the main thread. - RclConfig *myconf; - { - PTMutexLocker locker(thestableconfiglock); - myconf = new RclConfig(*thestableconfig); - } - int loglevel; - myconf->setKeyDir(""); - myconf->getConfParam("loglevel", &loglevel); - DebugLog::getdbl()->setloglevel(loglevel); - - Pidfile pidfile(myconf->getPidfile()); - if (pidfile.open() != 0) { - // Have to sleep a little here else the main thread - // won't see the status change because it only tests - // after seeing IDXTS_NULL at least once. Better - // interlock needed... - sleep(2); - indexingstatus = IDXTS_ERROR; - indexingReason = "Indexing failed: other process active? " + - pidfile.getreason(); - } else { - pidfile.write_pid(); - ConfIndexer *indexer = new ConfIndexer(myconf, this); - bool status = idxdocs.empty() ? - indexer->index(rezero, ConfIndexer::IxTAll) : - indexer->updateDocs(idxdocs); - - if (status) { - indexingstatus = IDXTS_OK; - indexingReason = ""; - } else { - indexingstatus = IDXTS_ERROR; - indexingReason = "Indexing failed: " + indexer->getReason(); - } - pidfile.close(); - delete indexer; - } - delete myconf; - myconf = 0; - rezero = false; - action_mutex.lock(); - } - - if (stopidxthread) { - action_mutex.unlock(); - return; - } - action_wait.wait(&action_mutex); - } -} - -static IdxThread idxthread; - -// Functions called by the main thread - -void start_idxthread() -{ - idxthread.start(); -} - -void stop_idxthread() -{ - action_mutex.lock(); - startindexing = 0; - stopindexing = 1; - stopidxthread = 1; - action_mutex.unlock(); - action_wait.wakeAll(); - idxthread.wait(); -} - -void stop_indexing() -{ - action_mutex.lock(); - startindexing = 0; - stopindexing = 1; - action_mutex.unlock(); - action_wait.wakeAll(); -} - -void start_indexing(bool raz, vector docs) -{ - action_mutex.lock(); - startindexing = 1; - rezero = raz; - idxdocs = docs; - action_mutex.unlock(); - action_wait.wakeAll(); -} - -DbIxStatus idxthread_idxStatus() -{ - QMutexLocker locker(&curfile_mutex); - return idxthread.m_statusSnap; -} - -bool idxthread_idxInterrupted() -{ - return idxthread.m_interrupted; -} - -string idxthread_getReason() -{ - return indexingReason; -} - -IdxThreadStatus idxthread_getStatus() -{ - return indexingstatus; -} diff --git a/src/qtgui/idxthread.h b/src/qtgui/idxthread.h deleted file mode 100644 index 7dbe3a99..00000000 --- a/src/qtgui/idxthread.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 2004 J.F.Dockes - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef _IDXTHREAD_H_INCLUDED_ -#define _IDXTHREAD_H_INCLUDED_ -#include -#include "indexer.h" -#include "rcldoc.h" - -// These two deal with starting / stopping the thread itself, not -// indexing sessions. -// cnf will be cloned each time we start an indexing pass. The pointer must -// stay valid for the whole program duration. -extern void start_idxthread(); -extern void stop_idxthread(); - -// Use these to to request action from thread -extern void start_indexing(bool rezero = false, - const vector docs = vector()); -extern void stop_indexing(); - -// Final status of indexing. indexingstatus is NULL iff indexing is -// currently in progress. -enum IdxThreadStatus {IDXTS_NULL = 0, IDXTS_OK = 1, IDXTS_ERROR = 2}; -extern IdxThreadStatus idxthread_getStatus(); -extern string idxthread_getReason(); - -// Current status of running indexing (phase, file name etc.) -extern DbIxStatus idxthread_idxStatus(); -// Did last op fail because of stop request ? -extern bool idxthread_idxInterrupted(); -#endif /* _IDXTHREAD_H_INCLUDED_ */ diff --git a/src/qtgui/main.cpp b/src/qtgui/main.cpp index d0779287..906df25b 100644 --- a/src/qtgui/main.cpp +++ b/src/qtgui/main.cpp @@ -97,7 +97,6 @@ Aspell *aspell; #endif int recollNeedsExit; -int startIndexingAfterConfig; RclMain *mainWindow; void startManual(const string& helpindex) @@ -352,10 +351,6 @@ int main(int argc, char **argv) app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); app.connect(&app, SIGNAL(aboutToQuit()), mainWindow, SLOT(close())); - // Start the indexing thread. It will immediately go to sleep waiting for - // something to do. - start_idxthread(); - mainWindow->sSearch->searchTypCMB->setCurrentIndex(prefs.ssearchTyp); mainWindow->sSearch->searchTypeChanged(prefs.ssearchTyp); if (op_flags & OPT_q) { diff --git a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp index a2afc95b..6c580245 100644 --- a/src/qtgui/rclmain_w.cpp +++ b/src/qtgui/rclmain_w.cpp @@ -48,6 +48,7 @@ using std::pair; #include #include #include +#include #include "recoll.h" #include "debuglog.h" @@ -73,6 +74,7 @@ using std::pair; #include "idxsched.h" #include "crontool.h" #include "rtitool.h" +#include "indexer.h" using namespace confgui; @@ -97,7 +99,8 @@ void RclMain::init() (const char *)tr("filtered").toUtf8()); periodictimer = new QTimer(this); - + m_watcher.addPath(QString::fromLocal8Bit( + theconfig->getIdxStatusFile().c_str())); // At least some versions of qt4 don't display the status bar if // it's not created here. (void)statusBar(); @@ -203,6 +206,8 @@ void RclMain::init() connect(sc, SIGNAL (activated()), this, SLOT (focusToSearch())); + connect(&m_watcher, SIGNAL(fileChanged(QString)), + this, SLOT(idxStatus())); connect(sSearch, SIGNAL(startSearch(RefCntr)), this, SLOT(startSearch(RefCntr))); connect(sSearch, SIGNAL(clearSearch()), @@ -473,82 +478,117 @@ void RclMain::fileExit() // We'd prefer to do this in the exit handler, but it's apparently to late // and some of the qt stuff is already dead at this point? LOGDEB2(("RclMain::fileExit() : stopping idx thread\n")); - stop_idxthread(); + + // Do we want to stop an ongoing index operation here ? + // I guess not. We did use to cancel the indexing thread. + // Let the exit handler clean up the rest (internal recoll stuff). exit(0); } -// This is called by a periodic timer to check the status of the -// indexing thread and a possible need to exit +void RclMain::idxStatus() +{ + ConfSimple cs(theconfig->getIdxStatusFile().c_str(), 1); + QString msg = tr("Indexing in progress: "); + DbIxStatus status; + string val; + cs.get("phase", val); + status.phase = DbIxStatus::Phase(atoi(val.c_str())); + cs.get("fn", status.fn); + cs.get("docsdone", val); + status.docsdone = atoi(val.c_str()); + cs.get("filesdone", val); + status.filesdone = atoi(val.c_str()); + cs.get("dbtotdocs", val); + status.dbtotdocs = atoi(val.c_str()); + + QString phs; + switch (status.phase) { + case DbIxStatus::DBIXS_NONE:phs=tr("None");break; + case DbIxStatus::DBIXS_FILES: phs=tr("Updating");break; + case DbIxStatus::DBIXS_PURGE: phs=tr("Purge");break; + case DbIxStatus::DBIXS_STEMDB: phs=tr("Stemdb");break; + case DbIxStatus::DBIXS_CLOSING:phs=tr("Closing");break; + case DbIxStatus::DBIXS_DONE:phs=tr("Done");break; + case DbIxStatus::DBIXS_MONITOR:phs=tr("Monitor");break; + default: phs=tr("Unknown");break; + } + msg += phs + " "; + if (status.phase == DbIxStatus::DBIXS_FILES) { + char cnts[100]; + if (status.dbtotdocs > 0) + sprintf(cnts,"(%d/%d/%d) ", status.docsdone, status.filesdone, + status.dbtotdocs); + else + sprintf(cnts, "(%d/%d) ", status.docsdone, status.filesdone); + msg += QString::fromAscii(cnts) + " "; + } + string mf;int ecnt = 0; + string fcharset = theconfig->getDefCharset(true); + if (!transcode(status.fn, mf, fcharset, "UTF-8", &ecnt) || ecnt) { + mf = url_encode(status.fn, 0); + } + msg += QString::fromUtf8(mf.c_str()); + statusBar()->showMessage(msg, 4000); +} + +// This is called by a periodic timer to check the status of +// indexing, a possible need to exit, and cleanup exited viewers void RclMain::periodic100() { - // Check if indexing thread done - if (idxthread_getStatus() != IDXTS_NULL) { - // Indexing is stopped - fileToggleIndexingAction->setText(tr("Update &Index")); - fileToggleIndexingAction->setEnabled(TRUE); - if (m_idxStatusAck == false) { - m_idxStatusAck = true; - if (idxthread_getStatus() != IDXTS_OK) { - if (idxthread_idxInterrupted()) { - QMessageBox::warning(0, "Recoll", - tr("Indexing interrupted")); - } else { - QMessageBox::warning(0, "Recoll", - QString::fromAscii(idxthread_getReason().c_str())); - } + LOGDEB2(("Periodic100\n")); + if (m_idxproc) { + // An indexing process was launched. If its' done, see status. + int status; + bool exited = m_idxproc->maybereap(&status); + if (exited) { + deleteZ(m_idxproc); + if (status) { + QMessageBox::warning(0, "Recoll", + tr("Indexing failed")); } - // Make sure we reopen the db to get the results. If there - // is current search data, we should reset it else things - // are inconsistent (ie: applying sort will fail. But we - // don't like erasing results while the user may be - // looking at them either). Fixing this would be - // relatively complicated (keep an open/close gen number - // and check this / restart query in DocSeqDb() ?) string reason; maybeOpenDb(reason, 1); - periodictimer->setInterval(1000); + } else { + // update/show status even if the status file did not + // change (else the status line goes blank during + // lengthy operations). + idxStatus(); } - } else { - // Indexing is running - m_idxStatusAck = false; + } + // Update the "start/stop indexing" menu entry, can't be done from + // the "start/stop indexing" slot itself + if (m_idxproc) { fileToggleIndexingAction->setText(tr("Stop &Indexing")); fileToggleIndexingAction->setEnabled(TRUE); - periodictimer->setInterval(100); - // The toggle thing is for the status to flash - if (m_periodicToggle < 9) { - QString msg = tr("Indexing in progress: "); - DbIxStatus status = idxthread_idxStatus(); - QString phs; - switch (status.phase) { - case DbIxStatus::DBIXS_FILES: phs=tr("Files");break; - case DbIxStatus::DBIXS_PURGE: phs=tr("Purge");break; - case DbIxStatus::DBIXS_STEMDB: phs=tr("Stemdb");break; - case DbIxStatus::DBIXS_CLOSING:phs=tr("Closing");break; - default: phs=tr("Unknown");break; - } - msg += phs + " "; - if (status.phase == DbIxStatus::DBIXS_FILES) { - char cnts[100]; - if (status.dbtotdocs>0) - sprintf(cnts,"(%d/%d) ",status.docsdone, status.dbtotdocs); - else - sprintf(cnts, "(%d) ", status.docsdone); - msg += QString::fromAscii(cnts) + " "; - } - string mf;int ecnt = 0; - string fcharset = theconfig->getDefCharset(true); - if (!transcode(status.fn, mf, fcharset, "UTF-8", &ecnt) || ecnt) { - mf = url_encode(status.fn, 0); - } - msg += QString::fromUtf8(mf.c_str()); - statusBar()->showMessage(msg, 4000); - } else if (m_periodicToggle == 9) { - statusBar()->showMessage(""); - } - if (++m_periodicToggle >= 10) - m_periodicToggle = 0; + } else { + fileToggleIndexingAction->setText(tr("Update &Index")); + // No indexer of our own runnin, but the real time one may be up, check + // for some other indexer. + Pidfile pidfile(theconfig->getPidfile()); + if (pidfile.open() == 0) { + fileToggleIndexingAction->setEnabled(TRUE); + } else { + fileToggleIndexingAction->setEnabled(FALSE); + } } + + // Possibly cleanup the dead viewers + for (vector::iterator it = m_viewers.begin(); + it != m_viewers.end(); it++) { + int status; + if ((*it)->maybereap(&status)) { + deleteZ(*it); + } + } + vector v; + for (vector::iterator it = m_viewers.begin(); + it != m_viewers.end(); it++) { + if (*it) + v.push_back(*it); + } + m_viewers = v; + if (recollNeedsExit) fileExit(); } @@ -558,14 +598,16 @@ void RclMain::periodic100() // re-enabled by the indexing status check void RclMain::toggleIndexing() { - if (idxthread_getStatus() == IDXTS_NULL) { - // Indexing was in progress, stop it - stop_indexing(); - periodictimer->setInterval(1000); - fileToggleIndexingAction->setText(tr("Update &Index")); + if (m_idxproc) { + // Indexing was in progress, request stop. Let the periodic + // routine check for the results. + kill(m_idxproc->getChildPid(), SIGTERM); } else { - start_indexing(false); - periodictimer->setInterval(100); + list args; + args.push_back("-c"); + args.push_back(theconfig->getConfDir()); + m_idxproc = new ExecCmd; + m_idxproc->startExec("recollindex", args, false, false); fileToggleIndexingAction->setText(tr("Stop &Indexing")); } fileToggleIndexingAction->setEnabled(FALSE); @@ -574,15 +616,14 @@ void RclMain::toggleIndexing() // Start a db query and set the reslist docsource void RclMain::startSearch(RefCntr sdata) { - LOGDEB(("RclMain::startSearch. Indexing %s\n", - idxthread_getStatus() == IDXTS_NULL?"on":"off")); + LOGDEB(("RclMain::startSearch. Indexing %s\n", m_idxproc?"on":"off")); emit searchReset(); m_source = RefCntr(); // The db may have been closed at the end of indexing string reason; // If indexing is being performed, we reopen the db at each query. - if (!maybeOpenDb(reason, idxthread_getStatus() == IDXTS_NULL)) { + if (!maybeOpenDb(reason, m_idxproc != 0)) { QMessageBox::critical(0, "Recoll", QString(reason.c_str())); return; } @@ -970,7 +1011,7 @@ void RclMain::startPreview(int docnum, Rcl::Doc doc, int mod) QMessageBox::warning(0, tr("Warning"), tr("Index not up to date for this file. " "Refusing to risk showing the wrong " - "data. Click ok to update the " + "entry. Click Ok to update the " "index for this file, then re-run the " "query when indexing is done. " "Else, Cancel."), @@ -980,7 +1021,8 @@ void RclMain::startPreview(int docnum, Rcl::Doc doc, int mod) if (rep == QMessageBox::Ok) { LOGDEB(("Requesting index update for %s\n", doc.url.c_str())); - start_indexing(false, vector(1, doc)); + vector docs(1, doc); + updateIdxForDocs(docs); } return; } @@ -1023,6 +1065,30 @@ void RclMain::startPreview(int docnum, Rcl::Doc doc, int mod) curPreview->makeDocCurrent(doc, docnum); } +void RclMain::updateIdxForDocs(vector& docs) +{ + if (m_idxproc) { + QMessageBox::warning(0, tr("Warning"), + tr("Can't update index: indexer running"), + QMessageBox::Ok, + QMessageBox::NoButton); + return; + } + + vector paths; + if (ConfIndexer::docsToPaths(docs, paths)) { + list args; + args.push_back("-c"); + args.push_back(theconfig->getConfDir()); + args.push_back("-i"); + args.insert(args.end(), paths.begin(), paths.end()); + m_idxproc = new ExecCmd; + m_idxproc->startExec("recollindex", args, false, false); + fileToggleIndexingAction->setText(tr("Stop &Indexing")); + } + fileToggleIndexingAction->setEnabled(FALSE); +} + /** * Open a preview window for a given document, no linking to result list * diff --git a/src/qtgui/rclmain_w.h b/src/qtgui/rclmain_w.h index 0cf4b192..c1255882 100644 --- a/src/qtgui/rclmain_w.h +++ b/src/qtgui/rclmain_w.h @@ -19,6 +19,7 @@ #include #include +#include #include "sortseq.h" #include "preview_w.h" @@ -66,7 +67,7 @@ public: displayingTable(0), m_idNoStem(0), m_idAllStem(0), - m_idxStatusAck(false), + m_idxproc(0), m_sortspecnochange(false), m_periodicToggle(0) { @@ -80,6 +81,7 @@ public: public slots: virtual bool close(); virtual void fileExit(); + virtual void idxStatus(); virtual void periodic100(); virtual void toggleIndexing(); virtual void startSearch(RefCntr sdata); @@ -155,11 +157,12 @@ private: bool displayingTable; QAction *m_idNoStem; QAction *m_idAllStem; + QFileSystemWatcher m_watcher; vector m_viewers; + ExecCmd *m_idxproc; // Indexing process map m_stemLangToId; vector m_catgbutvec; - bool m_idxStatusAck; // Did we act on last status? DocSeqFiltSpec m_filtspec; bool m_sortspecnochange; DocSeqSortSpec m_sortspec; @@ -175,6 +178,7 @@ private: virtual void showIndexSched(bool modal); virtual void showCronTool(bool modal); virtual void showRTITool(bool modal); + virtual void updateIdxForDocs(vector&); }; #endif // RCLMAIN_W_H diff --git a/src/qtgui/recoll.h b/src/qtgui/recoll.h index 6b565272..a7a265de 100644 --- a/src/qtgui/recoll.h +++ b/src/qtgui/recoll.h @@ -20,7 +20,6 @@ #include "rclconfig.h" #include "rcldb.h" -#include "idxthread.h" #include "ptmutex.h" // Misc declarations in need of sharing between the UI files @@ -41,7 +40,6 @@ extern void forgetTempFile(string &fn); extern Rcl::Db *rcldb; extern int recollNeedsExit; -extern int startIndexingAfterConfig; // 1st startup extern void startManual(const string& helpindex); #ifdef RCL_USE_ASPELL diff --git a/src/qtgui/recoll.pro.in b/src/qtgui/recoll.pro.in index eb93f80a..e2114a05 100644 --- a/src/qtgui/recoll.pro.in +++ b/src/qtgui/recoll.pro.in @@ -30,7 +30,6 @@ SOURCES += \ confgui/confguiindex.cpp \ crontool.cpp \ guiutils.cpp \ - idxthread.cpp \ main.cpp \ preview_w.cpp \ rclhelp.cpp \ diff --git a/src/utils/execmd.cpp b/src/utils/execmd.cpp index 7e53d698..82a96c30 100644 --- a/src/utils/execmd.cpp +++ b/src/utils/execmd.cpp @@ -17,6 +17,7 @@ #ifndef TEST_EXECMD #include "autoconfig.h" +#include #include #include #include @@ -138,7 +139,7 @@ public: int status; if (m_parent->m_pid > 0) { pid_t grp = getpgid(m_parent->m_pid); - LOGDEB2(("ExecCmd: killpg(%d, SIGTERM)\n", grp)); + LOGDEB(("ExecCmd: killpg(%d, SIGTERM)\n", grp)); int ret = killpg(grp, SIGTERM); if (ret == 0) { for (int i = 0; i < 3; i++) { @@ -385,7 +386,10 @@ int ExecCmd::doexec(const string &cmd, const list& args, // Normal return: deactivate cleaner, wait() will do the cleanup e.inactivate(); - return ExecCmd::wait(ret); + int ret1 = ExecCmd::wait(); + if (ret) + return -1; + return ret1; } int ExecCmd::send(const string& data) @@ -457,17 +461,46 @@ int ExecCmd::getline(string& data) } // Wait for command status and clean up all resources. -int ExecCmd::wait(bool haderror) +int ExecCmd::wait() { ExecCmdRsrc e(this); int status = -1; if (!m_killRequest && m_pid > 0) { - if (waitpid(m_pid, &status, 0) < 0) + if (waitpid(m_pid, &status, 0) < 0) { + LOGERR(("ExecCmd::waitpid: returned -1 errno %d\n", errno)); status = -1; + } LOGDEB(("ExecCmd::wait: got status 0x%x\n", status)); m_pid = -1; } - return haderror ? -1 : status; + // Let the ExecCmdRsrc cleanup + return status; +} + +bool ExecCmd::maybereap(int *status) +{ + ExecCmdRsrc e(this); + *status = -1; + + if (m_pid <= 0) { + // Already waited for ?? + return true; + } + + pid_t pid = waitpid(m_pid, status, WNOHANG); + if (pid < 0) { + LOGERR(("ExecCmd::maybereap: returned -1 errno %d\n", errno)); + m_pid = -1; + return true; + } else if (pid == 0) { + LOGDEB1(("ExecCmd::maybereap: not exited yet\n")); + e.inactivate(); + return false; + } else { + LOGDEB(("ExecCmd::maybereap: got status 0x%x\n", status)); + m_pid = -1; + return true; + } } // In child process. Set up pipes, environment, and exec command. @@ -591,8 +624,11 @@ void ReExec::init(int argc, char *args[]) free(cd); } +// Reexecute myself, as close as possible to the initial exec void ReExec::reexec() { + +#if 0 char *cwd; cwd = getcwd(0,0); FILE *fp = stdout; //fopen("/tmp/exectrace", "w"); @@ -604,10 +640,13 @@ void ReExec::reexec() } fprintf(fp, "\n"); } +#endif + + // Try to get back to the initial working directory if (m_cfd < 0 || fchdir(m_cfd) < 0) { - if (fp) fprintf(fp, "fchdir failed, trying chdir\n"); + LOGINFO(("ReExec::reexec: fchdir failed, trying chdir\n")); if (!m_curdir.empty() && chdir(m_curdir.c_str())) { - if (fp) fprintf(fp, "chdir failed too\n"); + LOGERR(("ReExec::reexec: chdir failed\n")); } } diff --git a/src/utils/execmd.h b/src/utils/execmd.h index c06f6261..c5d256e4 100644 --- a/src/utils/execmd.h +++ b/src/utils/execmd.h @@ -120,7 +120,7 @@ class ExecCmd { * @param args the argument list (NOT including argv[0]). * @param input Input to send TO the command. * @param output Output FROM the command. - * @return the exec ouput status (0 if ok). + * @return the exec ouput status (0 if ok), or -1 */ int doexec(const string &cmd, const list& args, const string *input = 0, @@ -135,7 +135,11 @@ class ExecCmd { int send(const string& data); int receive(string& data, int cnt = -1); int getline(string& data); - int wait(bool haderror = false); + int wait(); + /** Wait with WNOHANG set. + @return true if process exited, false else. + @param O: status, the wait(2) call's status value */ + bool maybereap(int *status); pid_t getChildPid() {return m_pid;}