Simplified the indexing status update code by treating the updater as a singleton

Add a 'flushing' state for when we commit the Xapian index.
This commit is contained in:
Jean-Francois Dockes 2021-04-16 13:27:42 +02:00
parent 72fe5a25a4
commit f1b2d3004a
14 changed files with 255 additions and 239 deletions

View File

@ -89,8 +89,6 @@ common/unacpp.h \
common/uproplist.h \
common/utf8fn.cpp \
common/utf8fn.h \
index/webqueue.cpp \
index/webqueue.h \
index/webqueuefetcher.cpp \
index/webqueuefetcher.h \
index/checkretryfailed.cpp \
@ -101,8 +99,6 @@ index/fetcher.cpp \
index/fetcher.h \
index/fsfetcher.cpp \
index/fsfetcher.h \
index/fsindexer.cpp \
index/fsindexer.h \
index/idxdiags.h \
index/idxdiags.cpp \
index/idxstatus.h \
@ -273,6 +269,8 @@ utils/utf8iter.h \
utils/wipedir.cpp \
utils/wipedir.h \
utils/workqueue.h \
utils/x11mon.cpp \
utils/x11mon.h \
utils/zlibut.cpp \
utils/zlibut.h \
xaposix/safefcntl.h \
@ -290,7 +288,7 @@ AM_YFLAGS = -d
# need it
librecoll_la_LDFLAGS = -release $(VERSION) -no-undefined @NO_UNDEF_LINK_FLAG@
librecoll_la_LIBADD = $(XSLT_LIBS) $(LIBXAPIAN) $(LIBICONV) $(LIBTHREADS)
librecoll_la_LIBADD = $(XSLT_LIBS) $(LIBXAPIAN) $(LIBICONV) $(X_LIBX11) $(LIBTHREADS)
# There is probably a better way to do this. The KIO needs to be linked
# with librecoll, but librecoll is installed into a non-standard place
@ -319,16 +317,19 @@ if MAKEXADUMP
endif
recollindex_SOURCES = \
index/recollindex.cpp \
index/checkindexed.cpp \
index/checkindexed.h \
index/indexer.cpp \
index/indexer.h \
index/rclmonprc.cpp \
index/rclmonrcv.cpp \
utils/x11mon.cpp \
utils/x11mon.h
recollindex_LDADD = librecoll.la $(X_LIBX11)
index/checkindexed.cpp \
index/checkindexed.h \
index/fsindexer.cpp \
index/fsindexer.h \
index/indexer.cpp \
index/indexer.h \
index/rclmonprc.cpp \
index/rclmonrcv.cpp \
index/recollindex.cpp \
index/webqueue.cpp \
index/webqueue.h
recollindex_LDADD = librecoll.la
recollq_SOURCES = query/recollqmain.cpp
recollq_LDADD = librecoll.la

View File

@ -57,14 +57,20 @@ bool FSDocFetcher::fetch(RclConfig* cnf, const Rcl::Doc& idoc, RawDoc& out)
out.data = fn;
return true;
}
void fsmakesig(const struct PathStat *stp, string& out)
{
out = lltodecstr(stp->pst_size) +
lltodecstr(o_uptodate_test_use_mtime ? stp->pst_mtime : stp->pst_ctime);
}
bool FSDocFetcher::makesig(RclConfig* cnf, const Rcl::Doc& idoc, string& sig)
{
string fn;
struct PathStat st;
if (urltopath(cnf, idoc, fn, st) != DocFetcher::FetchOk)
return false;
FsIndexer::makesig(&st, sig);
fsmakesig(&st, sig);
return true;
}

View File

@ -18,6 +18,7 @@
#define _FSFETCHER_H_INCLUDED_
#include "fetcher.h"
#include "pathut.h"
/**
* The file-system fetcher:
@ -32,4 +33,6 @@ class FSDocFetcher : public DocFetcher{
virtual ~FSDocFetcher() {}
};
extern void fsmakesig(const struct PathStat *stp, std::string& out);
#endif /* _FSFETCHER_H_INCLUDED_ */

View File

@ -48,6 +48,7 @@
#include "extrameta.h"
#include "utf8fn.h"
#include "idxdiags.h"
#include "fsfetcher.h"
#if defined(HAVE_POSIX_FADVISE)
#include <unistd.h>
#include <fcntl.h>
@ -103,8 +104,8 @@ public:
}
};
FsIndexer::FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc)
: m_config(cnf), m_db(db), m_updater(updfunc),
FsIndexer::FsIndexer(RclConfig *cnf, Rcl::Db *db)
: m_config(cnf), m_db(db),
m_missing(new FSIFIMissingStore), m_detectxattronly(false),
m_noretryfailed(false)
#ifdef IDX_THREADS
@ -186,12 +187,7 @@ bool FsIndexer::index(int flags)
if (!init())
return false;
if (m_updater) {
#ifdef IDX_THREADS
std::unique_lock<std::mutex> locker(m_updater->m_mutex);
#endif
m_updater->status.dbtotdocs = m_db->docCnt();
}
statusUpdater()->setDbTotDocs(m_db->docCnt());
m_walker.setSkippedPaths(m_config->getSkippedPaths());
if (quickshallow) {
@ -512,12 +508,6 @@ void FsIndexer::setlocalfields(const map<string, string>& fields, Rcl::Doc& doc)
}
}
void FsIndexer::makesig(const struct PathStat *stp, string& out)
{
out = lltodecstr(stp->pst_size) +
lltodecstr(o_uptodate_test_use_mtime ? stp->pst_mtime : stp->pst_ctime);
}
#ifdef IDX_THREADS
// Called updworker as seen from here, but the first step (and only in
// most meaningful configurations) is doing the word-splitting, which
@ -586,13 +576,8 @@ void *FsIndexerInternfileWorker(void * fsp)
FsTreeWalker::Status FsIndexer::processone(
const std::string &fn, const struct PathStat *stp, FsTreeWalker::CbFlag flg)
{
if (m_updater) {
#ifdef IDX_THREADS
std::unique_lock<std::mutex> locker(m_updater->m_mutex);
#endif
if (!m_updater->update()) {
return FsTreeWalker::FtwStop;
}
if (!statusUpdater()->update(DbIxStatus::DBIXS_FILES, fn)) {
return FsTreeWalker::FtwStop;
}
// If we're changing directories, possibly adjust parameters (set
@ -665,7 +650,7 @@ FsTreeWalker::Status FsIndexer::processonefile(
// m/ctime and size and the possibly new value is checked against
// the stored one.
string sig;
makesig(stp, sig);
fsmakesig(stp, sig);
string udi;
make_udi(fn, cstr_null, udi);
unsigned int existingDoc;
@ -706,16 +691,9 @@ FsTreeWalker::Status FsIndexer::processonefile(
if (!needupdate) {
LOGDEB0("processone: up to date: " << fn << "\n");
if (m_updater) {
#ifdef IDX_THREADS
std::unique_lock<std::mutex> locker(m_updater->m_mutex);
#endif
// Status bar update, abort request etc.
m_updater->status.fn = fn;
++(m_updater->status.filesdone);
if (!m_updater->update()) {
return FsTreeWalker::FtwStop;
}
if (!statusUpdater()->update(
DbIxStatus::DBIXS_FILES, fn, DbIxStatusUpdater::IncrFilesDone)) {
return FsTreeWalker::FtwStop;
}
return FsTreeWalker::FtwOk;
}
@ -827,26 +805,20 @@ FsTreeWalker::Status FsIndexer::processonefile(
}
// Tell what we are doing and check for interrupt request
if (m_updater) {
#ifdef IDX_THREADS
std::unique_lock<std::mutex> locker(m_updater->m_mutex);
#endif
++(m_updater->status.docsdone);
if (m_updater->status.dbtotdocs < m_updater->status.docsdone)
m_updater->status.dbtotdocs = m_updater->status.docsdone;
m_updater->status.fn = fn;
if (!doc.ipath.empty()) {
m_updater->status.fn += "|" + doc.ipath;
} else {
if (fis == FileInterner::FIError) {
++(m_updater->status.fileerrors);
}
++(m_updater->status.filesdone);
}
if (!m_updater->update()) {
return FsTreeWalker::FtwStop;
int incr = DbIxStatusUpdater::IncrDocsDone;
std::string sfn(fn);
if (!doc.ipath.empty()) {
sfn += "|" + doc.ipath;
} else {
if (fis == FileInterner::FIError) {
incr |= DbIxStatusUpdater::IncrFileErrors;
}
incr |= DbIxStatusUpdater::IncrFilesDone;
}
if (!statusUpdater()->update(DbIxStatus::DBIXS_FILES, sfn, incr)) {
return FsTreeWalker::FtwStop;
}
}
if (fis == FileInterner::FIError) {

View File

@ -26,7 +26,6 @@
#include "workqueue.h"
#endif // IDX_THREADS
class DbIxStatusUpdater;
class FIMissingStore;
struct PathStat;
@ -53,9 +52,8 @@ public:
/** Constructor does nothing but store parameters
*
* @param cnf Configuration data
* @param updfunc Status updater callback
*/
FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc = 0);
FsIndexer(RclConfig *cnf, Rcl::Db *db);
virtual ~FsIndexer();
/**
@ -77,10 +75,6 @@ public:
FsTreeWalker::Status
processone(const string &fn, const struct PathStat *, FsTreeWalker::CbFlag);
/** Make signature for file up to date checks */
static void makesig(const struct PathStat *stp, string& out);
private:
class PurgeCandidateRecorder {
@ -118,7 +112,6 @@ private:
RclConfig *m_config;
Rcl::Db *m_db;
string m_reason;
DbIxStatusUpdater *m_updater;
// Top/start directories list
std::vector<std::string> m_tdl;
// Store for missing filters and associated mime types

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017-2018 J.F.Dockes
/* Copyright (C) 2017-2021 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
@ -16,10 +16,18 @@
*/
#include "autoconfig.h"
#include "idxstatus.h"
#include <mutex>
#include "rclconfig.h"
#include "chrono.h"
#include "conftree.h"
#include "idxstatus.h"
#include "log.h"
#include "rclconfig.h"
#include "x11mon.h"
// Global stop request flag. This is checked in a number of place in the
// indexing routines.
int stopindexing;
void readIdxStatus(RclConfig *config, DbIxStatus &status)
{
@ -33,3 +41,126 @@ void readIdxStatus(RclConfig *config, DbIxStatus &status)
status.totfiles = (int)cs.getInt("totfiles", 0);
status.hasmonitor = cs.getBool("hasmonitor", false);
}
// Receive status updates from the ongoing indexing operation
// Also check for an interrupt request and return the info to caller which
// should subsequently orderly terminate what it is doing.
class DbIxStatusUpdater::Internal {
public:
#ifdef IDX_THREADS
std::mutex m_mutex;
#endif
Internal(const RclConfig *config, bool nox11mon)
: m_file(config->getIdxStatusFile().c_str()), m_stopfilename(config->getIdxStopFile()),
nox11monitor(nox11mon) {
// The total number of files included in the index is actually
// difficult to compute from the index itself. For display
// purposes, we save it in the status file from indexing to
// indexing (mostly...)
string stf;
if (m_file.get("totfiles", stf)) {
status.totfiles = atoi(stf.c_str());
}
}
virtual bool update() {
if (status.dbtotdocs < status.docsdone)
status.dbtotdocs = status.docsdone;
// Update the status file. Avoid doing it too often. Always do
// it at the end (status DONE)
if (status.phase == DbIxStatus::DBIXS_DONE ||
status.phase != m_prevphase || m_chron.millis() > 300) {
if (status.totfiles < status.filesdone || status.phase == DbIxStatus::DBIXS_DONE) {
status.totfiles = status.filesdone;
}
m_prevphase = status.phase;
m_chron.restart();
m_file.holdWrites(true);
m_file.set("phase", int(status.phase));
m_file.set("docsdone", status.docsdone);
m_file.set("filesdone", status.filesdone);
m_file.set("fileerrors", status.fileerrors);
m_file.set("dbtotdocs", status.dbtotdocs);
m_file.set("totfiles", status.totfiles);
m_file.set("fn", status.fn);
m_file.set("hasmonitor", status.hasmonitor);
m_file.holdWrites(false);
}
if (path_exists(m_stopfilename)) {
LOGINF("recollindex: asking indexer to stop because " << m_stopfilename << " exists\n");
path_unlink(m_stopfilename);
stopindexing = true;
}
if (stopindexing) {
return false;
}
#ifndef DISABLE_X11MON
// If we are in the monitor, we also need to check X11 status
// during the initial indexing pass (else the user could log
// out and the indexing would go on, not good (ie: if the user
// logs in again, the new recollindex will fail).
if (status.hasmonitor && !nox11monitor && !x11IsAlive()) {
LOGDEB("X11 session went away during initial indexing pass\n");
stopindexing = true;
return false;
}
#endif
return true;
}
DbIxStatus status;
ConfSimple m_file;
string m_stopfilename;
Chrono m_chron;
bool nox11monitor{false};
DbIxStatus::Phase m_prevphase{DbIxStatus::DBIXS_NONE};
};
DbIxStatusUpdater::DbIxStatusUpdater(const RclConfig *config, bool nox11monitor) {
m = new Internal(config, nox11monitor);
}
void DbIxStatusUpdater::setMonitor(bool onoff)
{
m->status.hasmonitor = onoff;
}
void DbIxStatusUpdater::setDbTotDocs(int totdocs)
{
#ifdef IDX_THREADS
std::unique_lock<std::mutex> lock(m->m_mutex);
#endif
m->status.dbtotdocs = totdocs;
}
bool DbIxStatusUpdater::update(DbIxStatus::Phase phase, const string& fn, int incr) {
#ifdef IDX_THREADS
std::unique_lock<std::mutex> lock(m->m_mutex);
#endif
// We don't change a FLUSH status except if the new status is NONE
// (recollindex init or rcldb after commit(). Else, the flush status maybe
// overwritten by a "file updated" status and not be displayed
if (phase == DbIxStatus::DBIXS_NONE || m->status.phase != DbIxStatus::DBIXS_FLUSH)
m->status.phase = phase;
m->status.fn = fn;
if (incr & IncrDocsDone)
m->status.docsdone++;
if (incr & IncrFilesDone)
m->status.filesdone++;
if (incr & IncrFileErrors)
m->status.fileerrors++;
return m->update();
}
static DbIxStatusUpdater *updater;
DbIxStatusUpdater *statusUpdater(RclConfig *config, bool nox11mon)
{
if (updater) {
return updater;
}
return (updater = new DbIxStatusUpdater(config, nox11mon));
}

View File

@ -24,10 +24,8 @@
// $RECOLL_CONFDIR/idxstatus.txt
class DbIxStatus {
public:
enum Phase {DBIXS_NONE,
DBIXS_FILES, DBIXS_PURGE, DBIXS_STEMDB, DBIXS_CLOSING,
DBIXS_MONITOR,
DBIXS_DONE};
enum Phase {DBIXS_NONE, DBIXS_FILES, DBIXS_FLUSH, DBIXS_PURGE, DBIXS_STEMDB, DBIXS_CLOSING,
DBIXS_MONITOR, DBIXS_DONE};
Phase phase;
std::string fn; // Last file processed
int docsdone; // Documents actually updated
@ -53,4 +51,27 @@ public:
class RclConfig;
extern void readIdxStatus(RclConfig *config, DbIxStatus &status);
/** Callback to say what we're doing. If the update func returns false, we
* stop as soon as possible without corrupting state */
class DbIxStatusUpdater {
public:
DbIxStatusUpdater(const RclConfig *config, bool nox11monitor);
virtual ~DbIxStatusUpdater(){}
enum Incr {IncrNone, IncrDocsDone = 0x1, IncrFilesDone = 0x2, IncrFileErrors = 0x4};
// Change phase/fn and update
virtual bool update(DbIxStatus::Phase phase, const std::string& fn, int incr = IncrNone);
void setMonitor(bool onoff);
void setDbTotDocs(int totdocs);
class Internal;
private:
Internal *m;
};
// We use the updater as a singleton everywhere. It is instanciated in
// idxstatus.cpp. Must be called once with non-null config at first.
extern DbIxStatusUpdater *statusUpdater(RclConfig *config=nullptr, bool nox11monitor=false);
#endif /* _IDXSTATUS_H_INCLUDED_ */

View File

@ -42,10 +42,6 @@ using std::list;
using std::string;
using std::vector;
// Global stop request flag. This is checked in a number of place in the
// indexing routines.
int stopindexing;
// This would more logically live in recollindex.cpp, but then librecoll would
// have an undefined symbol
ConfSimple idxreasons;
@ -94,10 +90,8 @@ bool runWebFilesMoverScript(RclConfig *config)
}
#endif
ConfIndexer::ConfIndexer(RclConfig *cnf, DbIxStatusUpdater *updfunc)
: m_config(cnf), m_db(cnf), m_fsindexer(0),
m_doweb(false), m_webindexer(0),
m_updater(updfunc)
ConfIndexer::ConfIndexer(RclConfig *cnf)
: m_config(cnf), m_db(cnf)
{
m_config->getConfParam("processwebqueue", &m_doweb);
}
@ -135,7 +129,7 @@ bool ConfIndexer::firstFsIndexingSequence()
{
LOGDEB("ConfIndexer::firstFsIndexingSequence\n");
deleteZ(m_fsindexer);
m_fsindexer = new FsIndexer(m_config, &m_db, m_updater);
m_fsindexer = new FsIndexer(m_config, &m_db);
if (!m_fsindexer) {
return false;
}
@ -170,7 +164,7 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun, int flags)
firstFsIndexingSequence();
}
deleteZ(m_fsindexer);
m_fsindexer = new FsIndexer(m_config, &m_db, m_updater);
m_fsindexer = new FsIndexer(m_config, &m_db);
if (!m_fsindexer || !m_fsindexer->index(flags)) {
if (stopindexing) {
addIdxReason("indexer", "Indexing was interrupted.");
@ -185,7 +179,7 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun, int flags)
if (m_doweb && (typestorun & IxTWebQueue)) {
runWebFilesMoverScript(m_config);
deleteZ(m_webindexer);
m_webindexer = new WebQueueIndexer(m_config, &m_db, m_updater);
m_webindexer = new WebQueueIndexer(m_config, &m_db);
if (!m_webindexer || !m_webindexer->index()) {
m_db.close();
addIdxReason("indexer", "Web index creation failed. See" + logloc);
@ -196,7 +190,7 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun, int flags)
if (typestorun == IxTAll) {
// Get rid of all database entries that don't exist in the
// filesystem anymore. Only if all *configured* indexers ran.
if (m_updater && !m_updater->update(DbIxStatus::DBIXS_PURGE, "")) {
if (!statusUpdater()->update(DbIxStatus::DBIXS_PURGE, string())) {
m_db.close();
addIdxReason("indexer", "Index purge failed. See" + logloc);
return false;
@ -207,8 +201,7 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun, int flags)
// The close would be done in our destructor, but we want status
// here. Makes no sense to check for cancel, we'll have to close
// anyway
if (m_updater)
m_updater->update(DbIxStatus::DBIXS_CLOSING, string());
statusUpdater()->update(DbIxStatus::DBIXS_CLOSING, string());
if (!m_db.close()) {
LOGERR("ConfIndexer::index: error closing database in " <<
m_config->getDbDir() << "\n");
@ -216,13 +209,13 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun, int flags)
return false;
}
if (m_updater && !m_updater->update(DbIxStatus::DBIXS_CLOSING, string()))
if (!statusUpdater()->update(DbIxStatus::DBIXS_CLOSING, string()))
return false;
bool ret = true;
if (!createStemmingDatabases()) {
ret = false;
}
if (m_updater && !m_updater->update(DbIxStatus::DBIXS_CLOSING, string()))
if (!statusUpdater()->update(DbIxStatus::DBIXS_CLOSING, string()))
return false;
// Don't fail indexing because of an aspell issue: we ignore the status.
@ -230,8 +223,7 @@ bool ConfIndexer::index(bool resetbefore, ixType typestorun, int flags)
(void)createAspellDict();
clearMimeHandlerCache();
if (m_updater)
m_updater->update(DbIxStatus::DBIXS_DONE, string());
statusUpdater()->update(DbIxStatus::DBIXS_DONE, string());
return ret;
}
@ -252,7 +244,7 @@ bool ConfIndexer::indexFiles(list<string>& ifiles, int flag)
m_config->setKeyDir(cstr_null);
bool ret = false;
if (!m_fsindexer)
m_fsindexer = new FsIndexer(m_config, &m_db, m_updater);
m_fsindexer = new FsIndexer(m_config, &m_db);
if (m_fsindexer)
ret = m_fsindexer->indexFiles(myfiles, flag);
LOGDEB2("ConfIndexer::indexFiles: fsindexer returned " << ret << ", " <<
@ -261,7 +253,7 @@ bool ConfIndexer::indexFiles(list<string>& ifiles, int flag)
if (m_doweb && !myfiles.empty() && !(flag & IxFNoWeb)) {
if (!m_webindexer)
m_webindexer = new WebQueueIndexer(m_config, &m_db, m_updater);
m_webindexer = new WebQueueIndexer(m_config, &m_db);
if (m_webindexer) {
ret = ret && m_webindexer->indexFiles(myfiles);
} else {
@ -313,14 +305,14 @@ bool ConfIndexer::purgeFiles(list<string> &files, int flag)
bool ret = false;
m_config->setKeyDir(cstr_null);
if (!m_fsindexer)
m_fsindexer = new FsIndexer(m_config, &m_db, m_updater);
m_fsindexer = new FsIndexer(m_config, &m_db);
if (m_fsindexer)
ret = m_fsindexer->purgeFiles(myfiles);
#ifndef DISABLE_WEB_INDEXER
if (m_doweb && !myfiles.empty() && !(flag & IxFNoWeb)) {
if (!m_webindexer)
m_webindexer = new WebQueueIndexer(m_config, &m_db, m_updater);
m_webindexer = new WebQueueIndexer(m_config, &m_db);
if (m_webindexer) {
ret = ret && m_webindexer->purgeFiles(myfiles);
} else {

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2004 J.F.Dockes
/* Copyright (C) 2004-2021 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
@ -16,7 +16,6 @@
*/
#ifndef _INDEXER_H_INCLUDED_
#define _INDEXER_H_INCLUDED_
#include "rclconfig.h"
#include <string>
#include <list>
@ -24,6 +23,7 @@
#include <vector>
#include <mutex>
#include "rclconfig.h"
#include "rcldb.h"
#include "rcldoc.h"
#include "idxstatus.h"
@ -31,31 +31,6 @@
class FsIndexer;
class WebQueueIndexer;
/** Callback to say what we're doing. If the update func returns false, we
* stop as soon as possible without corrupting state */
class DbIxStatusUpdater {
public:
#ifdef IDX_THREADS
std::mutex m_mutex;
#endif
DbIxStatus status;
virtual ~DbIxStatusUpdater(){}
// Convenience: change phase/fn and update
virtual bool update(DbIxStatus::Phase phase, const string& fn)
{
#ifdef IDX_THREADS
std::unique_lock<std::mutex> lock(m_mutex);
#endif
status.phase = phase;
status.fn = fn;
return update();
}
// To be implemented by user for sending info somewhere
virtual bool update() = 0;
};
/**
* The top level batch indexing object. Processes the configuration,
* then invokes file system walking or other to populate/update the
@ -64,7 +39,7 @@ public:
class ConfIndexer {
public:
enum runStatus {IndexerOk, IndexerError};
ConfIndexer(RclConfig *cnf, DbIxStatusUpdater *updfunc = 0);
ConfIndexer(RclConfig *cnf);
virtual ~ConfIndexer();
// Indexer types. Maybe we'll have something more dynamic one day
@ -118,11 +93,10 @@ public:
private:
RclConfig *m_config;
Rcl::Db m_db;
FsIndexer *m_fsindexer;
bool m_doweb;
WebQueueIndexer *m_webindexer;
DbIxStatusUpdater *m_updater;
string m_reason;
FsIndexer *m_fsindexer{nullptr};
bool m_doweb{false};
WebQueueIndexer *m_webindexer{nullptr};
string m_reason;
// The first time we index, we do things a bit differently to
// avoid user frustration (make at least some results available

View File

@ -60,7 +60,6 @@ using namespace std;
#endif
#include "execmd.h"
#include "checkretryfailed.h"
#include "idxstatus.h"
#include "circache.h"
#include "idxdiags.h"
@ -117,79 +116,6 @@ static void cleanup()
recoll_exitready();
}
// Receive status updates from the ongoing indexing operation
// Also check for an interrupt request and return the info to caller which
// should subsequently orderly terminate what it is doing.
class MyUpdater : public DbIxStatusUpdater {
public:
MyUpdater(const RclConfig *config)
: m_file(config->getIdxStatusFile().c_str()),
m_stopfilename(config->getIdxStopFile()),
m_prevphase(DbIxStatus::DBIXS_NONE) {
// The total number of files included in the index is actually
// difficult to compute from the index itself. For display
// purposes, we save it in the status file from indexing to
// indexing (mostly...)
string stf;
if (m_file.get("totfiles", stf)) {
status.totfiles = atoi(stf.c_str());
}
}
virtual bool update() {
// Update the status file. Avoid doing it too often. Always do
// it at the end (status DONE)
if (status.phase == DbIxStatus::DBIXS_DONE ||
status.phase != m_prevphase || m_chron.millis() > 300) {
if (status.totfiles < status.filesdone ||
status.phase == DbIxStatus::DBIXS_DONE) {
status.totfiles = status.filesdone;
}
m_prevphase = status.phase;
m_chron.restart();
m_file.holdWrites(true);
m_file.set("phase", int(status.phase));
m_file.set("docsdone", status.docsdone);
m_file.set("filesdone", status.filesdone);
m_file.set("fileerrors", status.fileerrors);
m_file.set("dbtotdocs", status.dbtotdocs);
m_file.set("totfiles", status.totfiles);
m_file.set("fn", status.fn);
m_file.set("hasmonitor", status.hasmonitor);
m_file.holdWrites(false);
}
if (path_exists(m_stopfilename)) {
LOGINF("recollindex: asking indexer to stop because " <<
m_stopfilename << " exists\n");
path_unlink(m_stopfilename);
stopindexing = true;
}
if (stopindexing) {
return false;
}
#ifndef DISABLE_X11MON
// If we are in the monitor, we also need to check X11 status
// during the initial indexing pass (else the user could log
// out and the indexing would go on, not good (ie: if the user
// logs in again, the new recollindex will fail).
if ((op_flags & OPT_m) && !(op_flags & OPT_x) && !x11IsAlive()) {
LOGDEB("X11 session went away during initial indexing pass\n");
stopindexing = true;
return false;
}
#endif
return true;
}
private:
ConfSimple m_file;
string m_stopfilename;
Chrono m_chron;
DbIxStatus::Phase m_prevphase;
};
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
@ -233,7 +159,7 @@ static void sigcleanup(int sig)
static void makeIndexerOrExit(RclConfig *config, bool inPlaceReset)
{
if (!confindexer) {
confindexer = new ConfIndexer(config, updater);
confindexer = new ConfIndexer(config);
if (inPlaceReset)
confindexer->setInPlaceReset();
}
@ -831,13 +757,20 @@ int main(int argc, char *argv[])
#endif
Pidfile pidfile(config->getPidfile());
updater = new MyUpdater(config);
lockorexit(&pidfile, config);
// Log something at LOGINFO to reset the trace file. Else at level
// 3 it's not even truncated if all docs are up to date.
LOGINFO("recollindex: starting up\n");
setMyPriority(config);
// Init status updater
if (nullptr == statusUpdater(config, op_flags & OPT_x)) {
std::cerr << "Could not initialize status updater\n";
LOGERR("Could not initialize status updater\n");
exit(1);
}
statusUpdater->update(DbIxStatus::DBIXS_NONE, "");
if (op_flags & OPT_r) {
if (aremain != 1)
@ -899,9 +832,7 @@ int main(int argc, char *argv[])
} else if (op_flags & OPT_m) {
if (aremain != 0)
Usage();
if (updater) {
updater->status.hasmonitor = true;
}
statusUpdater()->setMonitor(true);
if (!(op_flags&OPT_D)) {
LOGDEB("recollindex: daemonizing\n");
#ifndef _WIN32
@ -960,11 +891,8 @@ int main(int argc, char *argv[])
#endif
}
if (updater) {
updater->status.phase = DbIxStatus::DBIXS_MONITOR;
updater->status.fn.clear();
updater->update();
}
statusUpdater()->update(DbIxStatus::DBIXS_MONITOR, "");
int opts = RCLMON_NONE;
if (op_flags & OPT_D)
opts |= RCLMON_NOFORK;
@ -991,11 +919,7 @@ int main(int argc, char *argv[])
addIdxReason("indexer", confindexer->getReason());
cerr << confindexer->getReason() << endl;
}
if (updater) {
updater->status.phase = DbIxStatus::DBIXS_DONE;
updater->status.fn.clear();
updater->update();
}
statusUpdater()->update(DbIxStatus::DBIXS_DONE, "");
flushIdxReasons();
return !status;
}

View File

@ -173,8 +173,8 @@ public:
// Initialize. Compute paths and create a temporary directory that will be
// used by internfile()
WebQueueIndexer::WebQueueIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc)
: m_config(cnf), m_db(db), m_updater(updfunc)
WebQueueIndexer::WebQueueIndexer(RclConfig *cnf, Rcl::Db *db)
: m_config(cnf), m_db(db)
{
m_queuedir = m_config->getWebQueueDir();
path_catslash(m_queuedir);
@ -255,13 +255,7 @@ bool WebQueueIndexer::indexFromCache(const string& udi)
void WebQueueIndexer::updstatus(const string& udi)
{
if (m_updater) {
++(m_updater->status.docsdone);
if (m_updater->status.dbtotdocs < m_updater->status.docsdone)
m_updater->status.dbtotdocs = m_updater->status.docsdone;
m_updater->status.fn = udi;
m_updater->update();
}
statusUpdater()->update(DbIxStatus::DBIXS_FILES, udi, DbIxStatusUpdater::IncrDocsDone);
}
bool WebQueueIndexer::index()

View File

@ -30,7 +30,6 @@
#include "fstreewalk.h"
#include "rcldoc.h"
class DbIxStatusUpdater;
class CirCache;
class RclConfig;
class WebStore;
@ -40,8 +39,7 @@ class Db;
class WebQueueIndexer : public FsTreeWalkerCB {
public:
WebQueueIndexer(RclConfig *cnf, Rcl::Db *db,
DbIxStatusUpdater *updfunc = 0);
WebQueueIndexer(RclConfig *cnf, Rcl::Db *db);
~WebQueueIndexer();
/** This is called by the top indexer in recollindex.
@ -69,7 +67,6 @@ private:
Rcl::Db *m_db{nullptr};
WebStore *m_cache{nullptr};
std::string m_queuedir;
DbIxStatusUpdater *m_updater{nullptr};
// Don't process the cache. Set by indexFiles().
bool m_nocacheindex{false};
// Config: page erase interval. We normally keep only one

View File

@ -46,6 +46,7 @@ void RclMain::updateIdxStatus()
switch (status.phase) {
case DbIxStatus::DBIXS_NONE:phs=tr("None");break;
case DbIxStatus::DBIXS_FILES: phs=tr("Updating");break;
case DbIxStatus::DBIXS_FLUSH: phs=tr("Flushing");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;

View File

@ -63,6 +63,7 @@ using namespace std;
#include "rclaspell.h"
#endif
#include "zlibut.h"
#include "idxstatus.h"
#ifndef XAPIAN_AT_LEAST
// Added in Xapian 1.4.2. Define it here for older versions
@ -2021,8 +2022,10 @@ bool Db::doFlush()
}
string ermsg;
try {
statusUpdater()->update(DbIxStatus::DBIXS_FLUSH, "");
m_ndb->xwdb.commit();
} XCATCHERROR(ermsg);
statusUpdater()->update(DbIxStatus::DBIXS_NONE, "");
if (!ermsg.empty()) {
LOGERR("Db::doFlush: flush() failed: " << ermsg << "\n");
return false;
@ -2238,8 +2241,10 @@ bool Db::purge()
// because it doesn't really hurt.
m_reason.clear();
try {
statusUpdater()->update(DbIxStatus::DBIXS_FLUSH, "");
m_ndb->xwdb.commit();
} XCATCHERROR(m_reason);
statusUpdater()->update(DbIxStatus::DBIXS_NONE, "");
if (!m_reason.empty()) {
LOGERR("Db::purge: 1st flush failed: " << m_reason << "\n");
return false;
@ -2286,8 +2291,10 @@ bool Db::purge()
m_reason.clear();
try {
statusUpdater()->update(DbIxStatus::DBIXS_FLUSH, "");
m_ndb->xwdb.commit();
} XCATCHERROR(m_reason);
statusUpdater()->update(DbIxStatus::DBIXS_NONE, "");
if (!m_reason.empty()) {
LOGERR("Db::purge: 2nd flush failed: " << m_reason << "\n");
return false;