Add recollindex option to write file not indexed reasons to diagnostics file
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
#include "autoconfig.h"
|
||||
|
||||
#include "checkindexed.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
+17
-18
@@ -47,6 +47,7 @@
|
||||
#include "rclinit.h"
|
||||
#include "extrameta.h"
|
||||
#include "utf8fn.h"
|
||||
#include "idxdiags.h"
|
||||
#if defined(HAVE_POSIX_FADVISE)
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -397,8 +398,7 @@ bool FsIndexer::indexFiles(list<string>& files, int flags)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (processone(*it, &stb, FsTreeWalker::FtwRegular) !=
|
||||
FsTreeWalker::FtwOk) {
|
||||
if (processone(*it, &stb, FsTreeWalker::FtwRegular) != FsTreeWalker::FtwOk) {
|
||||
LOGERR("FsIndexer::indexFiles: processone failed\n");
|
||||
goto out;
|
||||
}
|
||||
@@ -560,9 +560,8 @@ void *FsIndexerInternfileWorker(void * fsp)
|
||||
return (void*)1;
|
||||
}
|
||||
LOGDEB0("FsIndexerInternfileWorker: task fn " << tsk->fn << "\n");
|
||||
if (fip->processonefile(&myconf, tsk->fn, &tsk->statbuf,
|
||||
tsk->localfields) !=
|
||||
FsTreeWalker::FtwOk) {
|
||||
if (fip->processonefile(
|
||||
&myconf, tsk->fn, &tsk->statbuf, tsk->localfields) != FsTreeWalker::FtwOk) {
|
||||
LOGERR("FsIndexerInternfileWorker: processone failed\n");
|
||||
tqp->workerExit();
|
||||
return (void*)0;
|
||||
@@ -584,9 +583,8 @@ void *FsIndexerInternfileWorker(void * fsp)
|
||||
/// Accent and majuscule handling are performed by the db module when doing
|
||||
/// the actual indexing work. The Rcl::Doc created by internfile()
|
||||
/// mostly contains pretty raw utf8 data.
|
||||
FsTreeWalker::Status
|
||||
FsIndexer::processone(const std::string &fn, const struct PathStat *stp,
|
||||
FsTreeWalker::CbFlag flg)
|
||||
FsTreeWalker::Status FsIndexer::processone(
|
||||
const std::string &fn, const struct PathStat *stp, FsTreeWalker::CbFlag flg)
|
||||
{
|
||||
if (m_updater) {
|
||||
#ifdef IDX_THREADS
|
||||
@@ -610,7 +608,10 @@ FsIndexer::processone(const std::string &fn, const struct PathStat *stp,
|
||||
if (flg == FsTreeWalker::FtwDirReturn)
|
||||
return FsTreeWalker::FtwOk;
|
||||
}
|
||||
|
||||
if (flg == FsTreeWalker::FtwSkipped) {
|
||||
IdxDiags::theDiags().record(IdxDiags::Skipped, fn);
|
||||
return FsTreeWalker::FtwOk;
|
||||
}
|
||||
#ifdef IDX_THREADS
|
||||
if (m_haveInternQ) {
|
||||
InternfileTask *tp = new InternfileTask(fn, stp, m_localfields);
|
||||
@@ -644,10 +645,9 @@ bool FsIndexer::launchAddOrUpdate(const string& udi, const string& parent_udi,
|
||||
return m_db->addOrUpdate(udi, parent_udi, doc);
|
||||
}
|
||||
|
||||
FsTreeWalker::Status
|
||||
FsIndexer::processonefile(RclConfig *config,
|
||||
const std::string &fn, const struct PathStat *stp,
|
||||
const map<string, string>& localfields)
|
||||
FsTreeWalker::Status FsIndexer::processonefile(
|
||||
RclConfig *config, const std::string &fn, const struct PathStat *stp,
|
||||
const map<string, string>& localfields)
|
||||
{
|
||||
////////////////////
|
||||
// Check db up to date ? Doing this before file type
|
||||
@@ -693,7 +693,7 @@ FsIndexer::processonefile(RclConfig *config,
|
||||
// If noretryfailed is set, check for a file which previously
|
||||
// failed to index, and avoid re-processing it
|
||||
if (needupdate && m_noretryfailed && existingDoc &&
|
||||
!oldsig.empty() && *oldsig.rbegin() == '+') {
|
||||
!oldsig.empty() && oldsig.back() == '+') {
|
||||
// Check that the sigs are the same except for the '+'. If the file
|
||||
// actually changed, we always retry (maybe it was fixed)
|
||||
string nold = oldsig.substr(0, oldsig.size()-1);
|
||||
@@ -720,8 +720,7 @@ FsIndexer::processonefile(RclConfig *config,
|
||||
return FsTreeWalker::FtwOk;
|
||||
}
|
||||
|
||||
LOGDEB0("processone: processing: [" <<
|
||||
displayableBytes(stp->pst_size) << "] " << fn << "\n");
|
||||
LOGDEB0("processone: processing: [" << displayableBytes(stp->pst_size) << "] " << fn << "\n");
|
||||
|
||||
// Note that we used to do the full path here, but I ended up
|
||||
// believing that it made more sense to use only the file name
|
||||
@@ -813,6 +812,7 @@ FsIndexer::processonefile(RclConfig *config,
|
||||
// myriads of such files, the ext script is executed for them
|
||||
// and fails every time)
|
||||
if (fis == FileInterner::FIError) {
|
||||
IdxDiags::theDiags().record(IdxDiags::Error, fn, doc.ipath);
|
||||
doc.sig += cstr_plus;
|
||||
}
|
||||
|
||||
@@ -822,8 +822,7 @@ FsIndexer::processonefile(RclConfig *config,
|
||||
|
||||
// Add document to database. If there is an ipath, add it
|
||||
// as a child of the file document.
|
||||
if (!launchAddOrUpdate(udi, doc.ipath.empty() ?
|
||||
cstr_null : parent_udi, doc)) {
|
||||
if (!launchAddOrUpdate(udi, doc.ipath.empty() ? cstr_null : parent_udi, doc)) {
|
||||
return FsTreeWalker::FtwError;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Copyright (C) 2021 J.F.Dockes
|
||||
*
|
||||
* License: GPL 2.1
|
||||
*
|
||||
* 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.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdio.h>
|
||||
#include <mutex>
|
||||
|
||||
#include "idxdiags.h"
|
||||
|
||||
static std::mutex diagmutex;
|
||||
|
||||
class IdxDiags::Internal {
|
||||
public:
|
||||
~Internal() {
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
FILE *fp{nullptr};
|
||||
};
|
||||
|
||||
IdxDiags::IdxDiags()
|
||||
{
|
||||
m = new Internal;
|
||||
}
|
||||
|
||||
IdxDiags::~IdxDiags()
|
||||
{
|
||||
delete m;
|
||||
}
|
||||
|
||||
bool IdxDiags::flush()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(diagmutex);
|
||||
if (m && m->fp) {
|
||||
return fflush(m->fp) ? false : true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static IdxDiags *theInstance;
|
||||
|
||||
IdxDiags& IdxDiags::theDiags()
|
||||
{
|
||||
if (nullptr == theInstance) {
|
||||
theInstance = new IdxDiags;
|
||||
}
|
||||
return *theInstance;
|
||||
}
|
||||
|
||||
bool IdxDiags::init(const std::string& outpath)
|
||||
{
|
||||
m->fp = fopen(outpath.c_str(), "w");
|
||||
if (nullptr == m->fp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IdxDiags::record(DiagKind diag, const std::string& path, const std::string& detail)
|
||||
{
|
||||
if (nullptr == m || nullptr == m->fp || (path.empty() && detail.empty())) {
|
||||
return true;
|
||||
}
|
||||
const char *skind = "Unknown";
|
||||
switch (diag) {
|
||||
case Ok: skind = "Ok";break;
|
||||
case Skipped: skind = "Skipped";break;
|
||||
case NoContentSuffix: skind = "NoContentSuffix";break;
|
||||
case MissingHelper: skind = "MissingHelper";break;
|
||||
case Error: skind = "Error";break;
|
||||
case NoHandler: skind = "NoHandler";break;
|
||||
case ExcludedMime: skind = "ExcludedMime";break;
|
||||
case NotIncludedMime: skind = "NotIncludedMime";break;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(diagmutex);
|
||||
fprintf(m->fp, "%s %s | %s\n", skind, path.c_str(), detail.c_str());
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Copyright (C) 2021 J.F.Dockes
|
||||
*
|
||||
* License: GPL 2.1
|
||||
*
|
||||
* 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.1 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.
|
||||
*/
|
||||
|
||||
#ifndef _IDXDIAGS_H_INCLUDED_
|
||||
#define _IDXDIAGS_H_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
|
||||
class IdxDiags {
|
||||
public:
|
||||
enum DiagKind {Ok, Skipped, NoContentSuffix, MissingHelper, Error, NoHandler,
|
||||
ExcludedMime, NotIncludedMime};
|
||||
|
||||
// Retrieve a reference to the single instance.
|
||||
static IdxDiags& theDiags();
|
||||
|
||||
// Initialize, setting the output file path. outpath will be truncated.
|
||||
// No locking: this must be called from the main thread, before going multithread.
|
||||
// If init is never called, further calls to record() or flush() will be noops.
|
||||
bool init(const std::string& outpath);
|
||||
|
||||
// Record a reason for a document not to be indexed.
|
||||
bool record(DiagKind diag, const std::string& path, const std::string& detail = std::string());
|
||||
bool flush();
|
||||
|
||||
class Internal;
|
||||
private:
|
||||
Internal *m;
|
||||
IdxDiags();
|
||||
~IdxDiags();
|
||||
};
|
||||
|
||||
#endif /* _IDXDIAGS_H_INCLUDED_ */
|
||||
+6
-11
@@ -66,20 +66,16 @@ static RclMonitor *makeMonitor();
|
||||
*/
|
||||
class WalkCB : public FsTreeWalkerCB {
|
||||
public:
|
||||
WalkCB(RclConfig *conf, RclMonitor *mon, RclMonEventQueue *queue,
|
||||
FsTreeWalker& walker)
|
||||
: m_config(conf), m_mon(mon), m_queue(queue), m_walker(walker)
|
||||
{}
|
||||
WalkCB(RclConfig *conf, RclMonitor *mon, RclMonEventQueue *queue, FsTreeWalker& walker)
|
||||
: m_config(conf), m_mon(mon), m_queue(queue), m_walker(walker) {}
|
||||
virtual ~WalkCB() {}
|
||||
|
||||
virtual FsTreeWalker::Status
|
||||
processone(const string &fn, const struct PathStat *st,
|
||||
FsTreeWalker::CbFlag flg) {
|
||||
virtual FsTreeWalker::Status processone(
|
||||
const string &fn, const struct PathStat *st, FsTreeWalker::CbFlag flg) {
|
||||
MONDEB("rclMonRcvRun: processone " << fn << " m_mon " << m_mon <<
|
||||
" m_mon->ok " << (m_mon ? m_mon->ok() : false) << std::endl);
|
||||
|
||||
if (flg == FsTreeWalker::FtwDirEnter ||
|
||||
flg == FsTreeWalker::FtwDirReturn) {
|
||||
if (flg == FsTreeWalker::FtwDirEnter || flg == FsTreeWalker::FtwDirReturn) {
|
||||
m_config->setKeyDir(fn);
|
||||
// Set up skipped patterns for this subtree.
|
||||
m_walker.setSkippedNames(m_config->getSkippedNames());
|
||||
@@ -106,8 +102,7 @@ public:
|
||||
m_mon->saved_errno != ENOENT)
|
||||
return FsTreeWalker::FtwError;
|
||||
}
|
||||
} else if (!m_mon->generatesExist() &&
|
||||
flg == FsTreeWalker::FtwRegular) {
|
||||
} else if (!m_mon->generatesExist() && flg == FsTreeWalker::FtwRegular) {
|
||||
// Have to synthetize events for regular files existence
|
||||
// at startup because the monitor does not do it
|
||||
// Note 2011-09-29: no sure this is actually needed. We just ran
|
||||
|
||||
+19
-11
@@ -62,6 +62,7 @@ using namespace std;
|
||||
#include "checkretryfailed.h"
|
||||
#include "idxstatus.h"
|
||||
#include "circache.h"
|
||||
#include "idxdiags.h"
|
||||
|
||||
// Command line options
|
||||
static int op_flags;
|
||||
@@ -93,11 +94,13 @@ static int op_flags;
|
||||
#define OPTVAL_WEBCACHE_COMPACT 1000
|
||||
#define OPTVAL_WEBCACHE_BURST 1001
|
||||
#define OPTVAL_DIAGS_NOTINDEXED 1002
|
||||
#define OPTVAL_DIAGS_DIAGFILE 1003
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"webcache-compact", 0, 0, OPTVAL_WEBCACHE_COMPACT},
|
||||
{"webcache-burst", required_argument, 0, OPTVAL_WEBCACHE_BURST},
|
||||
{"notindexed", 0, 0, OPTVAL_DIAGS_NOTINDEXED},
|
||||
{"diagfile", required_argument, 0, OPTVAL_DIAGS_DIAGFILE},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -110,6 +113,7 @@ static ConfIndexer *confindexer;
|
||||
static void cleanup()
|
||||
{
|
||||
deleteZ(confindexer);
|
||||
IdxDiags::theDiags().flush();
|
||||
recoll_exitready();
|
||||
}
|
||||
|
||||
@@ -274,20 +278,15 @@ static void setMyPriority(const RclConfig *config)
|
||||
class MakeListWalkerCB : public FsTreeWalkerCB {
|
||||
public:
|
||||
MakeListWalkerCB(list<string>& files, const vector<string>& selpats)
|
||||
: m_files(files), m_pats(selpats)
|
||||
{
|
||||
}
|
||||
virtual FsTreeWalker::Status
|
||||
processone(const string& fn, const struct PathStat *,
|
||||
FsTreeWalker::CbFlag flg) {
|
||||
: m_files(files), m_pats(selpats) {}
|
||||
virtual FsTreeWalker::Status processone(
|
||||
const string& fn, const struct PathStat *, FsTreeWalker::CbFlag flg) {
|
||||
if (flg== FsTreeWalker::FtwDirEnter || flg == FsTreeWalker::FtwRegular){
|
||||
if (m_pats.empty()) {
|
||||
cerr << "Selecting " << fn << endl;
|
||||
m_files.push_back(fn);
|
||||
} else {
|
||||
for (vector<string>::const_iterator it = m_pats.begin();
|
||||
it != m_pats.end(); it++) {
|
||||
if (fnmatch(it->c_str(), fn.c_str(), 0) == 0) {
|
||||
for (const auto& pat : m_pats) {
|
||||
if (fnmatch(pat.c_str(), fn.c_str(), 0) == 0) {
|
||||
m_files.push_back(fn);
|
||||
break;
|
||||
}
|
||||
@@ -451,6 +450,8 @@ static const char usage [] =
|
||||
" -Z : in place reset: consider all documents as changed. Can also\n"
|
||||
" be combined with -i or -r but not -m\n"
|
||||
" -k : retry files on which we previously failed\n"
|
||||
" --diagfile <outputpath> : list skipped or otherwise not indexed documents to <outputpath>\n"
|
||||
" <outputpath> will be truncated\n"
|
||||
#ifdef RCL_MONITOR
|
||||
"recollindex -m [-w <secs>] -x [-D] [-C]\n"
|
||||
" Perform real time indexing. Don't become a daemon if -D is set.\n"
|
||||
@@ -636,6 +637,7 @@ int main(int argc, char *argv[])
|
||||
bool diags_notindexed{false};
|
||||
|
||||
std::string burstdir;
|
||||
std::string diagfile;
|
||||
while ((ret = getopt_long(argc, (char *const*)&args[0], "c:CDdEefhikKlmnPp:rR:sS:w:xZz",
|
||||
long_options, NULL)) != -1) {
|
||||
switch (ret) {
|
||||
@@ -676,7 +678,7 @@ int main(int argc, char *argv[])
|
||||
case OPTVAL_WEBCACHE_COMPACT: webcache_compact = true; break;
|
||||
case OPTVAL_WEBCACHE_BURST: burstdir = optarg; webcache_burst = true;break;
|
||||
case OPTVAL_DIAGS_NOTINDEXED: diags_notindexed = true;break;
|
||||
|
||||
case OPTVAL_DIAGS_DIAGFILE: diagfile = optarg;break;
|
||||
default: Usage(); break;
|
||||
}
|
||||
}
|
||||
@@ -790,6 +792,12 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (!diagfile.empty()) {
|
||||
if (!IdxDiags::theDiags().init(diagfile)) {
|
||||
std::cerr << "Could not initialize diags file " << diagfile << "\n";
|
||||
LOGERR("recollindex: Could not initialize diags file " << diagfile << "\n");
|
||||
}
|
||||
}
|
||||
bool rezero((op_flags & OPT_z) != 0);
|
||||
bool inPlaceReset((op_flags & OPT_Z) != 0);
|
||||
|
||||
|
||||
@@ -411,8 +411,7 @@ WebQueueIndexer::processone(
|
||||
if (flg != FsTreeWalker::FtwRegular)
|
||||
return FsTreeWalker::FtwOk;
|
||||
|
||||
string dotpath = path_cat(path_getfather(path),
|
||||
string(DOTFILEPREFIX) + path_getsimple(path));
|
||||
string dotpath = path_cat(path_getfather(path), string(DOTFILEPREFIX) + path_getsimple(path));
|
||||
LOGDEB("WebQueueIndexer: prc1: [" << path << "]\n");
|
||||
|
||||
WebQueueDotFile dotfile(m_config, dotpath);
|
||||
|
||||
Reference in New Issue
Block a user