mirror of
https://github.com/matrix-construct/construct
synced 2024-12-29 08:54:02 +01:00
311 lines
6.1 KiB
C++
311 lines
6.1 KiB
C++
// Matrix Construct
|
|
//
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
//
|
|
// 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.
|
|
|
|
decltype(ircd::m::vm::log)
|
|
ircd::m::vm::log
|
|
{
|
|
"m.vm", 'v'
|
|
};
|
|
|
|
decltype(ircd::m::vm::dock)
|
|
ircd::m::vm::dock;
|
|
|
|
decltype(ircd::m::vm::ready)
|
|
ircd::m::vm::ready;
|
|
|
|
decltype(ircd::m::vm::default_copts)
|
|
ircd::m::vm::default_copts;
|
|
|
|
decltype(ircd::m::vm::default_opts)
|
|
ircd::m::vm::default_opts;
|
|
|
|
//
|
|
// init
|
|
//
|
|
|
|
ircd::m::vm::init::init()
|
|
{
|
|
id::event::buf event_id;
|
|
sequence::retired = sequence::get(event_id);
|
|
sequence::committed = sequence::retired;
|
|
sequence::uncommitted = sequence::committed;
|
|
|
|
vm::ready = true;
|
|
vm::dock.notify_all();
|
|
|
|
log::info
|
|
{
|
|
log, "BOOT %s @%lu [%s] db:%lu",
|
|
server_name(my()),
|
|
sequence::retired,
|
|
sequence::retired?
|
|
string_view{event_id} : "NO EVENTS"_sv,
|
|
m::dbs::events?
|
|
db::sequence(*m::dbs::events) : 0UL,
|
|
};
|
|
}
|
|
|
|
ircd::m::vm::init::~init()
|
|
noexcept
|
|
{
|
|
vm::ready = false;
|
|
|
|
if(!eval::list.empty())
|
|
log::warning
|
|
{
|
|
log, "Waiting for %zu evals (exec:%zu inject:%zu pending:%zu)",
|
|
eval::list.size(),
|
|
eval::executing,
|
|
eval::injecting,
|
|
sequence::pending,
|
|
};
|
|
|
|
vm::dock.wait([]
|
|
{
|
|
return !eval::executing && !eval::injecting;
|
|
});
|
|
|
|
if(sequence::pending)
|
|
log::warning
|
|
{
|
|
log, "Waiting for pending:%zu sequencing (retired:%zu committed:%zu uncommitted:%zu)",
|
|
sequence::pending,
|
|
sequence::retired,
|
|
sequence::committed,
|
|
sequence::uncommitted,
|
|
};
|
|
|
|
sequence::dock.wait([]
|
|
{
|
|
return !sequence::pending;
|
|
});
|
|
|
|
event::id::buf event_id;
|
|
const auto retired
|
|
{
|
|
sequence::get(event_id)
|
|
};
|
|
|
|
log::info
|
|
{
|
|
log, "HALT '%s' @%lu [%s] vm:%lu:%lu:%lu db:%lu",
|
|
server_name(my()),
|
|
retired,
|
|
retired?
|
|
string_view{event_id} : "NO EVENTS"_sv,
|
|
sequence::retired,
|
|
sequence::committed,
|
|
sequence::uncommitted,
|
|
m::dbs::events?
|
|
db::sequence(*m::dbs::events) : 0UL,
|
|
};
|
|
|
|
assert(retired == sequence::retired);
|
|
}
|
|
|
|
//
|
|
// m/vm.h
|
|
//
|
|
|
|
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}:
|
|
"<unidentified>"_sv,
|
|
};
|
|
}
|
|
|
|
ircd::http::code
|
|
ircd::m::vm::http_code(const fault &code)
|
|
{
|
|
switch(code)
|
|
{
|
|
case fault::ACCEPT: return http::OK;
|
|
case fault::EXISTS: return http::CONFLICT;
|
|
case fault::INVALID: return http::BAD_REQUEST;
|
|
case fault::GENERAL: return http::UNAUTHORIZED;
|
|
case fault::AUTH: return http::FORBIDDEN;
|
|
case fault::STATE: return http::NOT_FOUND;
|
|
case fault::EVENT: return http::NOT_FOUND;
|
|
default: return http::INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
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_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::AUTH_RELA: return "AUTH_RELA";
|
|
case phase::COMMIT: return "COMMIT";
|
|
case phase::AUTH_PRES: return "AUTH_PRES";
|
|
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::m::vm::reflect(const enum fault &code)
|
|
{
|
|
switch(code)
|
|
{
|
|
case fault::ACCEPT: return "#ACCEPT";
|
|
case fault::EXISTS: return "#EXISTS";
|
|
case fault::GENERAL: return "#GENERAL";
|
|
case fault::INVALID: return "#INVALID";
|
|
case fault::AUTH: return "#AUTH";
|
|
case fault::EVENT: return "#EVENT";
|
|
case fault::STATE: return "#STATE";
|
|
}
|
|
|
|
return "??????";
|
|
}
|
|
|
|
//
|
|
// sequence
|
|
//
|
|
|
|
decltype(ircd::m::vm::sequence::dock)
|
|
ircd::m::vm::sequence::dock;
|
|
|
|
decltype(ircd::m::vm::sequence::retired)
|
|
ircd::m::vm::sequence::retired;
|
|
|
|
decltype(ircd::m::vm::sequence::committed)
|
|
ircd::m::vm::sequence::committed;
|
|
|
|
decltype(ircd::m::vm::sequence::uncommitted)
|
|
ircd::m::vm::sequence::uncommitted;
|
|
|
|
uint64_t
|
|
ircd::m::vm::sequence::min()
|
|
{
|
|
const auto *const e
|
|
{
|
|
eval::seqmin()
|
|
};
|
|
|
|
return e? get(*e) : 0;
|
|
}
|
|
|
|
uint64_t
|
|
ircd::m::vm::sequence::max()
|
|
{
|
|
const auto *const e
|
|
{
|
|
eval::seqmax()
|
|
};
|
|
|
|
return e? get(*e) : 0;
|
|
}
|
|
|
|
uint64_t
|
|
ircd::m::vm::sequence::get(id::event::buf &event_id)
|
|
{
|
|
static constexpr auto column_idx
|
|
{
|
|
json::indexof<event, "event_id"_>()
|
|
};
|
|
|
|
auto &column
|
|
{
|
|
dbs::event_column.at(column_idx)
|
|
};
|
|
|
|
const auto it
|
|
{
|
|
column.rbegin()
|
|
};
|
|
|
|
if(!it)
|
|
{
|
|
// If this iterator is invalid the events db should
|
|
// be completely fresh.
|
|
assert(db::sequence(*dbs::events) == 0);
|
|
return 0;
|
|
}
|
|
|
|
const auto &ret
|
|
{
|
|
byte_view<uint64_t>(it->first)
|
|
};
|
|
|
|
event_id = it->second;
|
|
return ret;
|
|
}
|
|
|
|
const uint64_t &
|
|
ircd::m::vm::sequence::get(const eval &eval)
|
|
{
|
|
return eval.sequence;
|
|
}
|
|
|
|
//
|
|
// copts (creation options)
|
|
//
|
|
|
|
// Out-of-line linkage
|
|
ircd::m::vm::copts::copts()
|
|
noexcept
|
|
{
|
|
}
|
|
|
|
//
|
|
// opts (options)
|
|
//
|
|
|
|
// Out-of-line linkage
|
|
ircd::m::vm::opts::opts()
|
|
noexcept
|
|
{
|
|
}
|