recoll/src/index/idxstatus.cpp
Jean-Francois Dockes f1b2d3004a Simplified the indexing status update code by treating the updater as a singleton
Add a 'flushing' state for when we commit the Xapian index.
2021-04-16 13:27:53 +02:00

167 lines
5.8 KiB
C++

/* 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
* (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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "autoconfig.h"
#include <mutex>
#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)
{
ConfSimple cs(config->getIdxStatusFile().c_str(), 1);
status.phase = DbIxStatus::Phase(cs.getInt("phase", 0));
cs.get("fn", status.fn);
status.docsdone = (int)cs.getInt("docsdone", 0);
status.filesdone = (int)cs.getInt("filesdone", 0);
status.fileerrors = (int)cs.getInt("fileerrors", 0);
status.dbtotdocs = (int)cs.getInt("dbtotdocs", 0);
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));
}