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:
parent
0fd5570c14
commit
b764e75692
12 changed files with 142 additions and 99 deletions
include/ircd/m
matrix
modules
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
10
matrix/vm.cc
10
matrix/vm.cc
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue