construct/matrix/dbs_event_sender.cc

276 lines
6.5 KiB
C++

// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// 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.
decltype(ircd::m::dbs::event_sender)
ircd::m::dbs::event_sender;
decltype(ircd::m::dbs::desc::event_sender__comp)
ircd::m::dbs::desc::event_sender__comp
{
{ "name", "ircd.m.dbs._event_sender.comp" },
{ "default", "default" },
};
decltype(ircd::m::dbs::desc::event_sender__block__size)
ircd::m::dbs::desc::event_sender__block__size
{
{ "name", "ircd.m.dbs._event_sender.block.size" },
{ "default", 512L },
};
decltype(ircd::m::dbs::desc::event_sender__meta_block__size)
ircd::m::dbs::desc::event_sender__meta_block__size
{
{ "name", "ircd.m.dbs._event_sender.meta_block.size" },
{ "default", 4096L },
};
decltype(ircd::m::dbs::desc::event_sender__cache__size)
ircd::m::dbs::desc::event_sender__cache__size
{
{
{ "name", "ircd.m.dbs._event_sender.cache.size" },
{ "default", long(16_MiB) },
},
[](conf::item<void> &)
{
const size_t &value{event_sender__cache__size};
db::capacity(db::cache(dbs::event_sender), value);
}
};
decltype(ircd::m::dbs::desc::event_sender__cache_comp__size)
ircd::m::dbs::desc::event_sender__cache_comp__size
{
{
{ "name", "ircd.m.dbs._event_sender.cache_comp.size" },
{ "default", long(0_MiB) },
},
[](conf::item<void> &)
{
const size_t &value{event_sender__cache_comp__size};
db::capacity(db::cache_compressed(dbs::event_sender), value);
}
};
const ircd::db::prefix_transform
ircd::m::dbs::desc::event_sender__pfx
{
"_event_sender",
[](const string_view &key)
{
return startswith(key, '@')?
has(key, '\0'):
has(key, '@');
},
[](const string_view &key)
{
const auto &[prefix, suffix]
{
// Split @localpart:hostpart\0event_idx by '\0'
startswith(key, '@')?
split(key, '\0'):
// Split hostpart@localpart\0event_idx by '@'
split(key, '@')
};
return prefix;
}
};
const ircd::db::descriptor
ircd::m::dbs::desc::event_sender
{
// name
.name = "_event_sender",
.explain = R"(Index of senders to their events.
mxid | event_idx => --
origin | localpart, event_idx => --
The senders of events are indexed by this column. This allows for all
events from a sender to be iterated. Additionally, all events from a
server and all known servers can be iterated from this column.
key #1:
The first type of key is made from a user mxid and an event_idx concat.
key #2:
The second type of key is made from a user mxid and an event_id, where
the mxid is part-swapped so the origin comes first, and the @localpart
comes after.
Note that the indexers of this column ignores the actual "origin" field
of an event. Only the "sender" data is used here.
)",
.type =
{
typeid(string_view), typeid(string_view)
},
.prefix = event_sender__pfx,
.cache_size = bool(cache_enable)? -1 : 0, //uses conf item
.cache_size_comp = bool(cache_comp_enable)? -1 : 0,
.bloom_bits = 0,
.expect_queries_hit = false,
.block_size = size_t(event_sender__block__size),
.meta_block_size = size_t(event_sender__meta_block__size),
.compression = string_view{event_sender__comp},
.compaction_pri = "kOldestSmallestSeqFirst"s,
};
//
// indexer
//
void
ircd::m::dbs::_index_event_sender(db::txn &txn,
const event &event,
const opts &opts)
{
assert(opts.appendix.test(appendix::EVENT_SENDER));
assert(json::get<"sender"_>(event));
assert(opts.event_idx);
thread_local char buf[2][EVENT_SENDER_KEY_MAX_SIZE];
const string_view &sender_key
{
event_sender_key(buf[0], at<"sender"_>(event), opts.event_idx)
};
const string_view &sender_origin_key
{
event_sender_origin_key(buf[1], at<"sender"_>(event), opts.event_idx)
};
db::txn::append
{
txn, dbs::event_sender,
{
opts.op, sender_key
}
};
db::txn::append
{
txn, dbs::event_sender,
{
opts.op, sender_origin_key
}
};
}
//
// key
//
// sender_key
ircd::m::dbs::event_sender_tuple
ircd::m::dbs::event_sender_key(const string_view &amalgam)
{
const auto &parts
{
split(amalgam, '\0')
};
assert(empty(parts.first));
return
{
byte_view<event::idx>(parts.second),
};
}
ircd::string_view
ircd::m::dbs::event_sender_key(const mutable_buffer &out_,
const user::id &user_id,
const event::idx &event_idx)
{
assert(size(out_) >= EVENT_SENDER_KEY_MAX_SIZE);
assert(!event_idx || user_id);
mutable_buffer out{out_};
consume(out, copy(out, user_id));
if(user_id && event_idx)
{
consume(out, copy(out, '\0'));
consume(out, copy(out, byte_view<string_view>(event_idx)));
}
return { data(out_), data(out) };
}
bool
ircd::m::dbs::is_event_sender_key(const string_view &key)
{
return empty(key) || startswith(key, '@');
}
// sender_origin_key
ircd::m::dbs::event_sender_origin_tuple
ircd::m::dbs::event_sender_origin_key(const string_view &amalgam)
{
const auto &parts
{
split(amalgam, '\0')
};
assert(!empty(parts.first) && !empty(parts.second));
assert(startswith(parts.first, '@'));
return
{
parts.first,
byte_view<event::idx>(parts.second),
};
}
ircd::string_view
ircd::m::dbs::event_sender_origin_key(const mutable_buffer &out,
const user::id &user_id,
const event::idx &event_idx)
{
return event_sender_origin_key(out, user_id.host(), user_id.local(), event_idx);
}
ircd::string_view
ircd::m::dbs::event_sender_origin_key(const mutable_buffer &out_,
const string_view &origin,
const string_view &localpart,
const event::idx &event_idx)
{
assert(size(out_) >= EVENT_SENDER_KEY_MAX_SIZE);
assert(!event_idx || localpart);
assert(!localpart || startswith(localpart, '@'));
mutable_buffer out{out_};
consume(out, copy(out, origin));
consume(out, copy(out, localpart));
if(localpart && event_idx)
{
consume(out, copy(out, '\0'));
consume(out, copy(out, byte_view<string_view>(event_idx)));
}
return { data(out_), data(out) };
}
bool
ircd::m::dbs::is_event_sender_origin_key(const string_view &key)
{
return !startswith(key, '@');
}