diff --git a/construct/construct.cc b/construct/construct.cc index f3ea2ac8e..c7de5012d 100644 --- a/construct/construct.cc +++ b/construct/construct.cc @@ -38,6 +38,7 @@ bool yes6; bool norun; bool read_only; bool write_avoid; +bool slave; std::array smoketest; bool soft_assert; bool nomatrix; @@ -70,6 +71,7 @@ lgetopt opts[] { "norun", &norun, lgetopt::BOOL, "[debug & testing only] Initialize but never run the event loop" }, { "ro", &read_only, lgetopt::BOOL, "Read-only mode. No writes to database allowed" }, { "wa", &write_avoid, lgetopt::BOOL, "Like read-only mode, but writes permitted if triggered" }, + { "slave", &slave, lgetopt::BOOL, "Like read-only mode; allows multiple instances of server" }, { "smoketest", &smoketest[0], lgetopt::BOOL, "Starts and stops the daemon to return success" }, { "sassert", &soft_assert, lgetopt::BOOL, "Softens assertion effects in debug mode" }, { "nomatrix", &nomatrix, lgetopt::BOOL, "Prevent loading the matrix application module" }, @@ -483,6 +485,9 @@ applyargs() if(read_only) ircd::read_only.set("true"); + if(slave) + ircd::db::open_slave.set("true"); + // read_only implies write_avoid. if(write_avoid || read_only) ircd::write_avoid.set("true"); diff --git a/include/ircd/db/database.h b/include/ircd/db/database.h index 3da318774..5dca5d07b 100644 --- a/include/ircd/db/database.h +++ b/include/ircd/db/database.h @@ -19,6 +19,7 @@ namespace ircd::db extern conf::item open_check; extern conf::item open_recover; extern conf::item open_repair; + extern conf::item open_slave; extern conf::item auto_compact; // General information @@ -53,6 +54,7 @@ namespace ircd::db void bgcancel(database &, const bool &blocking = true); void bgcontinue(database &); void bgpause(database &); + void refresh(database &); void resume(database &); void check(database &, const string_view &file); void check(database &); @@ -105,7 +107,7 @@ struct ircd::db::database uint64_t checkpoint; std::string path; std::string optstr; - bool fsck, read_only; + bool fsck, slave, read_only; std::shared_ptr env; std::shared_ptr stats; std::shared_ptr logger; diff --git a/ircd/db.cc b/ircd/db.cc index b7984f322..f44674b16 100644 --- a/ircd/db.cc +++ b/ircd/db.cc @@ -453,6 +453,17 @@ ircd::db::auto_compact { "persist", false }, }; +/// Conf item dictates whether databases will be opened in slave mode; this +/// is a recent feature of RocksDB which may not be available. It allows two +/// instances of a database, so long as only one is not opened as a slave. +decltype(ircd::db::open_slave) +ircd::db::open_slave +{ + { "name", "ircd.db.open.slave" }, + { "default", false }, + { "persist", false }, +}; + void ircd::db::sync(database &d) { @@ -647,6 +658,27 @@ ircd::db::resume(database &d) }; } +void +ircd::db::refresh(database &d) +{ + assert(d.d); + + throw_on_error + { + #ifdef IRCD_DB_HAS_SECONDARY + d.d->TryCatchUpWithPrimary() + #else + rocksdb::Status::NotSupported(slice("Slave mode not supported by this RocksDB"_sv)) + #endif + }; + + log::debug + { + log, "[%s] Caught up with primary database.", + name(d) + }; +} + void ircd::db::bgpause(database &d) { @@ -1170,6 +1202,10 @@ try { db::open_repair } +,slave +{ + db::open_slave +} ,read_only { ircd::read_only @@ -1480,7 +1516,16 @@ try // Open DB into ptr rocksdb::DB *ptr; - if(read_only) + if(slave) + throw_on_error + { + #ifdef IRCD_DB_HAS_SECONDARY + rocksdb::DB::OpenAsSecondary(*opts, path, "/tmp/slave", columns, &handles, &ptr) + #else + rocksdb::Status::NotSupported(slice("Slave mode not supported by this RocksDB"_sv)) + #endif + }; + else if(read_only) throw_on_error { rocksdb::DB::OpenForReadOnly(*opts, path, columns, &handles, &ptr) diff --git a/ircd/db_has.h b/ircd/db_has.h index 445cd6945..70ab559bb 100644 --- a/ircd/db_has.h +++ b/ircd/db_has.h @@ -19,6 +19,12 @@ #define IRCD_DB_HAS_ENV_PRIO_USER #endif +#if ROCKSDB_MAJOR > 6 \ +|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 1) \ +|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 1 && ROCKSDB_PATCH >= 1) + #define IRCD_DB_HAS_SECONDARY +#endif + #if ROCKSDB_MAJOR > 6 \ || (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 2) \ || (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 2 && ROCKSDB_PATCH >= 2) diff --git a/modules/console.cc b/modules/console.cc index db0ed80f1..0e30c8f84 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -2834,6 +2834,35 @@ catch(const std::out_of_range &e) return true; } +bool +console_cmd__db__refresh(opt &out, const string_view &line) +try +{ + const params param{line, " ", + { + "dbname", + }}; + + const auto dbname + { + param.at(0) + }; + + auto &database + { + db::database::get(dbname) + }; + + refresh(database); + out << "done" << std::endl; + return true; +} +catch(const std::out_of_range &e) +{ + out << "No open database by that name" << std::endl; + return true; +} + bool console_cmd__db__loglevel(opt &out, const string_view &line) try