mirror of
https://github.com/matrix-construct/construct
synced 2024-11-26 00:32:35 +01:00
ircd:Ⓜ️ Events database interface to m::dbs; trim vm; [inconsistent].
This commit is contained in:
parent
7bff223748
commit
4540a32948
8 changed files with 1070 additions and 1975 deletions
|
@ -13,32 +13,66 @@
|
|||
|
||||
namespace ircd::m::dbs
|
||||
{
|
||||
struct init;
|
||||
struct cursor;
|
||||
|
||||
// Database instance
|
||||
extern std::shared_ptr<db::database> events;
|
||||
|
||||
// Event property columns
|
||||
constexpr const auto event_columns{event::size()};
|
||||
extern std::array<db::column, event_columns> event_column;
|
||||
|
||||
// Event metadata columns
|
||||
extern db::column state_node;
|
||||
extern db::column room_events;
|
||||
|
||||
// Lowlevel util
|
||||
string_view room_events_key(const mutable_buffer &out, const id::room &, const uint64_t &depth, const id::event &);
|
||||
|
||||
// Get the state root for an event (with as much information as you have)
|
||||
string_view state_root(const mutable_buffer &out, const id::room &, const id::event &, const uint64_t &depth);
|
||||
string_view state_root(const mutable_buffer &out, const id::room &, const id::event &);
|
||||
string_view state_root(const mutable_buffer &out, const id::event &);
|
||||
string_view state_root(const mutable_buffer &out, const event &);
|
||||
|
||||
// [GET] Query suite
|
||||
bool exists(const event::id &);
|
||||
|
||||
void append_indexes(const event &, db::txn &);
|
||||
void write(const event &, db::txn &);
|
||||
// [SET (txn)] Basic write suite
|
||||
string_view write(db::txn &, const mutable_buffer &rootout, const string_view &rootin, const event &);
|
||||
}
|
||||
|
||||
namespace ircd::m::dbs
|
||||
namespace ircd::m::dbs::desc
|
||||
{
|
||||
using closure = std::function<void (const event &)>;
|
||||
using closure_bool = std::function<bool (const event &)>;
|
||||
// Full description
|
||||
extern const database::description events;
|
||||
|
||||
bool _query(const query<> &, const closure_bool &);
|
||||
bool _query_event_id(const query<> &, const closure_bool &);
|
||||
bool _query_in_room_id(const query<> &, const closure_bool &, const id::room &);
|
||||
bool _query_for_type_state_key_in_room_id(const query<> &, const closure_bool &, const id::room &, const string_view &type, const string_view &state_key);
|
||||
// Direct columns
|
||||
extern const database::descriptor events_auth_events;
|
||||
extern const database::descriptor events_content;
|
||||
extern const database::descriptor events_depth;
|
||||
extern const database::descriptor events_event_id;
|
||||
extern const database::descriptor events_hashes;
|
||||
extern const database::descriptor events_membership;
|
||||
extern const database::descriptor events_origin;
|
||||
extern const database::descriptor events_origin_server_ts;
|
||||
extern const database::descriptor events_prev_events;
|
||||
extern const database::descriptor events_prev_state;
|
||||
extern const database::descriptor events_room_id;
|
||||
extern const database::descriptor events_sender;
|
||||
extern const database::descriptor events_signatures;
|
||||
extern const database::descriptor events_state_key;
|
||||
extern const database::descriptor events_type;
|
||||
|
||||
int _query_where_event_id(const query<where::equal> &, const closure_bool &);
|
||||
int _query_where_room_id_at_event_id(const query<where::equal> &, const closure_bool &);
|
||||
int _query_where_room_id(const query<where::equal> &, const closure_bool &);
|
||||
int _query_where(const query<where::equal> &where, const closure_bool &closure);
|
||||
int _query_where(const query<where::logical_and> &where, const closure_bool &closure);
|
||||
// Metadata columns
|
||||
extern const database::descriptor events__state_node;
|
||||
extern const db::prefix_transform events__room_events__pfx;
|
||||
extern const database::descriptor events__room_events;
|
||||
}
|
||||
|
||||
namespace ircd::m
|
||||
struct ircd::m::dbs::init
|
||||
{
|
||||
void _index_special0(const event &event, db::txn &txn, const db::op &, const string_view &prev_event_id);
|
||||
void _index_special1(const event &event, db::txn &txn, const db::op &, const string_view &prev_event_id);
|
||||
}
|
||||
|
||||
init();
|
||||
~init() noexcept;
|
||||
};
|
||||
|
|
|
@ -30,16 +30,13 @@ namespace ircd::m
|
|||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsubobject-linkage"
|
||||
/// The _Main Event_. Most fundamental primitive of the Matrix protocol.
|
||||
/// The Main Event
|
||||
///
|
||||
/// This json::tuple provides at least all of the legal members of the matrix
|
||||
/// standard event. This is the fundamental building block of the matrix
|
||||
/// system. Rooms are collections of events. Messages between servers are
|
||||
/// passed as bundles of events (or directly).
|
||||
///
|
||||
/// Due to the ubiquitous usage, and diversity of extensions, the class
|
||||
/// member interface is somewhat minimal.
|
||||
///
|
||||
/// It is better to have 100 functions operate on one data structure than
|
||||
/// to have 10 functions operate on 10 data structures.
|
||||
/// -Alan Perlis
|
||||
|
@ -61,11 +58,9 @@ struct ircd::m::event
|
|||
json::property<name::sender, json::string>,
|
||||
json::property<name::signatures, json::object>,
|
||||
json::property<name::state_key, json::string>,
|
||||
json::property<name::type, json::string>,
|
||||
json::property<name::unsigned_, string_view>
|
||||
json::property<name::type, json::string>
|
||||
>
|
||||
{
|
||||
struct init;
|
||||
struct fetch;
|
||||
struct sync;
|
||||
struct prev;
|
||||
|
@ -75,10 +70,6 @@ struct ircd::m::event
|
|||
using closure = std::function<void (const event &)>;
|
||||
using closure_bool = std::function<bool (const event &)>;
|
||||
|
||||
static const db::database::description description;
|
||||
static std::shared_ptr<db::database> events;
|
||||
static std::array<db::column, super_type::size()> column;
|
||||
|
||||
using super_type::tuple;
|
||||
using super_type::operator=;
|
||||
|
||||
|
@ -114,12 +105,6 @@ struct ircd::m::event::prev
|
|||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
struct ircd::m::event::init
|
||||
{
|
||||
init();
|
||||
~init() noexcept;
|
||||
};
|
||||
|
||||
inline bool
|
||||
ircd::m::my(const event &event)
|
||||
{
|
||||
|
|
|
@ -67,8 +67,7 @@ struct ircd::m::init
|
|||
void listeners();
|
||||
void modules();
|
||||
|
||||
event::init _event;
|
||||
state::init _state;
|
||||
dbs::init _dbs;
|
||||
keys::init _keys;
|
||||
|
||||
public:
|
||||
|
|
|
@ -13,29 +13,6 @@
|
|||
|
||||
/// Matrix Virtual Machine
|
||||
///
|
||||
/// This is the processing unit for matrix events. The front-end interface to
|
||||
/// m::vm consists of two parts: The query suite (observation) and the eval
|
||||
/// (modification). The back-end interface consists of modules which supply
|
||||
/// the features for the vm's logic. The m::vm operates primarily as a global
|
||||
/// singleton and facilitates synchronization between multiple ircd::ctx's
|
||||
/// using its interfaces.
|
||||
///
|
||||
/// The query suite tries to satisfy a query using the current state of the vm,
|
||||
/// the database, and may even use the network. An idea of a basic pseudo-
|
||||
/// query: was user X a member of room Y when event Z happened? Is X a member
|
||||
/// of Y right now? etc.
|
||||
///
|
||||
/// The vm::eval is the primary input receptacle for events. The eval of an
|
||||
/// event leads to its execution and will advance the global state of IRCd. That
|
||||
/// advance may broadcast its effects to clients of IRCd, federation servers,
|
||||
/// and alter the responses to future queries. Execution of an event is a
|
||||
/// unique phenomenon: it only happens once. IRCd has thenceforth borne witness
|
||||
/// to the event and will never execute it again unless it is forgotten by
|
||||
/// erasing the db. Simulation options allow for evals without execution.
|
||||
///
|
||||
/// The back-end provides the business logic and features for the above user
|
||||
/// interfaces.
|
||||
///
|
||||
namespace ircd::m::vm
|
||||
{
|
||||
IRCD_M_EXCEPTION(m::error, VM_ERROR, http::INTERNAL_SERVER_ERROR);
|
||||
|
@ -44,12 +21,9 @@ namespace ircd::m::vm
|
|||
enum fault :uint;
|
||||
struct front;
|
||||
struct eval;
|
||||
struct opts;
|
||||
|
||||
using closure = std::function<void (const event &)>;
|
||||
using closure_bool = std::function<bool (const event &)>;
|
||||
using dbs::where;
|
||||
using dbs::query;
|
||||
using dbs::cursor;
|
||||
|
||||
extern struct log::log log;
|
||||
|
@ -57,65 +31,41 @@ namespace ircd::m::vm
|
|||
extern uint64_t current_sequence;
|
||||
extern ctx::view<const event> inserted;
|
||||
|
||||
bool test(const query<> &, const closure_bool &);
|
||||
bool test(const query<> &);
|
||||
bool until(const query<> &, const closure_bool &);
|
||||
bool until(const query<> &);
|
||||
void for_each(const query<> &, const closure &);
|
||||
void for_each(const closure &);
|
||||
size_t count(const query<> &, const closure_bool &);
|
||||
size_t count(const query<> &);
|
||||
|
||||
event::id::buf commit(json::iov &event);
|
||||
event::id::buf commit(json::iov &event, const json::iov &content);
|
||||
}
|
||||
|
||||
/// Evaluation Options
|
||||
struct ircd::m::vm::opts
|
||||
/// Event Evaluation Device
|
||||
///
|
||||
/// This object conducts the evaluation of an event or a tape of multiple
|
||||
/// events. An event is evaluated in an attempt to execute it. Events which
|
||||
/// fail during evaluation won't be executed; such is the case for events which
|
||||
/// have already been executed, or events which are invalid or lead to invalid
|
||||
/// transitions or actions of the machine etc.
|
||||
///
|
||||
struct ircd::m::vm::eval
|
||||
{
|
||||
/// Setting to false will disable the eval from exiting with a fault and
|
||||
/// instead consider all faults as errors which throw exceptions. If
|
||||
/// nothrow is also specified then the exception will be stored in the
|
||||
/// exception_ptr and #gp will be set.
|
||||
bool faults {true};
|
||||
struct opts;
|
||||
|
||||
/// Setting to true will prevent any exception throwing from an eval and
|
||||
/// instead only use the exception_ptr field. Note that eval does not make
|
||||
/// a noexcept guarantee with or without this option and it may still throw
|
||||
/// some rare or unexpected exception aborting the eval.
|
||||
bool nothrow {false};
|
||||
struct opts static const default_opts;
|
||||
|
||||
/// Setting to true will cause a successful eval to commit the result
|
||||
/// which writes to the db and has global effects for the server.
|
||||
/// False is the simulation mode to test evaluation without effects.
|
||||
bool commit {false};
|
||||
const struct opts *opts {&default_opts};
|
||||
db::txn txn{*dbs::events};
|
||||
uint64_t cs{0};
|
||||
|
||||
/// Setting to false will prevent the release sequence after a commit.
|
||||
/// This is a really bad thing to do. testing/debug/devel use only.
|
||||
bool release {true};
|
||||
fault operator()(const event &);
|
||||
|
||||
/// Setting to true will force the eval to be aware of an m.room.create
|
||||
/// for a room for anything to succeed. There will be #ef's until found.
|
||||
bool genesis {false};
|
||||
eval(const event &, const struct opts & = default_opts);
|
||||
eval(const struct opts &);
|
||||
eval() = default;
|
||||
|
||||
/// Setting to true will cause #ef's until there is at least one unbroken
|
||||
/// link of events down to an m.room.create.
|
||||
bool cosmogonic {false};
|
||||
friend string_view reflect(const fault &);
|
||||
};
|
||||
|
||||
/// Setting to true will cause #ef's until the entire reference cone is
|
||||
/// known by the evaluation (if legit). i.e full history tree.
|
||||
bool fullcone {false};
|
||||
/// Evaluation Options
|
||||
struct ircd::m::vm::eval::opts
|
||||
{
|
||||
|
||||
/// Setting to 1 forces evaluations to only proceed from oldest to newest
|
||||
/// events; the capstan will only operate using forward mode and positive
|
||||
/// accumulations. Because events only reference the past the machine won't
|
||||
/// always #ef, it will just stop. More events can be input. Setting to
|
||||
/// -1 is anti-causal: evaluations only proceed from newest to oldest and
|
||||
/// only negative accumulations are used. 0 is automatic and may use both.
|
||||
int causal {0};
|
||||
|
||||
/// Option to skip event signature verification when false.
|
||||
bool verify_signature {true};
|
||||
};
|
||||
|
||||
/// Individual evaluation state
|
||||
|
@ -138,64 +88,6 @@ enum ircd::m::vm::fault
|
|||
STATE, ///< Required state is missing (#st)
|
||||
};
|
||||
|
||||
/// Event Evaluation Device
|
||||
///
|
||||
/// This object conducts the evaluation of an event or a tape of multiple
|
||||
/// events. An event is evaluated in an attempt to execute it. Events which
|
||||
/// fail during evaluation won't be executed; such is the case for events which
|
||||
/// have already been executed, or events which are invalid or lead to invalid
|
||||
/// transitions or actions of the machine etc.
|
||||
///
|
||||
/// Basic usage of the eval is simply calling the ctor like a function with an
|
||||
/// event; with the default options this evaluates and executes the event
|
||||
/// throwing all errors. Advanced usage of eval takes the form of an instance
|
||||
/// constructed with options; the user then drives the eval in a loop,
|
||||
/// responding to its needs for more data or other issues, and then continuing
|
||||
/// the loop until satisfied.
|
||||
///
|
||||
/// The back-end interface consists of a set of modules which register with the
|
||||
/// vm::eval class and provide their piece of eval functionality to instances.
|
||||
///
|
||||
struct ircd::m::vm::eval
|
||||
{
|
||||
static const struct opts default_opts;
|
||||
|
||||
const struct opts *opts;
|
||||
db::txn txn{*event::events};
|
||||
std::set<event::id> ef;
|
||||
uint64_t cs {0};
|
||||
|
||||
fault operator()();
|
||||
fault operator()(const event &);
|
||||
fault operator()(const vector_view<const event> &);
|
||||
fault operator()(const json::vector &);
|
||||
fault operator()(const json::array &);
|
||||
|
||||
template<class events> eval(const struct opts &, events&&);
|
||||
template<class events> eval(const events &);
|
||||
eval(const struct opts &);
|
||||
eval();
|
||||
|
||||
friend string_view reflect(const fault &);
|
||||
};
|
||||
|
||||
/// Convenience construction passes events through to operator().
|
||||
template<class events>
|
||||
ircd::m::vm::eval::eval(const events &event)
|
||||
:eval(default_opts)
|
||||
{
|
||||
operator()(event);
|
||||
}
|
||||
|
||||
/// Convenience construction passes events through to operator().
|
||||
template<class events>
|
||||
ircd::m::vm::eval::eval(const struct opts &opts,
|
||||
events&& event)
|
||||
:eval(opts)
|
||||
{
|
||||
operator()(std::forward<events>(event));
|
||||
}
|
||||
|
||||
/// The "event front" for a graph. This holds all of the childless events
|
||||
/// for a room. Each childless event may exist at a different depth, but
|
||||
/// we track the highest depth to increment it for issuing the next event.
|
||||
|
|
1607
ircd/m/dbs.cc
1607
ircd/m/dbs.cc
File diff suppressed because it is too large
Load diff
875
ircd/m/event.cc
875
ircd/m/event.cc
|
@ -10,48 +10,6 @@
|
|||
|
||||
#include <ircd/m/m.h>
|
||||
|
||||
decltype(ircd::m::event::column)
|
||||
ircd::m::event::column
|
||||
{};
|
||||
|
||||
decltype(ircd::m::event::events)
|
||||
ircd::m::event::events
|
||||
{};
|
||||
|
||||
//
|
||||
// init
|
||||
//
|
||||
|
||||
ircd::m::event::init::init()
|
||||
{
|
||||
// Open the events database
|
||||
event::events = std::make_shared<database>("events"s, ""s, event::description);
|
||||
|
||||
// Cache the columns for the event tuple in order for constant time lookup
|
||||
std::array<string_view, event::size()> keys; //TODO: why did this happen?
|
||||
_key_transform(event{}, begin(keys), end(keys)); //TODO: how did this happen?
|
||||
for(size_t i(0); i < keys.size(); ++i)
|
||||
event::column[i] = db::column
|
||||
{
|
||||
*event::events, keys[i]
|
||||
};
|
||||
}
|
||||
|
||||
ircd::m::event::init::~init()
|
||||
noexcept
|
||||
{
|
||||
// Columns have to be closed before DB closes
|
||||
for(auto &column : event::column)
|
||||
column = {};
|
||||
|
||||
// Close DB (if no other ref)
|
||||
event::events = {};
|
||||
}
|
||||
|
||||
//
|
||||
// misc
|
||||
//
|
||||
|
||||
ircd::m::id::event
|
||||
ircd::m::event_id(const event &event,
|
||||
id::event::buf &buf)
|
||||
|
@ -357,15 +315,15 @@ ircd::m::pretty_oneline(const event &event)
|
|||
ircd::m::event::event(const id &id,
|
||||
const mutable_buffer &buf)
|
||||
{
|
||||
assert(events);
|
||||
assert(bool(dbs::events));
|
||||
|
||||
db::gopts opts;
|
||||
opts.snapshot = database::snapshot{*events};
|
||||
for(size_t i(0); i < column.size(); ++i)
|
||||
opts.snapshot = database::snapshot{*dbs::events};
|
||||
for(size_t i(0); i < dbs::event_column.size(); ++i)
|
||||
{
|
||||
const db::cell cell
|
||||
{
|
||||
column[i], id, opts
|
||||
dbs::event_column[i], id, opts
|
||||
};
|
||||
|
||||
db::assign(*this, cell, id);
|
||||
|
@ -378,828 +336,3 @@ ircd::m::event::event(const id &id,
|
|||
|
||||
new (this) m::event(obj);
|
||||
}
|
||||
|
||||
ircd::m::event::event(fetch &tab)
|
||||
{
|
||||
io::acquire(tab);
|
||||
}
|
||||
|
||||
//
|
||||
// Database descriptors
|
||||
//
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_event_id_descriptor
|
||||
{
|
||||
// name
|
||||
"event_id",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
10.1
|
||||
The id of event.
|
||||
|
||||
10.4
|
||||
MUST NOT exceed 255 bytes.
|
||||
|
||||
### developer note:
|
||||
key is event_id. This is redundant data but we have to have it for now.
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_type_descriptor
|
||||
{
|
||||
// name
|
||||
"type",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
10.1
|
||||
The type of event. This SHOULD be namespaced similar to Java package naming conventions
|
||||
e.g. 'com.example.subdomain.event.type'.
|
||||
|
||||
10.4
|
||||
MUST NOT exceed 255 bytes.
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_content_descriptor
|
||||
{
|
||||
// name
|
||||
"content",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
10.1
|
||||
The fields in this object will vary depending on the type of event. When interacting
|
||||
with the REST API, this is the HTTP body.
|
||||
|
||||
### developer note:
|
||||
Since events must not exceed 65 KB the maximum size for the content is the remaining
|
||||
space after all the other fields for the event are rendered.
|
||||
|
||||
key is event_id
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_room_id_descriptor
|
||||
{
|
||||
// name
|
||||
"room_id",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
10.2 (apropos room events)
|
||||
Required. The ID of the room associated with this event.
|
||||
|
||||
10.4
|
||||
MUST NOT exceed 255 bytes.
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_sender_descriptor
|
||||
{
|
||||
// name
|
||||
"sender",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
10.2 (apropos room events)
|
||||
Required. Contains the fully-qualified ID of the user who sent this event.
|
||||
|
||||
10.4
|
||||
MUST NOT exceed 255 bytes.
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_state_key_descriptor
|
||||
{
|
||||
// name
|
||||
"state_key",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
10.3 (apropos room state events)
|
||||
A unique key which defines the overwriting semantics for this piece of room state.
|
||||
This value is often a zero-length string. The presence of this key makes this event a
|
||||
State Event. The key MUST NOT start with '_'.
|
||||
|
||||
10.4
|
||||
MUST NOT exceed 255 bytes.
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_origin_descriptor
|
||||
{
|
||||
// name
|
||||
"origin",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
FEDERATION 4.1
|
||||
DNS name of homeserver that created this PDU
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_origin_server_ts_descriptor
|
||||
{
|
||||
// name
|
||||
"origin_server_ts",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
FEDERATION 4.1
|
||||
Timestamp in milliseconds on origin homeserver when this PDU was created.
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
value is a machine integer (binary)
|
||||
|
||||
TODO: consider unsigned rather than time_t because of millisecond precision
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(time_t)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_unsigned_descriptor
|
||||
{
|
||||
// name
|
||||
"unsigned",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_signatures_descriptor
|
||||
{
|
||||
// name
|
||||
"signatures",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_auth_events_descriptor
|
||||
{
|
||||
// name
|
||||
"auth_events",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id.
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_depth_descriptor
|
||||
{
|
||||
// name
|
||||
"depth",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id value is long integer
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(int64_t)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_hashes_descriptor
|
||||
{
|
||||
// name
|
||||
"hashes",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id.
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_membership_descriptor
|
||||
{
|
||||
// name
|
||||
"membership",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id.
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_prev_events_descriptor
|
||||
{
|
||||
// name
|
||||
"prev_events",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id.
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
events_prev_state_descriptor
|
||||
{
|
||||
// name
|
||||
"prev_state",
|
||||
|
||||
// explanation
|
||||
R"(### protocol note:
|
||||
|
||||
### developer note:
|
||||
key is event_id.
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
}
|
||||
};
|
||||
|
||||
/// prefix transform for event_id suffixes
|
||||
///
|
||||
/// This transform expects a concatenation ending with an event_id which means
|
||||
/// the prefix can be the same for multiple event_id's; therefor we can find
|
||||
/// or iterate "event_id in X" where X is some key like a room_id
|
||||
///
|
||||
const ircd::db::prefix_transform
|
||||
event_id_in
|
||||
{
|
||||
"event_id in",
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return key.find('$') != key.npos;
|
||||
},
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return rsplit(key, '$').first;
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
event_id_in_sender
|
||||
{
|
||||
// name
|
||||
"event_id in sender",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
key is "@sender$event_id"
|
||||
the prefix transform is in effect. this column indexes events by
|
||||
sender offering an iterable bound of the index prefixed by sender
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator
|
||||
{},
|
||||
|
||||
// prefix transform
|
||||
event_id_in,
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
state_head_for_event_id_in_room_id
|
||||
{
|
||||
// name
|
||||
"state_head for event_id in room_id",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
key is "!room_id$event_id"
|
||||
the prefix transform is in effect. this column indexes events by
|
||||
room_id offering an iterable bound of the index prefixed by room_id
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator - sorts from highest to lowest
|
||||
{}, //ircd::db::reverse_cmp_ircd::string_view{},
|
||||
|
||||
// prefix transform
|
||||
event_id_in,
|
||||
};
|
||||
|
||||
/// prefix transform for origin in
|
||||
///
|
||||
/// This transform expects a concatenation ending with an origin which means
|
||||
/// the prefix can be the same for multiple origins; therefor we can find
|
||||
/// or iterate "origin in X" where X is some repeated prefix
|
||||
///
|
||||
/// TODO: strings will have character conflicts. must address
|
||||
const ircd::db::prefix_transform
|
||||
origin_in
|
||||
{
|
||||
"origin in",
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return has(key, ":::");
|
||||
//return key.find(':') != key.npos;
|
||||
},
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return split(key, ":::").first;
|
||||
//return rsplit(key, ':').first;
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
origin_in_room_id
|
||||
{
|
||||
// name
|
||||
"origin in room_id",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
key is "!room_id:origin"
|
||||
the prefix transform is in effect. this column indexes origins in a
|
||||
room_id offering an iterable bound of the index prefixed by room_id
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator - sorts from highest to lowest
|
||||
{}, //ircd::db::reverse_cmp_string_view{},
|
||||
|
||||
// prefix transform
|
||||
origin_in,
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
origin_joined_in_room_id
|
||||
{
|
||||
// name
|
||||
"origin_joined in room_id",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
key is "!room_id:origin"
|
||||
the prefix transform is in effect. this column indexes origins in a
|
||||
room_id offering an iterable bound of the index prefixed by room_id
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator - sorts from highest to lowest
|
||||
{}, //ircd::db::reverse_cmp_string_view{},
|
||||
|
||||
// prefix transform
|
||||
origin_in,
|
||||
};
|
||||
|
||||
/// prefix transform for room_id
|
||||
///
|
||||
/// This transform expects a concatenation ending with a room_id which means
|
||||
/// the prefix can be the same for multiple room_id's; therefor we can find
|
||||
/// or iterate "room_id in X" where X is some repeated prefix
|
||||
///
|
||||
const ircd::db::prefix_transform room_id_in
|
||||
{
|
||||
"room_id in",
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return key.find('!') != key.npos;
|
||||
},
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return rsplit(key, '!').first;
|
||||
}
|
||||
};
|
||||
|
||||
/// prefix transform for type,state_key in room_id
|
||||
///
|
||||
/// This transform is special for concatenating room_id with type and state_key
|
||||
/// in that order with prefix being the room_id (this may change to room_id+
|
||||
/// type
|
||||
///
|
||||
/// TODO: arbitrary type strings will have character conflicts. must address
|
||||
/// TODO: with grammars.
|
||||
const ircd::db::prefix_transform type_state_key_in_room_id
|
||||
{
|
||||
"type,state_key in room_id",
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return key.find("..") != key.npos;
|
||||
},
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return split(key, "..").first;
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
event_id_for_type_state_key_in_room_id
|
||||
{
|
||||
// name
|
||||
"event_id for type,state_key in room_id",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator
|
||||
{},
|
||||
|
||||
// prefix transform
|
||||
type_state_key_in_room_id
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
prev_event_id_for_event_id_in_room_id
|
||||
{
|
||||
// name
|
||||
"prev_event_id for event_id in room_id",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator
|
||||
{},
|
||||
|
||||
// prefix transform
|
||||
event_id_in
|
||||
};
|
||||
|
||||
/// prefix transform for event_id in room_id,type,state_key
|
||||
///
|
||||
/// This transform is special for concatenating room_id with type and state_key
|
||||
/// and event_id in that order with prefix being the room_id,type,state_key. This
|
||||
/// will index multiple event_ids with the same type,state_key in a room which
|
||||
/// allows for a temporal depth to the database; event_id for type,state_key only
|
||||
/// resolves to a single latest event and overwrites itself as per the room state
|
||||
/// algorithm whereas this can map all of them and then allows for tracing.
|
||||
///
|
||||
/// TODO: arbitrary type strings will have character conflicts. must address
|
||||
/// TODO: with grammars.
|
||||
const ircd::db::prefix_transform
|
||||
event_id_in_room_id_type_state_key
|
||||
{
|
||||
"event_id in room_id,type_state_key",
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return has(key, '$');
|
||||
},
|
||||
[](const ircd::string_view &key)
|
||||
{
|
||||
return split(key, '$').first;
|
||||
}
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
prev_event_id_for_type_state_key_event_id_in_room_id
|
||||
{
|
||||
// name
|
||||
"prev_event_id for type,state_key,event_id in room_id",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator
|
||||
{},
|
||||
|
||||
// prefix transform
|
||||
event_id_in_room_id_type_state_key
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
state_head
|
||||
{
|
||||
// name
|
||||
"state_head",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
key is "!room_id"
|
||||
value is the key of a state_node
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator
|
||||
{},
|
||||
|
||||
// prefix transform
|
||||
{},
|
||||
};
|
||||
|
||||
const ircd::database::descriptor
|
||||
state_node
|
||||
{
|
||||
// name
|
||||
"state_node",
|
||||
|
||||
// explanation
|
||||
R"(### developer note:
|
||||
|
||||
)",
|
||||
|
||||
// typing (key, value)
|
||||
{
|
||||
typeid(ircd::string_view), typeid(ircd::string_view)
|
||||
},
|
||||
|
||||
// options
|
||||
{},
|
||||
|
||||
// comparator
|
||||
{},
|
||||
|
||||
// prefix transform
|
||||
{},
|
||||
};
|
||||
|
||||
decltype(ircd::m::event::description)
|
||||
ircd::m::event::description
|
||||
{
|
||||
{ "default" },
|
||||
|
||||
////////
|
||||
//
|
||||
// These columns directly represent event fields indexed by event_id and
|
||||
// the value is the actual event values. Some values may be JSON, like
|
||||
// content.
|
||||
//
|
||||
events_event_id_descriptor,
|
||||
events_type_descriptor,
|
||||
events_content_descriptor,
|
||||
events_room_id_descriptor,
|
||||
events_sender_descriptor,
|
||||
events_state_key_descriptor,
|
||||
events_origin_descriptor,
|
||||
events_origin_server_ts_descriptor,
|
||||
events_unsigned_descriptor,
|
||||
events_signatures_descriptor,
|
||||
events_auth_events_descriptor,
|
||||
events_depth_descriptor,
|
||||
events_hashes_descriptor,
|
||||
events_membership_descriptor,
|
||||
events_prev_events_descriptor,
|
||||
events_prev_state_descriptor,
|
||||
|
||||
////////
|
||||
//
|
||||
// These columns are metadata composed from the event data. Specifically,
|
||||
// they are designed for fast sequential iterations.
|
||||
//
|
||||
|
||||
// (sender, event_id) => ()
|
||||
// Sequence of all events in all rooms for a sender, EVER
|
||||
// * broad but useful in cases
|
||||
event_id_in_sender,
|
||||
|
||||
// (room_id, event_id) => (state_head)
|
||||
// Sequence of all events for a room, EVER
|
||||
// * broad but useful in cases
|
||||
// ? eliminate for prev_event?
|
||||
// ? eliminate/combine with state tree related?
|
||||
state_head_for_event_id_in_room_id,
|
||||
|
||||
// (room_id, origin) => ()
|
||||
// Sequence of all origins for a room, EVER
|
||||
//TODO: value should have [JOIN, LEAVE, ...) counts/data
|
||||
//TODO: remove?
|
||||
origin_in_room_id,
|
||||
|
||||
// (room_id, origin) => ()
|
||||
// Sequence of all origins with joined member for a room, AT PRESENT
|
||||
// * Intended to be a fast sequential iteration for sending out messages.
|
||||
origin_joined_in_room_id,
|
||||
|
||||
// (room_id, type, state_key) => (event_id)
|
||||
// Sequence of events of type+state_key in a room, AT PRESENT
|
||||
// * Fast for current room state iteration, but only works for the present.
|
||||
event_id_for_type_state_key_in_room_id,
|
||||
|
||||
////////
|
||||
//
|
||||
// These columns are metadata composed from the event data. They are
|
||||
// linked forward lists where the value is used to lookup the next key
|
||||
// TODO: these might be better as sequences; if not removed altogether.
|
||||
//
|
||||
|
||||
// (room_id, event_id) => (prev event_id)
|
||||
// List of events in a room resolving to the previous event in a room
|
||||
// in our subjective euclidean tape TOTAL order.
|
||||
// * This is where any branches in the DAG are linearized based on how we
|
||||
// feel the state machine should execute them one by one.
|
||||
// * This is not a sequence; each value is the key for another lookup.
|
||||
prev_event_id_for_event_id_in_room_id,
|
||||
|
||||
// (room_id, type, state_key, event_id) => (prev event_id)
|
||||
// Events of a (type, state_key) in a room resolving to the previous event
|
||||
// of (type, state_key) in a room in our subjective euclidean tape order.
|
||||
// * Similar to the above but focuses only on state events for various
|
||||
// "state chains"
|
||||
prev_event_id_for_type_state_key_event_id_in_room_id,
|
||||
|
||||
////////
|
||||
//
|
||||
// These columns are metadata composed from the event data. They are
|
||||
// used to create structures that can represent the state of a room
|
||||
// at any given event.
|
||||
//
|
||||
|
||||
// (room_id) => (state_head)
|
||||
state_head,
|
||||
|
||||
// (state tree node id) => (state tree node)
|
||||
//
|
||||
state_node,
|
||||
};
|
||||
|
|
|
@ -190,8 +190,8 @@ ircd::m::init_listener(const json::object &conf,
|
|||
void
|
||||
ircd::m::init::bootstrap()
|
||||
{
|
||||
assert(event::events);
|
||||
assert(db::sequence(*event::events) == 0);
|
||||
assert(dbs::events);
|
||||
assert(db::sequence(*dbs::events) == 0);
|
||||
|
||||
ircd::log::notice
|
||||
(
|
||||
|
|
283
ircd/m/vm.cc
283
ircd/m/vm.cc
|
@ -20,6 +20,14 @@ decltype(ircd::m::vm::fronts)
|
|||
ircd::m::vm::fronts
|
||||
{};
|
||||
|
||||
ircd::ctx::view<const ircd::m::event>
|
||||
ircd::m::vm::inserted
|
||||
{};
|
||||
|
||||
uint64_t
|
||||
ircd::m::vm::current_sequence
|
||||
{};
|
||||
|
||||
/// This function takes an event object vector and adds our origin and event_id
|
||||
/// and hashes and signature and attempts to inject the event into the core.
|
||||
/// The caller is expected to have done their best to check if this event will
|
||||
|
@ -202,119 +210,27 @@ ircd::m::vm::commit(json::iov &iov)
|
|||
|
||||
namespace ircd::m::vm
|
||||
{
|
||||
bool check_fault_resume(eval &);
|
||||
void check_fault_throw(eval &);
|
||||
|
||||
void write(eval &);
|
||||
|
||||
enum fault evaluate(eval &, const event &);
|
||||
enum fault evaluate(eval &, const vector_view<const event> &);
|
||||
}
|
||||
|
||||
decltype(ircd::m::vm::eval::default_opts)
|
||||
ircd::m::vm::eval::default_opts
|
||||
{};
|
||||
|
||||
ircd::m::vm::eval::eval()
|
||||
:eval(default_opts)
|
||||
{
|
||||
}
|
||||
|
||||
ircd::m::vm::eval::eval(const struct opts &opts)
|
||||
:opts{&opts}
|
||||
{
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::eval::operator()()
|
||||
ircd::m::vm::eval::eval(const event &event,
|
||||
const struct opts &opts)
|
||||
:opts{&opts}
|
||||
{
|
||||
assert(0);
|
||||
return fault::ACCEPT;
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::eval::operator()(const json::array &events)
|
||||
{
|
||||
std::vector<m::event> event;
|
||||
event.reserve(events.count());
|
||||
|
||||
auto it(begin(events));
|
||||
for(; it != end(events); ++it)
|
||||
event.emplace_back(*it);
|
||||
|
||||
return operator()(vector_view<const m::event>(event));
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::eval::operator()(const json::vector &events)
|
||||
{
|
||||
std::vector<m::event> event;
|
||||
event.reserve(events.count());
|
||||
|
||||
auto it(begin(events));
|
||||
for(; it != end(events); ++it)
|
||||
event.emplace_back(*it);
|
||||
|
||||
return operator()(vector_view<const m::event>(event));
|
||||
operator()(event);
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::eval::operator()(const event &event)
|
||||
{
|
||||
return operator()(vector_view<const m::event>(&event, 1));
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::eval::operator()(const vector_view<const event> &events)
|
||||
{
|
||||
static const size_t max
|
||||
{
|
||||
128
|
||||
};
|
||||
|
||||
for(size_t i(0); i < events.size(); i += max)
|
||||
{
|
||||
const vector_view<const event> evs
|
||||
{
|
||||
events.data() + i, std::min(events.size() - i, size_t(max))
|
||||
};
|
||||
|
||||
enum fault code;
|
||||
switch((code = evaluate(*this, evs)))
|
||||
{
|
||||
case fault::ACCEPT:
|
||||
continue;
|
||||
|
||||
default:
|
||||
//check_fault_throw(*this);
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
return fault::ACCEPT;
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::evaluate(eval &eval,
|
||||
const vector_view<const event> &event)
|
||||
{
|
||||
|
||||
for(size_t i(0); i < event.size(); ++i)
|
||||
{
|
||||
if(evaluate(eval, event[i]) == fault::ACCEPT)
|
||||
{
|
||||
log.info("%s", pretty_oneline(event[i]));
|
||||
vm::inserted.notify(event[i]);
|
||||
}
|
||||
}
|
||||
|
||||
write(eval);
|
||||
return fault::ACCEPT;
|
||||
}
|
||||
|
||||
enum ircd::m::vm::fault
|
||||
ircd::m::vm::evaluate(eval &eval,
|
||||
const event &event)
|
||||
{
|
||||
const auto &event_id
|
||||
{
|
||||
|
@ -323,28 +239,49 @@ ircd::m::vm::evaluate(eval &eval,
|
|||
|
||||
const auto &depth
|
||||
{
|
||||
json::get<"depth"_>(event, 0)
|
||||
at<"depth"_>(event)
|
||||
};
|
||||
|
||||
const auto &room_id
|
||||
{
|
||||
json::get<"room_id"_>(event)
|
||||
at<"room_id"_>(event)
|
||||
};
|
||||
|
||||
auto &front
|
||||
const auto &type
|
||||
{
|
||||
fronts.get(room_id, event)
|
||||
at<"type"_>(event)
|
||||
};
|
||||
|
||||
front.top = depth;
|
||||
|
||||
auto code
|
||||
const event::prev prev{event};
|
||||
const json::array prev0
|
||||
{
|
||||
fault::ACCEPT
|
||||
at<"prev_events"_>(prev)[0]
|
||||
};
|
||||
|
||||
dbs::write(event, eval.txn);
|
||||
return code;
|
||||
const string_view previd
|
||||
{
|
||||
unquote(prev0[0])
|
||||
};
|
||||
|
||||
char old_rootbuf[64];
|
||||
const auto old_root
|
||||
{
|
||||
previd? dbs::state_root(old_rootbuf, previd) : string_view{}
|
||||
};
|
||||
|
||||
char new_rootbuf[64];
|
||||
const auto new_root
|
||||
{
|
||||
dbs::write(txn, new_rootbuf, old_root, event)
|
||||
};
|
||||
|
||||
++cs;
|
||||
log.info("%s %s",
|
||||
new_root,
|
||||
pretty_oneline(event));
|
||||
|
||||
write(*this);
|
||||
return fault::ACCEPT;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -359,54 +296,6 @@ ircd::m::vm::write(eval &eval)
|
|||
eval.cs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
bool
|
||||
ircd::m::vm::check_fault_resume(eval &eval)
|
||||
{
|
||||
switch(fault)
|
||||
{
|
||||
case fault::ACCEPT:
|
||||
return true;
|
||||
|
||||
default:
|
||||
check_fault_throw(eval);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::vm::check_fault_throw(eval &eval)
|
||||
{
|
||||
// With nothrow there is nothing else for this function to do as the user
|
||||
// will have to test the fault code and error ptr manually.
|
||||
if(eval.opts->nothrow)
|
||||
return;
|
||||
|
||||
switch(fault)
|
||||
{
|
||||
case fault::ACCEPT:
|
||||
return;
|
||||
|
||||
case fault::GENERAL:
|
||||
if(eval.error)
|
||||
std::rethrow_exception(eval.error);
|
||||
// [[fallthrough]]
|
||||
|
||||
default:
|
||||
throw VM_FAULT("(%u): %s", uint(fault), reflect(fault));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
ircd::ctx::view<const ircd::m::event>
|
||||
ircd::m::vm::inserted
|
||||
{};
|
||||
|
||||
uint64_t
|
||||
ircd::m::vm::current_sequence
|
||||
{};
|
||||
|
||||
ircd::m::vm::front &
|
||||
ircd::m::vm::fronts::get(const room::id &room_id,
|
||||
const event &event)
|
||||
|
@ -520,92 +409,6 @@ ircd::m::vm::fetch(const room::id &room_id,
|
|||
return front;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::vm::test(const query<> &where)
|
||||
{
|
||||
return test(where, [](const auto &event)
|
||||
{
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::vm::test(const query<> &clause,
|
||||
const closure_bool &closure)
|
||||
{
|
||||
bool ret{false};
|
||||
dbs::_query(clause, [&ret, &closure](const auto &event)
|
||||
{
|
||||
ret = closure(event);
|
||||
return true;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::vm::until(const query<> &where)
|
||||
{
|
||||
return until(where, [](const auto &event)
|
||||
{
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::vm::until(const query<> &clause,
|
||||
const closure_bool &closure)
|
||||
{
|
||||
bool ret{true};
|
||||
dbs::_query(clause, [&ret, &closure](const auto &event)
|
||||
{
|
||||
ret = closure(event);
|
||||
return ret;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::vm::count(const query<> &where)
|
||||
{
|
||||
return count(where, [](const auto &event)
|
||||
{
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::vm::count(const query<> &where,
|
||||
const closure_bool &closure)
|
||||
{
|
||||
size_t i(0);
|
||||
for_each(where, [&closure, &i](const auto &event)
|
||||
{
|
||||
i += closure(event);
|
||||
});
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::vm::for_each(const closure &closure)
|
||||
{
|
||||
const query<where::noop> where{};
|
||||
for_each(where, closure);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::m::vm::for_each(const query<> &clause,
|
||||
const closure &closure)
|
||||
{
|
||||
dbs::_query(clause, [&closure](const auto &event)
|
||||
{
|
||||
closure(event);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::vm::reflect(const enum fault &code)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue