mirror of
https://github.com/matrix-construct/construct
synced 2024-12-27 07:54:05 +01:00
ircd:Ⓜ️:state: Distill out any DB/IO for tree root; split out create(); remove init.
This commit is contained in:
parent
0cc37daf9d
commit
5c968f0949
2 changed files with 62 additions and 136 deletions
|
@ -11,7 +11,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_M_STATE_H
|
#define HAVE_IRCD_M_STATE_H
|
||||||
|
|
||||||
/// Matrix state machine unit and bus.
|
/// Matrix machine state unit and bus.
|
||||||
///
|
///
|
||||||
/// This section deals specifically with the aspect of Matrix called "state"
|
/// This section deals specifically with the aspect of Matrix called "state"
|
||||||
/// providing tools and utilities as well as local databasing. IO is done for
|
/// providing tools and utilities as well as local databasing. IO is done for
|
||||||
|
@ -25,7 +25,6 @@
|
||||||
///
|
///
|
||||||
namespace ircd::m::state
|
namespace ircd::m::state
|
||||||
{
|
{
|
||||||
struct init;
|
|
||||||
struct node;
|
struct node;
|
||||||
|
|
||||||
constexpr size_t ID_MAX_SZ { 64 };
|
constexpr size_t ID_MAX_SZ { 64 };
|
||||||
|
@ -52,12 +51,9 @@ namespace ircd::m::state
|
||||||
string_view set_node(db::txn &txn, const mutable_buffer &id, const json::object &node);
|
string_view set_node(db::txn &txn, const mutable_buffer &id, const json::object &node);
|
||||||
void get_node(const string_view &id, const node_closure &);
|
void get_node(const string_view &id, const node_closure &);
|
||||||
|
|
||||||
string_view get_head(const mutable_buffer &out, const id::room &);
|
string_view insert(db::txn &, const mutable_buffer &headout, const string_view &headin, const json::array &key, const id::event &);
|
||||||
string_view set_head(db::txn &txn, const id::room &, const string_view &head);
|
string_view insert(db::txn &, const mutable_buffer &headout, const string_view &headin, const string_view &type, const string_view &state_key, const id::event &);
|
||||||
|
string_view insert(db::txn &, const mutable_buffer &headout, const string_view &headin, const event &);
|
||||||
string_view insert(db::txn &, const mutable_buffer &head, const id::room &, const json::array &key, const id::event &);
|
|
||||||
string_view insert(db::txn &, const mutable_buffer &head, const id::room &, const string_view &type, const string_view &state_key, const id::event &);
|
|
||||||
string_view insert(db::txn &, const mutable_buffer &head, const event &);
|
|
||||||
|
|
||||||
bool dfs(const string_view &head, const json::array &key, const search_closure &);
|
bool dfs(const string_view &head, const json::array &key, const search_closure &);
|
||||||
bool dfs(const string_view &head, const search_closure &);
|
bool dfs(const string_view &head, const search_closure &);
|
||||||
|
@ -69,7 +65,6 @@ namespace ircd::m::state
|
||||||
|
|
||||||
void get(const string_view &head, const json::array &key, const val_closure &);
|
void get(const string_view &head, const json::array &key, const val_closure &);
|
||||||
void get(const string_view &head, const string_view &type, const string_view &state_key, const val_closure &);
|
void get(const string_view &head, const string_view &type, const string_view &state_key, const val_closure &);
|
||||||
void get__room(const id::room &, const string_view &type, const string_view &state_key, const val_closure &);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// JSON property name strings specifically for use in m::state
|
/// JSON property name strings specifically for use in m::state
|
||||||
|
@ -186,12 +181,3 @@ static_assert
|
||||||
(
|
(
|
||||||
ircd::m::state::NODE_MAX_KEY == ircd::m::state::NODE_MAX_VAL
|
ircd::m::state::NODE_MAX_KEY == ircd::m::state::NODE_MAX_VAL
|
||||||
);
|
);
|
||||||
|
|
||||||
struct ircd::m::state::init
|
|
||||||
{
|
|
||||||
db::column state_head;
|
|
||||||
db::column state_node;
|
|
||||||
|
|
||||||
init();
|
|
||||||
~init() noexcept;
|
|
||||||
};
|
|
||||||
|
|
176
ircd/m/state.cc
176
ircd/m/state.cc
|
@ -10,39 +10,6 @@
|
||||||
|
|
||||||
#include <ircd/m/m.h>
|
#include <ircd/m/m.h>
|
||||||
|
|
||||||
ircd::db::column *
|
|
||||||
state_node_column
|
|
||||||
{};
|
|
||||||
|
|
||||||
ircd::db::column *
|
|
||||||
state_head_column
|
|
||||||
{};
|
|
||||||
|
|
||||||
ircd::m::state::init::init()
|
|
||||||
:state_head{*event::events, "state_head"}
|
|
||||||
,state_node{*event::events, "state_node"}
|
|
||||||
{
|
|
||||||
state_head_column = &state_head;
|
|
||||||
state_node_column = &state_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::m::state::init::~init()
|
|
||||||
noexcept
|
|
||||||
{
|
|
||||||
state_head_column = nullptr;
|
|
||||||
state_node_column = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenience to get value from the current room head.
|
|
||||||
void
|
|
||||||
ircd::m::state::get__room(const id::room &room_id,
|
|
||||||
const string_view &type,
|
|
||||||
const string_view &state_key,
|
|
||||||
const val_closure &closure)
|
|
||||||
{
|
|
||||||
char head[ID_MAX_SZ];
|
|
||||||
return get(get_head(head, room_id), type, state_key, closure);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenience to get value making a key
|
/// Convenience to get value making a key
|
||||||
void
|
void
|
||||||
|
@ -211,56 +178,72 @@ ircd::m::state::_dfs_recurse(const search_closure &closure,
|
||||||
namespace ircd::m::state
|
namespace ircd::m::state
|
||||||
{
|
{
|
||||||
static mutable_buffer _getbuffer(const uint8_t &height);
|
static mutable_buffer _getbuffer(const uint8_t &height);
|
||||||
static string_view _insert_overwrite(db::txn &txn, const json::array &key, const string_view &val, const mutable_buffer &idbuf, node::rep &rep, const size_t &pos);
|
static string_view _insert_overwrite(db::txn &, const json::array &key, const string_view &val, const mutable_buffer &idbuf, node::rep &, const size_t &pos);
|
||||||
static string_view _insert_leaf_nonfull(db::txn &txn, const json::array &key, const string_view &val, const mutable_buffer &idbuf, node::rep &rep, const size_t &pos);
|
static string_view _insert_leaf_nonfull(db::txn &, const json::array &key, const string_view &val, const mutable_buffer &idbuf, node::rep &, const size_t &pos);
|
||||||
static json::object _insert_leaf_full(const int8_t &height, db::txn &txn, const json::array &key, const string_view &val, node::rep &rep, const size_t &pos, node::rep &push);
|
static json::object _insert_leaf_full(const int8_t &height, db::txn &, const json::array &key, const string_view &val, node::rep &, const size_t &pos, node::rep &push);
|
||||||
static string_view _insert_branch_nonfull(db::txn &txn, const mutable_buffer &idbuf, node::rep &rep, const size_t &pos, node::rep &pushed);
|
static string_view _insert_branch_nonfull(db::txn &, const mutable_buffer &idbuf, node::rep &, const size_t &pos, node::rep &pushed);
|
||||||
static json::object _insert_branch_full(const int8_t &height, db::txn &txn, node::rep &rep, const size_t &pos, node::rep &push, const node::rep &pushed);
|
static json::object _insert_branch_full(const int8_t &height, db::txn &, node::rep &, const size_t &pos, node::rep &push, const node::rep &pushed);
|
||||||
static string_view _insert(int8_t &height, db::txn &txn, const json::array &key, const string_view &val, const node &node, const mutable_buffer &idbuf, node::rep &push);
|
static string_view _insert(int8_t &height, db::txn &, const json::array &key, const string_view &val, const node &node, const mutable_buffer &idbuf, node::rep &push);
|
||||||
|
static string_view _create(db::txn &, const mutable_buffer &head, const string_view &type, const string_view &state_key, const string_view &val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State update from an event. (NOTE: sets the room head atm)
|
/// State update from an event. Leaves the root node ID in the head buffer;
|
||||||
/// Leaves the root node ID in the head buffer; returns view.
|
/// returns view.
|
||||||
|
///
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::m::state::insert(db::txn &txn,
|
ircd::m::state::insert(db::txn &txn,
|
||||||
const mutable_buffer &head,
|
const mutable_buffer &headout,
|
||||||
|
const string_view &headin,
|
||||||
const event &event)
|
const event &event)
|
||||||
{
|
{
|
||||||
const auto &type{at<"type"_>(event)};
|
const auto &type{at<"type"_>(event)};
|
||||||
const auto &state_key{at<"state_key"_>(event)};
|
const auto &state_key{at<"state_key"_>(event)};
|
||||||
const auto &event_id{at<"event_id"_>(event)};
|
const auto &event_id{at<"event_id"_>(event)};
|
||||||
const auto &room_id{at<"room_id"_>(event)};
|
|
||||||
|
|
||||||
if(type == "m.room.create")
|
if(type == "m.room.create")
|
||||||
{
|
{
|
||||||
// Because this is a new tree and nothing is read from the DB, all
|
assert(empty(headin));
|
||||||
// writes here are just copies into the txn and these buffers can
|
return _create(txn, headout, type, state_key, event_id);
|
||||||
// remain off-stack.
|
|
||||||
const critical_assertion ca;
|
|
||||||
thread_local char key[KEY_MAX_SZ];
|
|
||||||
thread_local char node[NODE_MAX_SZ];
|
|
||||||
|
|
||||||
node::rep rep;
|
|
||||||
rep.keys[0] = make_key(key, type, state_key);
|
|
||||||
rep.kn = 1;
|
|
||||||
rep.vals[0] = event_id;
|
|
||||||
rep.vn = 1;
|
|
||||||
rep.chld[0] = string_view{};
|
|
||||||
rep.cn = 1;
|
|
||||||
|
|
||||||
return set_head(txn, room_id, set_node(txn, head, rep.write(node)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return insert(txn, head, room_id, type, state_key, event_id);
|
assert(!empty(headin));
|
||||||
|
return insert(txn, headout, headin, type, state_key, event_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::m::state::_create(db::txn &txn,
|
||||||
|
const mutable_buffer &head,
|
||||||
|
const string_view &type,
|
||||||
|
const string_view &state_key,
|
||||||
|
const string_view &val)
|
||||||
|
{
|
||||||
|
assert(type == "m.room.create");
|
||||||
|
assert(defined(state_key));
|
||||||
|
|
||||||
|
// Because this is a new tree and nothing is read from the DB, all
|
||||||
|
// writes here are just copies into the txn and these buffers can
|
||||||
|
// remain off-stack.
|
||||||
|
const critical_assertion ca;
|
||||||
|
thread_local char key[KEY_MAX_SZ];
|
||||||
|
thread_local char node[NODE_MAX_SZ];
|
||||||
|
|
||||||
|
node::rep rep;
|
||||||
|
rep.keys[0] = make_key(key, type, state_key);
|
||||||
|
rep.kn = 1;
|
||||||
|
rep.vals[0] = val;
|
||||||
|
rep.vn = 1;
|
||||||
|
rep.chld[0] = string_view{};
|
||||||
|
rep.cn = 1;
|
||||||
|
|
||||||
|
return set_node(txn, head, rep.write(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State update for room_id inserting (type,state_key) = event_id into the
|
/// State update for room_id inserting (type,state_key) = event_id into the
|
||||||
/// tree. Leaves the root node ID in the head buffer; returns view.
|
/// tree. Leaves the root node ID in the head buffer; returns view.
|
||||||
/// (NOTE: sets the room head in the txn right now).
|
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::m::state::insert(db::txn &txn,
|
ircd::m::state::insert(db::txn &txn,
|
||||||
const mutable_buffer &head,
|
const mutable_buffer &headout,
|
||||||
const id::room &room_id,
|
const string_view &headin,
|
||||||
const string_view &type,
|
const string_view &type,
|
||||||
const string_view &state_key,
|
const string_view &state_key,
|
||||||
const id::event &event_id)
|
const id::event &event_id)
|
||||||
|
@ -268,32 +251,28 @@ ircd::m::state::insert(db::txn &txn,
|
||||||
// The insertion process reads from the DB and will yield this ircd::ctx
|
// The insertion process reads from the DB and will yield this ircd::ctx
|
||||||
// so the key buffer must stay on this stack.
|
// so the key buffer must stay on this stack.
|
||||||
char key[KEY_MAX_SZ];
|
char key[KEY_MAX_SZ];
|
||||||
return insert(txn, head, room_id, make_key(key, type, state_key), event_id);
|
return insert(txn, headout, headin, make_key(key, type, state_key), event_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::m::state::insert(db::txn &txn,
|
ircd::m::state::insert(db::txn &txn,
|
||||||
const mutable_buffer &headbuf,
|
const mutable_buffer &headout,
|
||||||
const id::room &room_id,
|
const string_view &headin,
|
||||||
const json::array &key,
|
const json::array &key,
|
||||||
const id::event &event_id)
|
const id::event &event_id)
|
||||||
{
|
{
|
||||||
string_view head
|
|
||||||
{
|
|
||||||
get_head(headbuf, room_id)
|
|
||||||
};
|
|
||||||
|
|
||||||
node::rep push;
|
node::rep push;
|
||||||
int8_t height{0};
|
int8_t height{0};
|
||||||
|
string_view head{headin};
|
||||||
get_node(head, [&](const node &node)
|
get_node(head, [&](const node &node)
|
||||||
{
|
{
|
||||||
head = _insert(height, txn, key, event_id, node, headbuf, push);
|
head = _insert(height, txn, key, event_id, node, headout, push);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(push.kn)
|
if(push.kn)
|
||||||
head = push.write(txn, headbuf);
|
head = push.write(txn, headout);
|
||||||
|
|
||||||
return set_head(txn, room_id, head);
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
|
@ -534,56 +513,18 @@ ircd::m::state::_getbuffer(const uint8_t &height)
|
||||||
return buffer.at(height % buffer.size());
|
return buffer.at(height % buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the root node ID for a room in this db transaction.
|
/// View a node by ID. This makes a DB query and may yield ircd::ctx.
|
||||||
ircd::string_view
|
|
||||||
ircd::m::state::set_head(db::txn &iov,
|
|
||||||
const id::room &room_id,
|
|
||||||
const string_view &head_id)
|
|
||||||
{
|
|
||||||
db::txn::append
|
|
||||||
{
|
|
||||||
iov, db::delta
|
|
||||||
{
|
|
||||||
"state_head", // col
|
|
||||||
room_id, // key
|
|
||||||
head_id, // val
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return head_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copy a room's root node ID into buffer.
|
|
||||||
ircd::string_view
|
|
||||||
ircd::m::state::get_head(const mutable_buffer &buf,
|
|
||||||
const id::room &room_id)
|
|
||||||
{
|
|
||||||
assert(state_head_column);
|
|
||||||
auto &column{*state_head_column};
|
|
||||||
|
|
||||||
string_view ret;
|
|
||||||
column(room_id, [&ret, &buf]
|
|
||||||
(const string_view &head)
|
|
||||||
{
|
|
||||||
ret = { data(buf), strlcpy(buf, head) };
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// View a node by ID. This can be used when user already has a reference
|
|
||||||
/// to the db column.
|
|
||||||
void
|
void
|
||||||
ircd::m::state::get_node(const string_view &node_id,
|
ircd::m::state::get_node(const string_view &node_id,
|
||||||
const node_closure &closure)
|
const node_closure &closure)
|
||||||
{
|
{
|
||||||
assert(state_node_column);
|
assert(bool(dbs::state_node));
|
||||||
auto &column{*state_node_column};
|
auto &column{dbs::state_node};
|
||||||
column(node_id, closure);
|
column(node_id, closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a node to the db::txn and returns the id of this node (a hash) into
|
/// Writes a node to the db::txn and returns the id of this node (a hash) into
|
||||||
/// the buffer. The template allows for arguments to be forwarded to make_node()
|
/// the buffer.
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::m::state::set_node(db::txn &iov,
|
ircd::m::state::set_node(db::txn &iov,
|
||||||
const mutable_buffer &hashbuf,
|
const mutable_buffer &hashbuf,
|
||||||
|
@ -601,10 +542,9 @@ ircd::m::state::set_node(db::txn &iov,
|
||||||
|
|
||||||
db::txn::append
|
db::txn::append
|
||||||
{
|
{
|
||||||
iov, db::delta
|
iov, dbs::state_node,
|
||||||
{
|
{
|
||||||
db::op::SET,
|
db::op::SET,
|
||||||
"state_node", // col
|
|
||||||
hashb64, // key
|
hashb64, // key
|
||||||
node, // val
|
node, // val
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue