fix timeouts for mh_execm filters

This commit is contained in:
Jean-Francois Dockes 2015-10-08 10:10:04 +02:00
parent bdf5cb8755
commit 4efb618250
7 changed files with 101 additions and 50 deletions

View file

@ -34,14 +34,28 @@
using namespace std; using namespace std;
// This is called periodically by ExeCmd when it is waiting for data, MimeHandlerExec::MimeHandlerExec(RclConfig *cnf, const std::string& id)
// or when it does receive some. We may choose to interrupt the : RecollFilter(cnf, id), missingHelper(false), m_filtermaxseconds(900),
// command. m_filtermaxmbytes(0)
class MEAdv : public ExecCmdAdvise { {
public: m_config->getConfParam("filtermaxseconds", &m_filtermaxseconds);
MEAdv(int maxsecs) : m_filtermaxseconds(maxsecs) {m_start = time(0L);} m_config->getConfParam("filtermaxmbytes", &m_filtermaxmbytes);
void newData(int n) { }
LOGDEB1(("MHExec:newData(%d)\n", n));
MEAdv::MEAdv(int maxsecs)
: m_filtermaxseconds(maxsecs)
{
m_start = time(0L);
}
void MEAdv::reset()
{
m_start = time(0L);
}
void MEAdv::newData(int n)
{
LOGDEB2(("MHExec:newData(%d)\n", n));
if (m_filtermaxseconds > 0 && if (m_filtermaxseconds > 0 &&
time(0L) - m_start > m_filtermaxseconds) { time(0L) - m_start > m_filtermaxseconds) {
LOGERR(("MimeHandlerExec: filter timeout (%d S)\n", LOGERR(("MimeHandlerExec: filter timeout (%d S)\n",
@ -53,10 +67,6 @@ public:
// would be to call ExeCmd::setCancel(). // would be to call ExeCmd::setCancel().
CancelCheck::instance().checkCancel(); CancelCheck::instance().checkCancel();
} }
time_t m_start;
int m_filtermaxseconds;
};
bool MimeHandlerExec::skip_to_document(const string& ipath) bool MimeHandlerExec::skip_to_document(const string& ipath)
{ {
@ -77,11 +87,6 @@ bool MimeHandlerExec::next_document()
return false; return false;
} }
int filtermaxseconds = 900;
m_config->getConfParam("filtermaxseconds", &filtermaxseconds);
int filtermaxmbytes = 0;
m_config->getConfParam("filtermaxmbytes", &filtermaxmbytes);
if (params.empty()) { if (params.empty()) {
// Hu ho // Hu ho
LOGERR(("MimeHandlerExec::mkDoc: empty params\n")); LOGERR(("MimeHandlerExec::mkDoc: empty params\n"));
@ -102,12 +107,12 @@ bool MimeHandlerExec::next_document()
string& output = m_metaData[cstr_dj_keycontent]; string& output = m_metaData[cstr_dj_keycontent];
output.erase(); output.erase();
ExecCmd mexec; ExecCmd mexec;
MEAdv adv(filtermaxseconds); MEAdv adv(m_filtermaxseconds);
mexec.setAdvise(&adv); mexec.setAdvise(&adv);
mexec.putenv("RECOLL_CONFDIR", m_config->getConfDir()); mexec.putenv("RECOLL_CONFDIR", m_config->getConfDir());
mexec.putenv(m_forPreview ? "RECOLL_FILTER_FORPREVIEW=yes" : mexec.putenv(m_forPreview ? "RECOLL_FILTER_FORPREVIEW=yes" :
"RECOLL_FILTER_FORPREVIEW=no"); "RECOLL_FILTER_FORPREVIEW=no");
mexec.setrlimit_as(filtermaxmbytes); mexec.setrlimit_as(m_filtermaxmbytes);
int status; int status;
try { try {

View file

@ -19,10 +19,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
using std::vector;
using std::string;
#include "mimehandler.h" #include "mimehandler.h"
#include "execmd.h"
/** /**
* Turn external document into internal one by executing an external filter. * Turn external document into internal one by executing an external filter.
@ -45,28 +44,33 @@ class MimeHandlerExec : public RecollFilter {
// Parameters: this has been built by our creator, from config file // Parameters: this has been built by our creator, from config file
// data. We always add the file name at the end before actual execution // data. We always add the file name at the end before actual execution
vector<string> params; std::vector<std::string> params;
// Filter output type. The default for ext. filters is to output html, // Filter output type. The default for ext. filters is to output html,
// but some don't, in which case the type is defined in the config. // but some don't, in which case the type is defined in the config.
string cfgFilterOutputMtype; std::string cfgFilterOutputMtype;
// Output character set if the above type is not text/html. For // Output character set if the above type is not text/html. For
// those filters, the output charset has to be known: ie set by a command // those filters, the output charset has to be known: ie set by a command
// line option. // line option.
string cfgFilterOutputCharset; std::string cfgFilterOutputCharset;
bool missingHelper; bool missingHelper;
// Resource management values
int m_filtermaxseconds;
int m_filtermaxmbytes;
//////////////// ////////////////
MimeHandlerExec(RclConfig *cnf, const string& id) MimeHandlerExec(RclConfig *cnf, const std::string& id);
: RecollFilter(cnf, id), missingHelper(false)
{} virtual bool set_document_file(const std::string& mt,
virtual bool set_document_file(const string& mt, const string &file_path) { const std::string &file_path) {
RecollFilter::set_document_file(mt, file_path); RecollFilter::set_document_file(mt, file_path);
m_fn = file_path; m_fn = file_path;
m_havedoc = true; m_havedoc = true;
return true; return true;
} }
virtual bool next_document(); virtual bool next_document();
virtual bool skip_to_document(const string& ipath); virtual bool skip_to_document(const std::string& ipath);
virtual void clear() { virtual void clear() {
m_fn.erase(); m_fn.erase();
m_ipath.erase(); m_ipath.erase();
@ -74,17 +78,36 @@ class MimeHandlerExec : public RecollFilter {
} }
protected: protected:
string m_fn; std::string m_fn;
string m_ipath; std::string m_ipath;
// Set up the character set metadata fields and possibly transcode // Set up the character set metadata fields and possibly transcode
// text/plain output. // text/plain output.
// @param charset when called from mh_execm, a possible explicit // @param charset when called from mh_execm, a possible explicit
// value from the filter (else the data will come from the config) // value from the filter (else the data will come from the config)
virtual void handle_cs(const string& mt, const string& charset = string()); virtual void handle_cs(const std::string& mt,
const std::string& charset = std::string());
private: private:
virtual void finaldetails(); virtual void finaldetails();
}; };
// This is called periodically by ExeCmd when it is waiting for data,
// or when it does receive some. We may choose to interrupt the
// command.
class MEAdv : public ExecCmdAdvise {
public:
MEAdv(int maxsecs = 900);
// Reset start time to now
void reset();
void setmaxsecs(int maxsecs) {
m_filtermaxseconds = maxsecs;
}
void newData(int n);
private:
time_t m_start;
int m_filtermaxseconds;
};
#endif /* _MH_EXEC_H_INCLUDED_ */ #endif /* _MH_EXEC_H_INCLUDED_ */

View file

@ -47,9 +47,6 @@ bool MimeHandlerExecMultiple::startCmd()
// Command name // Command name
string cmd = params.front(); string cmd = params.front();
int filtermaxmbytes = 0;
m_config->getConfParam("filtermaxmbytes", &filtermaxmbytes);
m_maxmemberkb = 50000; m_maxmemberkb = 50000;
m_config->getConfParam("membermaxkbs", &m_maxmemberkb); m_config->getConfParam("membermaxkbs", &m_maxmemberkb);
ostringstream oss; ostringstream oss;
@ -60,7 +57,9 @@ bool MimeHandlerExecMultiple::startCmd()
m_cmd.putenv(m_forPreview ? "RECOLL_FILTER_FORPREVIEW=yes" : m_cmd.putenv(m_forPreview ? "RECOLL_FILTER_FORPREVIEW=yes" :
"RECOLL_FILTER_FORPREVIEW=no"); "RECOLL_FILTER_FORPREVIEW=no");
m_cmd.setrlimit_as(filtermaxmbytes); m_cmd.setrlimit_as(m_filtermaxmbytes);
m_adv.setmaxsecs(m_filtermaxseconds);
m_cmd.setAdvise(&m_adv);
// Build parameter list: delete cmd name // Build parameter list: delete cmd name
vector<string>myparams(params.begin() + 1, params.end()); vector<string>myparams(params.begin() + 1, params.end());
@ -198,6 +197,8 @@ bool MimeHandlerExecMultiple::next_document()
return false; return false;
} }
m_adv.reset();
// Read answer (multiple elements) // Read answer (multiple elements)
LOGDEB1(("MHExecMultiple: reading answer\n")); LOGDEB1(("MHExecMultiple: reading answer\n"));
bool eofnext_received = false; bool eofnext_received = false;
@ -209,10 +210,16 @@ bool MimeHandlerExecMultiple::next_document()
string charset; string charset;
for (int loop=0;;loop++) { for (int loop=0;;loop++) {
string name, data; string name, data;
try {
if (!readDataElement(name, data)) { if (!readDataElement(name, data)) {
m_cmd.zapChild(); m_cmd.zapChild();
return false; return false;
} }
} catch (CancelExcept) {
LOGINFO(("MHExecMultiple: timeout or interrupt\n"));
m_cmd.zapChild();
return false;
}
if (name.empty()) if (name.empty())
break; break;
if (!stringlowercmp("eofnext:", name)) { if (!stringlowercmp("eofnext:", name)) {

View file

@ -120,6 +120,7 @@ private:
bool readDataElement(string& name, string& data); bool readDataElement(string& name, string& data);
bool m_filefirst; bool m_filefirst;
int m_maxmemberkb; int m_maxmemberkb;
MEAdv m_adv;
}; };
#endif /* _MH_EXECM_H_INCLUDED_ */ #endif /* _MH_EXECM_H_INCLUDED_ */

View file

@ -1,6 +1,8 @@
TEMPLATE = app TEMPLATE = app
LANGUAGE = C++ LANGUAGE = C++
DEFINES += BUILDING_RECOLL
@QMAKE_ENABLE_WEBKIT@ QT += webkit @QMAKE_ENABLE_WEBKIT@ QT += webkit
@QMAKE_DISABLE_WEBKIT@ QMAKE_CXXFLAGS += -DRESLIST_TEXTBROWSER -DSNIPPETS_TEXTBROWSER @QMAKE_DISABLE_WEBKIT@ QMAKE_CXXFLAGS += -DRESLIST_TEXTBROWSER -DSNIPPETS_TEXTBROWSER

View file

@ -907,8 +907,22 @@ int ExecCmd::getline(string& data)
} }
const int BS = 1024; const int BS = 1024;
char buf[BS]; char buf[BS];
int n = con->getline(buf, BS); int timeosecs = m->m_timeoutMs / 1000;
if (timeosecs == 0)
timeosecs = 1;
// Note that we only go once through here, except in case of
// timeout, which is why I think that the goto is more expressive
// than a loop
again:
int n = con->getline(buf, BS, timeosecs);
if (n < 0) { if (n < 0) {
if (con->timedout()) {
LOGDEB(("ExecCmd::getline: timeout\n"));
if (m->m_advise)
m->m_advise->newData(0);
goto again;
}
LOGERR(("ExecCmd::getline: error\n")); LOGERR(("ExecCmd::getline: error\n"));
} else if (n > 0) { } else if (n > 0) {
data.append(buf, n); data.append(buf, n);

View file

@ -117,8 +117,7 @@ int Netcon::select1(int fd, int timeo, int write)
ret = select(fd+1, &rd, 0, 0, &tv); ret = select(fd+1, &rd, 0, 0, &tv);
} }
if (!FD_ISSET(fd, &rd)) { if (!FD_ISSET(fd, &rd)) {
LOGERR(("Netcon::select1: fd not ready after select ??\n")); LOGDEB2(("Netcon::select1: fd %d timeout\n",fd));
return -1;
} }
return ret; return ret;
} }