diff --git a/src/mu-store-priv.hh b/src/mu-store-priv.hh index e8fa7594..a7d64f64 100644 --- a/src/mu-store-priv.hh +++ b/src/mu-store-priv.hh @@ -150,8 +150,7 @@ public: /* get a unique id for this message; note, this function returns a * static buffer -- not reentrant */ - const char* get_message_uid (const char* path); - const char* get_message_uid (MuMsg *msg); + const char *get_uid_term (const char *path); MuContacts* contacts() { return _contacts; } @@ -196,7 +195,11 @@ public: /* MuStore is ref-counted */ guint ref () { return ++_ref_count; } - guint unref () { return --_ref_count; } + guint unref () { + if (_ref_count < 1) + g_critical ("ref count error"); + return --_ref_count; + } /* by default, use transactions of 30000 messages */ static const unsigned DEFAULT_BATCH_SIZE = 30000; @@ -222,4 +225,9 @@ private: }; +/* Xapian DB prefix for the UID value */ +#define MU_STORE_UID_PREFIX "Q" + + + #endif /*__MU_STORE_PRIV_HH__*/ diff --git a/src/mu-store-read.cc b/src/mu-store-read.cc index c17df25c..f17bd0b3 100644 --- a/src/mu-store-read.cc +++ b/src/mu-store-read.cc @@ -39,27 +39,32 @@ #include "mu-flags.h" #include "mu-contacts.h" -/* get a unique id for this message; note, this function returns a - * static buffer -- not reentrant */ + +// note: not re-entrant const char* -_MuStore::get_message_uid (const char* path) { - char pfx = 0; - static char buf[PATH_MAX + 10]; - if (G_UNLIKELY(!pfx)) { - pfx = mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_PATH); - buf[0]=pfx; +_MuStore::get_uid_term (const char* path) +{ + // combination of DJB, BKDR hash functions to get a 64 bit + // value + + unsigned djbhash, bkdrhash, bkdrseed; + unsigned u; + static char hex[18]; + + djbhash = 5381; + bkdrhash = 0; + bkdrseed = 1313; + + + for(u = 0; path[u]; ++u) { + djbhash = ((djbhash << 5) + djbhash) + path[u]; + bkdrhash = bkdrhash * bkdrseed + path[u]; } - std::strcpy (buf + 1, path); - return buf; -} -/* get a unique id for this message; note, this function returns a - * static buffer -- not reentrant */ -const char* -_MuStore::get_message_uid (MuMsg *msg) { - return get_message_uid (mu_msg_get_path(msg)); -} + sprintf (hex, MU_STORE_UID_PREFIX "%08x%08x", djbhash, bkdrhash); + return hex; +} MuStore* @@ -155,7 +160,7 @@ mu_store_contains_message (MuStore *store, const char* path, GError **err) g_return_val_if_fail (path, FALSE); try { - const std::string uid (store->get_message_uid(path)); + const std::string uid (store->get_uid_term (path)); return store->db_read_only()->term_exists (uid) ? TRUE: FALSE; } MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(err, MU_ERROR_XAPIAN, FALSE); @@ -163,6 +168,30 @@ mu_store_contains_message (MuStore *store, const char* path, GError **err) } +unsigned +mu_store_get_docid_for_path (MuStore *store, const char* path, GError **err) +{ + g_return_val_if_fail (store, FALSE); + g_return_val_if_fail (path, FALSE); + + try { + Xapian::Query query (store->get_uid_term (path)); // uid is a term + Xapian::Enquire enq (*store->db_read_only()); + + enq.set_query (query); + + Xapian::MSet mset (enq.get_mset (0,1)); + if (mset.empty()) + throw MuStoreError (MU_ERROR_NO_MATCHES, + "message not found"); + + return *mset.begin(); + + } MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(err, MU_ERROR_XAPIAN, + MU_STORE_INVALID_DOCID); +} + + time_t mu_store_get_timestamp (MuStore *store, const char* msgpath, GError **err) diff --git a/src/mu-store-write.cc b/src/mu-store-write.cc index fc0100e0..809e5219 100644 --- a/src/mu-store-write.cc +++ b/src/mu-store-write.cc @@ -557,41 +557,37 @@ each_contact_info (MuMsgContact *contact, MsgDoc *msgdoc) } +Xapian::Document +doc_from_message (MuStore *store, MuMsg *msg) +{ + Xapian::Document doc; + MsgDoc docinfo = {&doc, msg, store}; + + mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_terms_values, &docinfo); + /* also store the contact-info as separate terms */ + mu_msg_contact_foreach (msg, (MuMsgContactForeachFunc)each_contact_info, + &docinfo); + return doc; +} + + unsigned -mu_store_add_msg (MuStore *store, MuMsg *msg, gboolean replace, - GError **err) +mu_store_add_msg (MuStore *store, MuMsg *msg, GError **err) { g_return_val_if_fail (store, MU_STORE_INVALID_DOCID); g_return_val_if_fail (msg, MU_STORE_INVALID_DOCID); try { - Xapian::Document newdoc; Xapian::docid id; - MsgDoc msgdoc = { &newdoc, msg, store }; - const std::string uid(store->get_message_uid(msg)); + Xapian::Document doc (doc_from_message(store, msg)); + const std::string uid (store->get_uid_term(mu_msg_get_path(msg))); if (!store->in_transaction()) store->begin_transaction(); - /* we must add a unique term, so we can replace - * matching documents */ - newdoc.add_term (uid); - mu_msg_field_foreach - ((MuMsgFieldForEachFunc)add_terms_values, &msgdoc); - /* also store the contact-info as separate terms */ - mu_msg_contact_foreach - (msg, - (MuMsgContactForeachFunc)each_contact_info, - &msgdoc); - - /* add_document is slightly - faster, we can use it when - * we know the document does not exist yet, eg., in - * case of a rebuild */ - if (replace) /* we replace all existing documents for this file */ - id = store->db_writable()->replace_document (uid, newdoc); - else - id = store->db_writable()->add_document (newdoc); + /* note, this will replace any other messages for this path */ + doc.add_term (uid); + id = store->db_writable()->replace_document (uid, doc); if (store->inc_processed() % store->batch_size() == 0) store->commit_transaction(); @@ -607,6 +603,36 @@ mu_store_add_msg (MuStore *store, MuMsg *msg, gboolean replace, } +unsigned +mu_store_update_msg (MuStore *store, unsigned docid, MuMsg *msg, GError **err) +{ + g_return_val_if_fail (store, MU_STORE_INVALID_DOCID); + g_return_val_if_fail (msg, MU_STORE_INVALID_DOCID); + g_return_val_if_fail (docid != 0, MU_STORE_INVALID_DOCID); + + try { + Xapian::Document doc (doc_from_message(store, msg)); + + if (!store->in_transaction()) + store->begin_transaction(); + + store->db_writable()->replace_document (docid, doc); + + if (store->inc_processed() % store->batch_size() == 0) + store->commit_transaction(); + + return docid; + + } MU_XAPIAN_CATCH_BLOCK_G_ERROR (err, MU_ERROR_XAPIAN_STORE_FAILED); + + if (store->in_transaction()) + store->rollback_transaction(); + + return MU_STORE_INVALID_DOCID; +} + + + unsigned mu_store_add_path (MuStore *store, const char *path, GError **err) { @@ -621,7 +647,7 @@ mu_store_add_path (MuStore *store, const char *path, GError **err) if (!msg) return MU_STORE_INVALID_DOCID; - docid = mu_store_add_msg (store, msg, TRUE, err); + docid = mu_store_add_msg (store, msg, err); mu_msg_unref (msg); return docid; @@ -644,9 +670,7 @@ mu_store_remove_path (MuStore *store, const char *msgpath) g_return_val_if_fail (msgpath, FALSE); try { - const std::string uid (store->get_message_uid (msgpath)); - - store->db_writable()->delete_document (uid); + store->db_writable()->delete_document (store->get_uid_term (msgpath)); store->inc_processed(); return TRUE;