store: support in-memory database
For testing, this is faster / and doesn't pollute the file system.
This commit is contained in:
@ -106,7 +106,7 @@ struct Store::Private {
|
|||||||
|
|
||||||
#define LOCKED std::lock_guard<std::mutex> l(lock_);
|
#define LOCKED std::lock_guard<std::mutex> l(lock_);
|
||||||
|
|
||||||
enum struct XapianOpts {ReadOnly, Open, CreateOverwrite };
|
enum struct XapianOpts {ReadOnly, Open, CreateOverwrite, InMemory };
|
||||||
|
|
||||||
Private (const std::string& path, bool readonly):
|
Private (const std::string& path, bool readonly):
|
||||||
read_only_{readonly},
|
read_only_{readonly},
|
||||||
@ -128,6 +128,14 @@ struct Store::Private {
|
|||||||
writable_db().begin_transaction();
|
writable_db().begin_transaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Private (const std::string& root_maildir,
|
||||||
|
const StringVec& personal_addresses, const Store::Config& conf):
|
||||||
|
read_only_{false},
|
||||||
|
db_{make_xapian_db("", XapianOpts::InMemory)},
|
||||||
|
mdata_{init_metadata(conf, "", root_maildir, personal_addresses)},
|
||||||
|
contacts_{"", mdata_.personal_addresses} {
|
||||||
|
}
|
||||||
|
|
||||||
~Private() try {
|
~Private() try {
|
||||||
g_debug("closing store @ %s", mdata_.database_path.c_str());
|
g_debug("closing store @ %s", mdata_.database_path.c_str());
|
||||||
if (!read_only_) {
|
if (!read_only_) {
|
||||||
@ -145,6 +153,8 @@ struct Store::Private {
|
|||||||
return std::make_unique<Xapian::WritableDatabase>(db_path, Xapian::DB_OPEN);
|
return std::make_unique<Xapian::WritableDatabase>(db_path, Xapian::DB_OPEN);
|
||||||
case XapianOpts::CreateOverwrite:
|
case XapianOpts::CreateOverwrite:
|
||||||
return std::make_unique<Xapian::WritableDatabase>(db_path, Xapian::DB_CREATE_OR_OVERWRITE);
|
return std::make_unique<Xapian::WritableDatabase>(db_path, Xapian::DB_CREATE_OR_OVERWRITE);
|
||||||
|
case XapianOpts::InMemory:
|
||||||
|
return std::make_unique<Xapian::WritableDatabase>(std::string{}, Xapian::DB_BACKEND_INMEMORY);
|
||||||
default:
|
default:
|
||||||
throw std::logic_error ("invalid xapian options");
|
throw std::logic_error ("invalid xapian options");
|
||||||
}
|
}
|
||||||
@ -174,6 +184,8 @@ struct Store::Private {
|
|||||||
void commit () try {
|
void commit () try {
|
||||||
g_debug("committing %zu modification(s)", dirtiness_);
|
g_debug("committing %zu modification(s)", dirtiness_);
|
||||||
dirtiness_ = 0;
|
dirtiness_ = 0;
|
||||||
|
if (mdata_.in_memory)
|
||||||
|
return; // not supported in the in-memory backend.
|
||||||
writable_db().commit_transaction();
|
writable_db().commit_transaction();
|
||||||
writable_db().begin_transaction();
|
writable_db().begin_transaction();
|
||||||
} MU_XAPIAN_CATCH_BLOCK;
|
} MU_XAPIAN_CATCH_BLOCK;
|
||||||
@ -200,6 +212,7 @@ struct Store::Private {
|
|||||||
|
|
||||||
mdata.batch_size = ::atoll(db().get_metadata(BatchSizeKey).c_str());
|
mdata.batch_size = ::atoll(db().get_metadata(BatchSizeKey).c_str());
|
||||||
mdata.max_message_size = ::atoll(db().get_metadata(MaxMessageSizeKey).c_str());
|
mdata.max_message_size = ::atoll(db().get_metadata(MaxMessageSizeKey).c_str());
|
||||||
|
mdata.in_memory = db_path.empty();
|
||||||
|
|
||||||
mdata.root_maildir = db().get_metadata(RootMaildirKey);
|
mdata.root_maildir = db().get_metadata(RootMaildirKey);
|
||||||
mdata.personal_addresses = Mu::split(db().get_metadata(PersonalAddressesKey),",");
|
mdata.personal_addresses = Mu::split(db().get_metadata(PersonalAddressesKey),",");
|
||||||
@ -288,6 +301,13 @@ Store::Store (const std::string& path, const std::string& maildir,
|
|||||||
priv_{std::make_unique<Private>(path, maildir, personal_addresses, conf)}
|
priv_{std::make_unique<Private>(path, maildir, personal_addresses, conf)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Store::Store (const std::string& maildir,
|
||||||
|
const StringVec& personal_addresses, const Config& conf):
|
||||||
|
priv_{std::make_unique<Private>(maildir, personal_addresses, conf)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
Store::~Store() = default;
|
Store::~Store() = default;
|
||||||
|
|
||||||
const Store::Metadata&
|
const Store::Metadata&
|
||||||
@ -307,7 +327,6 @@ const Xapian::Database&
|
|||||||
Store::database() const
|
Store::database() const
|
||||||
{
|
{
|
||||||
return priv_->db();
|
return priv_->db();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Xapian::WritableDatabase&
|
Xapian::WritableDatabase&
|
||||||
@ -370,7 +389,6 @@ maildir_from_path (const std::string& root, const std::string& path)
|
|||||||
return mdir;
|
return mdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
Store::add_message (const std::string& path)
|
Store::add_message (const std::string& path)
|
||||||
{
|
{
|
||||||
@ -395,7 +413,6 @@ Store::add_message (const std::string& path)
|
|||||||
return docid;
|
return docid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Store::update_message (MuMsg *msg, unsigned docid)
|
Store::update_message (MuMsg *msg, unsigned docid)
|
||||||
{
|
{
|
||||||
@ -573,9 +590,6 @@ Store::for_each_term (const std::string& field, Store::ForEachTermFunc func) con
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Store::commit () try
|
Store::commit () try
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright (C) 2020 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
** Copyright (C) 2021 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
**
|
**
|
||||||
** This program is free software; you can redistribute it and/or modify it
|
** 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 the
|
** under the terms of the GNU General Public License as published by the
|
||||||
@ -69,6 +69,16 @@ public:
|
|||||||
Store (const std::string& path, const std::string& maildir,
|
Store (const std::string& path, const std::string& maildir,
|
||||||
const StringVec& personal_addresses, const Config& conf);
|
const StringVec& personal_addresses, const Config& conf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an in-memory, writeable store for testing
|
||||||
|
*
|
||||||
|
* @param maildir maildir to use for this store
|
||||||
|
* @param personal_addresses addresses that should be recognized as
|
||||||
|
* 'personal' for identifying personal messages.
|
||||||
|
*/
|
||||||
|
Store (const std::string& maildir,
|
||||||
|
const StringVec& personal_addresses, const Config& conf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DTOR
|
* DTOR
|
||||||
*/
|
*/
|
||||||
@ -81,6 +91,7 @@ public:
|
|||||||
|
|
||||||
bool read_only; /**< Is the database opened read-only? */
|
bool read_only; /**< Is the database opened read-only? */
|
||||||
size_t batch_size; /**< Maximum database transaction batch size */
|
size_t batch_size; /**< Maximum database transaction batch size */
|
||||||
|
bool in_memory; /**< Is this an in-memory database (for testing)?*/
|
||||||
|
|
||||||
std::string root_maildir; /**< Absolute path to the top-level maildir */
|
std::string root_maildir; /**< Absolute path to the top-level maildir */
|
||||||
|
|
||||||
@ -117,7 +128,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
Xapian::WritableDatabase& writable_database();
|
Xapian::WritableDatabase& writable_database();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Indexer associated with this store. It is an error to call
|
* Get the Indexer associated with this store. It is an error to call
|
||||||
* this on a read-only store.
|
* this on a read-only store.
|
||||||
|
|||||||
@ -79,14 +79,46 @@ test_store_add_count_remove ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_store_add_count_remove_in_memory ()
|
||||||
|
{
|
||||||
|
Mu::Store store{MuTestMaildir, {}, {}};
|
||||||
|
|
||||||
|
g_assert_true (store.metadata().in_memory);
|
||||||
|
|
||||||
|
const auto id1 = store.add_message(MuTestMaildir + "/cur/1283599333.1840_11.cthulhu!2,");
|
||||||
|
|
||||||
|
g_assert_cmpuint(id1, !=, Mu::Store::InvalidId);
|
||||||
|
|
||||||
|
g_assert_cmpuint(store.size(), ==, 1);
|
||||||
|
g_assert_true(store.contains_message(MuTestMaildir + "/cur/1283599333.1840_11.cthulhu!2,"));
|
||||||
|
|
||||||
|
g_assert_cmpuint(store.add_message(MuTestMaildir2 + "/bar/cur/mail3"),
|
||||||
|
!=, Mu::Store::InvalidId);
|
||||||
|
|
||||||
|
g_assert_cmpuint(store.size(), ==, 2);
|
||||||
|
g_assert_true(store.contains_message(MuTestMaildir2 + "/bar/cur/mail3"));
|
||||||
|
|
||||||
|
store.remove_message(id1);
|
||||||
|
g_assert_cmpuint(store.size(), ==, 1);
|
||||||
|
g_assert_false(store.contains_message(MuTestMaildir + "/cur/1283599333.1840_11.cthulhu!2,"));
|
||||||
|
|
||||||
|
store.remove_message (MuTestMaildir2 + "/bar/cur/mail3");
|
||||||
|
g_assert_true(store.empty());
|
||||||
|
g_assert_false(store.contains_message(MuTestMaildir2 + "/bar/cur/mail3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
g_test_init (&argc, &argv, NULL);
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
/* mu_runtime_init/uninit */
|
/* mu_runtime_init/uninit */
|
||||||
g_test_add_func ("/mu-store/ctor-dtor", test_store_ctor_dtor);
|
g_test_add_func ("/store/ctor-dtor", test_store_ctor_dtor);
|
||||||
g_test_add_func ("/mu-store/add-count-remove", test_store_add_count_remove);
|
g_test_add_func ("/store/add-count-remove", test_store_add_count_remove);
|
||||||
|
g_test_add_func ("/store/in-memory/add-count-remove", test_store_add_count_remove_in_memory);
|
||||||
|
|
||||||
// if (!g_test_verbose())
|
// if (!g_test_verbose())
|
||||||
// g_log_set_handler (NULL,
|
// g_log_set_handler (NULL,
|
||||||
|
|||||||
Reference in New Issue
Block a user