in glean/rts/ownership/triearray.h [43:125]
void insert(const OwnershipUnit::Ids *start, const OwnershipUnit::Ids *finish, Get&& get) {
if (start == finish) {
return;
}
minkey_ = std::min(minkey_, start->start.toWord());
maxkey_ = std::max(maxkey_, finish[-1].finish.toWord());
// only 32-bit keys are supported; this property is assumed later
CHECK(maxkey_ <= std::numeric_limits<uint32_t>::max());
// Algorithm:
//
// - Collect previously existing values in `values`.
// - When we see a value for the first time, set its `link` field to point
// to the first `Tree` that contains it and add it to `values`.
// - When we see a value again, temporarily make the current `Tree` point
// to the previous tree that contained the value (from the value's `link`)
// and update the value's `link` to point to the current tree. This
// effectively maintains a linked list of trees which contain a value,
// with the value's `link` being the root.
// - Do the same for newly inserted trees which don't have a previous value
// via `null_link`.
// - Once we've collected everything, for each value in `values` compute the
// new value via `get` and then traverse the linked list of trees, storing
// a pointer to the new value in each one.
// - Do the same for `null_link`.
std::vector<T*> values;
Tree *null_link = nullptr;
while (start != finish) {
const auto [first_id, last_id] = *start++;
if (first_id <= last_id) {
traverse(
first_id.toWord(),
last_id.toWord() - first_id.toWord() + 1,
[&](Tree& tree, uint64_t key, uint64_t size, size_t block) {
if (size == block) {
if (const auto value = tree.value()) {
const auto prev = static_cast<Tree *>(value->link());
value->link(&tree);
tree = Tree::link(prev);
if (prev == nullptr) {
values.push_back(value);
} else {
value->use(-1);
}
} else {
tree = Tree::link(null_link);
null_link = &tree;
}
} else {
if (auto value = tree.value()) {
value->use(FANOUT-1);
}
tree = Tree::forest(pool_.alloc(tree));
}
});
}
}
const auto unlink = [&](Tree *tree, T * FOLLY_NULLABLE value) {
auto upd = get(value, 1);
uint32_t refs = 0;
while (tree != nullptr) {
auto next = tree->link();
*tree = Tree::value(upd);
tree = next;
++refs;
}
upd->use(refs-1);
};
if (null_link) {
unlink(null_link, nullptr);
}
for (auto value : values) {
Tree *tree = static_cast<Tree*>(value->link());
value->link(nullptr);
unlink(tree, value);
}
}