// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. // // Eval // // Processes any event from any place from any time and does whatever is // necessary to validate, reject, learn from new information, ignore old // information and advance the state of IRCd as best as possible. /// Instance list linkage for all of the evaluations. template<> decltype(ircd::util::instance_list::allocator) ircd::util::instance_list::allocator {}; template<> decltype(ircd::util::instance_list::list) ircd::util::instance_list::list { allocator }; decltype(ircd::m::vm::eval::id_ctr) ircd::m::vm::eval::id_ctr; decltype(ircd::m::vm::eval::executing) ircd::m::vm::eval::executing; decltype(ircd::m::vm::eval::injecting) ircd::m::vm::eval::injecting; size_t ircd::m::vm::prefetch_refs(const eval &eval) { assert(eval.opts); const dbs::write_opts &wopts { eval.opts->wopts }; size_t prefetched(0); for(const auto &event : eval.pdus) { if(event.event_id) prefetched += m::prefetch(event.event_id, "_event_idx"); prefetched += dbs::prefetch(event, wopts); } return prefetched; } ircd::m::vm::eval * ircd::m::vm::find_root(const eval &a, const ctx::ctx &c) noexcept { eval *ret {nullptr}, *parent {nullptr}; do { if(!(parent = find_parent(a, c))) return ret; ret = parent; } while(1); } ircd::m::vm::eval * ircd::m::vm::find_parent(const eval &a, const ctx::ctx &c) noexcept { eval *ret {nullptr}; eval::for_each(&c, [&ret, &a] (eval &eval) noexcept { const bool cond { (&eval != &a) && (!ret || eval.id > ret->id) }; ret = cond? &eval : ret; return true; }); return ret; } const ircd::m::event * ircd::m::vm::find_pdu(const eval &eval, const event::id &event_id) noexcept { const m::event *ret{nullptr}; for(const auto &event : eval.pdus) { if(event.event_id != event_id) continue; ret = std::addressof(event); break; } return ret; } ircd::string_view ircd::m::vm::loghead(const eval &eval) { thread_local char buf[128]; return loghead(buf, eval); } ircd::string_view ircd::m::vm::loghead(const mutable_buffer &buf, const eval &eval) { return fmt::sprintf { buf, "vm:%lu:%lu:%lu parent:%lu %s eval:%lu %s seq:%lu %s", sequence::retired, sequence::committed, sequence::uncommitted, eval.parent? eval.parent->id: 0UL, eval.parent? reflect(eval.parent->phase): reflect(phase::NONE), eval.id, reflect(eval.phase), sequence::get(eval), eval.event_? string_view{eval.event_->event_id}: ""_sv, }; } // // eval::eval // ircd::m::vm::eval::eval(const vm::opts &opts) :opts{&opts} ,parent { find_parent(*this) } { if(parent) { assert(!parent->child); parent->child = this; } } ircd::m::vm::eval::eval(const vm::copts &opts) :opts{&opts} ,copts{&opts} ,parent { find_parent(*this) } { if(parent) { assert(!parent->child); parent->child = this; } } ircd::m::vm::eval::eval(json::iov &event, const json::iov &content, const vm::copts &opts) :eval{opts} { inject(*this, event, content); } ircd::m::vm::eval::eval(const event &event, const vm::opts &opts) :eval { vector_view(&event, 1), opts } { } ircd::m::vm::eval::eval(const json::array &pdus, const vm::opts &opts) :eval{opts} { execute(*this, pdus); } ircd::m::vm::eval::eval(const vector_view &events, const vm::opts &opts) :eval{opts} { execute(*this, events); } ircd::m::vm::eval::~eval() noexcept { assert(!child); if(parent) { assert(parent->child == this); parent->child = nullptr; } } // // Tools // void ircd::m::vm::eval::seqsort() { eval::list.sort([] (const auto *const &a, const auto *const &b) { if(sequence::get(*a) == 0) return false; if(sequence::get(*b) == 0) return true; return sequence::get(*a) < sequence::get(*b); }); } ircd::m::vm::eval * ircd::m::vm::eval::seqmin() { const auto it { std::min_element(begin(eval::list), end(eval::list), [] (const auto *const &a, const auto *const &b) { if(sequence::get(*a) == 0) return false; if(sequence::get(*b) == 0) return true; return sequence::get(*a) < sequence::get(*b); }) }; if(it == end(eval::list)) return nullptr; if(sequence::get(**it) == 0) return nullptr; return *it; } ircd::m::vm::eval * ircd::m::vm::eval::seqmax() { const auto it { std::max_element(begin(eval::list), end(eval::list), [] (const auto *const &a, const auto *const &b) { return sequence::get(*a) < sequence::get(*b); }) }; if(it == end(eval::list)) return nullptr; if(sequence::get(**it) == 0) return nullptr; return *it; } ircd::m::vm::eval * ircd::m::vm::eval::seqnext(const uint64_t &seq) { eval *ret{nullptr}; for(auto *const &eval : eval::list) { if(sequence::get(*eval) <= seq) continue; if(!ret || sequence::get(*eval) < sequence::get(*ret)) ret = eval; } assert(!ret || sequence::get(*ret) > seq); return ret; } bool ircd::m::vm::eval::sequnique(const uint64_t &seq) { return 1 == std::count_if(begin(eval::list), end(eval::list), [&seq] (const auto *const &eval) { return sequence::get(*eval) == seq; }); } ircd::m::vm::eval & ircd::m::vm::eval::get(const event::id &event_id) { auto *const ret { find(event_id) }; if(unlikely(!ret)) throw std::out_of_range { "eval::get(): event_id not being evaluated." }; return *ret; } ircd::m::vm::eval * ircd::m::vm::eval::find(const event::id &event_id) { eval *ret{nullptr}; for_each([&event_id, &ret] (eval &e) noexcept { if(e.event_) if(e.event_->event_id == event_id) ret = &e; return ret == nullptr; }); return ret; } size_t ircd::m::vm::eval::count(const event::id &event_id) { size_t ret(0); for_each([&event_id, &ret] (eval &e) noexcept { if(e.event_) if(e.event_->event_id == event_id) ++ret; return true; }); return ret; } const ircd::m::event * ircd::m::vm::eval::find_pdu(const event::id &event_id) { const m::event *ret{nullptr}; for_each_pdu([&ret, &event_id] (const m::event &event) noexcept { if(event.event_id != event_id) return true; ret = std::addressof(event); return false; }); return ret; } size_t ircd::m::vm::eval::count(const ctx::ctx *const &c) { return std::count_if(begin(eval::list), end(eval::list), [&c] (const eval *const &eval) { return eval->ctx == c; }); } bool ircd::m::vm::eval::for_each(const ctx::ctx *const &c, const std::function &closure) { for(eval *const &eval : eval::list) if(eval->ctx == c) if(!closure(*eval)) return false; return true; } bool ircd::m::vm::eval::for_each_pdu(const std::function &closure) { return for_each([&closure](eval &e) { if(!empty(e.pdus)) { for(const auto &pdu : e.pdus) if(!closure(pdu)) return false; } else if(e.event_) { if(!closure(*e.event_)) return false; } return true; }); } bool ircd::m::vm::eval::for_each(const std::function &closure) { for(eval *const &eval : eval::list) if(!closure(*eval)) return false; return true; }