mirror of
https://github.com/matrix-construct/construct
synced 2024-09-27 11:18:51 +02:00
ircd:Ⓜ️:vm: Add enumeration for evaluation phases.
This commit is contained in:
parent
a1708a687e
commit
0fd5570c14
10 changed files with 227 additions and 63 deletions
|
@ -21,6 +21,7 @@ namespace ircd::m::vm
|
||||||
struct copts;
|
struct copts;
|
||||||
struct eval;
|
struct eval;
|
||||||
enum fault :uint;
|
enum fault :uint;
|
||||||
|
enum phase :uint;
|
||||||
using fault_t = std::underlying_type<fault>::type;
|
using fault_t = std::underlying_type<fault>::type;
|
||||||
|
|
||||||
extern const opts default_opts;
|
extern const opts default_opts;
|
||||||
|
@ -30,6 +31,7 @@ namespace ircd::m::vm
|
||||||
extern bool ready;
|
extern bool ready;
|
||||||
|
|
||||||
string_view reflect(const fault &);
|
string_view reflect(const fault &);
|
||||||
|
string_view reflect(const phase &);
|
||||||
http::code http_code(const fault &);
|
http::code http_code(const fault &);
|
||||||
string_view loghead(const mutable_buffer &, const eval &);
|
string_view loghead(const mutable_buffer &, const eval &);
|
||||||
string_view loghead(const eval &); // single tls buffer
|
string_view loghead(const eval &); // single tls buffer
|
||||||
|
@ -88,6 +90,7 @@ struct ircd::m::vm::eval
|
||||||
event::conforms report;
|
event::conforms report;
|
||||||
string_view room_version;
|
string_view room_version;
|
||||||
const hook::base::site *phase_hook {nullptr};
|
const hook::base::site *phase_hook {nullptr};
|
||||||
|
vm::phase phase {vm::phase(0)};
|
||||||
bool room_internal {false};
|
bool room_internal {false};
|
||||||
|
|
||||||
static bool for_each_pdu(const std::function<bool (const event &)> &);
|
static bool for_each_pdu(const std::function<bool (const event &)> &);
|
||||||
|
@ -149,6 +152,33 @@ enum ircd::m::vm::fault
|
||||||
EVENT = 0x20, ///< Eval requires addl events in the ef register (#ef)
|
EVENT = 0x20, ///< Eval requires addl events in the ef register (#ef)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Evaluation phases
|
||||||
|
enum ircd::m::vm::phase
|
||||||
|
:uint
|
||||||
|
{
|
||||||
|
NONE = 0x00, ///< No phase; not entered.
|
||||||
|
DUPCHK = 0x01, ///< Duplicate check & hold.
|
||||||
|
EXECUTE = 0x02, ///< Execution entered.
|
||||||
|
ISSUE = 0x03, ///< Issue phase.
|
||||||
|
CONFORM = 0x04, ///< Conformity phase.
|
||||||
|
ACCESS = 0x05, ///< Access control phase.
|
||||||
|
VERIFY = 0x06, ///< Signature verification.
|
||||||
|
FETCH = 0x07, ///< Fetch phase.
|
||||||
|
AUTHSTATIC = 0x08, ///< Authentication phase.
|
||||||
|
PRECOMMIT = 0x09, ///< Precommit sequence.
|
||||||
|
AUTHRELA = 0x0a, ///< Authentication phase.
|
||||||
|
COMMIT = 0x0b, ///< Commit sequence.
|
||||||
|
AUTHPRES = 0x0c, ///< Authentication phase.
|
||||||
|
EVALUATE = 0x0d, ///< Evaluation phase.
|
||||||
|
INDEX = 0x0e, ///< Indexing & transaction building phase.
|
||||||
|
POST = 0x0f, ///< Transaction-included effects phase.
|
||||||
|
WRITE = 0x10, ///< Write transaction.
|
||||||
|
RETIRE = 0x11, ///< Retire phase
|
||||||
|
NOTIFY = 0x12, ///< Notifications phase.
|
||||||
|
EFFECTS = 0x13, ///< Effects phase.
|
||||||
|
_NUM_
|
||||||
|
};
|
||||||
|
|
||||||
/// Evaluation Options
|
/// Evaluation Options
|
||||||
struct ircd::m::vm::opts
|
struct ircd::m::vm::opts
|
||||||
{
|
{
|
||||||
|
@ -161,46 +191,24 @@ struct ircd::m::vm::opts
|
||||||
/// The txnid from the node conducting the eval.
|
/// The txnid from the node conducting the eval.
|
||||||
string_view txn_id;
|
string_view txn_id;
|
||||||
|
|
||||||
/// Call conform hooks (detailed behavior can be tweaked below)
|
/// Enabled phases of evaluation.
|
||||||
bool conform {true};
|
std::bitset<num_of<vm::phase>()> phase {-1UL};
|
||||||
|
|
||||||
/// Check various access controls before processing event further.
|
|
||||||
bool access {true};
|
|
||||||
|
|
||||||
/// Make fetches or false to bypass fetch stage.
|
|
||||||
bool fetch {true};
|
|
||||||
|
|
||||||
/// Call eval hooks or false to bypass this stage.
|
|
||||||
bool eval {true};
|
|
||||||
|
|
||||||
/// Perform auth or false to bypass this state.
|
|
||||||
bool auth {true};
|
|
||||||
|
|
||||||
/// Make writes to database
|
|
||||||
bool write {true};
|
|
||||||
|
|
||||||
/// Custom write_opts to use during write.
|
/// Custom write_opts to use during write.
|
||||||
dbs::write_opts wopts;
|
dbs::write_opts wopts;
|
||||||
|
|
||||||
/// Call post hooks or false to bypass post-write / pre-notify effects.
|
|
||||||
bool post {true};
|
|
||||||
|
|
||||||
/// Broadcast to clients/servers. When true, individual notify options
|
|
||||||
/// that follow are considered. When false, no notifications occur.
|
|
||||||
short notify {true};
|
|
||||||
|
|
||||||
/// Broadcast to local clients (/sync stream).
|
/// Broadcast to local clients (/sync stream).
|
||||||
bool notify_clients {true};
|
bool notify_clients {true};
|
||||||
|
|
||||||
/// Broadcast to federation servers (/federation/send/).
|
/// Broadcast to federation servers (/federation/send/).
|
||||||
bool notify_servers {true};
|
bool notify_servers {true};
|
||||||
|
|
||||||
/// Apply effects of this event or false to bypass this stage.
|
|
||||||
bool effects {true};
|
|
||||||
|
|
||||||
/// False to allow a dirty conforms report (not recommended).
|
/// False to allow a dirty conforms report (not recommended).
|
||||||
bool conforming {true};
|
bool conforming {true};
|
||||||
|
|
||||||
|
/// False to bypass all auth phases.
|
||||||
|
bool auth {true};
|
||||||
|
|
||||||
/// Mask of conformity failures to allow without considering dirty.
|
/// Mask of conformity failures to allow without considering dirty.
|
||||||
event::conforms non_conform;
|
event::conforms non_conform;
|
||||||
|
|
||||||
|
@ -255,9 +263,6 @@ struct ircd::m::vm::opts
|
||||||
/// if the evaluator already performed this and the json source is good.
|
/// if the evaluator already performed this and the json source is good.
|
||||||
bool json_source {false};
|
bool json_source {false};
|
||||||
|
|
||||||
/// Verify the origin signature; recommended.
|
|
||||||
bool verify {true};
|
|
||||||
|
|
||||||
/// Whether to gather all unknown keys from an input vector of events and
|
/// Whether to gather all unknown keys from an input vector of events and
|
||||||
/// perform a parallel/mass fetch before proceeding with the evals.
|
/// perform a parallel/mass fetch before proceeding with the evals.
|
||||||
bool mfetch_keys {true};
|
bool mfetch_keys {true};
|
||||||
|
|
|
@ -331,7 +331,7 @@ ircd::m::commit(const room &room,
|
||||||
opts.non_conform |= event::conforms::MISMATCH_ORIGIN_SENDER;
|
opts.non_conform |= event::conforms::MISMATCH_ORIGIN_SENDER;
|
||||||
|
|
||||||
// Don't need this here
|
// Don't need this here
|
||||||
opts.verify = false;
|
opts.phase.reset(vm::phase::VERIFY);
|
||||||
|
|
||||||
return vm::eval
|
return vm::eval
|
||||||
{
|
{
|
||||||
|
|
|
@ -544,7 +544,7 @@ try
|
||||||
};
|
};
|
||||||
|
|
||||||
vmopts.nothrows = vm::fault::EXISTS;
|
vmopts.nothrows = vm::fault::EXISTS;
|
||||||
vmopts.fetch = false;
|
vmopts.phase.reset(vm::phase::FETCH);
|
||||||
m::vm::eval
|
m::vm::eval
|
||||||
{
|
{
|
||||||
auth_chain, vmopts
|
auth_chain, vmopts
|
||||||
|
@ -781,7 +781,7 @@ try
|
||||||
vmopts.infolog_accept = true;
|
vmopts.infolog_accept = true;
|
||||||
vmopts.room_version = room_version;
|
vmopts.room_version = room_version;
|
||||||
vmopts.user_id = user_id;
|
vmopts.user_id = user_id;
|
||||||
vmopts.fetch = false;
|
vmopts.phase.reset(vm::phase::FETCH);
|
||||||
vmopts.auth = false;
|
vmopts.auth = false;
|
||||||
const vm::eval eval
|
const vm::eval eval
|
||||||
{
|
{
|
||||||
|
|
|
@ -464,7 +464,7 @@ ircd::m::_create_event(const createroom &c)
|
||||||
|
|
||||||
m::vm::copts opts;
|
m::vm::copts opts;
|
||||||
opts.room_version = room_version;
|
opts.room_version = room_version;
|
||||||
opts.verify = false;
|
opts.phase.reset(vm::phase::VERIFY);
|
||||||
m::vm::eval
|
m::vm::eval
|
||||||
{
|
{
|
||||||
event, content, opts
|
event, content, opts
|
||||||
|
|
30
matrix/vm.cc
30
matrix/vm.cc
|
@ -157,6 +157,36 @@ ircd::m::vm::http_code(const fault &code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::m::vm::reflect(const enum phase &code)
|
||||||
|
{
|
||||||
|
switch(code)
|
||||||
|
{
|
||||||
|
case phase::NONE: return "NONE";
|
||||||
|
case phase::DUPCHK: return "DUPCHK";
|
||||||
|
case phase::EXECUTE: return "EXECUTE";
|
||||||
|
case phase::ISSUE: return "ISSUE";
|
||||||
|
case phase::CONFORM: return "CONFORM";
|
||||||
|
case phase::ACCESS: return "ACCESS";
|
||||||
|
case phase::VERIFY: return "VERIFY";
|
||||||
|
case phase::FETCH: return "FETCH";
|
||||||
|
case phase::AUTHSTATIC: return "AUTHSTATIC";
|
||||||
|
case phase::PRECOMMIT: return "PRECOMMIT";
|
||||||
|
case phase::AUTHRELA: return "AUTHRELA";
|
||||||
|
case phase::COMMIT: return "COMMIT";
|
||||||
|
case phase::AUTHPRES: return "AUTHPRES";
|
||||||
|
case phase::EVALUATE: return "EVALUATE";
|
||||||
|
case phase::INDEX: return "INDEX";
|
||||||
|
case phase::POST: return "POST";
|
||||||
|
case phase::WRITE: return "WRITE";
|
||||||
|
case phase::RETIRE: return "RETIRE";
|
||||||
|
case phase::NOTIFY: return "NOTIFY";
|
||||||
|
case phase::EFFECTS: return "EFFECTS";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "??????";
|
||||||
|
}
|
||||||
|
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::m::vm::reflect(const enum fault &code)
|
ircd::m::vm::reflect(const enum fault &code)
|
||||||
{
|
{
|
||||||
|
|
|
@ -291,7 +291,7 @@ ircd::m::vm::eval::operator()(const vector_view<m::event> &events)
|
||||||
this->pdus, events
|
this->pdus, events
|
||||||
};
|
};
|
||||||
|
|
||||||
if(likely(opts->verify && opts->mfetch_keys))
|
if(likely(opts->phase[phase::VERIFY] && opts->mfetch_keys))
|
||||||
mfetch_keys();
|
mfetch_keys();
|
||||||
|
|
||||||
// Conduct each eval without letting any one exception ruin things for the
|
// Conduct each eval without letting any one exception ruin things for the
|
||||||
|
|
|
@ -128,6 +128,11 @@ try
|
||||||
eval::executing
|
eval::executing
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::EXECUTE
|
||||||
|
};
|
||||||
|
|
||||||
const scope_notify notify
|
const scope_notify notify
|
||||||
{
|
{
|
||||||
vm::dock
|
vm::dock
|
||||||
|
@ -213,11 +218,18 @@ try
|
||||||
// evaluation is finished. If the other was successful, the exists()
|
// evaluation is finished. If the other was successful, the exists()
|
||||||
// check will skip this, otherwise we have to try again here because
|
// check will skip this, otherwise we have to try again here because
|
||||||
// this evaluator might be using different options/credentials.
|
// this evaluator might be using different options/credentials.
|
||||||
if(likely(opts.unique) && event.event_id)
|
if(likely(opts.phase[phase::DUPCHK] && opts.unique) && event.event_id)
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::DUPCHK
|
||||||
|
};
|
||||||
|
|
||||||
sequence::dock.wait([&event]
|
sequence::dock.wait([&event]
|
||||||
{
|
{
|
||||||
return eval::count(event.event_id) <= 1;
|
return eval::count(event.event_id) <= 1;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// We can elide a lot of grief here by not proceeding further and simply
|
// 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
|
// returning fault::EXISTS after an existence check. If we had to wait for
|
||||||
|
@ -320,8 +332,15 @@ try
|
||||||
|
|
||||||
// The issue hook is only called when this server is injecting a newly
|
// The issue hook is only called when this server is injecting a newly
|
||||||
// created event.
|
// created event.
|
||||||
if(eval.copts && eval.copts->issue)
|
if(opts.phase[phase::ISSUE] && eval.copts && eval.copts->issue)
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::ISSUE
|
||||||
|
};
|
||||||
|
|
||||||
call_hook(issue_hook, eval, event, eval);
|
call_hook(issue_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
// Branch on whether the event is an EDU or a PDU
|
// Branch on whether the event is an EDU or a PDU
|
||||||
const fault ret
|
const fault ret
|
||||||
|
@ -344,15 +363,29 @@ try
|
||||||
|
|
||||||
// The event was executed; now we broadcast the good news. This will
|
// The event was executed; now we broadcast the good news. This will
|
||||||
// include notifying client `/sync` and the federation sender.
|
// include notifying client `/sync` and the federation sender.
|
||||||
if(likely(opts.notify))
|
if(likely(opts.phase[phase::NOTIFY]))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::NOTIFY
|
||||||
|
};
|
||||||
|
|
||||||
call_hook(notify_hook, eval, event, eval);
|
call_hook(notify_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
// The "effects" of the event are created by listeners on the effect hook.
|
// The "effects" of the event are created by listeners on the effect hook.
|
||||||
// These can include the creation of even more events, such as creating a
|
// These can include the creation of even more events, such as creating a
|
||||||
// PDU out of an EDU, etc. Unlike the post_hook in execute_pdu(), the
|
// PDU out of an EDU, etc. Unlike the post_hook in execute_pdu(), the
|
||||||
// notify for the event at issue here has already been made.
|
// notify for the event at issue here has already been made.
|
||||||
if(likely(opts.effects))
|
if(likely(opts.phase[phase::EFFECTS]))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::EFFECTS
|
||||||
|
};
|
||||||
|
|
||||||
call_hook(effect_hook, eval, event, eval);
|
call_hook(effect_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
if(opts.infolog_accept || bool(log_accept_info))
|
if(opts.infolog_accept || bool(log_accept_info))
|
||||||
log::info
|
log::info
|
||||||
|
@ -431,11 +464,25 @@ ircd::m::vm::fault
|
||||||
ircd::m::vm::execute_edu(eval &eval,
|
ircd::m::vm::execute_edu(eval &eval,
|
||||||
const event &event)
|
const event &event)
|
||||||
{
|
{
|
||||||
if(likely(eval.opts->eval))
|
if(likely(eval.opts->phase[phase::EVALUATE]))
|
||||||
call_hook(eval_hook, eval, event, eval);
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::EVALUATE
|
||||||
|
};
|
||||||
|
|
||||||
|
call_hook(eval_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(likely(eval.opts->phase[phase::POST]))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::POST
|
||||||
|
};
|
||||||
|
|
||||||
if(likely(eval.opts->post))
|
|
||||||
call_hook(post_hook, eval, event, eval);
|
call_hook(post_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
return fault::ACCEPT;
|
return fault::ACCEPT;
|
||||||
}
|
}
|
||||||
|
@ -487,8 +534,13 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
|
|
||||||
// The conform hook runs static checks on an event's formatting and
|
// The conform hook runs static checks on an event's formatting and
|
||||||
// composure; these checks only require the event data itself.
|
// composure; these checks only require the event data itself.
|
||||||
if(likely(opts.conform))
|
if(likely(opts.phase[phase::CONFORM]))
|
||||||
{
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::CONFORM
|
||||||
|
};
|
||||||
|
|
||||||
const ctx::critical_assertion ca;
|
const ctx::critical_assertion ca;
|
||||||
call_hook(conform_hook, eval, event, eval);
|
call_hook(conform_hook, eval, event, eval);
|
||||||
}
|
}
|
||||||
|
@ -501,11 +553,18 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
|
|
||||||
// Wait for any pending duplicate evals before proceeding.
|
// Wait for any pending duplicate evals before proceeding.
|
||||||
assert(eval::count(event_id));
|
assert(eval::count(event_id));
|
||||||
if(likely(opts.unique))
|
if(likely(opts.phase[phase::DUPCHK] && opts.unique))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::DUPCHK
|
||||||
|
};
|
||||||
|
|
||||||
sequence::dock.wait([&event_id]
|
sequence::dock.wait([&event_id]
|
||||||
{
|
{
|
||||||
return eval::count(event_id) <= 1;
|
return eval::count(event_id) <= 1;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if(likely(opts.unique) && unlikely(eval::count(event_id) > 1))
|
if(likely(opts.unique) && unlikely(eval::count(event_id) > 1))
|
||||||
throw error
|
throw error
|
||||||
|
@ -519,22 +578,41 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
fault::EXISTS, "Event has already been evaluated."
|
fault::EXISTS, "Event has already been evaluated."
|
||||||
};
|
};
|
||||||
|
|
||||||
if(likely(opts.access))
|
if(likely(opts.phase[phase::ACCESS]))
|
||||||
call_hook(access_hook, eval, event, eval);
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::ACCESS
|
||||||
|
};
|
||||||
|
|
||||||
if(likely(opts.verify) && !verify(event))
|
call_hook(access_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(likely(opts.phase[phase::VERIFY]) && unlikely(!verify(event)))
|
||||||
throw m::BAD_SIGNATURE
|
throw m::BAD_SIGNATURE
|
||||||
{
|
{
|
||||||
"Signature verification failed"
|
"Signature verification failed."
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch dependencies
|
// Fetch dependencies
|
||||||
if(likely(opts.fetch))
|
if(likely(opts.phase[phase::FETCH]))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::FETCH
|
||||||
|
};
|
||||||
|
|
||||||
call_hook(fetch_hook, eval, event, eval);
|
call_hook(fetch_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluation by auth system; throws
|
// Evaluation by auth system; throws
|
||||||
if(likely(authenticate))
|
if(likely(opts.phase[phase::AUTHSTATIC]) && authenticate)
|
||||||
{
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::AUTHSTATIC
|
||||||
|
};
|
||||||
|
|
||||||
const auto &[pass, fail]
|
const auto &[pass, fail]
|
||||||
{
|
{
|
||||||
room::auth::check_static(event)
|
room::auth::check_static(event)
|
||||||
|
@ -564,13 +642,18 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
log, "%s | event sequenced", loghead(eval)
|
log, "%s | event sequenced", loghead(eval)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scope_restore eval_phase_precommit
|
||||||
|
{
|
||||||
|
eval.phase, phase::PRECOMMIT
|
||||||
|
};
|
||||||
|
|
||||||
// Wait until this is the lowest sequence number
|
// Wait until this is the lowest sequence number
|
||||||
sequence::dock.wait([&eval]
|
sequence::dock.wait([&eval]
|
||||||
{
|
{
|
||||||
return eval::seqnext(sequence::uncommitted) == &eval;
|
return eval::seqnext(sequence::uncommitted) == &eval;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(likely(authenticate))
|
if(likely(opts.phase[phase::AUTHRELA]) && authenticate)
|
||||||
{
|
{
|
||||||
const auto &[pass, fail]
|
const auto &[pass, fail]
|
||||||
{
|
{
|
||||||
|
@ -597,6 +680,11 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
assert(eval::sequnique(sequence::get(eval)));
|
assert(eval::sequnique(sequence::get(eval)));
|
||||||
sequence::uncommitted = sequence::get(eval);
|
sequence::uncommitted = sequence::get(eval);
|
||||||
|
|
||||||
|
const scope_restore eval_phase_commit
|
||||||
|
{
|
||||||
|
eval.phase, phase::COMMIT
|
||||||
|
};
|
||||||
|
|
||||||
// Wait until this is the lowest sequence number
|
// Wait until this is the lowest sequence number
|
||||||
sequence::dock.wait([&eval]
|
sequence::dock.wait([&eval]
|
||||||
{
|
{
|
||||||
|
@ -604,12 +692,26 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reevaluation of auth against the present state of the room.
|
// Reevaluation of auth against the present state of the room.
|
||||||
if(likely(authenticate))
|
if(likely(opts.phase[phase::AUTHPRES]) && authenticate)
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::AUTHPRES
|
||||||
|
};
|
||||||
|
|
||||||
room::auth::check_present(event);
|
room::auth::check_present(event);
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluation by module hooks
|
// Evaluation by module hooks
|
||||||
if(likely(opts.eval))
|
if(likely(opts.phase[phase::EVALUATE]))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::EVALUATE
|
||||||
|
};
|
||||||
|
|
||||||
call_hook(eval_hook, eval, event, eval);
|
call_hook(eval_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
log::debug
|
log::debug
|
||||||
{
|
{
|
||||||
|
@ -620,22 +722,49 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
assert(sequence::retired < sequence::get(eval));
|
assert(sequence::retired < sequence::get(eval));
|
||||||
sequence::committed = sequence::get(eval);
|
sequence::committed = sequence::get(eval);
|
||||||
|
|
||||||
write_prepare(eval, event);
|
if(likely(opts.phase[phase::INDEX]))
|
||||||
write_append(eval, event);
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::INDEX
|
||||||
|
};
|
||||||
|
|
||||||
|
write_prepare(eval, event);
|
||||||
|
write_append(eval, event);
|
||||||
|
}
|
||||||
|
|
||||||
// Generate post-eval/pre-notify effects. This function may conduct
|
// Generate post-eval/pre-notify effects. This function may conduct
|
||||||
// an entire eval of several more events recursively before returning.
|
// an entire eval of several more events recursively before returning.
|
||||||
if(likely(opts.post))
|
if(likely(opts.phase[phase::POST]))
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::POST
|
||||||
|
};
|
||||||
|
|
||||||
call_hook(post_hook, eval, event, eval);
|
call_hook(post_hook, eval, event, eval);
|
||||||
|
}
|
||||||
|
|
||||||
// Commit the transaction to database iff this eval is at the stack base.
|
// Commit the transaction to database iff this eval is at the stack base.
|
||||||
if(likely(opts.write) && !eval.sequence_shared[0])
|
if(likely(opts.phase[phase::WRITE]) && !eval.sequence_shared[0])
|
||||||
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::WRITE
|
||||||
|
};
|
||||||
|
|
||||||
write_commit(eval);
|
write_commit(eval);
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for sequencing only if this is the stack base, otherwise we'll
|
// Wait for sequencing only if this is the stack base, otherwise we'll
|
||||||
// never return back to that stack base.
|
// never return back to that stack base.
|
||||||
if(likely(!eval.sequence_shared[0]))
|
if(likely(!eval.sequence_shared[0]))
|
||||||
{
|
{
|
||||||
|
const scope_restore eval_phase
|
||||||
|
{
|
||||||
|
eval.phase, phase::RETIRE
|
||||||
|
};
|
||||||
|
|
||||||
sequence::dock.wait([&eval]
|
sequence::dock.wait([&eval]
|
||||||
{
|
{
|
||||||
return eval::seqnext(sequence::retired) == std::addressof(eval);
|
return eval::seqnext(sequence::retired) == std::addressof(eval);
|
||||||
|
|
|
@ -7968,11 +7968,11 @@ console_cmd__eval(opt &out, const string_view &line)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "nowrite"_:
|
case "nowrite"_:
|
||||||
opts.write = false;
|
opts.phase.reset(m::vm::phase::WRITE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "noverify"_:
|
case "noverify"_:
|
||||||
opts.verify = false;
|
opts.phase.reset(m::vm::phase::VERIFY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -14909,7 +14909,7 @@ console_cmd__vm(opt &out, const string_view &line)
|
||||||
<< std::right << std::setw(5) << "DONE" << " "
|
<< std::right << std::setw(5) << "DONE" << " "
|
||||||
<< std::right << std::setw(9) << "SEQUENCE" << " "
|
<< std::right << std::setw(9) << "SEQUENCE" << " "
|
||||||
<< std::right << std::setw(9) << "SEQSHARE" << " "
|
<< std::right << std::setw(9) << "SEQSHARE" << " "
|
||||||
<< std::left << std::setw(9) << "PHASE" << " "
|
<< std::left << std::setw(10) << "PHASE" << " "
|
||||||
<< std::right << std::setw(6) << "SIZE" << " "
|
<< std::right << std::setw(6) << "SIZE" << " "
|
||||||
<< std::right << std::setw(5) << "CELLS" << " "
|
<< std::right << std::setw(5) << "CELLS" << " "
|
||||||
<< std::right << std::setw(8) << "DEPTH" << " "
|
<< std::right << std::setw(8) << "DEPTH" << " "
|
||||||
|
@ -14942,7 +14942,7 @@ console_cmd__vm(opt &out, const string_view &line)
|
||||||
<< std::right << std::setw(5) << done << " "
|
<< std::right << std::setw(5) << done << " "
|
||||||
<< std::right << std::setw(9) << eval->sequence << " "
|
<< std::right << std::setw(9) << eval->sequence << " "
|
||||||
<< std::right << std::setw(9) << std::max(eval->sequence_shared[0], eval->sequence_shared[1]) << " "
|
<< std::right << std::setw(9) << std::max(eval->sequence_shared[0], eval->sequence_shared[1]) << " "
|
||||||
<< std::left << std::setw(9) << (eval->phase_hook? eval->phase_hook->name() : ""_sv) << " "
|
<< std::left << std::setw(10) << trunc(reflect(eval->phase), 10) << " "
|
||||||
<< std::right << std::setw(6) << (eval->txn? eval->txn->bytes() : 0UL) << " "
|
<< std::right << std::setw(6) << (eval->txn? eval->txn->bytes() : 0UL) << " "
|
||||||
<< std::right << std::setw(5) << (eval->txn? eval->txn->size() : 0UL) << " "
|
<< std::right << std::setw(5) << (eval->txn? eval->txn->size() : 0UL) << " "
|
||||||
<< std::right << std::setw(8) << (eval->event_ && eval->event_id? long(json::get<"depth"_>(*eval->event_)) : -1L) << " "
|
<< std::right << std::setw(8) << (eval->event_ && eval->event_id? long(json::get<"depth"_>(*eval->event_)) : -1L) << " "
|
||||||
|
|
|
@ -153,7 +153,7 @@ put__send_join(client &client,
|
||||||
};
|
};
|
||||||
|
|
||||||
m::vm::opts vmopts;
|
m::vm::opts vmopts;
|
||||||
vmopts.fetch = false;
|
vmopts.phase.reset(m::vm::phase::FETCH);
|
||||||
m::vm::eval eval
|
m::vm::eval eval
|
||||||
{
|
{
|
||||||
event, vmopts
|
event, vmopts
|
||||||
|
|
|
@ -120,7 +120,7 @@ ircd::m::vm::fetch::handle(const event &event,
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assert(eval.opts);
|
assert(eval.opts);
|
||||||
assert(eval.opts->fetch);
|
assert(eval.opts->phase[phase::FETCH]);
|
||||||
const auto &opts
|
const auto &opts
|
||||||
{
|
{
|
||||||
*eval.opts
|
*eval.opts
|
||||||
|
|
Loading…
Reference in a new issue