0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2025-03-13 21:10:32 +01:00

ircd:Ⓜ️:state: Optimize DFS branches recursed based on key argument prefix.

This commit is contained in:
Jason Volk 2018-02-05 17:27:43 -08:00
parent 025e1d7c78
commit 49027cc312
2 changed files with 81 additions and 33 deletions

View file

@ -44,7 +44,9 @@ namespace ircd::m::state
using iter_bool_closure = std::function<bool (const json::array &, const string_view &)>;
int keycmp(const json::array &a, const json::array &b);
bool prefix_eq(const json::array &a, const json::array &b);
json::array make_key(const mutable_buffer &out, const string_view &type, const string_view &state_key);
json::array make_key(const mutable_buffer &out, const string_view &type);
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 &);
@ -56,7 +58,9 @@ namespace ircd::m::state
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 search_closure &);
bool each(const string_view &head, const iter_bool_closure &);
bool each(const string_view &head, const string_view &type, const iter_bool_closure &);
size_t count(const string_view &head, const iter_bool_closure &);

View file

@ -112,27 +112,25 @@ ircd::m::state::count(const string_view &head,
return ret;
}
///TODO: optimize
bool
ircd::m::state::each(const string_view &head,
const iter_bool_closure &closure)
{
return each(head, string_view{}, closure);
}
bool
ircd::m::state::each(const string_view &head,
const string_view &type,
const iter_bool_closure &closure)
{
return each(head, [&type, &closure]
(const json::array &key, const string_view &val)
char buf[KEY_MAX_SZ];
const json::array key
{
if(unquote(key.at(0)) != type)
return true;
make_key(buf, type)
};
return closure(key, val);
});
}
bool
ircd::m::state::each(const string_view &head,
const iter_bool_closure &closure)
{
return dfs(head, [&closure]
return dfs(head, key, [&closure]
(const json::array &key, const string_view &val, const uint &, const uint &)
{
return closure(key, val);
@ -141,19 +139,27 @@ ircd::m::state::each(const string_view &head,
namespace ircd::m::state
{
bool _dfs_recurse(const search_closure &, const node &, int &);
bool _dfs_recurse(const search_closure &, const node &, const json::array &key, int &);
}
bool
ircd::m::state::dfs(const string_view &head,
const search_closure &closure)
{
return dfs(head, json::array{}, closure);
}
bool
ircd::m::state::dfs(const string_view &head,
const json::array &key,
const search_closure &closure)
{
bool ret{true};
get_node(head, [&closure, &ret]
get_node(head, [&closure, &key, &ret]
(const auto &node)
{
int depth(-1);
ret = _dfs_recurse(closure, node, depth);
ret = _dfs_recurse(closure, node, key, depth);
});
return ret;
@ -162,6 +168,7 @@ ircd::m::state::dfs(const string_view &head,
bool
ircd::m::state::_dfs_recurse(const search_closure &closure,
const node &node,
const json::array &key,
int &depth)
{
++depth;
@ -171,33 +178,30 @@ ircd::m::state::_dfs_recurse(const search_closure &closure,
}};
const node::rep rep{node};
for(uint pos(0); pos < rep.kn || pos < rep.cn; ++pos)
const auto kpos{rep.find(key)};
for(uint pos(kpos); pos < rep.kn || pos < rep.cn; ++pos)
{
const auto child
{
unquote(rep.chld[pos])
};
if(!empty(child))
if(!empty(rep.chld[pos]))
{
bool ret{true};
get_node(child, [&closure, &depth, &ret]
get_node(rep.chld[pos], [&closure, &key, &depth, &ret]
(const auto &node)
{
ret = _dfs_recurse(closure, node, depth);
ret = _dfs_recurse(closure, node, key, depth);
});
if(!ret)
return ret;
}
if(rep.kn > pos)
{
const auto &key{rep.keys[pos]};
const auto &val{unquote(rep.vals[pos])};
if(!closure(key, val, depth, pos))
return false;
}
if(rep.kn <= pos)
continue;
if(!empty(key) && !prefix_eq(key, rep.keys[pos]))
break;
if(!closure(rep.keys[pos], rep.vals[pos], depth, pos))
return false;
}
return true;
@ -629,6 +633,46 @@ ircd::m::state::make_key(const mutable_buffer &out,
return { data(out), json::print(out, key) };
}
ircd::json::array
ircd::m::state::make_key(const mutable_buffer &out,
const string_view &type)
{
const json::value key_parts[]
{
type
};
const json::value key
{
key_parts, 1
};
return { data(out), json::print(out, key) };
}
bool
ircd::m::state::prefix_eq(const json::array &a,
const json::array &b)
{
ushort i(0);
auto ait(begin(a));
auto bit(begin(b));
for(; ait != end(a) && bit != end(b) && i < 2; ++ait, ++bit)
{
assert(surrounds(*ait, '"'));
assert(surrounds(*bit, '"'));
if(*ait == *bit)
{
if(i)
return false;
}
else ++i;
}
return ait != end(a) || bit != end(b)? i == 0 : i < 2;
}
/// Compares two keys. Keys are arrays of strings which become safely
/// concatenated for a linear lexical comparison. Returns -1 if a less
/// than b; 0 if equal; 1 if a greater than b.