0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2025-04-29 13:04:17 +02:00

ircd:Ⓜ️:vm: Additional fetch phases; split fetch hook sites.

This commit is contained in:
Jason Volk 2020-05-11 20:24:54 -07:00
parent 0fd5570c14
commit b764e75692
12 changed files with 142 additions and 99 deletions

View file

@ -160,22 +160,24 @@ enum ircd::m::vm::phase
DUPCHK = 0x01, ///< Duplicate check & hold.
EXECUTE = 0x02, ///< Execution entered.
ISSUE = 0x03, ///< Issue phase.
CONFORM = 0x04, ///< Conformity phase.
CONFORM = 0x04, ///< Conformity check 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.
FETCH_AUTH = 0x07, ///< Authentication events fetch phase.
AUTH_STATIC = 0x08, ///< Static authentication phase.
FETCH_PREV = 0x09, ///< Previous events fetch phase.
FETCH_STATE = 0x0a, ///< State events fetch phase.
PRECOMMIT = 0x0b, ///< Precommit sequence.
AUTH_RELA = 0x0c, ///< Relative authentication phase.
COMMIT = 0x0d, ///< Commit sequence.
AUTH_PRES = 0x0e, ///< Authentication phase.
EVALUATE = 0x0f, ///< Evaluation phase.
INDEX = 0x10, ///< Indexing & transaction building phase.
POST = 0x11, ///< Transaction-included effects phase.
WRITE = 0x12, ///< Write transaction.
RETIRE = 0x13, ///< Retire phase
NOTIFY = 0x14, ///< Notifications phase.
EFFECTS = 0x15, ///< Effects phase.
_NUM_
};
@ -209,6 +211,9 @@ struct ircd::m::vm::opts
/// False to bypass all auth phases.
bool auth {true};
/// False to bypass all fetch phases.
bool fetch {true};
/// Mask of conformity failures to allow without considering dirty.
event::conforms non_conform;
@ -267,16 +272,6 @@ struct ircd::m::vm::opts
/// perform a parallel/mass fetch before proceeding with the evals.
bool mfetch_keys {true};
/// Whether to automatically fetch the auth events when they do not exist.
bool fetch_auth {true};
/// Whether to automatically fetch the room state when there is no state
/// or incomplete state for the room found on the this server.
bool fetch_state {true};
/// Dispatches a fetch operation when a prev_event does not exist locally.
bool fetch_prev {true};
/// Throws fault::EVENT if *all* of the prev_events do not exist locally.
/// This is used to enforce that at least one path is traversable. This
/// test is conducted after waiting if fetch_prev and fetch_prev_wait.

View file

@ -313,8 +313,8 @@ try
m::vm::opts vmopts;
vmopts.infolog_accept = true;
vmopts.fetch_prev = !below_viewport;
vmopts.fetch_state = below_viewport;
vmopts.phase.set(m::vm::phase::FETCH_PREV, !below_viewport);
vmopts.phase.set(m::vm::phase::FETCH_STATE, below_viewport);
vmopts.warnlog &= ~vm::fault::EXISTS;
vmopts.node_id = opts.hint;
vmopts.notify_servers = false;

View file

@ -256,8 +256,8 @@ try
vmopts.warnlog &= ~vm::fault::EXISTS;
vmopts.nothrows = -1;
vmopts.room_version = room_version;
vmopts.fetch_state = false;
vmopts.fetch_prev = false;
vmopts.phase.reset(m::vm::phase::FETCH_PREV);
vmopts.phase.reset(m::vm::phase::FETCH_STATE);
m::roomstrap::fetch_keys(auth_chain);
m::roomstrap::eval_auth_chain(auth_chain, vmopts);
@ -544,7 +544,7 @@ try
};
vmopts.nothrows = vm::fault::EXISTS;
vmopts.phase.reset(vm::phase::FETCH);
vmopts.fetch = false;
m::vm::eval
{
auth_chain, vmopts
@ -781,7 +781,7 @@ try
vmopts.infolog_accept = true;
vmopts.room_version = room_version;
vmopts.user_id = user_id;
vmopts.phase.reset(vm::phase::FETCH);
vmopts.fetch = false;
vmopts.auth = false;
const vm::eval eval
{

View file

@ -169,12 +169,14 @@ ircd::m::vm::reflect(const enum phase &code)
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::FETCH_AUTH: return "FETCH_AUTH";
case phase::AUTH_STATIC: return "AUTH_STATIC";
case phase::FETCH_PREV: return "FETCH_PREV";
case phase::FETCH_STATE: return "FETCH_STATE";
case phase::PRECOMMIT: return "PRECOMMIT";
case phase::AUTHRELA: return "AUTHRELA";
case phase::AUTH_RELA: return "AUTH_RELA";
case phase::COMMIT: return "COMMIT";
case phase::AUTHPRES: return "AUTHPRES";
case phase::AUTH_PRES: return "AUTH_PRES";
case phase::EVALUATE: return "EVALUATE";
case phase::INDEX: return "INDEX";
case phase::POST: return "POST";

View file

@ -24,14 +24,16 @@ namespace ircd::m::vm
static void fini();
static void init();
extern hook::site<eval &> issue_hook; ///< Called when this server is issuing event
extern hook::site<eval &> conform_hook; ///< Called for static evaluations of event
extern hook::site<eval &> access_hook; ///< Called for access control checking
extern hook::site<eval &> fetch_hook; ///< Called to resolve dependencies
extern hook::site<eval &> eval_hook; ///< Called for final event evaluation
extern hook::site<eval &> post_hook; ///< Called to apply effects pre-notify
extern hook::site<eval &> notify_hook; ///< Called to broadcast successful eval
extern hook::site<eval &> effect_hook; ///< Called to apply effects post-notify
extern hook::site<eval &> issue_hook; ///< Called when this server is issuing event
extern hook::site<eval &> conform_hook; ///< Called for static evaluations of event
extern hook::site<eval &> access_hook; ///< Called for access control checking
extern hook::site<eval &> fetch_auth_hook; ///< Called to resolve dependencies
extern hook::site<eval &> fetch_prev_hook; ///< Called to resolve dependencies
extern hook::site<eval &> fetch_state_hook; ///< Called to resolve dependencies
extern hook::site<eval &> eval_hook; ///< Called for final event evaluation
extern hook::site<eval &> post_hook; ///< Called to apply effects pre-notify
extern hook::site<eval &> notify_hook; ///< Called to broadcast successful eval
extern hook::site<eval &> effect_hook; ///< Called to apply effects post-notify
extern conf::item<bool> log_commit_debug;
extern conf::item<bool> log_accept_debug;
@ -77,10 +79,22 @@ ircd::m::vm::access_hook
{ "name", "vm.access" }
};
decltype(ircd::m::vm::fetch_hook)
ircd::m::vm::fetch_hook
decltype(ircd::m::vm::fetch_auth_hook)
ircd::m::vm::fetch_auth_hook
{
{ "name", "vm.fetch" }
{ "name", "vm.fetch.auth" }
};
decltype(ircd::m::vm::fetch_prev_hook)
ircd::m::vm::fetch_prev_hook
{
{ "name", "vm.fetch.prev" }
};
decltype(ircd::m::vm::fetch_state_hook)
ircd::m::vm::fetch_state_hook
{
{ "name", "vm.fetch.state" }
};
decltype(ircd::m::vm::eval_hook)
@ -594,23 +608,22 @@ ircd::m::vm::execute_pdu(eval &eval,
"Signature verification failed."
};
// Fetch dependencies
if(likely(opts.phase[phase::FETCH]))
if(likely(opts.phase[phase::FETCH_AUTH] && opts.fetch))
{
const scope_restore eval_phase
{
eval.phase, phase::FETCH
eval.phase, phase::FETCH_AUTH
};
call_hook(fetch_hook, eval, event, eval);
call_hook(fetch_auth_hook, eval, event, eval);
}
// Evaluation by auth system; throws
if(likely(opts.phase[phase::AUTHSTATIC]) && authenticate)
if(likely(opts.phase[phase::AUTH_STATIC]) && authenticate)
{
const scope_restore eval_phase
{
eval.phase, phase::AUTHSTATIC
eval.phase, phase::AUTH_STATIC
};
const auto &[pass, fail]
@ -626,6 +639,26 @@ ircd::m::vm::execute_pdu(eval &eval,
};
}
if(likely(opts.phase[phase::FETCH_PREV] && opts.fetch))
{
const scope_restore eval_phase
{
eval.phase, phase::FETCH_PREV
};
call_hook(fetch_prev_hook, eval, event, eval);
}
if(likely(opts.phase[phase::FETCH_STATE] && opts.fetch))
{
const scope_restore eval_phase
{
eval.phase, phase::FETCH_STATE
};
call_hook(fetch_state_hook, eval, event, eval);
}
// Obtain sequence number here.
const auto *const &top(eval::seqmax());
eval.sequence_shared[0] = 0;
@ -653,8 +686,13 @@ ircd::m::vm::execute_pdu(eval &eval,
return eval::seqnext(sequence::uncommitted) == &eval;
});
if(likely(opts.phase[phase::AUTHRELA]) && authenticate)
if(likely(opts.phase[phase::AUTH_RELA]) && authenticate)
{
const scope_restore eval_phase
{
eval.phase, phase::AUTH_RELA
};
const auto &[pass, fail]
{
room::auth::check_relative(event)
@ -692,11 +730,11 @@ ircd::m::vm::execute_pdu(eval &eval,
});
// Reevaluation of auth against the present state of the room.
if(likely(opts.phase[phase::AUTHPRES]) && authenticate)
if(likely(opts.phase[phase::AUTH_PRES]) && authenticate)
{
const scope_restore eval_phase
{
eval.phase, phase::AUTHPRES
eval.phase, phase::AUTH_PRES
};
room::auth::check_present(event);

View file

@ -13619,8 +13619,8 @@ console_cmd__fed__sync(opt &out, const string_view &line)
m::vm::opts vmopts;
vmopts.nothrows = -1;
vmopts.debuglog_accept = true;
vmopts.fetch_prev = false;
vmopts.fetch_state = false;
vmopts.phase.set(m::vm::phase::FETCH_PREV, false);
vmopts.phase.set(m::vm::phase::FETCH_STATE, false);
vmopts.notify_servers = false;
char rembuf[256];
vmopts.node_id = string(rembuf, remote);
@ -13736,8 +13736,8 @@ console_cmd__fed__state(opt &out, const string_view &line)
m::vm::opts vmopts;
vmopts.nothrows = -1;
vmopts.fetch_state = false;
vmopts.fetch_prev = false;
vmopts.phase.set(m::vm::phase::FETCH_PREV, false);
vmopts.phase.set(m::vm::phase::FETCH_STATE, false);
vmopts.notify_servers = false;
m::vm::eval
@ -13919,8 +13919,8 @@ console_cmd__fed__backfill(opt &out, const string_view &line)
vmopts.nothrows = -1;
vmopts.room_head = false;
vmopts.room_head_resolve = true;
vmopts.fetch_prev = false;
vmopts.fetch_state = false;
vmopts.phase.set(m::vm::phase::FETCH_PREV, false);
vmopts.phase.set(m::vm::phase::FETCH_STATE, false);
char rembuf[256];
vmopts.node_id = string(rembuf, remote);
vmopts.notify_servers = false;
@ -14081,8 +14081,8 @@ console_cmd__fed__event(opt &out, const string_view &line)
if(has(op, "eval"))
{
m::vm::opts vmopts;
vmopts.fetch_prev = has(op, "prev");
vmopts.fetch_state = false;
vmopts.phase.set(m::vm::phase::FETCH_PREV, has(op, "prev"));
vmopts.phase.set(m::vm::phase::FETCH_STATE, false);
vmopts.notify_servers = false;
m::vm::eval eval
{

View file

@ -162,7 +162,7 @@ put__invite(client &client,
vmopts.node_id = request.node_id;
// Synapse may 403 a fetch of the prev_event of the invite event.
vmopts.fetch_prev = false;
vmopts.phase.set(m::vm::phase::FETCH_PREV, false);
// We don't want this eval throwing an exception because the response has
// already been made for this request.

View file

@ -232,7 +232,7 @@ try
vmopts.node_id = request.node_id;
// Synapse may 403 a fetch of the prev_event of the invite event.
vmopts.fetch_prev = false;
vmopts.phase.set(m::vm::phase::FETCH_PREV, false);
// Don't throw an exception for a re-evaluation; this will just be a no-op
vmopts.nothrows |= m::vm::fault::EXISTS;

View file

@ -92,8 +92,8 @@ handle_pdus(client &client,
vmopts.nothrows = -1U;
vmopts.node_id = request.node_id;
vmopts.txn_id = txn_id;
vmopts.fetch_prev = bool(fetch_prev);
vmopts.fetch_state = bool(fetch_state);
vmopts.phase.set(m::vm::phase::FETCH_PREV, bool(fetch_prev));
vmopts.phase.set(m::vm::phase::FETCH_STATE, bool(fetch_state));
vmopts.fetch_prev_wait_count = -1;
m::vm::eval eval
{

View file

@ -153,7 +153,7 @@ put__send_join(client &client,
};
m::vm::opts vmopts;
vmopts.phase.reset(m::vm::phase::FETCH);
vmopts.fetch = false;
m::vm::eval eval
{
event, vmopts

View file

@ -41,7 +41,7 @@ ircd::m::relation::fetch_hook
{
handle_fetch,
{
{ "_site", "vm.fetch" },
{ "_site", "vm.fetch.prev" },
}
};
@ -52,10 +52,7 @@ try
{
assert(eval.opts);
const auto &opts{*eval.opts};
if(!opts.fetch_prev)
return;
if(!fetch_enable)
if(!opts.fetch || !fetch_enable)
return;
if(my(event))
@ -124,8 +121,8 @@ try
};
auto eval_opts(opts);
eval_opts.fetch_prev = false;
eval_opts.fetch_state = false;
eval_opts.phase.set(vm::phase::FETCH_PREV, false);
eval_opts.phase.set(vm::phase::FETCH_STATE, false);
vm::eval
{
result, eval_opts

View file

@ -29,7 +29,9 @@ namespace ircd::m::vm::fetch
extern conf::item<seconds> state_timeout;
extern conf::item<seconds> auth_timeout;
extern conf::item<bool> enable;
extern hookfn<vm::eval &> hook;
extern hookfn<vm::eval &> auth_hook;
extern hookfn<vm::eval &> prev_hook;
extern hookfn<vm::eval &> state_hook;
extern log::log log;
}
@ -45,12 +47,30 @@ ircd::m::vm::fetch::log
"m.vm.fetch"
};
decltype(ircd::m::vm::fetch::hook)
ircd::m::vm::fetch::hook
decltype(ircd::m::vm::fetch::auth_hook)
ircd::m::vm::fetch::auth_hook
{
handle,
{
{ "_site", "vm.fetch" }
{ "_site", "vm.fetch.auth" }
}
};
decltype(ircd::m::vm::fetch::prev_hook)
ircd::m::vm::fetch::prev_hook
{
handle,
{
{ "_site", "vm.fetch.prev" }
}
};
decltype(ircd::m::vm::fetch::state_hook)
ircd::m::vm::fetch::state_hook
{
handle,
{
{ "_site", "vm.fetch.state" }
}
};
@ -120,7 +140,6 @@ ircd::m::vm::fetch::handle(const event &event,
try
{
assert(eval.opts);
assert(eval.opts->phase[phase::FETCH]);
const auto &opts
{
*eval.opts
@ -150,14 +169,14 @@ try
m::room room{room_id};
room.event_id = event_id;
if(opts.fetch_auth)
auth(event, eval, room);
if(eval.phase == phase::FETCH_AUTH)
return auth(event, eval, room);
if(opts.fetch_prev)
prev(event, eval, room);
if(eval.phase == phase::FETCH_PREV)
return prev(event, eval, room);
if(opts.fetch_state)
state(event, eval, room);
if(eval.phase == phase::FETCH_STATE)
return state(event, eval, room);
}
catch(const std::exception &e)
{
@ -222,12 +241,6 @@ try
vm::fault::AUTH, "Fetching auth_events disabled by configuration",
};
if(!opts.fetch_auth)
throw vm::error
{
vm::fault::AUTH, "Not fetching auth_events for this evaluation",
};
// This is a blocking call to recursively fetch and evaluate the auth_chain
// for this event. Upon return all of the auth_events for this event will
// have themselves been fetched and auth'ed recursively.
@ -330,9 +343,7 @@ try
{
assert(eval.opts);
auto opts(*eval.opts);
opts.fetch_prev = false;
opts.fetch_state = false;
opts.fetch_auth = false;
opts.fetch = false;
opts.infolog_accept = true;
opts.warnlog &= ~vm::fault::EXISTS;
opts.notify_servers = false;
@ -444,8 +455,8 @@ try
};
auto opts(*eval.opts);
opts.fetch_prev = false;
opts.fetch_state = false;
opts.phase.set(m::vm::phase::FETCH_PREV, false);
opts.phase.set(m::vm::phase::FETCH_STATE, false);
opts.notify_servers = false;
vm::eval
{
@ -600,7 +611,7 @@ ircd::m::vm::fetch::prev(const event &event,
if(prev_wait(event, eval))
return;
if(!opts.fetch_prev || !m::vm::fetch::enable)
if(!m::vm::fetch::enable)
{
prev_check(event, eval);
return;
@ -673,8 +684,8 @@ ircd::m::vm::fetch::prev(const event &event,
};
auto opts(*eval.opts);
opts.fetch_prev = false;
opts.fetch_state = false;
opts.phase.set(m::vm::phase::FETCH_PREV, false);
opts.phase.set(m::vm::phase::FETCH_STATE, false);
opts.notify_servers = false;
log::debug
{