mirror of
https://github.com/matrix-construct/construct
synced 2024-11-17 15:30:52 +01:00
ircd:Ⓜ️:state: Add branch accounting to b-tree node.
This commit is contained in:
parent
bc7efd8bff
commit
4643a78c47
2 changed files with 209 additions and 15 deletions
|
@ -60,6 +60,9 @@ namespace ircd::m::state
|
|||
bool dfs(const id &root, const json::array &key, const search_closure &);
|
||||
bool dfs(const id &root, const search_closure &);
|
||||
|
||||
size_t count(const id &root, const string_view &type);
|
||||
size_t count(const id &root);
|
||||
|
||||
bool test(const id &root, const iter_bool_closure &);
|
||||
bool test(const id &root, const string_view &type, const iter_bool_closure &);
|
||||
bool test(const id &root, const string_view &type, const string_view &state_key_lb, const iter_bool_closure &);
|
||||
|
@ -67,8 +70,7 @@ namespace ircd::m::state
|
|||
void for_each(const id &root, const iter_closure &);
|
||||
void for_each(const id &root, const string_view &type, const iter_closure &);
|
||||
|
||||
size_t count(const id &root, const iter_bool_closure &);
|
||||
size_t count(const id &root);
|
||||
size_t accumulate(const id &root, const iter_bool_closure &);
|
||||
|
||||
bool get(std::nothrow_t, const id &root, const json::array &key, const val_closure &);
|
||||
void get(const id &root, const json::array &key, const val_closure &);
|
||||
|
@ -83,6 +85,7 @@ namespace ircd::m::state::name
|
|||
constexpr const char *const k {"k"};
|
||||
constexpr const char *const v {"v"};
|
||||
constexpr const char *const c {"c"};
|
||||
constexpr const char *const n {"n"};
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
|
@ -110,6 +113,12 @@ namespace ircd::m::state::name
|
|||
/// "PcxAAACvkvyUMz19AZcCfrC3S84s", ; Center child
|
||||
/// "2jVYKIMKErJ6w6BLMhfVjsXearhB", ; Right child
|
||||
/// ] ;
|
||||
/// "n": ; Counting array
|
||||
/// [ ;
|
||||
/// 15, ; Left child value count
|
||||
/// 12, ; Center child value count
|
||||
/// 19, ; Right child value count
|
||||
/// ] ;
|
||||
/// } ;
|
||||
///
|
||||
/// Elements are ordered based on type+state_key lexical sort. The type and
|
||||
|
@ -130,7 +139,8 @@ struct ircd::m::state::node
|
|||
<
|
||||
json::property<name::k, json::array>,
|
||||
json::property<name::v, json::array>,
|
||||
json::property<name::c, json::array>
|
||||
json::property<name::c, json::array>,
|
||||
json::property<name::n, json::array>
|
||||
>
|
||||
{
|
||||
struct rep;
|
||||
|
@ -138,14 +148,18 @@ struct ircd::m::state::node
|
|||
size_t keys() const;
|
||||
size_t vals() const;
|
||||
size_t childs() const;
|
||||
size_t counts() const;
|
||||
size_t totals() const;
|
||||
|
||||
json::array key(const size_t &) const;
|
||||
string_view val(const size_t &) const;
|
||||
state::id child(const size_t &) const;
|
||||
size_t count(const size_t &) const;
|
||||
|
||||
size_t keys(json::array *const &out, const size_t &max) const;
|
||||
size_t vals(string_view *const &out, const size_t &max) const;
|
||||
size_t childs(state::id *const &out, const size_t &max) const;
|
||||
size_t counts(size_t *const &out, const size_t &max) const;
|
||||
|
||||
size_t find(const json::array &key) const;
|
||||
bool has_key(const json::array &key) const;
|
||||
|
@ -168,16 +182,21 @@ struct ircd::m::state::node::rep
|
|||
std::array<json::array, NODE_MAX_KEY + 1> keys;
|
||||
std::array<string_view, NODE_MAX_VAL + 1> vals;
|
||||
std::array<state::id, NODE_MAX_DEG + 1> chld;
|
||||
std::array<size_t, NODE_MAX_DEG + 1> cnts;
|
||||
size_t kn {0};
|
||||
size_t vn {0};
|
||||
size_t cn {0};
|
||||
size_t nn {0};
|
||||
|
||||
bool full() const;
|
||||
bool overfull() const;
|
||||
bool duplicates() const;
|
||||
size_t childs() const;
|
||||
size_t counts() const;
|
||||
size_t totals() const;
|
||||
size_t find(const json::array &key) const;
|
||||
|
||||
void shl(const size_t &pos);
|
||||
void shr(const size_t &pos);
|
||||
|
||||
json::object write(const mutable_buffer &out);
|
||||
|
|
199
ircd/m/state.cc
199
ircd/m/state.cc
|
@ -93,18 +93,8 @@ ircd::m::state::get(std::nothrow_t,
|
|||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::count(const string_view &root)
|
||||
{
|
||||
return count(root, []
|
||||
(const json::array &key, const string_view &val)
|
||||
{
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::count(const string_view &root,
|
||||
const iter_bool_closure &closure)
|
||||
ircd::m::state::accumulate(const string_view &root,
|
||||
const iter_bool_closure &closure)
|
||||
{
|
||||
size_t ret{0};
|
||||
for_each(root, [&ret, &closure]
|
||||
|
@ -189,6 +179,83 @@ ircd::m::state::test(const string_view &root,
|
|||
});
|
||||
}
|
||||
|
||||
namespace ircd::m::state
|
||||
{
|
||||
size_t _count_recurse(const node &, const json::array &key, const json::array &dom);
|
||||
size_t _count(const string_view &root, const json::array &key);
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::count(const string_view &root)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::count(const string_view &root,
|
||||
const string_view &type)
|
||||
{
|
||||
char buf[KEY_MAX_SZ];
|
||||
const json::array key
|
||||
{
|
||||
make_key(buf, type)
|
||||
};
|
||||
|
||||
return _count(root, key);
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::_count(const string_view &root,
|
||||
const json::array &key)
|
||||
{
|
||||
size_t ret{0};
|
||||
get_node(root, [&key, &ret]
|
||||
(const auto &node)
|
||||
{
|
||||
ret += _count_recurse(node, key, json::array{});
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::_count_recurse(const node &node,
|
||||
const json::array &key,
|
||||
const json::array &dom)
|
||||
{
|
||||
const node::rep rep{node};
|
||||
|
||||
bool under{!empty(dom)};
|
||||
for(uint pos(0); under && pos < rep.kn; ++pos)
|
||||
if(!prefix_eq(dom, rep.keys[pos]))
|
||||
under = false;
|
||||
|
||||
if(under)
|
||||
return rep.totals();
|
||||
|
||||
size_t ret{0};
|
||||
const auto kpos{rep.find(key)};
|
||||
for(uint pos(kpos); pos < rep.kn || pos < rep.cn; ++pos)
|
||||
{
|
||||
if(!empty(rep.chld[pos]))
|
||||
get_node(rep.chld[pos], [&key, &ret, &rep, &pos]
|
||||
(const auto &node)
|
||||
{
|
||||
ret += _count_recurse(node, key, rep.keys[pos]);
|
||||
});
|
||||
|
||||
if(pos < rep.kn)
|
||||
{
|
||||
if(prefix_eq(key, rep.keys[pos]))
|
||||
++ret;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace ircd::m::state
|
||||
{
|
||||
bool _dfs_recurse(const search_closure &, const node &, const json::array &key, int &);
|
||||
|
@ -319,6 +386,8 @@ ircd::m::state::_create(db::txn &txn,
|
|||
rep.vn = 1;
|
||||
rep.chld[0] = string_view{};
|
||||
rep.cn = 1;
|
||||
rep.cnts[0] = 0;
|
||||
rep.nn = 1;
|
||||
|
||||
return set_node(txn, root, rep.write(node));
|
||||
}
|
||||
|
@ -414,6 +483,7 @@ ircd::m::state::_insert(int8_t &height,
|
|||
|
||||
// Indicates no push, and the child value is just an ID of a node.
|
||||
rep.chld[pos] = child;
|
||||
rep.cnts[pos]++;
|
||||
return rep.write(txn, idbuf);
|
||||
}
|
||||
|
||||
|
@ -437,6 +507,10 @@ ircd::m::state::_insert_branch_full(const int8_t &height,
|
|||
rep.chld[pos + 1] = pushed.chld[1];
|
||||
++rep.cn;
|
||||
|
||||
rep.cnts[pos] = pushed.cnts[0];
|
||||
rep.cnts[pos + 1] = pushed.cnts[1];
|
||||
++rep.nn;
|
||||
|
||||
size_t i(0);
|
||||
node::rep left;
|
||||
for(; i < rep.kn / 2; ++i)
|
||||
|
@ -444,8 +518,10 @@ ircd::m::state::_insert_branch_full(const int8_t &height,
|
|||
left.keys[left.kn++] = rep.keys[i];
|
||||
left.vals[left.vn++] = rep.vals[i];
|
||||
left.chld[left.cn++] = rep.chld[i];
|
||||
left.cnts[left.nn++] = rep.cnts[i];
|
||||
}
|
||||
left.chld[left.cn++] = rep.chld[i];
|
||||
left.cnts[left.nn++] = rep.cnts[i];
|
||||
|
||||
push.keys[push.kn++] = rep.keys[i];
|
||||
push.vals[push.vn++] = rep.vals[i];
|
||||
|
@ -456,12 +532,16 @@ ircd::m::state::_insert_branch_full(const int8_t &height,
|
|||
right.keys[right.kn++] = rep.keys[i];
|
||||
right.vals[right.vn++] = rep.vals[i];
|
||||
right.chld[right.cn++] = rep.chld[i];
|
||||
right.cnts[right.nn++] = rep.cnts[i];
|
||||
}
|
||||
right.chld[right.cn++] = rep.chld[i];
|
||||
right.cnts[right.nn++] = rep.cnts[i];
|
||||
|
||||
thread_local char lc[ID_MAX_SZ], rc[ID_MAX_SZ];
|
||||
push.chld[push.cn++] = left.write(txn, lc);
|
||||
push.chld[push.cn++] = right.write(txn, rc);
|
||||
push.cnts[push.nn++] = left.totals();
|
||||
push.cnts[push.nn++] = right.totals();
|
||||
|
||||
const auto ret
|
||||
{
|
||||
|
@ -497,6 +577,7 @@ ircd::m::state::_insert_leaf_full(const int8_t &height,
|
|||
left.keys[left.kn++] = rep.keys[i];
|
||||
left.vals[left.vn++] = rep.vals[i];
|
||||
left.chld[left.cn++] = string_view{};
|
||||
left.cnts[left.nn++] = 0;
|
||||
}
|
||||
|
||||
push.keys[push.kn++] = rep.keys[i];
|
||||
|
@ -508,11 +589,14 @@ ircd::m::state::_insert_leaf_full(const int8_t &height,
|
|||
right.keys[right.kn++] = rep.keys[i];
|
||||
right.vals[right.vn++] = rep.vals[i];
|
||||
right.chld[right.cn++] = string_view{};
|
||||
right.cnts[right.nn++] = 0;
|
||||
}
|
||||
|
||||
thread_local char lc[ID_MAX_SZ], rc[ID_MAX_SZ];
|
||||
push.chld[push.cn++] = left.write(txn, lc);
|
||||
push.chld[push.cn++] = right.write(txn, rc);
|
||||
push.cnts[push.nn++] = left.totals();
|
||||
push.cnts[push.nn++] = right.totals();
|
||||
|
||||
const auto ret
|
||||
{
|
||||
|
@ -543,6 +627,10 @@ ircd::m::state::_insert_branch_nonfull(db::txn &txn,
|
|||
rep.chld[pos + 1] = pushed.chld[1];
|
||||
++rep.cn;
|
||||
|
||||
rep.cnts[pos] = pushed.cnts[0];
|
||||
rep.cnts[pos + 1] = pushed.cnts[1];
|
||||
++rep.nn;
|
||||
|
||||
return rep.write(txn, idbuf);
|
||||
}
|
||||
|
||||
|
@ -565,6 +653,9 @@ ircd::m::state::_insert_leaf_nonfull(db::txn &txn,
|
|||
rep.chld[pos] = string_view{};
|
||||
++rep.cn;
|
||||
|
||||
rep.cnts[pos] = 0;
|
||||
++rep.nn;
|
||||
|
||||
return rep.write(txn, idbuf);
|
||||
}
|
||||
|
||||
|
@ -733,7 +824,9 @@ ircd::m::state::node::rep::rep(const node &node)
|
|||
:kn{node.keys(keys.data(), keys.size())}
|
||||
,vn{node.vals(vals.data(), vals.size())}
|
||||
,cn{node.childs(chld.data(), chld.size())}
|
||||
,nn{node.counts(cnts.data(), cnts.size())}
|
||||
{
|
||||
assert(cn == nn);
|
||||
}
|
||||
|
||||
ircd::m::state::id
|
||||
|
@ -748,6 +841,7 @@ ircd::json::object
|
|||
ircd::m::state::node::rep::write(const mutable_buffer &out)
|
||||
{
|
||||
assert(kn == vn);
|
||||
assert(cn == nn);
|
||||
assert(cn <= kn + 1);
|
||||
assert(!childs() || childs() > kn);
|
||||
assert(!duplicates());
|
||||
|
@ -775,12 +869,19 @@ ircd::m::state::node::rep::write(const mutable_buffer &out)
|
|||
chld[i] = this->chld[i];
|
||||
};
|
||||
|
||||
json::value cnts[nn];
|
||||
{
|
||||
for(size_t i(0); i < nn; ++i)
|
||||
cnts[i] = json::value{long(this->cnts[i])};
|
||||
};
|
||||
|
||||
json::iov iov;
|
||||
const json::iov::push push[]
|
||||
{
|
||||
{ iov, { "k"_sv, { keys, kn } } },
|
||||
{ iov, { "v"_sv, { vals, vn } } },
|
||||
{ iov, { "c"_sv, { chld, cn } } },
|
||||
{ iov, { "n"_sv, { cnts, nn } } },
|
||||
};
|
||||
|
||||
return { data(out), json::print(out, iov) };
|
||||
|
@ -793,6 +894,17 @@ ircd::m::state::node::rep::shr(const size_t &pos)
|
|||
std::copy_backward(begin(keys) + pos, begin(keys) + kn, begin(keys) + kn + 1);
|
||||
std::copy_backward(begin(vals) + pos, begin(vals) + vn, begin(vals) + vn + 1);
|
||||
std::copy_backward(begin(chld) + pos, begin(chld) + cn, begin(chld) + cn + 1);
|
||||
std::copy_backward(begin(cnts) + pos, begin(cnts) + nn, begin(cnts) + nn + 1);
|
||||
}
|
||||
|
||||
/// Shift left.
|
||||
void
|
||||
ircd::m::state::node::rep::shl(const size_t &pos)
|
||||
{
|
||||
std::copy(begin(keys) + pos + 1, begin(keys) + kn, begin(keys) + std::max(ssize_t(kn) - 1, 0L));
|
||||
std::copy(begin(vals) + pos + 1, begin(vals) + vn, begin(vals) + std::max(ssize_t(vn) - 1, 0L));
|
||||
std::copy(begin(chld) + pos + 1, begin(chld) + cn, begin(chld) + std::max(ssize_t(cn) - 1, 0L));
|
||||
std::copy(begin(cnts) + pos + 1, begin(cnts) + nn, begin(cnts) + std::max(ssize_t(nn) - 1, 0L));
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -807,6 +919,24 @@ const
|
|||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::node::rep::totals()
|
||||
const
|
||||
{
|
||||
return kn + counts();
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::node::rep::counts()
|
||||
const
|
||||
{
|
||||
size_t ret(0);
|
||||
for(size_t i(0); i < nn; ++i)
|
||||
ret += cnts[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::node::rep::childs()
|
||||
const
|
||||
|
@ -900,6 +1030,19 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::node::counts(size_t *const &out,
|
||||
const size_t &max)
|
||||
const
|
||||
{
|
||||
size_t i(0);
|
||||
for(const string_view &c : json::get<"n"_>(*this))
|
||||
if(likely(i < max))
|
||||
out[i++] = lex_cast<size_t>(c);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::node::childs(state::id *const &out,
|
||||
const size_t &max)
|
||||
|
@ -939,6 +1082,18 @@ const
|
|||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::m::state::node::count(const size_t &pos)
|
||||
const
|
||||
{
|
||||
const json::array &counts
|
||||
{
|
||||
json::get<"n"_>(*this, json::empty_array)
|
||||
};
|
||||
|
||||
return counts.at<size_t>(pos);
|
||||
}
|
||||
|
||||
ircd::m::state::id
|
||||
ircd::m::state::node::child(const size_t &pos)
|
||||
const
|
||||
|
@ -977,6 +1132,26 @@ const
|
|||
return keys[pos];
|
||||
}
|
||||
|
||||
// Count counts in node
|
||||
size_t
|
||||
ircd::m::state::node::totals()
|
||||
const
|
||||
{
|
||||
return keys() + counts();
|
||||
}
|
||||
|
||||
// Count counts in node
|
||||
size_t
|
||||
ircd::m::state::node::counts()
|
||||
const
|
||||
{
|
||||
size_t ret(0);
|
||||
for(const auto &c : json::get<"n"_>(*this))
|
||||
ret += lex_cast<size_t>(c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Count children in node
|
||||
size_t
|
||||
ircd::m::state::node::childs()
|
||||
|
|
Loading…
Reference in a new issue