diff --git a/lib/mu-store.cc b/lib/mu-store.cc index 375e0a6d..817e9b5a 100644 --- a/lib/mu-store.cc +++ b/lib/mu-store.cc @@ -303,44 +303,31 @@ Store::Private::find_message_unlocked(Store::Id docid) const Store::Store(const std::string& path, Store::Options opts) : priv_{std::make_unique(path, none_of(opts & Store::Options::Writable))} { - if (properties().schema_version == ExpectedSchemaVersion) - return; // all is good. + if (none_of(opts & Store::Options::Writable) && + any_of(opts & Store::Options::ReInit)) + throw Mu::Error(Error::Code::InvalidArgument, + "Options::ReInit requires Options::Writable"); - // Now, it seems the schema versions do not match; shall we automatically - // update? - - if (none_of(opts & Store::Options::AutoUpgrade)) { - // not allowed to auto-upgrade, so we give up. - throw Mu::Error(Error::Code::SchemaMismatch, - "expected schema-version %s, but got %s; " - "cannot auto-upgrade; please use 'mu init'", - ExpectedSchemaVersion, - properties().schema_version.c_str()); + if (any_of(opts & Store::Options::ReInit)) { + /* user wants to re-initialize an existing store */ + Config conf{}; + conf.batch_size = properties().batch_size; + conf.max_message_size = properties().max_message_size; + const auto root_maildir{properties().root_maildir}; + const auto addrs{properties().personal_addresses}; + /* close the old one */ + this->priv_.reset(); + /* and create a new one. */ + Store new_store(path, root_maildir, addrs, conf); + this->priv_ = std::move(new_store.priv_); } - // Okay, let's attempt an auto-upgrade. - g_info("attempt reinit database from schema %s --> %s", - properties().schema_version.c_str(), ExpectedSchemaVersion); - - Config conf; - conf.batch_size = properties().batch_size; - conf.max_message_size = properties().max_message_size; - - priv_.reset(); - priv_ = std::make_unique(path, - properties().root_maildir, - properties().personal_addresses, - conf); - // Now let's try again. - priv_.reset(); - priv_ = std::make_unique(path, none_of(opts & Store::Options::Writable)); + /* otherwise, the schema version should match. */ if (properties().schema_version != ExpectedSchemaVersion) - // Nope, we failed. throw Mu::Error(Error::Code::SchemaMismatch, - "failed to auto-upgrade from %s to %s; " - "please use 'mu init'", - properties().schema_version.c_str(), - ExpectedSchemaVersion); + "expected schema-version %s, but got %s", + ExpectedSchemaVersion, + properties().schema_version.c_str()); } Store::Store(const std::string& path, diff --git a/lib/mu-store.hh b/lib/mu-store.hh index 49b172ae..0a745a6f 100644 --- a/lib/mu-store.hh +++ b/lib/mu-store.hh @@ -45,15 +45,11 @@ public: /** * Configuration options. - * - * @param path - * @param readonly */ enum struct Options { - None = 0, /**< No specific options */ - Writable = 1 << 0, /**< Open in writable mode */ - AutoUpgrade = 1 << 1, /**< automatically re-initialize - * versions do not match */ + None = 0, /**< No specific options */ + Writable = 1 << 0, /**< Open in writable mode */ + ReInit = 1 << 1, /**< Re-initialize based on existing */ }; /** @@ -62,7 +58,7 @@ public: * @param path path to the database * @param options startup options * - * A store or an error. + * @return A store or an error. */ static Result make(const std::string& path, Options opts=Options::None) noexcept try { @@ -93,6 +89,8 @@ public: * @param personal_addresses addresses that should be recognized as * 'personal' for identifying personal messages. * @param config a configuration object + * + * @return a store or an error */ static Result make_new(const std::string& path, const std::string& maildir, @@ -448,6 +446,7 @@ private: */ Store(const std::string& path, Options opts=Options::None); + /** * Construct a store for a not-yet-existing document database * diff --git a/lib/tests/test-mu-store.cc b/lib/tests/test-mu-store.cc index 1a140e30..0de724f0 100644 --- a/lib/tests/test-mu-store.cc +++ b/lib/tests/test-mu-store.cc @@ -53,6 +53,62 @@ test_store_ctor_dtor() store->properties().schema_version.c_str()); } + + +static void +test_store_reinit() +{ + TempDir tempdir; + { + Store::Config conf{}; + conf.max_message_size = 1234567; + conf.batch_size = 7654321; + + StringVec my_addresses{ "foo@example.com", "bar@example.com" }; + + auto store{Store::make_new(tempdir.path(), MuTestMaildir, my_addresses, conf)}; + assert_valid_result(store); + + g_assert_true(store->empty()); + g_assert_cmpuint(0, ==, store->size()); + + g_assert_cmpstr(MU_STORE_SCHEMA_VERSION, ==, + store->properties().schema_version.c_str()); + + const auto msgpath{MuTestMaildir + "/cur/1283599333.1840_11.cthulhu!2,"}; + const auto id = store->add_message(msgpath); + assert_valid_result(id); + g_assert_true(store->contains_message(msgpath)); + g_assert_cmpuint(store->size(), ==, 1); + } + + //now let's reinitialize it. + { + auto store{Store::make(tempdir.path(), + Store::Options::Writable|Store::Options::ReInit)}; + + assert_valid_result(store); + g_assert_true(store->empty()); + + assert_equal(store->properties().database_path, tempdir.path()); + g_assert_cmpuint(store->properties().batch_size,==,7654321); + g_assert_cmpuint(store->properties().max_message_size,==,1234567); + + const auto addrs{store->properties().personal_addresses}; + g_assert_cmpuint(addrs.size(),==,2); + g_assert_true(seq_some(addrs, [](auto&& a){return a=="foo@example.com";})); + g_assert_true(seq_some(addrs, [](auto&& a){return a=="bar@example.com";})); + + const auto msgpath{MuTestMaildir + "/cur/1283599333.1840_11.cthulhu!2,"}; + const auto id = store->add_message(msgpath); + assert_valid_result(id); + g_assert_true(store->contains_message(msgpath)); + g_assert_cmpuint(store->size(), ==, 1); + } +} + + + static void test_store_add_count_remove() { @@ -69,8 +125,6 @@ test_store_add_count_remove() g_assert_cmpuint(store->size(), ==, 1); g_assert_true(store->contains_message(msgpath)); - g_assert_true(store->contains_message(msgpath)); - const auto id2 = store->add_message(MuTestMaildir2 + "/bar/cur/mail3"); g_assert_false(!!id2); // wrong maildir. store->commit(); @@ -346,13 +400,13 @@ test_store_fail() } } - int main(int argc, char* argv[]) { mu_test_init(&argc, &argv); g_test_add_func("/store/ctor-dtor", test_store_ctor_dtor); + g_test_add_func("/store/reinit", test_store_reinit); g_test_add_func("/store/add-count-remove", test_store_add_count_remove); g_test_add_func("/store/message/mailing-list", test_message_mailing_list);