0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd:Ⓜ️:dbs: Consolidate event_refs column. Drop prev_events column.

This commit is contained in:
Jason Volk 2019-02-14 13:11:37 -08:00
parent 30d27df649
commit 17e1bb96bf
6 changed files with 465 additions and 488 deletions

View file

@ -34,8 +34,7 @@ namespace ircd::m::dbs
// Event metadata columns
extern db::column event_idx; // event_id => event_idx
extern db::column event_json; // event_idx => full json
extern db::index event_refs; // event_idx | event_idx
extern db::index event_auth; // event_idx | event_idx
extern db::index event_refs; // event_idx | ref_type, event_idx
extern db::index room_head; // room_id | event_id => event_idx
extern db::index room_events; // room_id | depth, event_idx => node_id
extern db::index room_joined; // room_id | origin, member => event_idx
@ -43,13 +42,13 @@ namespace ircd::m::dbs
extern db::column state_node; // node_id => state::node
// Lowlevel util
enum class ref :uint8_t;
constexpr size_t EVENT_REFS_KEY_MAX_SIZE {sizeof(event::idx) + sizeof(event::idx)};
string_view event_refs_key(const mutable_buffer &out, const event::idx &tgt, const event::idx &referer);
std::tuple<event::idx> event_refs_key(const string_view &amalgam);
constexpr size_t EVENT_AUTH_KEY_MAX_SIZE {sizeof(event::idx) + sizeof(event::idx)};
string_view event_auth_key(const mutable_buffer &out, const event::idx &tgt, const event::idx &referer);
std::tuple<event::idx> event_auth_key(const string_view &amalgam);
constexpr size_t ref_shift {8 * (sizeof(event::idx) - sizeof(ref))};
constexpr event::idx ref_mask {0xFFUL << ref_shift};
string_view event_refs_key(const mutable_buffer &out, const event::idx &tgt, const ref &type, const event::idx &referer);
std::tuple<ref, event::idx> event_refs_key(const string_view &amalgam);
string_view reflect(const ref &);
constexpr size_t ROOM_HEAD_KEY_MAX_SIZE {id::MAX_SIZE + 1 + id::MAX_SIZE};
string_view room_head_key(const mutable_buffer &out, const id::room &, const id::event &);
@ -84,20 +83,76 @@ namespace ircd::m::dbs
void blacklist(db::txn &, const event::id &, const write_opts &);
}
/// Options that affect the dbs::write() of an event to the transaction.
struct ircd::m::dbs::write_opts
{
uint64_t event_idx {0};
string_view root_in;
mutable_buffer root_out;
static const std::bitset<256> event_refs_all;
/// Operation code
db::op op {db::op::SET};
bool present {true};
bool history {true};
bool room_head {true};
bool room_refs {true};
/// Principal's index number. Most codepaths do not permit zero; must set.
uint64_t event_idx {0};
/// Whether the event_id should be indexed in event_idx (you want yes).
bool event_id {true};
bool event_refs {true};
bool event_auth {true};
/// Whether the event.source can be used directly for event_json. Defaults
/// to false unless the caller wants to avoid a redundant re-stringify.
bool json_source {false};
/// Selection of what reference types to manipulate in event_refs. Refs
/// will not be made if it is not appropriate for the event anyway, so
/// this defaults to all bits. User can disable one or more ref types
/// by clearing a bit.
std::bitset<256> event_refs {event_refs_all};
/// User can supply a view of already-generated keys with event_refs_key().
/// This vector will be checked first before generating that key, which
/// can avoid any index() queries internally to generate it.
vector_view<const string_view> event_refs_hint;
/// Whether the present state table `room_state` should be updated by
/// this operation if appropriate.
bool present {true};
/// Whether the history state btree `state_node` + `room_events` value
/// should be updated by this operation if appropriate.
bool history {true};
/// The state btree root to perform the update on.
string_view root_in;
/// After the update is performed, the new state btree root is returned
/// into this buffer.
mutable_buffer root_out;
/// Whether the event should be added to the room_head, indicating that
/// it has not yet been referenced at the time of this write. Defaults
/// to true, but if this is an older event this opt should be rethought.
bool room_head {true};
/// Whether the event removes the prev_events it references from the
/// room_head. This defaults to true and should almost always be true.
bool room_refs {true};
};
/// Types of references indexed by event_refs. This is a single byte integer,
/// which should be plenty of namespace. Internally event_refs_key() and
/// event_refs store this in a high order byte of an event::idx integer. This
/// is an alternative to having separate columns for each type of reference.
enum class ircd::m::dbs::ref
:uint8_t
{
// DAG
PREV = 0x00,
AUTH = 0x01,
// m.receipt
M_RECEIPT__M_READ = 0x10,
// m.relates_to
M_RELATES__M_REPLY = 0x20,
};
/// Database Schema Descriptors
@ -137,12 +192,6 @@ namespace ircd::m::dbs::desc
extern conf::item<size_t> events__origin_server_ts__cache_comp__size;
extern const db::descriptor events_origin_server_ts;
extern conf::item<size_t> events__prev_events__block__size;
extern conf::item<size_t> events__prev_events__meta_block__size;
extern conf::item<size_t> events__prev_events__cache__size;
extern conf::item<size_t> events__prev_events__cache_comp__size;
extern const db::descriptor events_prev_events;
extern conf::item<size_t> events__room_id__block__size;
extern conf::item<size_t> events__room_id__meta_block__size;
extern conf::item<size_t> events__room_id__cache__size;
@ -187,26 +236,15 @@ namespace ircd::m::dbs::desc
extern conf::item<size_t> events__event_json__bloom__bits;
extern const db::descriptor events__event_json;
// events graph
// events graphing
extern conf::item<size_t> events__event_refs__block__size;
extern conf::item<size_t> events__event_refs__meta_block__size;
extern conf::item<size_t> events__event_refs__cache__size;
extern conf::item<size_t> events__event_refs__cache_comp__size;
extern conf::item<size_t> events__event_refs__bloom__bits;
extern const db::prefix_transform events__event_refs__pfx;
extern const db::comparator events__event_refs__cmp;
extern const db::descriptor events__event_refs;
// events auth
extern conf::item<size_t> events__event_auth__block__size;
extern conf::item<size_t> events__event_auth__meta_block__size;
extern conf::item<size_t> events__event_auth__cache__size;
extern conf::item<size_t> events__event_auth__cache_comp__size;
extern conf::item<size_t> events__event_auth__bloom__bits;
extern const db::prefix_transform events__event_auth__pfx;
extern const db::comparator events__event_auth__cmp;
extern const db::descriptor events__event_auth;
// room head mapping sequence
extern conf::item<size_t> events__room_head__block__size;
extern conf::item<size_t> events__room_head__meta_block__size;
@ -261,8 +299,11 @@ namespace ircd::m::dbs
string_view _index_redact(db::txn &, const event &, const write_opts &);
string_view _index_other(db::txn &, const event &, const write_opts &);
string_view _index_room(db::txn &, const event &, const write_opts &);
void _index_event_refs_m_receipt_m_read(db::txn &, const event &, const write_opts &);
void _index_event_refs_m_relates_m_reply(db::txn &, const event &, const write_opts &);
void _index_event_refs_auth(db::txn &, const event &, const write_opts &);
void _index_event_refs_prev(db::txn &, const event &, const write_opts &);
void _index_event_refs(db::txn &, const event &, const write_opts &);
void _index_event_auth(db::txn &, const event &, const write_opts &);
void _index_event_id(db::txn &, const event &, const write_opts &);
void _index_event(db::txn &, const event &, const write_opts &);
void _append_json(db::txn &, const event &, const write_opts &);

View file

@ -49,8 +49,6 @@ struct ircd::m::event::auth::refs
{
assert(idx);
}
static void rebuild();
};
struct ircd::m::event::auth::chain

View file

@ -36,11 +36,6 @@ decltype(ircd::m::dbs::event_refs)
ircd::m::dbs::event_refs
{};
/// Linkage for a reference to the event_auth column.
decltype(ircd::m::dbs::event_auth)
ircd::m::dbs::event_auth
{};
/// Linkage for a reference to the room_head column
decltype(ircd::m::dbs::room_head)
ircd::m::dbs::room_head
@ -145,7 +140,6 @@ ircd::m::dbs::init::init(std::string dbopts)
event_idx = db::column{*events, desc::events__event_idx.name};
event_json = db::column{*events, desc::events__event_json.name};
event_refs = db::index{*events, desc::events__event_refs.name};
event_auth = db::index{*events, desc::events__event_auth.name};
room_head = db::index{*events, desc::events__room_head.name};
room_events = db::index{*events, desc::events__room_events.name};
room_joined = db::index{*events, desc::events__room_joined.name};
@ -162,6 +156,18 @@ noexcept
events = {};
}
//
// write_opts
//
decltype(ircd::m::dbs::write_opts::event_refs_all)
ircd::m::dbs::write_opts::event_refs_all
{[]{
char full[256];
memset(full, '1', sizeof(full));
return std::bitset<256>(full, sizeof(full));
}()};
//
// Basic write suite
//
@ -318,10 +324,7 @@ ircd::m::dbs::_index_event(db::txn &txn,
if(opts.event_id)
_index_event_id(txn, event, opts);
if(opts.event_auth && event::auth::is_power_event(event))
_index_event_auth(txn, event, opts);
if(opts.event_refs)
if(opts.event_refs.any())
_index_event_refs(txn, event, opts);
}
@ -346,10 +349,34 @@ ircd::m::dbs::_index_event_refs(db::txn &txn,
const event &event,
const write_opts &opts)
{
if(opts.event_refs.test(uint(ref::PREV)))
_index_event_refs_prev(txn, event, opts);
if(opts.event_refs.test(uint(ref::AUTH)))
_index_event_refs_auth(txn, event, opts);
if(opts.event_refs.test(uint(ref::M_RECEIPT__M_READ)))
_index_event_refs_m_receipt_m_read(txn, event, opts);
if(opts.event_refs.test(uint(ref::M_RELATES__M_REPLY)))
_index_event_refs_m_relates_m_reply(txn, event, opts);
}
void
ircd::m::dbs::_index_event_refs_prev(db::txn &txn,
const event &event,
const write_opts &opts)
{
assert(opts.event_refs.test(uint(ref::PREV)));
const event::prev &prev{event};
for(size_t i(0); i < prev.prev_events_count(); ++i)
{
const event::id &prev_id{prev.prev_event(i)};
const event::id &prev_id
{
prev.prev_event(i)
};
const event::idx &prev_idx
{
m::index(prev_id, std::nothrow) // query
@ -362,7 +389,7 @@ ircd::m::dbs::_index_event_refs(db::txn &txn,
assert(opts.event_idx != 0 && prev_idx != 0);
const string_view &key
{
event_refs_key(buf, prev_idx, opts.event_idx)
event_refs_key(buf, prev_idx, ref::PREV, opts.event_idx)
};
db::txn::append
@ -376,16 +403,22 @@ ircd::m::dbs::_index_event_refs(db::txn &txn,
}
void
ircd::m::dbs::_index_event_auth(db::txn &txn,
const event &event,
const write_opts &opts)
ircd::m::dbs::_index_event_refs_auth(db::txn &txn,
const event &event,
const write_opts &opts)
{
assert(event::auth::is_power_event(event));
assert(opts.event_refs.test(uint(ref::AUTH)));
if(!event::auth::is_power_event(event))
return;
const event::prev &prev{event};
for(size_t i(0); i < prev.auth_events_count(); ++i)
{
const event::id &auth_id{prev.auth_event(i)};
const event::id &auth_id
{
prev.auth_event(i)
};
const event::idx &auth_idx
{
m::index(auth_id, std::nothrow) // query
@ -394,16 +427,16 @@ ircd::m::dbs::_index_event_auth(db::txn &txn,
if(!auth_idx)
continue;
thread_local char buf[EVENT_AUTH_KEY_MAX_SIZE];
thread_local char buf[EVENT_REFS_KEY_MAX_SIZE];
assert(opts.event_idx != 0 && auth_idx != 0);
const string_view &key
{
event_auth_key(buf, auth_idx, opts.event_idx)
event_refs_key(buf, auth_idx, ref::AUTH, opts.event_idx)
};
db::txn::append
{
txn, dbs::event_auth,
txn, dbs::event_refs,
{
opts.op, key, string_view{}
}
@ -411,6 +444,114 @@ ircd::m::dbs::_index_event_auth(db::txn &txn,
}
}
void
ircd::m::dbs::_index_event_refs_m_receipt_m_read(db::txn &txn,
const event &event,
const write_opts &opts)
{
assert(opts.event_refs.test(uint(ref::M_RECEIPT__M_READ)));
if(json::get<"type"_>(event) != "ircd.read")
return;
if(!my_host(json::get<"origin"_>(event)))
return;
//TODO: disallow local forge?
const auto &event_id
{
unquote(json::get<"content"_>(event).get("event_id"))
};
const event::idx &event_idx
{
m::index(event_id, std::nothrow) // query
};
if(!event_idx)
return;
thread_local char buf[EVENT_REFS_KEY_MAX_SIZE];
assert(opts.event_idx != 0 && event_idx != 0);
const string_view &key
{
event_refs_key(buf, event_idx, ref::M_RECEIPT__M_READ, opts.event_idx)
};
db::txn::append
{
txn, dbs::event_refs,
{
opts.op, key, string_view{}
}
};
}
void
ircd::m::dbs::_index_event_refs_m_relates_m_reply(db::txn &txn,
const event &event,
const write_opts &opts)
{
assert(opts.event_refs.test(uint(ref::M_RELATES__M_REPLY)));
if(json::get<"type"_>(event) != "m.room.message")
return;
if(!json::get<"content"_>(event).has("m.relates_to"))
return;
if(json::type(json::get<"content"_>(event).get("m.relates_to")) != json::OBJECT)
return;
const json::object &m_relates_to
{
json::get<"content"_>(event).get("m.relates_to")
};
if(!m_relates_to.has("m.in_reply_to"))
return;
if(json::type(m_relates_to.get("m.in_reply_to")) != json::OBJECT)
return;
const json::object &m_in_reply_to
{
m_relates_to.get("m.in_reply_to")
};
const auto &event_id
{
unquote(m_in_reply_to.get("event_id"))
};
if(!valid(m::id::USER, event_id))
return;
const event::idx &event_idx
{
m::index(event_id, std::nothrow) // query
};
if(!event_idx)
return;
thread_local char buf[EVENT_REFS_KEY_MAX_SIZE];
assert(opts.event_idx != 0 && event_idx != 0);
const string_view &key
{
event_refs_key(buf, event_idx, ref::M_RELATES__M_REPLY, opts.event_idx)
};
db::txn::append
{
txn, dbs::event_refs,
{
opts.op, key, string_view{}
}
};
}
ircd::string_view
ircd::m::dbs::_index_room(db::txn &txn,
const event &event,
@ -1063,18 +1204,34 @@ ircd::m::dbs::desc::events__event_refs__cache_comp__size
}
};
decltype(ircd::m::dbs::desc::events__event_refs__bloom__bits)
ircd::m::dbs::desc::events__event_refs__bloom__bits
ircd::string_view
ircd::m::dbs::reflect(const ref &type)
{
{ "name", "ircd.m.dbs.events._event_refs.bloom.bits" },
{ "default", 0L },
};
switch(type)
{
case ref::PREV:
return "PREV";
case ref::AUTH:
return "AUTH";
case ref::M_RECEIPT__M_READ:
return "M_RECEIPT__M_READ";
case ref::M_RELATES__M_REPLY:
return "M_RELATES__M_REPLY";
}
return "????";
}
ircd::string_view
ircd::m::dbs::event_refs_key(const mutable_buffer &out,
const event::idx &tgt,
const ref &type,
const event::idx &src)
{
assert((src & ref_mask) == 0);
assert(size(out) >= sizeof(event::idx) * 2);
event::idx *const &key
{
@ -1083,23 +1240,24 @@ ircd::m::dbs::event_refs_key(const mutable_buffer &out,
key[0] = tgt;
key[1] = src;
key[1] |= uint64_t(type) << ref_shift;
return string_view
{
data(out), data(out) + sizeof(event::idx) * 2
};
}
std::tuple<ircd::m::event::idx>
std::tuple<ircd::m::dbs::ref, ircd::m::event::idx>
ircd::m::dbs::event_refs_key(const string_view &amalgam)
{
const byte_view<event::idx> key
const event::idx key
{
amalgam
byte_view<event::idx>{amalgam}
};
return
{
key
ref(key >> ref_shift), key & ~ref_mask
};
}
@ -1167,15 +1325,18 @@ ircd::m::dbs::desc::events__event_refs
// explanation
R"(Inverse reference graph of events.
event_idx | event_idx => --
event_idx | ref, event_idx => --
The first part of the key is the event being referenced. The second part
of the key is the event which refers to the first event somewhere in its
prev_events references.
prev_events references. The event_idx in the second part of the key also
contains a dbs::ref type in its highest order byte so we can store
different kinds of references.
The prefix transform is in effect; an event may be referenced multiple
times. We can find all the events we have which reference a target. The
database must contain both events (hence they have event::idx numbers).
times. We can find all the events we have which reference a target, and
why. The database must already contain both events (hence they have
event::idx numbers).
The value is currently unused/empty; we may eventually store metadata with
information about this reference (i.e. is depth adjacent? is the ref
@ -1207,7 +1368,7 @@ ircd::m::dbs::desc::events__event_refs
bool(events_cache_comp_enable)? -1 : 0,
// bloom filter bits
size_t(events__event_refs__bloom__bits),
0,
// expect queries hit
true,
@ -1219,204 +1380,6 @@ ircd::m::dbs::desc::events__event_refs
size_t(events__event_refs__meta_block__size),
};
//
// event_auth
//
decltype(ircd::m::dbs::desc::events__event_auth__block__size)
ircd::m::dbs::desc::events__event_auth__block__size
{
{ "name", "ircd.m.dbs.events._event_auth.block.size" },
{ "default", 512L },
};
decltype(ircd::m::dbs::desc::events__event_auth__meta_block__size)
ircd::m::dbs::desc::events__event_auth__meta_block__size
{
{ "name", "ircd.m.dbs.events._event_auth.meta_block.size" },
{ "default", 512L },
};
decltype(ircd::m::dbs::desc::events__event_auth__cache__size)
ircd::m::dbs::desc::events__event_auth__cache__size
{
{
{ "name", "ircd.m.dbs.events._event_auth.cache.size" },
{ "default", long(16_MiB) },
}, []
{
const size_t &value{events__event_auth__cache__size};
db::capacity(db::cache(event_auth), value);
}
};
decltype(ircd::m::dbs::desc::events__event_auth__cache_comp__size)
ircd::m::dbs::desc::events__event_auth__cache_comp__size
{
{
{ "name", "ircd.m.dbs.events._event_auth.cache_comp.size" },
{ "default", long(0_MiB) },
}, []
{
const size_t &value{events__event_auth__cache_comp__size};
db::capacity(db::cache_compressed(event_auth), value);
}
};
decltype(ircd::m::dbs::desc::events__event_auth__bloom__bits)
ircd::m::dbs::desc::events__event_auth__bloom__bits
{
{ "name", "ircd.m.dbs.events._event_auth.bloom.bits" },
{ "default", 0L },
};
ircd::string_view
ircd::m::dbs::event_auth_key(const mutable_buffer &out,
const event::idx &tgt,
const event::idx &src)
{
assert(size(out) >= sizeof(event::idx) * 2);
event::idx *const &key
{
reinterpret_cast<event::idx *>(data(out))
};
key[0] = tgt;
key[1] = src;
return string_view
{
data(out), data(out) + sizeof(event::idx) * 2
};
}
std::tuple<ircd::m::event::idx>
ircd::m::dbs::event_auth_key(const string_view &amalgam)
{
const byte_view<event::idx> key
{
amalgam
};
return
{
key
};
}
const ircd::db::prefix_transform
ircd::m::dbs::desc::events__event_auth__pfx
{
"_event_auth",
[](const string_view &key)
{
return size(key) >= sizeof(event::idx) * 2;
},
[](const string_view &key)
{
assert(size(key) >= sizeof(event::idx));
return string_view
{
data(key), data(key) + sizeof(event::idx)
};
}
};
const ircd::db::comparator
ircd::m::dbs::desc::events__event_auth__cmp
{
"_event_auth",
// less
[](const string_view &a, const string_view &b)
{
static const size_t half(sizeof(event::idx));
static const size_t full(half * 2);
assert(size(a) >= half);
assert(size(b) >= half);
const event::idx *const key[2]
{
reinterpret_cast<const event::idx *>(data(a)),
reinterpret_cast<const event::idx *>(data(b)),
};
return
key[0][0] < key[1][0]? true:
key[0][0] > key[1][0]? false:
size(a) < size(b)? true:
size(a) > size(b)? false:
size(a) == half? false:
key[0][1] < key[1][1]? true:
false;
},
// equal
[](const string_view &a, const string_view &b)
{
return size(a) == size(b) && memcmp(data(a), data(b), size(a)) == 0;
}
};
const ircd::db::descriptor
ircd::m::dbs::desc::events__event_auth
{
// name
"_event_auth",
// explanation
R"(Inverse reference graph of events.
event_idx | event_idx => --
The first part of the key is the event being referenced. The second part
of the key is the event which refers to the first event somewhere in its
auth_events references.
The prefix transform is in effect; an event may be referenced multiple
times. We can find all the events we have which reference a target. The
database must contain both events (hence they have event::idx numbers).
The value is currently unused/empty.
)",
// typing (key, value)
{
typeid(uint64_t), typeid(string_view)
},
// options
{},
// comparator
events__event_auth__cmp,
// prefix transform
events__event_auth__pfx,
// drop column
false,
// cache size
bool(events_cache_enable)? -1 : 0, //uses conf item
// cache size for compressed assets
bool(events_cache_comp_enable)? -1 : 0,
// bloom filter bits
size_t(events__event_auth__bloom__bits),
// expect queries hit
true,
// block size
size_t(events__event_auth__block__size),
// meta_block size
size_t(events__event_auth__meta_block__size),
};
//
// room_head
//
@ -3098,101 +3061,6 @@ ircd::m::dbs::desc::events_depth
size_t(events__depth__meta_block__size),
};
//
// prev_events
//
decltype(ircd::m::dbs::desc::events__prev_events__block__size)
ircd::m::dbs::desc::events__prev_events__block__size
{
{ "name", "ircd.m.dbs.events.prev_events.block.size" },
{ "default", 1024L },
};
decltype(ircd::m::dbs::desc::events__prev_events__meta_block__size)
ircd::m::dbs::desc::events__prev_events__meta_block__size
{
{ "name", "ircd.m.dbs.events.prev_events.meta_block.size" },
{ "default", 512L },
};
decltype(ircd::m::dbs::desc::events__prev_events__cache__size)
ircd::m::dbs::desc::events__prev_events__cache__size
{
{
{ "name", "ircd.m.dbs.events.prev_events.cache.size" },
{ "default", long(16_MiB) },
}, []
{
auto &column(event_column.at(json::indexof<event, "prev_events"_>()));
const size_t &value{events__prev_events__cache__size};
db::capacity(db::cache(column), value);
}
};
decltype(ircd::m::dbs::desc::events__prev_events__cache_comp__size)
ircd::m::dbs::desc::events__prev_events__cache_comp__size
{
{
{ "name", "ircd.m.dbs.events.prev_events.cache_comp.size" },
{ "default", long(16_MiB) },
}, []
{
auto &column(event_column.at(json::indexof<event, "prev_events"_>()));
const size_t &value{events__prev_events__cache_comp__size};
db::capacity(db::cache_compressed(column), value);
}
};
const ircd::db::descriptor
ircd::m::dbs::desc::events_prev_events
{
// name
"prev_events",
// explanation
R"(Stores the prev_events property of an event.
### developer note:
key is event_idx number.
)",
// typing (key, value)
{
typeid(uint64_t), typeid(string_view)
},
// options
{},
// comparator
{},
// prefix transform
{},
// drop column
false,
// cache size
bool(events_cache_enable)? -1 : 0,
// cache size for compressed assets
bool(events_cache_comp_enable)? -1 : 0,
// bloom filter bits
size_t(events___event__bloom__bits),
// expect queries hit
true,
// block size
size_t(events__prev_events__block__size),
// meta_block size
size_t(events__prev_events__meta_block__size),
};
//
// Other column descriptions
//
@ -3211,9 +3079,13 @@ namespace ircd::m::dbs::desc
extern const ircd::db::descriptor events_hashes;
extern const ircd::db::descriptor events_membership;
extern const ircd::db::descriptor events_origin;
extern const ircd::db::descriptor events_prev_events;
extern const ircd::db::descriptor events_prev_state;
extern const ircd::db::descriptor events_redacts;
extern const ircd::db::descriptor events_signatures;
extern const ircd::db::descriptor events__event_auth;
extern const ircd::db::comparator events__event_auth__cmp;
extern const ircd::db::prefix_transform events__event_auth__pfx;
extern const ircd::db::descriptor events__event_bad;
//
@ -3223,6 +3095,107 @@ namespace ircd::m::dbs::desc
extern const ircd::db::descriptor events__default;
};
const ircd::db::prefix_transform
ircd::m::dbs::desc::events__event_auth__pfx
{
"_event_auth",
[](const string_view &key)
{
return size(key) >= sizeof(event::idx) * 2;
},
[](const string_view &key)
{
assert(size(key) >= sizeof(event::idx));
return string_view
{
data(key), data(key) + sizeof(event::idx)
};
}
};
const ircd::db::comparator
ircd::m::dbs::desc::events__event_auth__cmp
{
"_event_auth",
// less
[](const string_view &a, const string_view &b)
{
static const size_t half(sizeof(event::idx));
static const size_t full(half * 2);
assert(size(a) >= half);
assert(size(b) >= half);
const event::idx *const key[2]
{
reinterpret_cast<const event::idx *>(data(a)),
reinterpret_cast<const event::idx *>(data(b)),
};
return
key[0][0] < key[1][0]? true:
key[0][0] > key[1][0]? false:
size(a) < size(b)? true:
size(a) > size(b)? false:
size(a) == half? false:
key[0][1] < key[1][1]? true:
false;
},
// equal
[](const string_view &a, const string_view &b)
{
return size(a) == size(b) && memcmp(data(a), data(b), size(a)) == 0;
}
};
const ircd::db::descriptor
ircd::m::dbs::desc::events__event_auth
{
// name
"_event_auth",
// explanation
R"(Inverse reference graph of events.
event_idx | ref, event_idx => --
The first part of the key is the event being referenced. The second part
of the key is the event which refers to the first event somewhere in its
prev_events references. The event_idx in the second part of the key also
contains a dbs::ref type in its highest order byte so we can store
different kinds of references.
The prefix transform is in effect; an event may be referenced multiple
times. We can find all the events we have which reference a target, and
why. The database must already contain both events (hence they have
event::idx numbers).
The value is currently unused/empty; we may eventually store metadata with
information about this reference (i.e. is depth adjacent? is the ref
redundant with another in the same event and should not be made? etc).
)",
// typing (key, value)
{
typeid(uint64_t), typeid(string_view)
},
// options
{},
// comparator
events__event_auth__cmp,
// prefix transform
events__event_auth__pfx,
// drop column
true,
};
const ircd::db::descriptor
ircd::m::dbs::desc::events__event_bad
{
@ -3383,6 +3356,38 @@ ircd::m::dbs::desc::events_origin
true,
};
const ircd::db::descriptor
ircd::m::dbs::desc::events_prev_events
{
// name
"prev_events",
// explanation
R"(
This column is deprecated and has been dropped from the schema. This
descriptor will erase its presence in the database upon next open.
)",
// typing (key, value)
{
typeid(uint64_t), typeid(string_view)
},
// options
{},
// comparator
{},
// prefix transform
{},
// drop column
true,
};
const ircd::db::descriptor
ircd::m::dbs::desc::events_prev_state
{
@ -3541,7 +3546,6 @@ ircd::m::dbs::desc::events
events_event_id,
events_origin,
events_origin_server_ts,
events_prev_events,
events_room_id,
events_sender,
events_state_key,
@ -3563,10 +3567,6 @@ ircd::m::dbs::desc::events
// Reverse mapping of the event reference graph.
events__event_refs,
// event_idx | event_idx
// Reverse mapping of the auth reference graph.
events__event_auth,
// (room_id, (depth, event_idx)) => (state_root)
// Sequence of all events for a room, ever.
events__room_events,
@ -3594,8 +3594,10 @@ ircd::m::dbs::desc::events
events_auth_events,
events_hashes,
events_membership,
events_prev_events,
events_prev_state,
events_redacts,
events_signatures,
events__event_auth,
events__event_bad,
};

View file

@ -1332,19 +1332,6 @@ ircd::m::event::auth::is_power_event(const m::event &event)
// event::auth::refs
//
void
ircd::m::event::auth::refs::rebuild()
{
using prototype = void ();
static mods::import<prototype> rebuild
{
"m_event", "ircd::m::event::auth::refs::rebuild"
};
rebuild();
}
size_t
ircd::m::event::auth::refs::count()
const noexcept
@ -1403,33 +1390,37 @@ ircd::m::event::auth::refs::for_each(const string_view &type,
const
{
assert(idx);
auto &column
thread_local char buf[dbs::EVENT_REFS_KEY_MAX_SIZE];
const string_view key
{
dbs::event_auth
};
const byte_view<string_view> &key
{
idx
dbs::event_refs_key(buf, idx, dbs::ref::AUTH, 0)
};
auto it
{
column.begin(key)
dbs::event_refs.begin(key)
};
for(; it; ++it)
{
const auto parts
{
dbs::event_auth_key(it->first)
dbs::event_refs_key(it->first)
};
const auto &ref_type
{
std::get<0>(parts)
};
const auto &ref
{
std::get<0>(parts)
std::get<1>(parts)
};
if(ref_type != dbs::ref::AUTH)
break;
bool match;
const auto matcher
{
@ -1550,19 +1541,16 @@ bool
ircd::m::event::refs::for_each(const closure_bool &closure)
const
{
auto &column
assert(idx);
thread_local char buf[dbs::EVENT_REFS_KEY_MAX_SIZE];
const string_view key
{
dbs::event_refs
};
const byte_view<string_view> &key
{
idx
dbs::event_refs_key(buf, idx, dbs::ref::PREV, 0)
};
auto it
{
column.begin(key)
dbs::event_refs.begin(key)
};
for(; it; ++it)
@ -1572,11 +1560,19 @@ const
dbs::event_refs_key(it->first)
};
const auto &ref
const auto &type
{
std::get<0>(parts)
};
if(type != dbs::ref::PREV)
break;
const auto &ref
{
std::get<1>(parts)
};
assert(idx != ref);
if(!closure(ref))
return false;

View file

@ -5936,8 +5936,22 @@ console_cmd__event__visible(opt &out, const string_view &line)
return true;
}
bool
console_cmd__event__refs__rebuild(opt &out, const string_view &line)
{
m::event::refs::rebuild();
out << "done" << std::endl;
return true;
}
bool
console_cmd__event__refs(opt &out, const string_view &line)
{
return true;
}
bool
console_cmd__event__refs__prev(opt &out, const string_view &line)
{
const params param{line, " ",
{
@ -5975,15 +5989,7 @@ console_cmd__event__refs(opt &out, const string_view &line)
}
bool
console_cmd__event__refs__rebuild(opt &out, const string_view &line)
{
m::event::refs::rebuild();
out << "done" << std::endl;
return true;
}
bool
console_cmd__event__auth__refs(opt &out, const string_view &line)
console_cmd__event__refs__auth(opt &out, const string_view &line)
{
const params param{line, " ",
{
@ -6026,14 +6032,6 @@ console_cmd__event__auth__refs(opt &out, const string_view &line)
return true;
}
bool
console_cmd__event__auth__rebuild(opt &out, const string_view &line)
{
m::event::refs::rebuild();
out << "done" << std::endl;
return true;
}
//
// state
//

View file

@ -565,68 +565,6 @@ ircd::m::pretty_oneline(std::ostream &s,
void
IRCD_MODULE_EXPORT
ircd::m::event::refs::rebuild()
{
static const size_t pool_size{64};
static const size_t log_interval{8192};
db::txn txn
{
*m::dbs::events
};
auto &column
{
dbs::event_json
};
auto it
{
column.begin()
};
ctx::dock dock;
ctx::pool pool;
pool.min(pool_size);
size_t i(0), j(0);
for(; it; ++it)
{
std::string event{it->second};
const m::event::idx event_idx
{
byte_view<m::event::idx>(it->first)
};
pool([&txn, &dock, &i, &j, event(std::move(event)), event_idx]
{
m::dbs::write_opts wopts;
wopts.event_idx = event_idx;
m::dbs::_index_event_refs(txn, json::object{event}, wopts);
if(++j % log_interval == 0) log::info
{
m::log, "Refs builder @%zu:%zu of %lu (@idx: %lu)",
i,
j,
m::vm::current_sequence,
event_idx
};
dock.notify_one();
});
++i;
}
dock.wait([&i, &j]
{
return i == j;
});
txn();
}
void
IRCD_MODULE_EXPORT
ircd::m::event::auth::refs::rebuild()
{
static const size_t pool_size{96};
static const size_t log_interval{8192};
@ -649,34 +587,38 @@ ircd::m::event::auth::refs::rebuild()
ctx::dock dock;
ctx::pool pool;
pool.min(pool_size);
size_t i(0), j(0);
const ctx::uninterruptible::nothrow ui;
for(; it; ++it)
{
const m::event &e(json::object(it->second));
if(!is_power_event(e))
continue;
if(ctx::interruption_requested())
break;
std::string event{it->second};
const m::event::idx event_idx
{
byte_view<m::event::idx>(it->first)
};
std::string event{it->second};
pool([&txn, &dock, &i, &j, event(std::move(event)), event_idx]
{
m::dbs::write_opts wopts;
wopts.event_idx = event_idx;
m::dbs::_index_event_auth(txn, json::object{event}, wopts);
m::dbs::_index_event_refs(txn, json::object{event}, wopts);
if(++j % log_interval == 0) log::info
{
m::log, "Auth builder @%zu:%zu of %lu (@idx: %lu)",
m::log, "Refs builder @%zu:%zu of %lu (@idx: %lu)",
i,
j,
m::vm::current_sequence,
event_idx
};
dock.notify_one();
if(j >= i)
dock.notify_one();
});
++i;