From c32928981b5a6392b25592959c1028c766ec5b88 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Sat, 6 Aug 2022 00:55:55 -0700 Subject: [PATCH] ircd::m::dbs::init: Split unit; preliminary schema update vector; ctor exceptions. --- include/ircd/m/dbs/dbs.h | 11 +-- include/ircd/m/dbs/init.h | 28 ++++++++ matrix/Makefile.am | 1 + matrix/dbs.cc | 92 ------------------------ matrix/dbs_init.cc | 144 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 174 insertions(+), 102 deletions(-) create mode 100644 include/ircd/m/dbs/init.h create mode 100644 matrix/dbs_init.cc diff --git a/include/ircd/m/dbs/dbs.h b/include/ircd/m/dbs/dbs.h index ef466d65e..00b158653 100644 --- a/include/ircd/m/dbs/dbs.h +++ b/include/ircd/m/dbs/dbs.h @@ -59,6 +59,7 @@ namespace ircd::m::dbs::appendix #include "room_state_space.h" // room_id | type, state_key, depth, event_idx #include "room_joined.h" // room_id | origin, member => event_idx #include "room_head.h" // room_id | event_id => event_idx +#include "init.h" /// Options that affect the dbs::write() of an event to the transaction. struct ircd::m::dbs::write_opts @@ -193,16 +194,6 @@ enum ircd::m::dbs::appendix::index ROOM_REDACT, }; -struct ircd::m::dbs::init -{ - std::string our_dbpath; - std::string their_dbpath; - - public: - init(const string_view &servername, std::string dbopts = {}); - ~init() noexcept; -}; - // Internal utils (here for now) namespace ircd::m::dbs { diff --git a/include/ircd/m/dbs/init.h b/include/ircd/m/dbs/init.h new file mode 100644 index 000000000..30478e140 --- /dev/null +++ b/include/ircd/m/dbs/init.h @@ -0,0 +1,28 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2022 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_M_DBS_INIT_H + +struct ircd::m::dbs::init +{ + std::string our_dbpath; + std::string their_dbpath; + + private: + static bool (*update[])(void); + void apply_updates(); + void init_columns(); + void init_database(); + + public: + init(const string_view &servername, std::string dbopts = {}); + ~init() noexcept; +}; diff --git a/matrix/Makefile.am b/matrix/Makefile.am index 930456b69..5a3041a78 100644 --- a/matrix/Makefile.am +++ b/matrix/Makefile.am @@ -98,6 +98,7 @@ libircd_matrix_la_SOURCES += dbs_room_state_space.cc libircd_matrix_la_SOURCES += dbs_room_joined.cc libircd_matrix_la_SOURCES += dbs_room_head.cc libircd_matrix_la_SOURCES += dbs_desc.cc +libircd_matrix_la_SOURCES += dbs_init.cc libircd_matrix_la_SOURCES += hook.cc libircd_matrix_la_SOURCES += event.cc libircd_matrix_la_SOURCES += event_cached.cc diff --git a/matrix/dbs.cc b/matrix/dbs.cc index 72fe861c5..5b4cc5261 100644 --- a/matrix/dbs.cc +++ b/matrix/dbs.cc @@ -73,98 +73,6 @@ ircd::m::dbs::sst_write_buffer_size } }; -// -// init -// - -/// Initializes the m::dbs subsystem; sets up the events database. Held/called -/// by m::init. Most of the extern variables in m::dbs are not ready until -/// this call completes. -/// -/// We also update the fs::basepath for the database directory to include our -/// servername in the path component. The fs::base::DB setting was generated -/// during the build and install process, and is unaware of our servername -/// at runtime. This change deconflicts multiple instances of IRCd running in -/// the same installation prefix using different servernames (i.e clustering -/// on the same machine). -/// -ircd::m::dbs::init::init(const string_view &servername, - std::string dbopts) -:our_dbpath -{ - fs::path_string(fs::path_views - { - fs::base::db, servername - }) -} -,their_dbpath -{ - fs::base::db -} -{ - // NOTE that this is a global change that leaks outside of ircd::m. The - // database directory for the entire process is being changed here. - fs::base::db.set(our_dbpath); - - // Recall the db directory init manually with the now-updated basepath - db::chdir(); - - // Open the events database - static const string_view &dbname{"events"}; - events = std::make_shared(dbname, std::move(dbopts), desc::events); - - // Cache the columns for the event tuple in order for constant time lookup - assert(event_columns == event::size()); - std::array keys; //TODO: why did this happen? - _key_transform(event{}, begin(keys), end(keys)); //TODO: how did this happen? - - // Construct global convenience references for the event property columns. - for(size_t i(0); i < keys.size(); ++i) - event_column.at(i) = db::column - { - *events, keys.at(i), std::nothrow - }; - - // Construct global convenience references for the metadata columns - event_idx = db::column{*events, desc::event_idx.name}; - event_json = db::column{*events, desc::event_json.name}; - event_refs = db::domain{*events, desc::event_refs.name}; - event_horizon = db::domain{*events, desc::event_horizon.name}; - event_sender = db::domain{*events, desc::event_sender.name}; - event_type = db::domain{*events, desc::event_type.name}; - event_state = db::domain{*events, desc::event_state.name}; - room_head = db::domain{*events, desc::room_head.name}; - room_events = db::domain{*events, desc::room_events.name}; - room_type = db::domain{*events, desc::room_type.name}; - room_joined = db::domain{*events, desc::room_joined.name}; - room_state = db::domain{*events, desc::room_state.name}; - room_state_space = db::domain{*events, desc::room_state_space.name}; -} - -/// Shuts down the m::dbs subsystem; closes the events database. The extern -/// variables in m::dbs will no longer be functioning after this call. -ircd::m::dbs::init::~init() -noexcept -{ - // Unref DB (should close) - events = {}; - - // restore the fs::base::DB path the way we found it. - fs::base::db.set(their_dbpath); -} - -/// Cancels all background work by the events database. This will make the -/// database shutdown more fluid, without waiting for large compactions. -static const ircd::run::changed -ircd_m_dbs_handle_quit -{ - ircd::run::level::QUIT, [] - { - if(ircd::m::dbs::events) - ircd::db::bgcancel(*ircd::m::dbs::events, false); // non-blocking - } -}; - // // write_opts // diff --git a/matrix/dbs_init.cc b/matrix/dbs_init.cc new file mode 100644 index 000000000..cd580c7b2 --- /dev/null +++ b/matrix/dbs_init.cc @@ -0,0 +1,144 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2022 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +/// Cancels all background work by the events database. This will make the +/// database shutdown more fluid, without waiting for large compactions. +static const ircd::run::changed +ircd_m_dbs_handle_quit +{ + ircd::run::level::QUIT, [] + { + if(ircd::m::dbs::events) + ircd::db::bgcancel(*ircd::m::dbs::events, false); // non-blocking + } +}; + +/// Initializes the m::dbs subsystem; sets up the events database. Held/called +/// by m::init. Most of the extern variables in m::dbs are not ready until +/// this call completes. +/// +/// We also update the fs::basepath for the database directory to include our +/// servername in the path component. The fs::base::DB setting was generated +/// during the build and install process, and is unaware of our servername +/// at runtime. This change deconflicts multiple instances of IRCd running in +/// the same installation prefix using different servernames (i.e clustering +/// on the same machine). +/// +ircd::m::dbs::init::init(const string_view &servername, + std::string dbopts) +:our_dbpath +{ + fs::path_string(fs::path_views + { + fs::base::db, servername + }) +} +,their_dbpath +{ + fs::base::db +} +{ + const unwind_exceptional dtors + { + [this] { this->~init(); } + }; + + // NOTE that this is a global change that leaks outside of ircd::m. The + // database directory for the entire process is being changed here. + fs::base::db.set(our_dbpath); + + // Recall the db directory init manually with the now-updated basepath + db::chdir(); + + // Open database + events = std::make_shared + ( + "events", std::move(dbopts), desc::events + ); + + init_columns(); + apply_updates(); +} + +/// Shuts down the m::dbs subsystem; closes the events database. The extern +/// variables in m::dbs will no longer be functioning after this call. +ircd::m::dbs::init::~init() +noexcept +{ + // Unref DB (should close) + events = {}; + + // restore the fs::base::DB path the way we found it. + fs::base::db.set(their_dbpath); +} + +void +ircd::m::dbs::init::init_columns() +{ + // Cache the columns for the event tuple in order for constant time lookup + assert(event_columns == event::size()); + std::array keys; + _key_transform(event{}, begin(keys), end(keys)); + + // Construct global convenience references for the event property columns. + for(size_t i(0); i < keys.size(); ++i) + event_column.at(i) = db::column + { + *events, keys.at(i), std::nothrow + }; + + // Construct global convenience references for the metadata columns + event_idx = db::column{*events, desc::event_idx.name}; + event_json = db::column{*events, desc::event_json.name}; + event_refs = db::domain{*events, desc::event_refs.name}; + event_horizon = db::domain{*events, desc::event_horizon.name}; + event_sender = db::domain{*events, desc::event_sender.name}; + event_type = db::domain{*events, desc::event_type.name}; + event_state = db::domain{*events, desc::event_state.name}; + room_head = db::domain{*events, desc::room_head.name}; + room_events = db::domain{*events, desc::room_events.name}; + room_type = db::domain{*events, desc::room_type.name}; + room_joined = db::domain{*events, desc::room_joined.name}; + room_state = db::domain{*events, desc::room_state.name}; + room_state_space = db::domain{*events, desc::room_state_space.name}; +} + +void +ircd::m::dbs::init::apply_updates() +{ + size_t i(0); + for(auto update(init::update); *update; ++update, ++i) try + { + log::debug + { + log, "Checking for database schema update #%zu ...", + i, + }; + + (*update)(); + } + catch(const std::exception &e) + { + log::critical + { + log, "Database schema update #%zu :%s", + i, + e.what(), + }; + + throw; + } +} + +decltype(ircd::m::dbs::init::update) +ircd::m::dbs::init::update +{ + nullptr, +};