From 49637dbc3a2f1ad09f75cda91eab9f5fbe9bde74 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Mon, 18 Oct 2021 12:22:26 +0300 Subject: [PATCH] lib: replace CATCH_BLOCK macros with template magic --- lib/mu-msg-doc.cc | 37 +++----- lib/mu-query-match-deciders.cc | 14 +-- lib/mu-query-results.hh | 50 +++++----- lib/mu-query.cc | 28 +++--- lib/mu-store.cc | 167 ++++++++++++++++----------------- lib/utils/mu-utils.hh | 99 +++++-------------- 6 files changed, 172 insertions(+), 223 deletions(-) diff --git a/lib/mu-msg-doc.cc b/lib/mu-msg-doc.cc index 0df4f91d..ea555b48 100644 --- a/lib/mu-msg-doc.cc +++ b/lib/mu-msg-doc.cc @@ -46,25 +46,22 @@ MuMsgDoc* Mu::mu_msg_doc_new (XapianDocument *doc, GError **err) { g_return_val_if_fail (doc, NULL); - - try { + MuMsgDoc *mdoc = xapian_try([&]{ return new MuMsgDoc ((Xapian::Document*)doc); + }, (MuMsgDoc*)nullptr); - } MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(err, MU_ERROR_XAPIAN, NULL); - - return FALSE; + if (!mdoc) + mu_util_g_set_error (err, MU_ERROR_INTERNAL, + "failed to create message doc"); + return mdoc; } void Mu::mu_msg_doc_destroy (MuMsgDoc *self) { - try { - delete self; - - } MU_XAPIAN_CATCH_BLOCK; + xapian_try([&]{delete self;}); } - gchar* Mu::mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid) { @@ -78,14 +75,12 @@ Mu::mu_msg_doc_get_str_field (MuMsgDoc *self, MuMsgFieldId mfid) // have to convert to numbers first, esp. when it's a date // time_t) - try { + return xapian_try([&]{ const std::string s (self->doc().get_value(mfid)); return s.empty() ? NULL : g_strdup (s.c_str()); - - } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL); + },(gchar*)nullptr); } - GSList* Mu::mu_msg_doc_get_str_list_field (MuMsgDoc *self, MuMsgFieldId mfid) { @@ -93,12 +88,11 @@ Mu::mu_msg_doc_get_str_list_field (MuMsgDoc *self, MuMsgFieldId mfid) g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL); g_return_val_if_fail (mu_msg_field_is_string_list(mfid), NULL); - try { + return xapian_try([&]{ /* return a comma-separated string as a GSList */ const std::string s (self->doc().get_value(mfid)); return s.empty() ? NULL : mu_str_to_list(s.c_str(),',',TRUE); - - } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL); + },(GSList*)nullptr); } @@ -109,17 +103,16 @@ Mu::mu_msg_doc_get_num_field (MuMsgDoc *self, MuMsgFieldId mfid) g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), -1); g_return_val_if_fail (mu_msg_field_is_numeric(mfid), -1); - try { + return xapian_try([&]{ const std::string s (self->doc().get_value(mfid)); if (s.empty()) - return 0; + return (gint64)0; else if (mfid == MU_MSG_FIELD_ID_DATE || mfid == MU_MSG_FIELD_ID_SIZE) - return strtol (s.c_str(), NULL, 10); + return static_cast(strtol (s.c_str(), NULL, 10)); else { return static_cast (Xapian::sortable_unserialise(s)); } - - } MU_XAPIAN_CATCH_BLOCK_RETURN(-1); + }, (gint64)-1); } diff --git a/lib/mu-query-match-deciders.cc b/lib/mu-query-match-deciders.cc index c7e91049..5fa69168 100644 --- a/lib/mu-query-match-deciders.cc +++ b/lib/mu-query-match-deciders.cc @@ -98,12 +98,14 @@ struct MatchDecider : public Xapian::MatchDecider { DeciderInfo & decider_info_; private: - Option opt_string (const Xapian::Document &doc, MuMsgFieldId id) const noexcept - try { - auto &&val{doc.get_value (id)}; - return val.empty() ? Nothing : Some (val); - } - MU_XAPIAN_CATCH_BLOCK_RETURN (Nothing); + Option opt_string (const Xapian::Document &doc, MuMsgFieldId id) + const noexcept { + std::string val = xapian_try([&]{ return doc.get_value (id);}, std::string{""}); + if (val.empty()) + return Nothing; + else + return Some(std::move(val)); + } }; struct MatchDeciderLeader final : public MatchDecider { diff --git a/lib/mu-query-results.hh b/lib/mu-query-results.hh index 1cc157c5..db92f854 100644 --- a/lib/mu-query-results.hh +++ b/lib/mu-query-results.hh @@ -280,12 +280,14 @@ class QueryResultsIterator * * @return the value */ - Option opt_string (MuMsgFieldId id) const noexcept - try { - auto &&val{document().get_value (id)}; - return val.empty() ? Nothing : Some (val); - } - MU_XAPIAN_CATCH_BLOCK_RETURN (Nothing); + Option opt_string (MuMsgFieldId id) const noexcept { + std::string empty; + std::string val = xapian_try([&]{ return document().get_value (id);}, empty); + if (val.empty()) + return Nothing; + else + return Some(std::move(val)); + } /** * Get the Query match info for this message. @@ -306,27 +308,27 @@ class QueryResultsIterator /** * get the corresponding MuMsg for this iter; this instance is owned by * @this, and becomes invalid when iterating to the next, or @this is -k * destroyed.; it's a 'floating' reference. + * destroyed.; it's a 'floating' reference. * * @return a MuMsg* or NUL in case of error */ - MuMsg *floating_msg() G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT - try { - auto docp{reinterpret_cast (new Xapian::Document (document()))}; - GError *err{}; - g_clear_pointer (&msg_, mu_msg_unref); - if (!(msg_ = mu_msg_new_from_doc (docp, &err))) { - delete docp; - g_warning ("failed to crate message for %s: %s", - path().value_or ("").c_str(), - err ? err->message : "somethng went wrong"); - g_clear_error (&err); - } - - return msg_; - } - MU_XAPIAN_CATCH_BLOCK_RETURN (NULL); - + MuMsg *floating_msg() G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT { + return xapian_try([&]{ + auto docp{reinterpret_cast ( + new Xapian::Document (document()))}; + GError *err{}; + g_clear_pointer (&msg_, mu_msg_unref); + if (!(msg_ = mu_msg_new_from_doc (docp, &err))) { + delete docp; + g_warning ("failed to crate message for %s: %s", + path().value_or ("").c_str(), + err ? err->message : "somethng went wrong"); + g_clear_error (&err); + } + return msg_; + }, (MuMsg*)NULL); + } + private: Xapian::MSetIterator mset_it_; QueryMatches & query_matches_; diff --git a/lib/mu-query.cc b/lib/mu-query.cc index 59e99734..f779c6de 100644 --- a/lib/mu-query.cc +++ b/lib/mu-query.cc @@ -174,10 +174,14 @@ Query::Private::run_singular (const std::string& expr, MuMsgFieldId sortfieldid, } static Option -opt_string(const Xapian::Document& doc, MuMsgFieldId id) noexcept try { - auto&& val{doc.get_value(id)}; - return val.empty() ? Nothing : Some(val); -} MU_XAPIAN_CATCH_BLOCK_RETURN (Nothing); +opt_string (const Xapian::Document &doc, MuMsgFieldId id) noexcept +{ + std::string val = xapian_try([&]{ return doc.get_value (id);}, std::string{""}); + if (val.empty()) + return Nothing; + else + return Some(std::move(val)); +} Option Query::Private::run_related (const std::string& expr, MuMsgFieldId sortfieldid, @@ -259,15 +263,15 @@ Query::run (const std::string& expr, MuMsgFieldId sortfieldid, size_t -Query::count (const std::string& expr) const try +Query::count (const std::string& expr) const { - const auto enq{priv_->make_enquire(expr, MU_MSG_FIELD_ID_NONE, {})}; - auto mset{enq.get_mset(0, priv_->store_.size())}; - mset.fetch(); - - return mset.size(); - -}MU_XAPIAN_CATCH_BLOCK_RETURN (0); + return xapian_try([&] { + const auto enq{priv_->make_enquire(expr, MU_MSG_FIELD_ID_NONE, {})}; + auto mset{enq.get_mset(0, priv_->store_.size())}; + mset.fetch(); + return mset.size(); + }, 0); +} diff --git a/lib/mu-store.cc b/lib/mu-store.cc index a3b5c9f9..11d95fd8 100644 --- a/lib/mu-store.cc +++ b/lib/mu-store.cc @@ -115,7 +115,7 @@ struct Store::Private { contacts_{db().get_metadata(ContactsKey), mdata_.personal_addresses} { if (!readonly) - writable_db().begin_transaction(); + begin_transaction(); } Private (const std::string& path, const std::string& root_maildir, @@ -125,7 +125,7 @@ struct Store::Private { mdata_{init_metadata(conf, path, root_maildir, personal_addresses)}, contacts_{"", mdata_.personal_addresses} { - writable_db().begin_transaction(); + begin_transaction(); } Private (const std::string& root_maildir, @@ -136,25 +136,32 @@ struct Store::Private { contacts_{"", mdata_.personal_addresses} { } - ~Private() try { + ~Private() { g_debug("closing store @ %s", mdata_.database_path.c_str()); if (!read_only_) { - writable_db().set_metadata (ContactsKey, contacts_.serialize()); - commit(); + xapian_try([&]{ + writable_db().set_metadata (ContactsKey, contacts_.serialize()); + commit(); + }); } - } MU_XAPIAN_CATCH_BLOCK; + } - std::unique_ptr make_xapian_db (const std::string db_path, XapianOpts opts) try { + std::unique_ptr make_xapian_db ( + const std::string db_path, XapianOpts opts) try { + in_transaction_ = false; + switch (opts) { case XapianOpts::ReadOnly: return std::make_unique(db_path); case XapianOpts::Open: return std::make_unique(db_path, Xapian::DB_OPEN); case XapianOpts::CreateOverwrite: - return std::make_unique(db_path, Xapian::DB_CREATE_OR_OVERWRITE); + return std::make_unique( + db_path, Xapian::DB_CREATE_OR_OVERWRITE); case XapianOpts::InMemory: - return std::make_unique(std::string{}, Xapian::DB_BACKEND_INMEMORY); + return std::make_unique( + std::string{}, Xapian::DB_BACKEND_INMEMORY); default: throw std::logic_error ("invalid xapian options"); } @@ -176,22 +183,32 @@ struct Store::Private { return dynamic_cast(*db_.get()); } - void dirty () try { + void dirty () { if (++dirtiness_ > mdata_.batch_size) - commit(); - } MU_XAPIAN_CATCH_BLOCK; + xapian_try([this]{commit();}); + } - void commit () try { + void begin_transaction() noexcept { + g_return_if_fail (!in_transaction_); + xapian_try([this]{ + writable_db().begin_transaction(); + in_transaction_ = true; + }); + } + + void commit () noexcept { g_debug("committing %zu modification(s)", dirtiness_); dirtiness_ = 0; if (mdata_.in_memory) return; // not supported in the in-memory backend. - if (in_transaction_) - writable_db().commit_transaction(); - writable_db().begin_transaction(); - in_transaction_ = true; - } MU_XAPIAN_CATCH_BLOCK; - + xapian_try([this]{ + if (in_transaction_) + writable_db().commit_transaction(); + in_transaction_ = false; + begin_transaction(); + }); + } + void add_synonyms () { mu_flags_foreach ((MuFlagsForeachFunc)add_synonym_for_flag, &writable_db()); @@ -250,7 +267,7 @@ struct Store::Private { return make_metadata(path); } - Xapian::docid add_or_update_msg (Xapian::docid docid, MuMsg *msg, GError **err); + Xapian::docid add_or_update_msg (Xapian::docid docid, MuMsg *msg); Xapian::Document new_doc_from_message (MuMsg *msg); const bool read_only_{}; @@ -404,11 +421,11 @@ Store::add_message (const std::string& path) throw Error{Error::Code::Message, "failed to create message: %s", gerr ? gerr->message : "something went wrong"}; - const auto docid{priv_->add_or_update_msg (0, msg, &gerr)}; + const auto docid{priv_->add_or_update_msg (0, msg)}; mu_msg_unref (msg); - if (G_UNLIKELY(docid == InvalidId)) - throw Error{Error::Code::Message, "failed to add message: %s", - gerr ? gerr->message : "something went wrong"}; + + if (G_UNLIKELY(docid == InvalidId)) + throw Error{Error::Code::Message, "failed to add message"}; g_debug ("added message @ %s; docid = %u", path.c_str(), docid); priv_->dirty(); @@ -419,14 +436,12 @@ Store::add_message (const std::string& path) bool Store::update_message (MuMsg *msg, unsigned docid) { - GError *gerr{}; - const auto docid2{priv_->add_or_update_msg (docid, msg, &gerr)}; + const auto docid2{priv_->add_or_update_msg (docid, msg)}; if (G_UNLIKELY(docid != docid2)) - throw Error{Error::Code::Internal, "failed to update message", - gerr ? gerr->message : "something went wrong"}; + throw Error{Error::Code::Internal, "failed to update message"}; - g_debug ("updated message @ %s; docid = %u", + g_debug ("updated message @ %s; docid = %u", mu_msg_get_path(msg), docid); priv_->dirty(); @@ -437,33 +452,29 @@ Store::update_message (MuMsg *msg, unsigned docid) bool Store::remove_message (const std::string& path) { - LOCKED; - - try { + return xapian_try([&]{ + LOCKED; const std::string term{(get_uid_term(path.c_str()))}; priv_->writable_db().delete_document(term); - } MU_XAPIAN_CATCH_BLOCK_RETURN (false); + g_debug ("deleted message @ %s from store", path.c_str()); + priv_->dirty(); - g_debug ("deleted message @ %s from store", path.c_str()); - priv_->dirty(); - - return true; + return true; + }, false); } void Store::remove_messages (const std::vector& ids) { - LOCKED; - - try { + xapian_try([&]{ + LOCKED; for (auto&& id: ids) { priv_->writable_db().delete_document(id); priv_->dirty(); } - - } MU_XAPIAN_CATCH_BLOCK; + }); } time_t @@ -494,9 +505,8 @@ Store::set_dirstamp (const std::string& path, time_t tstamp) MuMsg* Store::find_message (unsigned docid) const { - LOCKED; - - try { + return xapian_try([&]{ + LOCKED; Xapian::Document *doc{new Xapian::Document{priv_->db().get_document (docid)}}; GError *gerr{}; auto msg{mu_msg_new_from_doc (reinterpret_cast(doc), &gerr)}; @@ -505,48 +515,40 @@ Store::find_message (unsigned docid) const "something went wrong"); g_clear_error(&gerr); } - return msg; - - } MU_XAPIAN_CATCH_BLOCK_RETURN (nullptr); + }, (MuMsg*)nullptr); } bool Store::contains_message (const std::string& path) const { - LOCKED; - - try { + return xapian_try([&]{ + LOCKED; const std::string term (get_uid_term(path.c_str())); return priv_->db().term_exists (term); - - } MU_XAPIAN_CATCH_BLOCK_RETURN(false); + }, false); } std::size_t -Store::for_each_message_path (Store::ForEachMessageFunc func) const +Store::for_each_message_path (Store::ForEachMessageFunc msg_func) const { - LOCKED; - - size_t n{}; - - try { - Xapian::Enquire enq{priv_->db()}; - + size_t n{}; + + xapian_try([&]{ + LOCKED; + Xapian::Enquire enq{priv_->db()}; enq.set_query (Xapian::Query::MatchAll); enq.set_cutoff (0,0); Xapian::MSet matches(enq.get_mset (0, priv_->db().get_doccount())); - for (auto&& it = matches.begin(); it != matches.end(); ++it, ++n) - if (!func (*it, it.get_document().get_value(MU_MSG_FIELD_ID_PATH))) + if (!msg_func (*it, it.get_document().get_value(MU_MSG_FIELD_ID_PATH))) break; + }); - } MU_XAPIAN_CATCH_BLOCK; - - return n; + return n; } static MuMsgFieldId @@ -570,36 +572,31 @@ field_id (const std::string& field) std::size_t Store::for_each_term (const std::string& field, Store::ForEachTermFunc func) const { - LOCKED; - size_t n{}; - - try { + + xapian_try([&]{ + LOCKED; const auto id = field_id (field.c_str()); if (id == MU_MSG_FIELD_ID_NONE) - return {}; - + return; + char pfx[] = { mu_msg_field_xapian_prefix(id), '\0' }; - std::vector terms; for (auto it = priv_->db().allterms_begin(pfx); it != priv_->db().allterms_end(pfx); ++it) { if (!func(*it)) break; } - - } MU_XAPIAN_CATCH_BLOCK; + }); return n; } void -Store::commit () try +Store::commit () { - LOCKED; - priv_->commit(); - -} MU_XAPIAN_CATCH_BLOCK; + xapian_try([&]{ LOCKED; priv_->commit(); }); +} static void add_terms_values_date (Xapian::Document& doc, MuMsg *msg, MuMsgFieldId mfid) @@ -1059,11 +1056,11 @@ update_threading_info (MuMsg *msg, Xapian::Document& doc) Xapian::docid -Store::Private::add_or_update_msg (unsigned docid, MuMsg *msg, GError **err) +Store::Private::add_or_update_msg (unsigned docid, MuMsg *msg) { g_return_val_if_fail (msg, InvalidId); - - try { + + return xapian_try([&]{ Xapian::Document doc (new_doc_from_message(msg)); const std::string term (get_uid_term (mu_msg_get_path(msg))); @@ -1080,7 +1077,5 @@ Store::Private::add_or_update_msg (unsigned docid, MuMsg *msg, GError **err) writable_db().replace_document (docid, doc); return docid; - } MU_XAPIAN_CATCH_BLOCK_G_ERROR (err, MU_ERROR_XAPIAN_STORE_FAILED); - - return InvalidId; + }, InvalidId); } diff --git a/lib/utils/mu-utils.hh b/lib/utils/mu-utils.hh index 651cb266..848e200b 100644 --- a/lib/utils/mu-utils.hh +++ b/lib/utils/mu-utils.hh @@ -28,6 +28,8 @@ #include #include #include +#include +#include namespace Mu { @@ -64,8 +66,6 @@ std::string utf8_clean (const std::string& dirty); std::string remove_ctrl (const std::string& str); - - /** * Split a string in parts * @@ -245,78 +245,31 @@ private: const bool color_; }; -/** - * - * don't repeat these catch blocks everywhere... - * - */ - -#define MU_XAPIAN_CATCH_BLOCK \ - catch (const Xapian::Error &xerr) { \ - g_critical ("%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const std::runtime_error& re) { \ - g_critical ("%s: error: %s", __func__, re.what()); \ - } catch (...) { \ - g_critical ("%s: caught exception", __func__); \ - } - -#define MU_XAPIAN_CATCH_BLOCK_G_ERROR(GE,E) \ - catch (const Xapian::DatabaseLockError &xerr) { \ - mu_util_g_set_error ((GE), \ - MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK, \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const Xapian::DatabaseError &xerr) { \ - mu_util_g_set_error ((GE),MU_ERROR_XAPIAN, \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const Xapian::Error &xerr) { \ - mu_util_g_set_error ((GE),(E), \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const std::runtime_error& ex) { \ - mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ - "%s: error: %s", __func__, ex.what()); \ - \ - } catch (...) { \ - mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ - "%s: caught exception", __func__); \ - } - - -#define MU_XAPIAN_CATCH_BLOCK_RETURN(R) \ - catch (const Xapian::Error &xerr) { \ - g_critical ("%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - return (R); \ - } catch (const std::runtime_error& ex) { \ - g_critical("%s: error: %s", __func__, ex.what()); \ - return (R); \ - } catch (...) { \ - g_critical ("%s: caught exception", __func__); \ - return (R); \ - } - -#define MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(GE,E,R) \ - catch (const Xapian::Error &xerr) { \ - mu_util_g_set_error ((GE),(E), \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - return (R); \ - } catch (const std::runtime_error& ex) { \ - mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ - "%s: error: %s", __func__, ex.what()); \ - return (R); \ - } catch (...) { \ - if ((GE)&&!(*(GE))) \ - mu_util_g_set_error ((GE), \ - (MU_ERROR_INTERNAL), \ - "%s: caught exception", __func__); \ - return (R); \ - } - +template void xapian_try(Func&& func) noexcept try { + func(); +} catch (const Xapian::Error &xerr) { + g_critical ("%s: xapian error '%s'", + __func__, xerr.get_msg().c_str()); +} catch (const std::runtime_error& re) { + g_critical ("%s: error: %s", __func__, re.what()); +} catch (...) { + g_critical ("%s: caught exception", __func__); +} +template > +auto xapian_try(Func&& func, Default&& def) noexcept -> std::decay_t try { + return func(); +} catch (const Xapian::Error &xerr) { + g_critical ("%s: xapian error '%s'", + __func__, xerr.get_msg().c_str()); + return static_cast(def); +} catch (const std::runtime_error& re) { + g_critical ("%s: error: %s", __func__, re.what()); + return static_cast(def); +} catch (...) { + g_critical ("%s: caught exception", __func__); + return static_cast(def); +} /// Allow using enum structs as bitflags