diff --git a/src/mu-msg-iter.cc b/src/mu-msg-iter.cc index ba21cb38..981618df 100644 --- a/src/mu-msg-iter.cc +++ b/src/mu-msg-iter.cc @@ -1,5 +1,5 @@ /* -** Copyright (C) 2008-2010 Dirk-Jan C. Binnema +** Copyright (C) 2008-2011 Dirk-Jan C. Binnema ** ** 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 @@ -28,7 +28,24 @@ #include "mu-msg-iter-priv.hh" struct _MuMsgIter { - Xapian::Enquire *_enq; + + _MuMsgIter (const Xapian::Enquire &enq, size_t batchsize): + _enq(enq), _batchsize(batchsize), _offset(0) { + + _matches = _enq.get_mset (0, _batchsize); + _cursor = _matches.begin(); + _is_null = _matches.empty(); + + for (int i = 0; i != MU_MSG_FIELD_ID_NUM; ++i) + _str[i] = NULL; + } + + ~_MuMsgIter () { + for (int i = 0; i != MU_MSG_FIELD_ID_NUM; ++i) + g_free (_str[i]); + } + + const Xapian::Enquire _enq; Xapian::MSet _matches; Xapian::MSet::const_iterator _cursor; size_t _batchsize, _offset; @@ -41,25 +58,9 @@ struct _MuMsgIter { MuMsgIter* mu_msg_iter_new (const Xapian::Enquire& enq, size_t batchsize) { - MuMsgIter *iter; - try { - iter = new MuMsgIter; - memset (iter->_str, 0, sizeof(iter->_str)); - - iter->_enq = new Xapian::Enquire(enq); - iter->_matches = iter->_enq->get_mset (0, batchsize); - if (!iter->_matches.empty()) { - iter->_cursor = iter->_matches.begin(); - iter->_is_null = false; - } else - iter->_is_null = true; + return new MuMsgIter (enq, batchsize); - iter->_batchsize = batchsize; - iter->_offset = 0; - - return iter; - } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL); } @@ -67,16 +68,7 @@ mu_msg_iter_new (const Xapian::Enquire& enq, size_t batchsize) void mu_msg_iter_destroy (MuMsgIter *iter) { - if (iter) { - for (int i = 0; i != MU_MSG_FIELD_ID_NUM; ++i) - g_free (iter->_str[i]); - - try { - delete iter->_enq; - delete iter; - - } MU_XAPIAN_CATCH_BLOCK; - } + try { delete iter; } MU_XAPIAN_CATCH_BLOCK; } @@ -122,8 +114,7 @@ message_is_readable (MuMsgIter *iter) static MuMsgIter* get_next_batch (MuMsgIter *iter) { - iter->_matches = iter->_enq->get_mset (iter->_offset, - iter->_batchsize); + iter->_matches = iter->_enq.get_mset (iter->_offset, iter->_batchsize); if (iter->_matches.empty()) { iter->_cursor = iter->_matches.end(); iter->_is_null = true; diff --git a/src/mu-query.cc b/src/mu-query.cc index 7166960e..a5d158ad 100644 --- a/src/mu-query.cc +++ b/src/mu-query.cc @@ -132,8 +132,8 @@ private: class MuSizeRangeProcessor : public Xapian::NumberValueRangeProcessor { public: - MuSizeRangeProcessor(Xapian::valueno v) - : Xapian::NumberValueRangeProcessor(v) { + MuSizeRangeProcessor(): + Xapian::NumberValueRangeProcessor(MU_MSG_FIELD_ID_SIZE) { } Xapian::valueno operator()(std::string &begin, std::string &end) { @@ -185,64 +185,30 @@ private: static void add_prefix (MuMsgFieldId field, Xapian::QueryParser* qparser); struct _MuQuery { - Xapian::Database* _db; - Xapian::QueryParser* _qparser; - Xapian::ValueRangeProcessor* _date_range_processor; - Xapian::ValueRangeProcessor* _size_range_processor; -}; - -static void -uninit_mu_query (MuQuery *mqx) -{ - try { - delete mqx->_db; - delete mqx->_qparser; - - delete mqx->_date_range_processor; - delete mqx->_size_range_processor; - - } MU_XAPIAN_CATCH_BLOCK; -} - -static gboolean -init_mu_query (MuQuery *mqx, const char* dbpath) -{ - try { - mqx->_db = new Xapian::Database(dbpath); - mqx->_qparser = new Xapian::QueryParser; + _MuQuery (const char* dbpath): + _db (Xapian::Database(dbpath)) { - mqx->_qparser->set_database (*mqx->_db); - mqx->_qparser->set_default_op (Xapian::Query::OP_AND); + _qparser.set_database (_db); + _qparser.set_default_op (Xapian::Query::OP_AND); - /* check for dates */ - mqx->_date_range_processor = new MuDateRangeProcessor (); - mqx->_qparser->add_valuerangeprocessor - (mqx->_date_range_processor); - - /* check for sizes */ - mqx->_size_range_processor = new MuSizeRangeProcessor - (MU_MSG_FIELD_ID_SIZE); - mqx->_qparser->add_valuerangeprocessor - (mqx->_size_range_processor); + _qparser.add_valuerangeprocessor (&_date_range_processor); + _qparser.add_valuerangeprocessor (&_size_range_processor); mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_prefix, - (gpointer)mqx->_qparser); + &_qparser); + } - return TRUE; - - } MU_XAPIAN_CATCH_BLOCK; - - // things went wrong, cleanup resources - uninit_mu_query (mqx); - - return FALSE; -} + Xapian::Database _db; + Xapian::QueryParser _qparser; + MuDateRangeProcessor _date_range_processor; + MuSizeRangeProcessor _size_range_processor; +}; static bool set_query (MuQuery *mqx, Xapian::Query& q, const char* searchexpr, GError **err) { try { - q = mqx->_qparser->parse_query + q = mqx->_qparser.parse_query (searchexpr, Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PURE_NOT | @@ -295,10 +261,8 @@ add_prefix (MuMsgFieldId mfid, Xapian::QueryParser* qparser) MuQuery* mu_query_new (const char* xpath, GError **err) { - MuQuery *mqx; - g_return_val_if_fail (xpath, NULL); - + if (!mu_util_check_dir (xpath, TRUE, FALSE)) { g_set_error (err, 0, MU_ERROR_XAPIAN_DIR, "'%s' is not a readable xapian dir", xpath); @@ -314,28 +278,21 @@ mu_query_new (const char* xpath, GError **err) if (mu_util_xapian_is_empty (xpath)) g_warning ("database %s is empty; nothing to do", xpath); - - mqx = g_new0 (MuQuery, 1); - if (!init_mu_query (mqx, xpath)) { - g_set_error (err, 0, MU_ERROR_INTERNAL, - "failed to initialize the Xapian query object"); - g_free (mqx); - return NULL; - } - - return mqx; + try { + + return new MuQuery (xpath); + + } MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN (err, MU_ERROR_XAPIAN, NULL); + + return 0; } void mu_query_destroy (MuQuery *self) { - if (!self) - return; - - uninit_mu_query (self); - g_free (self); + try { delete self; } MU_XAPIAN_CATCH_BLOCK; } @@ -380,10 +337,10 @@ mu_query_run (MuQuery *self, const char* searchexpr, } g_free (preprocessed); - Xapian::Enquire enq (*self->_db); + Xapian::Enquire enq (self->_db); if (batchsize == 0) - batchsize = self->_db->get_doccount(); + batchsize = self->_db.get_doccount(); if (sortfieldid != MU_MSG_FIELD_ID_NONE) enq.set_sort_by_value ((Xapian::valueno)sortfieldid, @@ -397,7 +354,7 @@ mu_query_run (MuQuery *self, const char* searchexpr, } char* -mu_query_as_string (MuQuery *self, const char *searchexpr, GError **err) +mu_query_as_string (MuQuery *self, const char *searchexpr, GError **err) { g_return_val_if_fail (self, NULL); g_return_val_if_fail (searchexpr, NULL); diff --git a/src/mu-store.cc b/src/mu-store.cc index dd25b203..68121020 100644 --- a/src/mu-store.cc +++ b/src/mu-store.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include "mu-msg.h" #include "mu-msg-contact.h" @@ -39,19 +40,53 @@ /* http://article.gmane.org/gmane.comp.search.xapian.general/3656 */ #define MU_STORE_MAX_TERM_LENGTH 240 -struct _MuStore { - Xapian::WritableDatabase *_db; +static void add_synonyms (MuStore *store); +static gboolean check_version (MuStore *store); - /* contacts object to cache all the contact information */ - MuContacts *_contacts; +struct _MuStore { + _MuStore (const char *xpath, const char *contacts_cache) : + _db (xpath, Xapian::DB_CREATE_OR_OPEN), _in_transaction(0), + _processed (0), _trx_size(MU_STORE_DEFAULT_TRX_SIZE), _contacts (0), + _version (0){ - char *_version; + if (!check_version (this)) + throw std::runtime_error + ("xapian db version check failed"); + + if (contacts_cache) { + _contacts = mu_contacts_new (contacts_cache); + if (!_contacts) /* don't bail-out for this */ + throw std::runtime_error + ("failed to init contacts cache"); + } + + add_synonyms (this); + MU_WRITE_LOG ("%s: opened %s (batch size: %u)", + __FUNCTION__, xpath, _trx_size); + } + + ~_MuStore () { + try { + mu_contacts_destroy (_contacts); + mu_store_flush (this); + + MU_WRITE_LOG ("closing xapian database with %d documents", + (int)_db.get_doccount()); + } MU_XAPIAN_CATCH_BLOCK; + } + + Xapian::WritableDatabase _db; /* transaction handling */ bool _in_transaction; int _processed; size_t _trx_size; - guint _batchsize; /* batch size of a xapian transaction */ + guint _batchsize; /* batch size of a xapian transaction */ + + /* contacts object to cache all the contact information */ + MuContacts *_contacts; + + char *_version; }; @@ -87,9 +122,9 @@ static void add_synonyms (MuStore *store) { mu_msg_flags_foreach ((MuMsgFlagsForeachFunc)add_synonym_for_flag, - store->_db); + &store->_db); mu_msg_prio_foreach ((MuMsgPrioForeachFunc)add_synonym_for_prio, - store->_db); + &store->_db); } static gboolean @@ -125,43 +160,13 @@ MuStore* mu_store_new (const char* xpath, const char *contacts_cache, GError **err) { - MuStore *store (0); - g_return_val_if_fail (xpath, NULL); + try { - store = g_new0(MuStore,1); - - store->_db = new Xapian::WritableDatabase - (xpath,Xapian::DB_CREATE_OR_OPEN); - - if (!check_version (store)) { - mu_store_destroy (store); - return NULL; - } - - if (contacts_cache) { - store->_contacts = mu_contacts_new (contacts_cache); - if (!store->_contacts) /* don't bail-out for this */ - g_warning ("failed to init contacts cache"); - } - - /* keep count of processed docs */ - store->_in_transaction = false; - store->_processed = 0; - store->_trx_size = MU_STORE_DEFAULT_TRX_SIZE; - - add_synonyms (store); - - MU_WRITE_LOG ("%s: opened %s (batch size: %u)", - __FUNCTION__, xpath, store->_trx_size); - - return store; + return new _MuStore (xpath, contacts_cache); } MU_XAPIAN_CATCH_BLOCK_G_ERROR(err,MU_ERROR_XAPIAN); - try { delete store->_db; } MU_XAPIAN_CATCH_BLOCK; - - g_free (store); return NULL; } @@ -169,22 +174,7 @@ mu_store_new (const char* xpath, const char *contacts_cache, void mu_store_destroy (MuStore *store) { - if (!store) - return; - - try { - mu_store_flush (store); - - MU_WRITE_LOG ("closing xapian database with %d documents", - (int)store->_db->get_doccount()); - - mu_contacts_destroy (store->_contacts); - - g_free (store->_version); - delete store->_db; - g_free (store); - - } MU_XAPIAN_CATCH_BLOCK; + try { delete store; } MU_XAPIAN_CATCH_BLOCK; } @@ -192,11 +182,8 @@ void mu_store_set_batch_size (MuStore *store, guint batchsize) { g_return_if_fail (store); - - if (batchsize == 0) - store->_trx_size = MU_STORE_DEFAULT_TRX_SIZE; - else - store->_trx_size = batchsize; + + store->_trx_size = batchsize ? batchsize : MU_STORE_DEFAULT_TRX_SIZE; } @@ -207,7 +194,7 @@ mu_store_count (MuStore *store) g_return_val_if_fail (store, 0); try { - return store->_db->get_doccount(); + return store->_db.get_doccount(); } MU_XAPIAN_CATCH_BLOCK; @@ -233,7 +220,7 @@ mu_store_set_metadata (MuStore *store, const char *key, const char *val) g_return_val_if_fail (val, FALSE); try { - store->_db->set_metadata (key, val); + store->_db.set_metadata (key, val); return TRUE; } MU_XAPIAN_CATCH_BLOCK; @@ -249,7 +236,7 @@ mu_store_get_metadata (MuStore *store, const char *key) g_return_val_if_fail (key, NULL); try { - const std::string val (store->_db->get_metadata (key)); + const std::string val (store->_db.get_metadata (key)); return val.empty() ? NULL : g_strdup (val.c_str()); } MU_XAPIAN_CATCH_BLOCK; @@ -264,7 +251,7 @@ begin_trx_if (MuStore *store, gboolean cond) { if (cond) { g_debug ("beginning Xapian transaction"); - store->_db->begin_transaction(); + store->_db.begin_transaction(); store->_in_transaction = true; } } @@ -275,7 +262,7 @@ commit_trx_if (MuStore *store, gboolean cond) if (cond) { g_debug ("comitting Xapian transaction"); store->_in_transaction = false; - store->_db->commit_transaction(); + store->_db.commit_transaction(); } } @@ -285,7 +272,7 @@ rollback_trx_if (MuStore *store, gboolean cond) if (cond) { g_debug ("rolling back Xapian transaction"); store->_in_transaction = false; - store->_db->cancel_transaction(); + store->_db.cancel_transaction(); } } @@ -296,7 +283,7 @@ mu_store_flush (MuStore *store) try { commit_trx_if (store, store->_in_transaction); - store->_db->flush (); /* => commit, post X 1.1.x */ + store->_db.flush (); /* => commit, post X 1.1.x */ } MU_XAPIAN_CATCH_BLOCK; } @@ -482,7 +469,7 @@ each_contact_info (MuMsgContact *contact, MsgDoc *msgdoc) if (!pfxp) return; /* unsupported contact type */ - if (contact->name && contact->name[0] != '\0') { + if (!mu_str_is_empty(contact->name)) { Xapian::TermGenerator termgen; termgen.set_document (*msgdoc->_doc); char *norm = mu_str_normalize (contact->name, TRUE); @@ -547,7 +534,7 @@ mu_store_store (MuStore *store, MuMsg *msg) &msgdoc); /* we replace all existing documents for this file */ - id = store->_db->replace_document (uid, newdoc); + id = store->_db.replace_document (uid, newdoc); ++store->_processed; commit_trx_if (store, store->_processed % store->_trx_size == 0); @@ -573,7 +560,7 @@ mu_store_remove (MuStore *store, const char *msgpath) begin_trx_if (store, !store->_in_transaction); - store->_db->delete_document (uid); + store->_db.delete_document (uid); ++store->_processed; /* do we need to commit now? */ @@ -593,7 +580,7 @@ mu_store_contains_message (MuStore *store, const char* path) try { const std::string uid (get_message_uid(path)); - return store->_db->term_exists (uid) ? TRUE: FALSE; + return store->_db.term_exists (uid) ? TRUE: FALSE; } MU_XAPIAN_CATCH_BLOCK_RETURN (FALSE); } @@ -640,21 +627,19 @@ mu_store_foreach (MuStore *self, g_return_val_if_fail (func, MU_ERROR); try { - Xapian::Enquire enq (*self->_db); + Xapian::Enquire enq (self->_db); + enq.set_query (Xapian::Query::MatchAll); enq.set_cutoff (0,0); - Xapian::MSet matches - (enq.get_mset (0, self->_db->get_doccount())); + Xapian::MSet matches (enq.get_mset (0, self->_db.get_doccount())); if (matches.empty()) return MU_OK; /* database is empty */ for (Xapian::MSet::iterator iter = matches.begin(); iter != matches.end(); ++iter) { Xapian::Document doc (iter.get_document()); - const std::string path( - doc.get_value(MU_MSG_FIELD_ID_PATH)); - + const std::string path(doc.get_value(MU_MSG_FIELD_ID_PATH)); MuResult res = func (path.c_str(), user_data); if (res != MU_OK) return res;