From 3086238b33dfd3587cb344e4519e9b0a78fb0bc4 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sun, 13 Feb 2022 15:22:09 +0200 Subject: [PATCH] store: expose metadata()/set_metadata() Allow for storing metadata in the database, and consider the cache. --- lib/index/mu-indexer.cc | 3 +- lib/mu-store.cc | 65 ++++++++++++++++++++++++----------------- lib/mu-store.hh | 23 +++++++++++++-- 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/lib/index/mu-indexer.cc b/lib/index/mu-indexer.cc index 92d73dc4..07cf047d 100644 --- a/lib/index/mu-indexer.cc +++ b/lib/index/mu-indexer.cc @@ -235,8 +235,7 @@ Indexer::Private::item_worker() ++progress_.updated; break; case WorkItem::Type::Dir: - store_.set_dirstamp(item.full_path, ::time(NULL), - true /*use-transaction*/); + store_.set_dirstamp(item.full_path, ::time(NULL)); break; default: g_warn_if_reached(); diff --git a/lib/mu-store.cc b/lib/mu-store.cc index 2a406262..c4a35ca8 100644 --- a/lib/mu-store.cc +++ b/lib/mu-store.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -194,10 +195,10 @@ struct Store::Private { }); } g_debug("committing transaction (n=%zu,%zu)", - transaction_size_, metadatas_.size()); + transaction_size_, metadata_cache_.size()); xapian_try([this] { writable_db().commit_transaction(); - for (auto&& mdata : metadatas_) + for (auto&& mdata : metadata_cache_) writable_db().set_metadata(mdata.first, mdata.second); transaction_size_ = 0; }); @@ -276,8 +277,7 @@ struct Store::Private { Xapian::Document new_doc_from_message(MuMsg* msg); /* metadata to write as part of a transaction commit */ - using StringPair = std::pair; - std::vector metadatas_; + std::unordered_map metadata_cache_; const bool read_only_{}; std::unique_ptr db_; @@ -485,41 +485,54 @@ Store::remove_messages(const std::vector& ids) priv_->transaction_maybe_commit(true /*force*/); } -time_t -Store::dirstamp(const std::string& path) const + +std::string +Store::metadata(const std::string& key) const { + // get metadata either from the (uncommitted) cache or from the store. + std::lock_guard guard{priv_->lock_}; - constexpr auto epoch = static_cast(0); - return xapian_try([&] { - const auto ts = priv_->db().get_metadata(path); - if (ts.empty()) - return epoch; - else - return static_cast(strtoll(ts.c_str(), NULL, 16)); - }, - epoch); + const auto it = priv_->metadata_cache_.find(key); + if (it != priv_->metadata_cache_.end()) + return it->second; + else + return xapian_try([&] { + return priv_->db().get_metadata(key); + }, ""); } void -Store::set_dirstamp(const std::string& path, time_t tstamp, bool use_transaction) +Store::set_metadata(const std::string& key, const std::string& val) { + // get metadata either from the (uncommitted) cache or from the store. + std::lock_guard guard{priv_->lock_}; - std::array data{}; + priv_->metadata_cache_.erase(key); + priv_->metadata_cache_.emplace(key, val); +} + +time_t +Store::dirstamp(const std::string& path) const +{ + constexpr auto epoch = static_cast(0); + const auto ts{metadata(path)}; + if (ts.empty()) + return epoch; + else + return static_cast(strtoll(ts.c_str(), NULL, 16)); +} + +void +Store::set_dirstamp(const std::string& path, time_t tstamp) +{ + std::array data{}; const auto len = static_cast( g_snprintf(data.data(), data.size(), "%zx", tstamp)); - /* set_metadata is not otherwise part of a "transaction" but we want it - * to be so, so a dirstamp _only_ gets updated when the messages in the - * dir are commited */ - - Private::StringPair item{path, std::string{data.data(), len}}; - if (use_transaction) - priv_->metadatas_.emplace_back(std::move(item)); - else - xapian_try([&] { priv_->writable_db().set_metadata(item.first, item.second); }); + set_metadata(path, std::string{data.data(), len}); } MuMsg* diff --git a/lib/mu-store.hh b/lib/mu-store.hh index 2b67b991..bee74df2 100644 --- a/lib/mu-store.hh +++ b/lib/mu-store.hh @@ -283,6 +283,25 @@ public: */ size_t for_each_term(const std::string& field, ForEachTermFunc func) const; + + /** + * Get the store metadata for @p key + * + * @param key the metadata key + * + * @return the metadata value or empty for none. + */ + std::string metadata(const std::string& key) const; + + + /** + * Write metadata to the store. + * + * @param key key + * @param val value + */ + void set_metadata(const std::string& key, const std::string& val); + /** * Get the timestamp for some message, or 0 if not found * @@ -306,10 +325,8 @@ public: * * @param path a filesystem path * @param tstamp the timestamp for that path - * @param whether to do this as part of a transaction */ - void set_dirstamp(const std::string& path, time_t tstamp, - bool use_transaction = false); + void set_dirstamp(const std::string& path, time_t tstamp); /** * Get the number of documents in the document database