// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 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. ircd::m::room::state::space::space(const m::room &room) :room { room } { } bool ircd::m::room::state::space::prefetch(const string_view &type) const { return prefetch(type, string_view{}); } bool ircd::m::room::state::space::prefetch(const string_view &type, const string_view &state_key) const { return prefetch(type, state_key, -1); } bool ircd::m::room::state::space::prefetch(const string_view &type, const string_view &state_key, const int64_t &depth) const { const int64_t &_depth { type? depth : 0L }; char buf[dbs::ROOM_STATE_SPACE_KEY_MAX_SIZE]; const string_view &key { dbs::room_state_space_key(buf, room.room_id, type, state_key, _depth, 0UL) }; return db::prefetch(dbs::room_state_space, key); } bool ircd::m::room::state::space::has(const string_view &type) const { return has(type, string_view{}); } bool ircd::m::room::state::space::has(const string_view &type, const string_view &state_key) const { return has(type, state_key, -1); } bool ircd::m::room::state::space::has(const string_view &type, const string_view &state_key, const int64_t &depth) const { return !for_each(type, state_key, depth, [] (const auto &, const auto &, const auto &, const auto &) noexcept { return false; }); } size_t ircd::m::room::state::space::count() const { return count(string_view{}); } size_t ircd::m::room::state::space::count(const string_view &type) const { return count(type, string_view{}); } size_t ircd::m::room::state::space::count(const string_view &type, const string_view &state_key) const { return count(type, state_key, -1L); } size_t ircd::m::room::state::space::count(const string_view &type, const string_view &state_key, const int64_t &depth) const { size_t ret(0); for_each(type, state_key, depth, [&ret] (const auto &, const auto &, const auto &, const auto &) noexcept { ++ret; return true; }); return ret; } bool ircd::m::room::state::space::for_each(const closure &closure) const { return for_each(string_view{}, string_view{}, -1L, closure); } bool ircd::m::room::state::space::for_each(const string_view &type, const closure &closure) const { return for_each(type, string_view{}, -1L, closure); } bool ircd::m::room::state::space::for_each(const string_view &type, const string_view &state_key, const closure &closure) const { return for_each(type, state_key, -1L, closure); } bool ircd::m::room::state::space::for_each(const string_view &type, const string_view &state_key, const int64_t &depth, const closure &closure) const { const int64_t &_depth { type? depth : 0L }; char buf[dbs::ROOM_STATE_SPACE_KEY_MAX_SIZE]; const string_view &key { dbs::room_state_space_key(buf, room.room_id, type, state_key, _depth, 0UL) }; auto it { dbs::room_state_space.begin(key) }; for(; it; ++it) { const auto &[_type, _state_key, _depth, _event_idx] { dbs::room_state_space_key(it->first) }; if(type && type != _type) break; if(state_key && state_key != _state_key) break; if(depth >= 0 && depth != _depth) break; if(!closure(_type, _state_key, _depth, _event_idx)) return false; } return true; } // // room::state::space::rebuild // ircd::m::room::state::space::rebuild::rebuild(const room::id &room_id) { db::txn txn { *m::dbs::events }; m::room::events it { room_id, uint64_t(0) }; if(!it) return; const bool check_auth { !m::internal(room_id) }; m::event::fetch event; size_t state_count(0), messages_count(0), state_deleted(0); for(; it; ++it, ++messages_count) try { const m::event::idx &event_idx { it.event_idx() }; if(!state::is(std::nothrow, event_idx)) continue; if(!seek(std::nothrow, event, event_idx)) continue; ++state_count; const auto &[pass_static, reason_static] { check_auth? room::auth::check_static(event): room::auth::passfail{true, {}} }; if(!pass_static) log::dwarning { log, "%s in %s erased from state space (static) :%s", string_view{event.event_id}, string_view{room_id}, what(reason_static), }; const auto &[pass_relative, reason_relative] { !check_auth? room::auth::passfail{true, {}}: pass_static? room::auth::check_relative(event): room::auth::passfail{false, {}}, }; if(pass_static && !pass_relative) log::dwarning { log, "%s in %s erased from state space (relative) :%s", string_view{event.event_id}, string_view{room_id}, what(reason_relative), }; dbs::opts opts; opts.event_idx = event_idx; opts.appendix.reset(); opts.appendix.set(dbs::appendix::ROOM_STATE_SPACE); opts.op = pass_static && pass_relative? db::op::SET : db::op::DELETE; state_deleted += opts.op == db::op::DELETE; dbs::write(txn, event, opts); } catch(const ctx::interrupted &e) { log::dwarning { log, "room::state::space::rebuild :%s", e.what() }; throw; } catch(const std::exception &e) { log::error { log, "room::state::space::rebuild :%s", e.what() }; } log::info { log, "room::state::space::rebuild %s complete msgs:%zu state:%zu del:%zu transaction elems:%zu size:%s", string_view{room_id}, messages_count, state_count, state_deleted, txn.size(), pretty(iec(txn.bytes())) }; txn(); }