unified retrying for databaseModified errors

This commit is contained in:
dockes 2009-10-24 15:02:49 +00:00
parent 0bd1b1a674
commit 709be40f5c
4 changed files with 250 additions and 233 deletions

View File

@ -108,25 +108,20 @@ static inline string make_parentterm(const string& udi)
bool Db::Native::subDocs(const string &udi, vector<Xapian::docid>& docids)
{
LOGDEB2(("subDocs: [%s]\n", uniterm.c_str()));
string ermsg;
string pterm = make_parentterm(udi);
for (int tries = 0; tries < 2; tries++) {
try {
Xapian::PostingIterator it = xrdb.postlist_begin(pterm);
for (; it != xrdb.postlist_end(pterm); it++) {
docids.push_back(*it);
}
LOGDEB(("Db::Native::subDocs: returning %d ids\n", docids.size()));
return true;
} catch (const Xapian::DatabaseModifiedError &e) {
LOGDEB(("Db::subDocs: got modified error. reopen/retry\n"));
xrdb.reopen();
} XCATCHERROR(ermsg);
if (!ermsg.empty())
break;
XAPTRY(docids.clear();
docids.insert(docids.begin(), xrdb.postlist_begin(pterm),
xrdb.postlist_end(pterm)),
xrdb, m_rcldb->m_reason);
if (!m_rcldb->m_reason.empty()) {
LOGERR(("Rcl::Db::subDocs: %s\n", m_rcldb->m_reason.c_str()));
return false;
} else {
LOGDEB(("Db::Native::subDocs: returning %d ids\n", docids.size()));
return true;
}
LOGERR(("Rcl::Db::subDocs: %s\n", ermsg.c_str()));
return false;
}
// Only ONE field name inside the index data record differs from the
@ -206,6 +201,9 @@ static list<string> noPrefixList(const list<string>& in)
// Build a document abstract by extracting text chunks around the query terms
// This uses the db termlists, not the original document.
//
// DatabaseModified and other general exceptions are catched and
// possibly retried by our caller
string Db::Native::makeAbstract(Xapian::docid docid, Query *query)
{
Chrono chron;
@ -655,20 +653,14 @@ bool Db::adjustdbs()
int Db::docCnt()
{
int res = -1;
string ermsg;
if (m_ndb && m_ndb->m_isopen) {
try {
res = m_ndb->xdb().get_doccount();
} catch (const Xapian::DatabaseModifiedError &e) {
LOGDEB(("Db::docCnt: got modified error. reopen/retry\n"));
// Doesn't make sense if we are the writer !
if (m_ndb->m_iswritable)
return -1;
m_ndb->xdb().reopen();
res = m_ndb->xdb().get_doccount();
} XCATCHERROR(ermsg);
if (!ermsg.empty())
LOGERR(("Db::docCnt: got error: %s\n", ermsg.c_str()));
if (!m_ndb || !m_ndb->m_isopen)
return -1;
XAPTRY(res = m_ndb->xdb().get_doccount(), m_ndb->xrdb, m_reason);
if (!m_reason.empty()) {
LOGERR(("Db::docCnt: got error: %s\n", m_reason.c_str()));
return -1;
}
return res;
}
@ -1125,15 +1117,14 @@ bool Db::needUpdate(const string &udi, const string& sig)
// the actual document file, or, for a multi-document file, the
// pseudo-doc we create to stand for the file itself.
// We try twice in case database needs to be reopened. (Ulterior
// note: this does not make sense as we are the sole writer!)
// We try twice in case database needs to be reopened.
for (int tries = 0; tries < 2; tries++) {
try {
// Get the doc or pseudo-doc
Xapian::PostingIterator docid =m_ndb->xrdb.postlist_begin(uniterm);
if (docid == m_ndb->xrdb.postlist_end(uniterm)) {
// If no document exist with this path, we do need update
LOGDEB(("Db::needUpdate: no path: [%s]\n", uniterm.c_str()));
LOGDEB(("Db::needUpdate:yes (new): [%s]\n", uniterm.c_str()));
return true;
}
Xapian::Document doc = m_ndb->xrdb.get_document(*docid);
@ -1148,9 +1139,9 @@ bool Db::needUpdate(const string &udi, const string& sig)
osig.c_str(), sig.c_str()));
// Db is not up to date. Let's index the file
return true;
}
}
LOGDEB(("Db::needUpdate: uptodate: [%s]\n", uniterm.c_str()));
LOGDEB(("Db::needUpdate:no: [%s]\n", uniterm.c_str()));
// Up to date.
@ -1173,13 +1164,14 @@ bool Db::needUpdate(const string &udi, const string& sig)
return false;
} catch (const Xapian::DatabaseModifiedError &e) {
LOGDEB(("Db::needUpdate: got modified error. reopen/retry\n"));
m_ndb->xdb().reopen();
} XCATCHERROR(ermsg);
if (!ermsg.empty())
break;
m_reason = e.get_msg();
m_ndb->xrdb.reopen();
continue;
} XCATCHERROR(m_reason);
break;
}
LOGERR(("Db::needUpdate: error while checking existence: %s\n",
ermsg.c_str()));
m_reason.c_str()));
return true;
}
@ -1393,7 +1385,7 @@ bool Db::termMatch(MatchType typ, const string &lang,
{
if (!m_ndb || !m_ndb->m_isopen)
return false;
Xapian::Database db = m_ndb->xdb();
Xapian::Database xdb = m_ndb->xdb();
res.clear();
@ -1417,7 +1409,10 @@ bool Db::termMatch(MatchType typ, const string &lang,
res.unique();
for (list<TermMatchEntry>::iterator it = res.begin();
it != res.end(); it++) {
it->wcf = db.get_collection_freq(it->term);
XAPTRY(it->wcf = xdb.get_collection_freq(it->term),
xdb, m_reason);
if (!m_reason.empty())
return false;
LOGDEB1(("termMatch: %d [%s]\n", it->wcf, it->term.c_str()));
}
} else {
@ -1446,34 +1441,44 @@ bool Db::termMatch(MatchType typ, const string &lang,
}
LOGDEB(("termMatch: initsec: [%s]\n", is.c_str()));
string ermsg;
try {
Xapian::TermIterator it = db.allterms_begin();
if (!is.empty())
it.skip_to(is.c_str());
for (int n = 0; it != db.allterms_end(); it++) {
// If we're beyond the terms matching the initial string, end
if (!is.empty() && (*it).find(is) != 0)
break;
string term;
if (!prefix.empty())
term = (*it).substr(prefix.length());
else
term = *it;
if (typ == ET_WILD) {
if (fnmatch(droot.c_str(), term.c_str(), 0) == FNM_NOMATCH)
continue;
} else {
if (regexec(&reg, term.c_str(), 0, 0, 0))
continue;
}
// Do we want stem expansion here? We don't do it for now
res.push_back(TermMatchEntry(term, it.get_termfreq()));
++n;
}
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("termMatch: %s\n", ermsg.c_str()));
for (int tries = 0; tries < 2; tries++) {
try {
Xapian::TermIterator it = xdb.allterms_begin();
if (!is.empty())
it.skip_to(is.c_str());
for (int n = 0; it != xdb.allterms_end(); it++) {
// If we're beyond the terms matching the initial
// string, end
if (!is.empty() && (*it).find(is) != 0)
break;
string term;
if (!prefix.empty())
term = (*it).substr(prefix.length());
else
term = *it;
if (typ == ET_WILD) {
if (fnmatch(droot.c_str(), term.c_str(), 0) ==
FNM_NOMATCH)
continue;
} else {
if (regexec(&reg, term.c_str(), 0, 0, 0))
continue;
}
// Do we want stem expansion here? We don't do it for now
res.push_back(TermMatchEntry(term, it.get_termfreq()));
++n;
}
m_reason.erase();
break;
} catch (const Xapian::DatabaseModifiedError &e) {
m_reason = e.get_msg();
xdb.reopen();
continue;
} XCATCHERROR(m_reason);
break;
}
if (!m_reason.empty()) {
LOGERR(("termMatch: %s\n", m_reason.c_str()));
return false;
}
@ -1508,12 +1513,9 @@ TermIter *Db::termWalkOpen()
TermIter *tit = new TermIter;
if (tit) {
tit->db = m_ndb->xdb();
string ermsg;
try {
tit->it = tit->db.allterms_begin();
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("Db::termWalkOpen: xapian error: %s\n", ermsg.c_str()));
XAPTRY(tit->it = tit->db.allterms_begin(), tit->db, m_reason);
if (!m_reason.empty()) {
LOGERR(("Db::termWalkOpen: xapian error: %s\n", m_reason.c_str()));
return 0;
}
}
@ -1521,15 +1523,15 @@ TermIter *Db::termWalkOpen()
}
bool Db::termWalkNext(TermIter *tit, string &term)
{
string ermsg;
try {
XAPTRY(
if (tit && tit->it != tit->db.allterms_end()) {
term = *(tit->it)++;
return true;
}
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("Db::termWalkOpen: xapian error: %s\n", ermsg.c_str()));
, tit->db, m_reason);
if (!m_reason.empty()) {
LOGERR(("Db::termWalkOpen: xapian error: %s\n", m_reason.c_str()));
}
return false;
}
@ -1544,13 +1546,12 @@ bool Db::termExists(const string& word)
{
if (!m_ndb || !m_ndb->m_isopen)
return 0;
string ermsg;
try {
if (!m_ndb->xdb().term_exists(word))
return false;
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("Db::termWalkOpen: xapian error: %s\n", ermsg.c_str()));
XAPTRY(if (!m_ndb->xdb().term_exists(word)) return false,
m_ndb->xrdb, m_reason);
if (!m_reason.empty()) {
LOGERR(("Db::termWalkOpen: xapian error: %s\n", m_reason.c_str()));
return false;
}
return true;
@ -1573,27 +1574,14 @@ bool Db::stemDiffers(const string& lang, const string& word,
bool Db::makeDocAbstract(Doc &doc, Query *query, string& abstract)
{
LOGDEB1(("Db::makeDocAbstract: exti %d\n", exti));
if (!m_ndb) {
if (!m_ndb || !m_ndb->m_isopen) {
LOGERR(("Db::makeDocAbstract: no db\n"));
return false;
}
m_reason.erase();
for (int i = 0; i < 2; i++) {
try {
abstract = m_ndb->makeAbstract(doc.xdocid, query);
m_reason.erase();
break;
} catch (const Xapian::DatabaseModifiedError &error) {
LOGDEB(("Db:makeDocAbstract: caught DatabaseModified\n"));
m_reason = error.get_msg();
m_ndb->xdb().reopen();
} catch (const Xapian::Error & error) {
LOGERR(("Db::makeDocAbstract: exception: %s\n",
error.get_msg().c_str()));
m_reason = error.get_msg();
break;
}
}
XAPTRY(abstract = m_ndb->makeAbstract(doc.xdocid, query),
m_ndb->xrdb, m_reason);
return m_reason.empty() ? true : false;
}
@ -1609,25 +1597,32 @@ bool Db::getDoc(const string &udi, Doc &doc)
doc.pc = 100;
string uniterm = make_uniterm(udi);
string ermsg;
try {
if (!m_ndb->xrdb.term_exists(uniterm)) {
// Document found in history no longer in the database.
// We return true (because their might be other ok docs further)
// but indicate the error with pc = -1
doc.pc = -1;
LOGINFO(("Db:getDoc: no such doc in index: [%s] (len %d)\n",
uniterm.c_str(), uniterm.length()));
return true;
}
Xapian::PostingIterator docid = m_ndb->xrdb.postlist_begin(uniterm);
Xapian::Document xdoc = m_ndb->xrdb.get_document(*docid);
string data = xdoc.get_data();
return m_ndb->dbDataToRclDoc(*docid, data, doc, 100);
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("Db::getDoc: %s\n", ermsg.c_str()));
for (int tries = 0; tries < 2; tries++) {
try {
if (!m_ndb->xrdb.term_exists(uniterm)) {
// Document found in history no longer in the
// database. We return true (because their might be
// other ok docs further) but indicate the error with
// pc = -1
doc.pc = -1;
LOGINFO(("Db:getDoc: no such doc in index: [%s] (len %d)\n",
uniterm.c_str(), uniterm.length()));
return true;
}
Xapian::PostingIterator docid =
m_ndb->xrdb.postlist_begin(uniterm);
Xapian::Document xdoc = m_ndb->xrdb.get_document(*docid);
string data = xdoc.get_data();
return m_ndb->dbDataToRclDoc(*docid, data, doc, 100);
} catch (const Xapian::DatabaseModifiedError &e) {
m_reason = e.get_msg();
m_ndb->xrdb.reopen();
continue;
} XCATCHERROR(m_reason);
break;
}
LOGERR(("Db::getDoc: %s\n", m_reason.c_str()));
return false;
}

View File

@ -31,6 +31,20 @@ enum value_slot {
MSG = "Caught unknown xapian exception"; \
}
#define XAPTRY(STMTTOTRY, XAPDB, ERSTR) \
for (int tries = 0; tries < 2; tries++) { \
try { \
STMTTOTRY; \
ERSTR.erase(); \
break; \
} catch (const Xapian::DatabaseModifiedError &e) { \
ERSTR = e.get_msg(); \
XAPDB.reopen(); \
continue; \
} XCATCHERROR(ERSTR); \
break; \
}
class Query;
// A class for data and methods that would have to expose

View File

@ -151,34 +151,44 @@ bool Query::setQuery(RefCntr<SearchData> sdata)
m_reason += sdata->getReason();
return false;
}
m_nq->query = xq;
string ermsg;
m_nq->xquery = xq;
string d;
try {
m_nq->enquire = new Xapian::Enquire(m_db->m_ndb->xrdb);
if (m_collapseDuplicates) {
m_nq->enquire->set_collapse_key(Rcl::VALUE_MD5);
} else {
m_nq->enquire->set_collapse_key(Xapian::BAD_VALUENO);
}
if (!m_sortField.empty()) {
if (m_sorter) {
delete (QSorter*)m_sorter;
m_sorter = 0;
}
m_sorter = new QSorter(m_sortField);
// It really seems there is a xapian bug about sort order, we
// invert here.
m_nq->enquire->set_sort_by_key((QSorter*)m_sorter,
!m_sortAscending);
}
m_nq->enquire->set_query(m_nq->query);
m_nq->mset = Xapian::MSet();
// Get the query description and trim the "Xapian::Query"
d = m_nq->query.get_description();
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGDEB(("Query::SetQuery: xapian error %s\n", ermsg.c_str()));
for (int tries = 0; tries < 2; tries++) {
try {
m_nq->xenquire = new Xapian::Enquire(m_db->m_ndb->xrdb);
if (m_collapseDuplicates) {
m_nq->xenquire->set_collapse_key(Rcl::VALUE_MD5);
} else {
m_nq->xenquire->set_collapse_key(Xapian::BAD_VALUENO);
}
if (!m_sortField.empty()) {
if (m_sorter) {
delete (QSorter*)m_sorter;
m_sorter = 0;
}
m_sorter = new QSorter(m_sortField);
// It really seems there is a xapian bug about sort order, we
// invert here.
m_nq->xenquire->set_sort_by_key((QSorter*)m_sorter,
!m_sortAscending);
}
m_nq->xenquire->set_query(m_nq->xquery);
m_nq->xmset = Xapian::MSet();
// Get the query description and trim the "Xapian::Query"
d = m_nq->xquery.get_description();
m_reason.erase();
break;
} catch (const Xapian::DatabaseModifiedError &e) {
m_reason = e.get_msg();
m_db->m_ndb->xrdb.reopen();
continue;
} XCATCHERROR(m_reason);
break;
}
if (!m_reason.empty()) {
LOGDEB(("Query::SetQuery: xapian error %s\n", m_reason.c_str()));
return false;
}
@ -202,8 +212,8 @@ bool Query::getQueryTerms(list<string>& terms)
Xapian::TermIterator it;
string ermsg;
try {
for (it = m_nq->query.get_terms_begin();
it != m_nq->query.get_terms_end(); it++) {
for (it = m_nq->xquery.get_terms_begin();
it != m_nq->xquery.get_terms_end(); it++) {
terms.push_back(*it);
}
} XCATCHERROR(ermsg);
@ -216,7 +226,7 @@ bool Query::getQueryTerms(list<string>& terms)
bool Query::getMatchTerms(const Doc& doc, list<string>& terms)
{
if (ISNULL(m_nq) || !m_nq->enquire) {
if (ISNULL(m_nq) || !m_nq->xenquire) {
LOGERR(("Query::getMatchTerms: no query opened\n"));
return -1;
}
@ -224,15 +234,14 @@ bool Query::getMatchTerms(const Doc& doc, list<string>& terms)
terms.clear();
Xapian::TermIterator it;
Xapian::docid id = Xapian::docid(doc.xdocid);
string ermsg;
try {
for (it=m_nq->enquire->get_matching_terms_begin(id);
it != m_nq->enquire->get_matching_terms_end(id); it++) {
terms.push_back(*it);
}
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("getQueryTerms: xapian error: %s\n", ermsg.c_str()));
XAPTRY(terms.insert(terms.begin(),
m_nq->xenquire->get_matching_terms_begin(id),
m_nq->xenquire->get_matching_terms_end(id)),
m_db->m_ndb->xrdb, m_reason);
if (!m_reason.empty()) {
LOGERR(("getQueryTerms: xapian error: %s\n", m_reason.c_str()));
return false;
}
@ -246,25 +255,23 @@ static const int qquantum = 30;
// the search job in there, this can be long
int Query::getResCnt()
{
if (ISNULL(m_nq) || !m_nq->enquire) {
if (ISNULL(m_nq) || !m_nq->xenquire) {
LOGERR(("Query::getResCnt: no query opened\n"));
return -1;
}
string ermsg;
int ret = -1;
if (m_nq->mset.size() <= 0) {
if (m_nq->xmset.size() <= 0) {
Chrono chron;
try {
m_nq->mset = m_nq->enquire->get_mset(0, qquantum,0, m_nq->decider);
ret = m_nq->mset.get_matches_lower_bound();
} catch (const Xapian::DatabaseModifiedError &error) {
m_db->m_ndb->xrdb.reopen();
m_nq->mset = m_nq->enquire->get_mset(0, qquantum,0, m_nq->decider);
ret = m_nq->mset.get_matches_lower_bound();
} XCATCHERROR(ermsg);
XAPTRY(m_nq->xmset =
m_nq->xenquire->get_mset(0, qquantum,0, m_nq->decider);
ret = m_nq->xmset.get_matches_lower_bound(),
m_db->m_ndb->xrdb, m_reason);
LOGDEB(("Query::getResCnt: %d mS\n", chron.millis()));
if (!ermsg.empty())
LOGERR(("enquire->get_mset: exception: %s\n", ermsg.c_str()));
if (!m_reason.empty())
LOGERR(("xenquire->get_mset: exception: %s\n", m_reason.c_str()));
}
return ret;
}
@ -282,7 +289,7 @@ int Query::getResCnt()
bool Query::getDoc(int exti, Doc &doc)
{
LOGDEB1(("Query::getDoc: exti %d\n", exti));
if (ISNULL(m_nq) || !m_nq->enquire) {
if (ISNULL(m_nq) || !m_nq->xenquire) {
LOGERR(("Query::getDoc: no query opened\n"));
return false;
}
@ -301,31 +308,29 @@ bool Query::getDoc(int exti, Doc &doc)
while (exti >= (int)m_nq->m_dbindices.size()) {
LOGDEB(("Query::getDoc: fetching %d starting at %d\n",
qquantum, first));
try {
m_nq->mset = m_nq->enquire->get_mset(first, qquantum);
} catch (const Xapian::DatabaseModifiedError &error) {
m_db->m_ndb->xrdb.reopen();
m_nq->mset = m_nq->enquire->get_mset(first, qquantum);
} catch (const Xapian::Error & error) {
LOGERR(("enquire->get_mset: exception: %s\n",
error.get_msg().c_str()));
m_reason = error.get_msg();
return false;
XAPTRY(m_nq->xmset = m_nq->xenquire->get_mset(first, qquantum),
m_db->m_ndb->xrdb, m_reason);
if (!m_reason.empty()) {
LOGERR(("enquire->get_mset: exception: %s\n",
m_reason.c_str()));
return false;
}
if (m_nq->mset.empty()) {
if (m_nq->xmset.empty()) {
LOGDEB(("Query::getDoc: got empty mset\n"));
return false;
}
first = m_nq->mset.get_firstitem();
for (unsigned int i = 0; i < m_nq->mset.size() ; i++) {
first = m_nq->xmset.get_firstitem();
for (unsigned int i = 0; i < m_nq->xmset.size() ; i++) {
LOGDEB(("Query::getDoc: [%d]\n", i));
Xapian::Document xdoc = m_nq->mset[i].get_document();
Xapian::Document xdoc = m_nq->xmset[i].get_document();
if ((*m_nq->postfilter)(xdoc)) {
m_nq->m_dbindices.push_back(first + i);
}
}
first = first + m_nq->mset.size();
first = first + m_nq->xmset.size();
}
}
xapi = m_nq->m_dbindices[exti];
@ -334,34 +339,31 @@ bool Query::getDoc(int exti, Doc &doc)
}
// From there on, we work with a xapian enquire item number. Fetch it
int first = m_nq->mset.get_firstitem();
int last = first + m_nq->mset.size() -1;
int first = m_nq->xmset.get_firstitem();
int last = first + m_nq->xmset.size() -1;
if (!(xapi >= first && xapi <= last)) {
LOGDEB(("Fetching for first %d, count %d\n", xapi, qquantum));
try {
m_nq->mset = m_nq->enquire->get_mset(xapi, qquantum,
0, m_nq->decider);
} catch (const Xapian::DatabaseModifiedError &error) {
m_db->m_ndb->xrdb.reopen();
m_nq->mset = m_nq->enquire->get_mset(xapi, qquantum,
0, m_nq->decider);
} catch (const Xapian::Error & error) {
LOGERR(("enquire->get_mset: exception: %s\n",
error.get_msg().c_str()));
m_reason = error.get_msg();
return false;
XAPTRY(m_nq->xmset = m_nq->xenquire->get_mset(xapi, qquantum,
0, m_nq->decider),
m_db->m_ndb->xrdb, m_reason);
if (!m_reason.empty()) {
LOGERR(("enquire->get_mset: exception: %s\n", m_reason.c_str()));
return false;
}
if (m_nq->mset.empty())
if (m_nq->xmset.empty()) {
LOGDEB(("enquire->get_mset: got empty result\n"));
return false;
first = m_nq->mset.get_firstitem();
last = first + m_nq->mset.size() -1;
}
first = m_nq->xmset.get_firstitem();
last = first + m_nq->xmset.size() -1;
}
LOGDEB1(("Query::getDoc: Qry [%s] win [%d-%d] Estimated results: %d",
m_nq->query.get_description().c_str(),
first, last, m_nq->mset.get_matches_lower_bound()));
first, last, m_nq->xmset.get_matches_lower_bound()));
Xapian::Document xdoc;
Xapian::docid docid = 0;
@ -370,41 +372,42 @@ bool Query::getDoc(int exti, Doc &doc)
m_reason.erase();
for (int xaptries=0; xaptries < 2; xaptries++) {
try {
xdoc = m_nq->mset[xapi-first].get_document();
docid = *(m_nq->mset[xapi-first]);
pc = m_nq->mset.convert_to_percent(m_nq->mset[xapi-first]);
xdoc = m_nq->xmset[xapi-first].get_document();
docid = *(m_nq->xmset[xapi-first]);
pc = m_nq->xmset.convert_to_percent(m_nq->xmset[xapi-first]);
data = xdoc.get_data();
m_reason.erase();
break;
} catch (Xapian::DatabaseModifiedError &error) {
// retry or end of loop
LOGDEB(("getDoc: caught DatabaseModified\n"));
m_reason = error.get_msg();
continue;
}
XCATCHERROR(m_reason);
break;
}
if (!m_reason.empty()) {
LOGERR(("Query::getDoc: %s\n", m_reason.c_str()));
return false;
}
// Parse xapian document's data and populate doc fields
return m_reason.empty() ?
m_db->m_ndb->dbDataToRclDoc(docid, data, doc, pc) : false;
return m_db->m_ndb->dbDataToRclDoc(docid, data, doc, pc);
}
list<string> Query::expand(const Doc &doc)
{
list<string> res;
if (ISNULL(m_nq) || !m_nq->enquire) {
if (ISNULL(m_nq) || !m_nq->xenquire) {
LOGERR(("Query::expand: no query opened\n"));
return res;
}
string ermsg;
for (int tries = 0; tries < 2; tries++) {
try {
Xapian::RSet rset;
rset.add_document(Xapian::docid(doc.xdocid));
// We don't exclude the original query terms.
Xapian::ESet eset = m_nq->enquire->get_eset(20, rset, false);
Xapian::ESet eset = m_nq->xenquire->get_eset(20, rset, false);
LOGDEB(("ESet terms:\n"));
// We filter out the special terms
for (Xapian::ESetIterator it = eset.begin();
@ -416,16 +419,21 @@ list<string> Query::expand(const Doc &doc)
if (res.size() >= 10)
break;
}
} catch (const Xapian::DatabaseModifiedError &error) {
continue;
} XCATCHERROR(ermsg);
if (!ermsg.empty()) {
LOGERR(("Query::expand: xapian error %s\n", ermsg.c_str()));
res.clear();
}
m_reason.erase();
break;
} catch (const Xapian::DatabaseModifiedError &e) {
m_reason = e.get_msg();
m_db->m_ndb->xrdb.reopen();
continue;
} XCATCHERROR(m_reason);
break;
}
if (!m_reason.empty()) {
LOGERR(("Query::expand: xapian error %s\n", m_reason.c_str()));
res.clear();
}
return res;
}

View File

@ -20,7 +20,7 @@ public:
/** query descriptor: terms and subqueries joined by operators
* (or/and etc...)
*/
Xapian::Query query;
Xapian::Query xquery;
/** In case there is a postq filter: sequence of db indices that match */
vector<int> m_dbindices;
@ -47,13 +47,13 @@ public:
Xapian::MatchDecider *decider; // Xapian does the filtering
Xapian::MatchDecider *postfilter; // Result filtering done by Recoll
Xapian::Enquire *enquire; // Open query descriptor.
Xapian::MSet mset; // Partial result set
Xapian::Enquire *xenquire; // Open query descriptor.
Xapian::MSet xmset; // Partial result set
// Term frequencies for current query. See makeAbstract, setQuery
map<string, double> termfreqs;
Native(Query *q)
: m_q(q), decider(0), postfilter(0), enquire(0)
: m_q(q), decider(0), postfilter(0), xenquire(0)
{ }
~Native() {
clear();
@ -62,7 +62,7 @@ public:
m_dbindices.clear();
delete decider; decider = 0;
delete postfilter; postfilter = 0;
delete enquire; enquire = 0;
delete xenquire; xenquire = 0;
termfreqs.clear();
}
};