0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2025-03-13 21:10:32 +01:00

ircd:Ⓜ️:vm: Move vm::eval inner-loop logic into vm::execute; fix room_version/event_id.

This commit is contained in:
Jason Volk 2020-03-20 12:44:23 -07:00
parent ebae05d1f3
commit 8db2bf629e
2 changed files with 73 additions and 50 deletions

View file

@ -299,46 +299,11 @@ ircd::m::vm::eval::operator()(const vector_view<m::event> &events)
size_t ret(0);
for(auto it(begin(events)); it != end(events); ++it) try
{
auto &event
const m::event &event
{
const_cast<m::event &>(*it)
*it
};
// We have to set the event_id in the event instance if it didn't come
// with the event JSON.
if(!opts->edu && !event.event_id)
event.event_id = opts->room_version == "3"?
event::id{event::id::v3{this->event_id, event}}:
event::id{event::id::v4{this->event_id, event}};
// If we set the event_id in the event instance we have to unset
// it so other contexts don't see an invalid reference.
const unwind event_id{[&event]
{
event.event_id = json::get<"event_id"_>(event)?
event.event_id:
m::event::id{};
}};
// When a fault::EXISTS would not actually be revealed to the user in
// any way we can elide a lot of grief by checking this here first and
// skipping the event. The query path will be adequately cached anyway.
if(event.event_id && ~(opts->warnlog | opts->errorlog) & fault::EXISTS)
{
// If the event is already being evaluated, wait here until the other
// evaluation is finished. If the other was successful, the exists()
// check will skip this, otherwise we have to try again here because
// this evaluator might be using different options/credentials.
if(likely(opts->unique))
sequence::dock.wait([&event]
{
return eval::count(event.event_id) == 0;
});
if(likely(!opts->replays) && m::exists(event.event_id))
continue;
}
const auto status
{
operator()(event)

View file

@ -18,6 +18,7 @@ namespace ircd::m::vm
static void write_prepare(eval &, const event &);
static fault execute_edu(eval &, const event &);
static fault execute_pdu(eval &, const event &);
static fault execute_du(eval &, const event &);
static fault inject3(eval &, json::iov &, const json::iov &);
static fault inject1(eval &, json::iov &, const json::iov &);
static void fini();
@ -115,7 +116,6 @@ ircd::m::vm::effect_hook
ircd::m::vm::fault
ircd::m::vm::execute(eval &eval,
const event &event)
try
{
// This assertion is tripped if the end of your context's stack is
// danger close; try increasing your stack size.
@ -132,17 +132,10 @@ try
vm::dock
};
// Set a member pointer to the event currently being evaluated. This
// allows other parallel evals to have deep access to this eval.
assert(!eval.event_);
const scope_restore eval_event
assert(eval.opts);
const auto &opts
{
eval.event_, &event
};
const scope_restore<event::id> eval_event_id
{
eval.event_id, event.event_id? event.event_id : eval.event_id
*eval.opts
};
// Set a member to the room_id for convenient access, without stepping on
@ -180,15 +173,80 @@ try
m::version(room_version_buf, room{eval.room_id}, std::nothrow)
};
assert(eval.opts);
assert(eval.event_);
// We have to set the event_id in the event instance if it didn't come
// with the event JSON.
if(!opts.edu && !event.event_id)
const_cast<m::event &>(event).event_id = eval.room_version == "3"?
event::id{event::id::v3{eval.event_id, event}}:
event::id{event::id::v4{eval.event_id, event}};
// If we set the event_id in the event instance we have to unset
// it so other contexts don't see an invalid reference.
const unwind restore_event_id{[&event]
{
const_cast<m::event &>(event).event_id = json::get<"event_id"_>(event)?
event.event_id:
m::event::id{};
}};
// If the event is already being evaluated, wait here until the other
// evaluation is finished. If the other was successful, the exists()
// check will skip this, otherwise we have to try again here because
// this evaluator might be using different options/credentials.
if(likely(opts.unique) && event.event_id)
sequence::dock.wait([&event]
{
return eval::count(event.event_id) <= 1;
});
// We can elide a lot of grief here by not proceeding further and simply
// returning fault::EXISTS after an existence check. If we had to wait for
// a duplicate eval this check will indicate its success.
if(likely(!opts.replays && opts.nothrows & fault::EXISTS) && event.event_id)
if(m::exists(event.event_id))
return fault::EXISTS;
return execute_du(eval, event);
}
ircd::m::vm::fault
ircd::m::vm::execute_du(eval &eval,
const event &event)
try
{
assert(eval.id);
assert(eval.ctx);
assert(eval.opts);
const auto &opts
{
*eval.opts
};
// Set a member pointer to the event currently being evaluated. This
// allows other parallel evals to have deep access to this eval. It also
// will be used to count this event as currently being evaluated.
assert(!eval.event_);
const scope_restore eval_event
{
eval.event_, &event
};
// Ensure the member pointer/buffer to the eval's event_id is set in case
// anything needs this to be in sync with event.event_id. This may be also
// be used to onsider this event as currently being evaluated.
const scope_restore<event::id> eval_event_id
{
eval.event_id,
event.event_id?
event.event_id:
eval.event_id
};
assert(eval.opts->edu || event.event_id);
assert(eval.opts->edu || eval.event_id);
assert(eval.event_id == event.event_id);
assert(eval.event_);
// The issue hook is only called when this server is injecting a newly
// created event.
if(eval.copts && eval.copts->issue)