0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-05-29 08:13:46 +02:00

ircd:Ⓜ️:vm: Reorg commit stack; move room commit thing to m::vm.

This commit is contained in:
Jason Volk 2018-05-06 16:04:51 -07:00
parent 7758a80927
commit 68c863e7f9
10 changed files with 390 additions and 224 deletions

View file

@ -113,7 +113,7 @@ struct ircd::m::room
id room_id;
event::id event_id;
const vm::opts::commit *opts {nullptr};
const vm::copts *opts {nullptr};
operator const id &() const;
@ -145,13 +145,13 @@ struct ircd::m::room
bool membership(const m::id::user &, const string_view &membership = "join") const;
string_view membership(const mutable_buffer &out, const m::id::user &) const;
room(const id &room_id, const string_view &event_id, const vm::opts::commit *const &opts = nullptr)
room(const id &room_id, const string_view &event_id, const vm::copts *const &opts = nullptr)
:room_id{room_id}
,event_id{event_id? event::id{event_id} : event::id{}}
,opts{opts}
{}
room(const id &room_id, const vm::opts::commit *const &opts = nullptr)
room(const id &room_id, const vm::copts *const &opts = nullptr)
:room_id{room_id}
,opts{opts}
{}

View file

@ -18,6 +18,7 @@ namespace ircd::m::vm
struct init;
struct error; // custom exception
struct opts;
struct copts;
struct eval;
struct accepted;
enum fault :uint;
@ -27,6 +28,7 @@ namespace ircd::m::vm
extern uint64_t current_sequence;
extern ctx::shared_view<accepted> accept;
extern const opts default_opts;
extern const copts default_copts;
const uint64_t &sequence(const eval &);
uint64_t retired_sequence(id::event::buf &);
@ -49,14 +51,24 @@ struct ircd::m::vm::init
///
struct ircd::m::vm::eval
{
const vm::opts *opts;
db::txn *txn;
const vm::opts *opts {&default_opts};
const vm::copts *copts {nullptr};
db::txn *txn {nullptr};
uint64_t sequence {0};
event::id::buf event_id;
operator const event::id::buf &() const;
fault operator()(const event &);
fault operator()(json::iov &event, const json::iov &content);
fault operator()(const room &, json::iov &event, const json::iov &content);
eval(const vm::opts &);
eval(const vm::copts &);
eval(const event &, const vm::opts & = default_opts);
eval(const vm::opts & = default_opts);
eval(json::iov &event, const json::iov &content, const vm::copts & = default_copts);
eval(const room &, json::iov &event, const json::iov &content);
eval() = default;
eval(eval &&) = delete;
eval(const eval &) = delete;
@ -88,9 +100,6 @@ enum ircd::m::vm::fault
/// Evaluation Options
struct ircd::m::vm::opts
{
// Extended opts specific to creating events originating from this server.
struct commit;
/// Make writes to database
bool write {true};
@ -186,18 +195,10 @@ struct ircd::m::vm::opts
bool infolog_accept {false};
};
namespace ircd::m::vm
{
extern const opts::commit default_commit_opts;
fault commit(const m::event &, const opts::commit & = default_commit_opts);
event::id::buf commit(json::iov &event, const json::iov &content, const opts::commit & = default_commit_opts);
}
/// Extension structure to vm::opts which includes additional options for
/// commissioning events originating from this server which are then passed
/// through eval (this process is committing).
struct ircd::m::vm::opts::commit
struct ircd::m::vm::copts
:opts
{
// Hash and include hashes object.

View file

@ -2108,14 +2108,29 @@ ircd::m::commit(const room &room,
json::iov &event,
const json::iov &contents)
{
using prototype = event::id::buf (const m::room &, json::iov &, const json::iov &);
static import<prototype> function
vm::copts opts
{
"client_rooms", "commit__iov_iov"
room.opts? *room.opts : vm::default_copts
};
return function(room, event, contents);
// Some functionality on this server may create an event on behalf
// of remote users. It's safe for us to mask this here, but eval'ing
// this event in any replay later will require special casing.
opts.non_conform |= event::conforms::MISMATCH_ORIGIN_SENDER;
// Stupid protocol workaround
opts.non_conform |= event::conforms::MISSING_PREV_STATE;
// Don't need this here
opts.verify = false;
vm::eval eval
{
opts
};
eval(room, event, contents);
return eval.event_id;
}
ircd::m::id::room::buf

View file

@ -26,8 +26,8 @@ decltype(ircd::m::vm::default_opts)
ircd::m::vm::default_opts
{};
decltype(ircd::m::vm::default_commit_opts)
ircd::m::vm::default_commit_opts
decltype(ircd::m::vm::default_copts)
ircd::m::vm::default_copts
{};
//
@ -59,18 +59,319 @@ ircd::m::vm::init::~init()
current_sequence? string_view{event_id} : "NO EVENTS"_sv);
}
//
// commit
//
/// 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.
///
ircd::m::event::id::buf
ircd::m::vm::commit(json::iov &event,
const json::iov &contents,
const opts::commit &opts)
namespace ircd::m::vm
{
extern hook::site commit_hook;
}
decltype(ircd::m::vm::commit_hook)
ircd::m::vm::commit_hook
{
{ "name", "vm.commit" }
};
//
// Eval
//
// Processes any event from any place from any time and does whatever is
// necessary to validate, reject, learn from new information, ignore old
// information and advance the state of IRCd as best as possible.
namespace ircd::m::vm
{
extern hook::site eval_hook;
extern hook::site notify_hook;
void _tmp_effects(const m::event &event); //TODO: X
void write(eval &);
fault _eval_edu(eval &, const event &);
fault _eval_pdu(eval &, const event &);
}
decltype(ircd::m::vm::eval_hook)
ircd::m::vm::eval_hook
{
{ "name", "vm.eval" }
};
decltype(ircd::m::vm::notify_hook)
ircd::m::vm::notify_hook
{
{ "name", "vm.notify" }
};
ircd::m::vm::eval::eval(const room &room,
json::iov &event,
const json::iov &content)
:eval{}
{
operator()(room, event, content);
}
ircd::m::vm::eval::eval(json::iov &event,
const json::iov &content,
const vm::copts &opts)
:eval{opts}
{
operator()(event, content);
}
ircd::m::vm::eval::eval(const event &event,
const vm::opts &opts)
:eval{opts}
{
operator()(event);
}
ircd::m::vm::eval::eval(const vm::copts &opts)
:opts{&opts}
,copts{&opts}
{
}
ircd::m::vm::eval::eval(const vm::opts &opts)
:opts{&opts}
{
}
ircd::m::vm::eval::operator
const event::id::buf &()
const
{
return event_id;
}
/// Inject a new event in a room originating from this server.
///
enum ircd::m::vm::fault
ircd::m::vm::eval::operator()(const room &room,
json::iov &event,
const json::iov &contents)
{
// This eval entry point is only used for commits. We try to find the
// commit opts the user supplied directly to this eval or with the room.
if(!copts)
copts = room.opts;
if(!copts)
copts = &vm::default_copts;
// Note that the regular opts is unconditionally overridden because the
// user should have provided copts instead.
this->opts = copts;
const auto &opts(this->copts);
const json::iov::push room_id
{
event, { "room_id", room.room_id }
};
int64_t depth{-1};
event::id::buf prev_event_id
{
};
if(room.event_id)
prev_event_id = room.event_id;
else
std::tie(prev_event_id, depth, std::ignore) = m::top(std::nothrow, room.room_id);
//TODO: X
const event::fetch evf
{
prev_event_id, std::nothrow
};
if(room.event_id)
depth = at<"depth"_>(evf);
//TODO: X
const json::iov::set_if depth_
{
event, !event.has("depth"),
{
"depth", depth + 1
}
};
char ae_buf[512];
json::array auth_events
{
json::get<"auth_events"_>(evf)?
json::get<"auth_events"_>(evf):
json::array{"[]"}
};
if(depth != -1)
{
std::vector<json::value> ae;
room.get(std::nothrow, "m.room.create", "", [&ae]
(const m::event &event)
{
const json::value ae0[]
{
{ json::get<"event_id"_>(event) },
{ json::get<"hashes"_>(event) }
};
const json::value ae_
{
ae0, 2
};
ae.emplace_back(ae_);
});
room.get(std::nothrow, "m.room.join_rules", "", [&ae]
(const m::event &event)
{
const json::value ae0[]
{
{ json::get<"event_id"_>(event) },
{ json::get<"hashes"_>(event) }
};
const json::value ae_
{
ae0, 2
};
ae.emplace_back(ae_);
});
auth_events = json::stringify(mutable_buffer{ae_buf}, json::value
{
ae.data(), ae.size()
});
room.get(std::nothrow, "m.room.power_levels", "", [&ae]
(const m::event &event)
{
const json::value ae0[]
{
{ json::get<"event_id"_>(event) },
{ json::get<"hashes"_>(event) }
};
const json::value ae_
{
ae0, 2
};
ae.emplace_back(ae_);
});
auth_events = json::stringify(mutable_buffer{ae_buf}, json::value
{
ae.data(), ae.size()
});
if(event.at("type") != "m.room.member")
room.get(std::nothrow, "m.room.member", event.at("sender"), [&ae]
(const m::event &event)
{
const json::value ae0[]
{
{ json::get<"event_id"_>(event) },
{ json::get<"hashes"_>(event) }
};
const json::value ae_
{
ae0, 2
};
ae.emplace_back(ae_);
});
auth_events = json::stringify(mutable_buffer{ae_buf}, json::value
{
ae.data(), ae.size()
});
}
//TODO: X
const auto &prev_state
{
json::get<"prev_state"_>(evf)?
json::get<"prev_state"_>(evf):
json::array{"[]"}
};
/*
const event::fetch pvf
{
prev_event_id, std::nothrow
};
*/
//TODO: X
json::value prev_event0[]
{
{ string_view{prev_event_id} },
{ json::get<"hashes"_>(evf) }
};
//TODO: X
json::value prev_event
{
prev_event0, empty(prev_event_id)? 0UL: 2UL
};
//TODO: X
json::value prev_events_
{
&prev_event, !empty(prev_event_id)
};
std::string prev_events
{
json::strung(prev_events_)
};
//TODO: X
const json::iov::push prevs[]
{
{ event, { "auth_events", auth_events } },
{ event, { "prev_events", prev_events } },
{ event, { "prev_state", prev_state } },
};
return operator()(event, contents);
}
/// Inject a new event originating from this server.
///
/// Figure 1:
/// in . <-- injection
/// ===:::::::==//
/// | ||||||| // <-- this function
/// | \\|// //|
/// | ||| // | | acceleration
/// | |||// | |
/// | |||/ | |
/// | ||| | V
/// | !!! |
/// | * | <----- nozzle
/// | ///|||\\\ |
/// |/|/|/|\|\|\| <---- propagation cone
/// _/|/|/|/|\|\|\|\_
/// out
///
enum ircd::m::vm::fault
ircd::m::vm::eval::operator()(json::iov &event,
const json::iov &contents)
{
// This eval entry point is only used for commits. If the user did not
// supply commit opts we supply the default ones here.
if(!copts)
copts = &vm::default_copts;
// Note that the regular opts is unconditionally overridden because the
// user should have provided copts instead.
assert(copts);
this->opts = copts;
const auto &opts(*this->copts);
const json::iov::add_if _origin
{
event, opts.origin,
@ -109,11 +410,10 @@ ircd::m::vm::commit(json::iov &event,
};
}
event::id::buf eid_buf;
const string_view event_id
{
opts.event_id?
make_id(event, eid_buf, event_id_hash):
make_id(event, this->event_id, event_id_hash):
string_view{}
};
@ -157,124 +457,30 @@ ircd::m::vm::commit(json::iov &event,
event, { "content", content },
};
commit(event, opts);
return eid_buf;
}
namespace ircd::m::vm
{
extern hook::site commit_hook;
}
decltype(ircd::m::vm::commit_hook)
ircd::m::vm::commit_hook
{
{ "name", "vm.commit" }
};
/// Insert a new event originating from this server.
///
/// Figure 1:
/// in . <-- injection
/// ===:::::::==//
/// | ||||||| // <-- this function
/// | \\|// //|
/// | ||| // | | acceleration
/// | |||// | |
/// | |||/ | |
/// | ||| | V
/// | !!! |
/// | * | <----- nozzle
/// | ///|||\\\ |
/// |/|/|/|\|\|\| <---- propagation cone
/// _/|/|/|/|\|\|\|\_
/// out
///
ircd::m::vm::fault
ircd::m::vm::commit(const event &event,
const opts::commit &opts)
{
if(opts.debuglog_precommit)
log.debug("injecting event(mark +%ld) %s",
vm::current_sequence,
pretty_oneline(event));
check_size(event);
commit_hook(event);
auto opts_{opts};
opts_.verify = false;
// Some functionality on this server may create an event on behalf
// of remote users. It's safe for us to mask this here, but eval'ing
// this event in any replay later will require special casing.
opts_.non_conform |= event::conforms::MISMATCH_ORIGIN_SENDER;
//TODO: X
opts_.non_conform |= event::conforms::MISSING_PREV_STATE;
vm::eval eval{opts_};
const fault ret
{
eval(event)
};
if(opts_.infolog_postcommit)
log.info("%s @%lu %s",
reflect(ret),
sequence(eval),
pretty_oneline(event, false));
return ret;
}
//
// Eval
//
// Processes any event from any place from any time and does whatever is
// necessary to validate, reject, learn from new information, ignore old
// information and advance the state of IRCd as best as possible.
namespace ircd::m::vm
{
extern hook::site eval_hook;
extern hook::site notify_hook;
void _tmp_effects(const m::event &event); //TODO: X
void write(eval &);
fault _eval_edu(eval &, const event &);
fault _eval_pdu(eval &, const event &);
}
decltype(ircd::m::vm::eval_hook)
ircd::m::vm::eval_hook
{
{ "name", "vm.eval" }
};
decltype(ircd::m::vm::notify_hook)
ircd::m::vm::notify_hook
{
{ "name", "vm.notify" }
};
ircd::m::vm::eval::eval(const vm::opts &opts)
:opts{&opts}
,txn{nullptr}
{
}
ircd::m::vm::eval::eval(const event &event,
const vm::opts &opts)
:eval{opts}
{
operator()(event);
return operator()(event);
}
enum ircd::m::vm::fault
ircd::m::vm::eval::operator()(const event &event)
try
{
if(copts)
{
if(unlikely(!my_host(at<"origin"_>(event))))
throw error
{
fault::GENERAL, "Committing event for origin: %s", at<"origin"_>(event)
};
if(copts->debuglog_precommit)
log.debug("injecting event(mark +%ld) %s",
vm::current_sequence,
pretty_oneline(event));
check_size(event);
commit_hook(event);
}
assert(opts);
const event::conforms &report
{

View file

@ -190,15 +190,18 @@ bootstrap(const m::room::alias &room_alias,
{ content, !empty(avatar_url), { "avatar_url", avatar_url }},
};
m::vm::opts::commit opts;
m::vm::copts opts;
opts.non_conform.set(m::event::conforms::MISSING_MEMBERSHIP);
opts.non_conform.set(m::event::conforms::MISSING_PREV_STATE);
opts.prev_check_exists = false;
opts.history = false;
opts.infolog_accept = true;
const auto event_id
const m::event::id::buf event_id
{
m::vm::commit(event, content, opts)
m::vm::eval
{
event, content, opts
}
};
const unique_buffer<mutable_buffer> ebuf

View file

@ -112,15 +112,17 @@ commit__m_receipt_m_read(const m::room::id &room_id,
}}}
};
m::vm::opts::commit opts;
m::vm::copts opts;
opts.hash = false;
opts.sign = false;
opts.event_id = false;
opts.origin = true;
opts.origin_server_ts = false;
opts.conforming = false;
return m::vm::commit(event, content, opts);
return m::vm::eval
{
event, content, opts
};
}
bool

View file

@ -190,66 +190,3 @@ method_post
method_post.REQUIRES_AUTH
}
};
extern "C" event::id::buf
commit__iov_iov(const room &room,
json::iov &event,
const json::iov &contents)
{
const json::iov::push room_id
{
event, { "room_id", room.room_id }
};
int64_t depth;
event::id::buf prev_event_id;
std::tie(prev_event_id, depth, std::ignore) = m::top(std::nothrow, room.room_id);
//TODO: X
const json::iov::set_if depth_
{
event, !event.has("depth"),
{
"depth", depth + 1
}
};
//TODO: X
const string_view auth_events{};
//TODO: X
const string_view prev_state{};
//TODO: X
json::value prev_event0
{
prev_event_id, json::STRING
};
//TODO: X
json::value prev_event
{
&prev_event0, !empty(prev_event_id)
};
//TODO: X
json::value prev_events
{
&prev_event, !empty(prev_event_id)
};
//TODO: X
const json::iov::push prevs[]
{
{ event, { "auth_events", auth_events } },
{ event, { "prev_state", prev_state } },
{ event, { "prev_events", prev_events } },
};
const auto &vmopts
{
room.opts? *room.opts : vm::default_commit_opts
};
return m::vm::commit(event, contents, vmopts);
}

View file

@ -159,15 +159,17 @@ commit__m_typing(const m::typing &edu)
{ content, { "typing", json::get<"typing"_>(edu) } },
};
m::vm::opts::commit opts;
m::vm::copts opts;
opts.hash = false;
opts.sign = false;
opts.event_id = false;
opts.origin = true;
opts.origin_server_ts = false;
opts.conforming = false;
return m::vm::commit(event, content, opts);
return m::vm::eval
{
event, content, opts
};
}
ircd::steady_point

View file

@ -152,7 +152,7 @@ try
content_type
};
m::vm::opts::commit vmopts;
m::vm::copts vmopts;
vmopts.history = false;
const m::room room
{

View file

@ -58,7 +58,7 @@ post__upload(client &client,
file_room_id(server, randstr)
};
m::vm::opts::commit vmopts;
m::vm::copts vmopts;
vmopts.history = false;
const m::room room
{