diff --git a/include/ircd/m/vm.h b/include/ircd/m/vm.h index a269f2977..c99542f41 100644 --- a/include/ircd/m/vm.h +++ b/include/ircd/m/vm.h @@ -36,8 +36,8 @@ namespace ircd::m::vm string_view loghead(const mutable_buffer &, const eval &); string_view loghead(const eval &); // single tls buffer - fault execute(eval &, const event &); - size_t execute(eval &, const vector_view &); + fault execute(eval &, const vector_view &); + fault execute(eval &, const json::array &); fault inject(eval &, json::iov &, const json::iov &); } @@ -84,6 +84,9 @@ struct ircd::m::vm::eval uint64_t sequence {0}; std::shared_ptr txn; unique_mutable_buffer buf; + size_t evaluated {0}; + size_t accepted {0}; + size_t faulted {0}; vector_view pdus; const json::iov *issue {nullptr}; @@ -108,8 +111,8 @@ struct ircd::m::vm::eval eval(const vm::opts &); eval(const vm::copts &); eval(const event &, const vm::opts & = default_opts); - eval(const vector_view &, const vm::opts & = default_opts); - eval(const json::array &event, const vm::opts & = default_opts); + eval(const vector_view &, const vm::opts & = default_opts); + eval(const json::array &, const vm::opts & = default_opts); eval(json::iov &event, const json::iov &content, const vm::copts & = default_copts); eval() = default; eval(eval &&) = delete; diff --git a/matrix/homeserver_bootstrap.cc b/matrix/homeserver_bootstrap.cc index 0c8861b15..8b507d6c1 100644 --- a/matrix/homeserver_bootstrap.cc +++ b/matrix/homeserver_bootstrap.cc @@ -316,15 +316,9 @@ try }; // process the event batch; make the batch size 0 for validate - const size_t accepted - { - validate_json_only? - 0UL: - execute(eval, batch) - }; + if(likely(!validate_json_only)) + execute(eval, batch); - assert(i >= accepted); - accept += accepted; count += i; auto opts(map_opts); @@ -355,10 +349,10 @@ try log::info { - log, "Bootstrap retired:%zu count:%zu accept:%zu %s in %s | %zu event/s; input %s/s; output %s/s", + log, "Bootstrap sequence:%zu accepts:%zu faults:%zu %s in %s | %zu event/s; input %s/s; output %s/s", vm::sequence::retired, - count, - accept, + eval.accepted, + eval.faulted, pretty(pbuf[0], iec(ebytes[1])), stopwatch.pretty(pbuf[1]), (count / std::max(elapsed, 1L)), diff --git a/matrix/vm_eval.cc b/matrix/vm_eval.cc index c08666930..eac158a1d 100644 --- a/matrix/vm_eval.cc +++ b/matrix/vm_eval.cc @@ -360,28 +360,22 @@ ircd::m::vm::eval::eval(json::iov &event, ircd::m::vm::eval::eval(const event &event, const vm::opts &opts) -:eval{opts} +:eval +{ + vector_view(&event, 1), + opts +} { - execute(*this, event); } ircd::m::vm::eval::eval(const json::array &pdus, const vm::opts &opts) :eval{opts} { - std::vector events(begin(pdus), end(pdus)); - if(events.size() > opts.limit) - events.resize(opts.limit); - - // Sort the events first to avoid complicating the evals; the events might - // be from different rooms but it doesn't matter. - if(likely(!opts.ordered)) - std::sort(begin(events), end(events)); - - execute(*this, events); + execute(*this, pdus); } -ircd::m::vm::eval::eval(const vector_view &events, +ircd::m::vm::eval::eval(const vector_view &events, const vm::opts &opts) :eval{opts} { diff --git a/matrix/vm_execute.cc b/matrix/vm_execute.cc index b43c3e21c..26d792927 100644 --- a/matrix/vm_execute.cc +++ b/matrix/vm_execute.cc @@ -18,6 +18,7 @@ namespace ircd::m::vm static fault execute_edu(eval &, const event &); static fault execute_pdu(eval &, const event &); static fault execute_du(eval &, const event &); + static fault execute(eval &, const event &); static fault inject3(eval &, json::iov &, const json::iov &); static fault inject1(eval &, json::iov &, const json::iov &); static void fini(); @@ -128,7 +129,60 @@ ircd::m::vm::effect_hook // execute // -size_t +ircd::m::vm::fault +ircd::m::vm::execute(eval &eval, + const json::array &pdus) +{ + assert(eval.opts); + const auto &opts + { + *eval.opts + }; + + auto it(begin(pdus)); + const bool empty + { + it == end(pdus) + }; + + if(unlikely(empty)) + return fault::ACCEPT; + + // Determine iff pdus.size()==1 without iterating the whole array + const bool single + { + std::next(begin(pdus)) == end(pdus) + }; + + if(likely(single)) + { + const m::event event + { + json::object(*it) + }; + + return execute(eval, vector_view(&event, 1)); + } + + fault ret{fault::ACCEPT}; + std::vector eventv(64); do + { + size_t i(0); + for(; i < eventv.size() && it != end(pdus); ++i, ++it) + eventv[i] = json::object(*it); + + if(likely(!opts.ordered)) + std::sort(begin(eventv), begin(eventv) + i); + + assert(i <= eventv.size()); + execute(eval, vector_view(eventv.data(), i)); //XXX + } + while(it != end(pdus) && eval.evaluated < opts.limit); + + return ret; +} + +ircd::m::vm::fault ircd::m::vm::execute(eval &eval, const vector_view &events) { @@ -147,10 +201,10 @@ ircd::m::vm::execute(eval &eval, eval.mfetch_keys(); size_t accepted(0), existed(0), i, j, k; - for(i = 0; i < events.size() && i < opts.limit; i += j) + for(i = 0; i < events.size(); i += j) { id::event ids[64]; - for(j = 0; j < 64 && i + j < events.size() && i + j < opts.limit; ++j) + for(j = 0; j < 64 && i + j < events.size() && eval.evaluated + j < opts.limit; ++j) ids[j] = events[i + j].event_id; // Bitset indicating which events already exist. @@ -161,8 +215,14 @@ ircd::m::vm::execute(eval &eval, 0UL }; - existed += __builtin_popcountl(exists); - for(k = 0; k < j; ++k) try + const auto num_exists + { + __builtin_popcountl(exists) + }; + + existed += num_exists; + eval.faulted + num_exists; + for(k = 0; k < j; ++k, ++eval.evaluated) try { if(exists & (1 << k)) continue; @@ -173,18 +233,27 @@ ircd::m::vm::execute(eval &eval, }; accepted += status == fault::ACCEPT; + eval.accepted += status == fault::ACCEPT; + eval.faulted += status != fault::ACCEPT; } catch(const ctx::interrupted &) { + ++eval.faulted; throw; } catch(const std::exception &) { + ++eval.faulted; continue; } + catch(...) + { + ++eval.faulted; + throw; + } } - return accepted; + return fault::ACCEPT; } ircd::m::vm::fault diff --git a/matrix/vm_inject.cc b/matrix/vm_inject.cc index 5d24d0c66..bce8453da 100644 --- a/matrix/vm_inject.cc +++ b/matrix/vm_inject.cc @@ -428,7 +428,12 @@ ircd::m::vm::inject1(eval &eval, log, "Issuing: %s", pretty_oneline(event_tuple) }; - return execute(eval, event_tuple); + const vector_view events + { + &event_tuple, 1 + }; + + return execute(eval, events); } /// New event branch @@ -518,5 +523,10 @@ ircd::m::vm::inject3(eval &eval, log, "Issuing: %s", pretty_oneline(event_tuple) }; - return execute(eval, event_tuple); + const vector_view events + { + &event_tuple, 1 + }; + + return execute(eval, events); } diff --git a/modules/console.cc b/modules/console.cc index 8eef42d94..a31c77634 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -7282,40 +7282,23 @@ console_cmd__stage__eval(opt &out, const string_view &line) opts }; - if(id == -1) - for(size_t i(0); i < stage.size(); ++i) - execute(eval, m::event{stage.at(i)}); - else - execute(eval, m::event{stage.at(id)}); - - return true; -} - -bool -console_cmd__stage__commit(opt &out, const string_view &line) -{ - const params param{line, " ", + if(id >= 0) { - "[id]", - }}; + const std::vector events + { + json::object(stage.at(id)) + }; - const int &id + execute(eval, events); + return true; + } + + const std::vector events { - param.at(0, -1) + std::begin(stage), std::end(stage) }; - m::vm::copts copts; - m::vm::eval eval - { - copts - }; - - if(id == -1) - for(size_t i(0); i < stage.size(); ++i) - execute(eval, m::event{stage.at(i)}); - else - execute(eval, m::event{stage.at(id)}); - + execute(eval, events); return true; } @@ -14611,14 +14594,11 @@ console_cmd__fed__sync(opt &out, const string_view &line) vmopts.phase.set(m::vm::phase::FETCH_STATE, false); vmopts.notify_servers = false; vmopts.node_id = remote; - m::vm::eval eval + m::vm::eval { - vmopts + events, vmopts }; - for(const auto &event : events) - execute(eval, event); - return true; } @@ -15926,8 +15906,10 @@ console_cmd__vm(opt &out, const string_view &line) << std::right << std::setw(4) << "CTX" << " " << std::left << std::setw(8) << " " << " " << std::left << std::setw(24) << "USER" << " " - << std::right << std::setw(5) << "PDUS" << " " - << std::right << std::setw(5) << "DONE" << " " + << std::right << std::setw(4) << "PDUS" << " " + << std::right << std::setw(4) << "EVAL" << " " + << std::right << std::setw(4) << "EXEC" << " " + << std::right << std::setw(4) << "ERRS" << " " << std::right << std::setw(8) << "PARENT" << " " << std::right << std::setw(9) << "SEQUENCE" << " " << std::left << std::setw(4) << "HOOK" << " " @@ -15948,20 +15930,15 @@ console_cmd__vm(opt &out, const string_view &line) assert(eval); assert(eval->ctx); - const auto done - { - !eval->pdus.empty() && eval->event_? - std::distance(begin(eval->pdus), eval->event_): - 0L - }; - out << std::right << std::setw(8) << eval->id << " " << std::right << std::setw(4) << (eval->ctx? ctx::id(*eval->ctx) : 0UL) << " " << std::left << std::setw(8) << (eval->ctx? trunc(ctx::name(*eval->ctx), 8) : string_view{}) << " " << std::left << std::setw(24) << trunc(eval->opts->node_id?: eval->opts->user_id, 24) << " " - << std::right << std::setw(5) << eval->pdus.size() << " " - << std::right << std::setw(5) << done << " " + << std::right << std::setw(4) << eval->pdus.size() << " " + << std::right << std::setw(4) << eval->evaluated << " " + << std::right << std::setw(4) << eval->accepted << " " + << std::right << std::setw(4) << eval->faulted << " " << std::right << std::setw(8) << (eval->parent? eval->parent->id : 0UL) << " " << std::right << std::setw(9) << eval->sequence << " " << std::right << std::setw(4) << (eval->hook? eval->hook->id(): 0U) << " "