0
0
Fork 0
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:
Jason Volk 2018-02-24 19:27:17 -08:00
parent bc7efd8bff
commit 4643a78c47
2 changed files with 209 additions and 15 deletions

View file

@ -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);

View file

@ -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()