[btree] Implement btree::destroy() to delete the entire tree

Also decrease the reference count of the mapped values.
(e.g., bitmap blocks of btree_index_store)
This commit is contained in:
Ming-Hung Tsai 2020-06-02 11:47:38 +08:00
parent 4e1ec9326b
commit f803c44e93
2 changed files with 113 additions and 2 deletions

View File

@ -124,6 +124,9 @@ namespace persistent_data {
template <typename RefCounter>
void inc_children(RefCounter &rc);
template <typename RefCounter>
void dec_children(RefCounter &rc);
disk_node *raw() {
return raw_;
}

View File

@ -25,6 +25,7 @@
#include <iostream>
#include <sstream>
#include <stack>
//----------------------------------------------------------------
@ -33,6 +34,56 @@ namespace {
using namespace persistent_data;
using namespace btree_detail;
using namespace std;
struct frame {
frame(block_address blocknr,
uint32_t level,
uint32_t nr_entries)
: blocknr_(blocknr),
level_(level),
nr_entries_(nr_entries),
current_child_(0) {
}
block_address blocknr_;
uint32_t level_;
uint32_t nr_entries_;
uint32_t current_child_;
};
// stack for postorder DFS traversal
// TODO: Refactor it into a spine-like class, e.g., btree_del_spine,
// "Spine" sounds better for btree operations.
struct btree_del_stack {
public:
btree_del_stack(transaction_manager &tm): tm_(tm) {
}
void push_frame(block_address blocknr,
uint32_t level,
uint32_t nr_entries) {
if (tm_.get_sm()->get_count(blocknr) > 1)
tm_.get_sm()->dec(blocknr);
else
spine_.push(frame(blocknr, level, nr_entries));
}
void pop_frame() {
tm_.get_sm()->dec(spine_.top().blocknr_);
spine_.pop();
}
frame &top_frame() {
return spine_.top();
}
bool is_empty() {
return spine_.empty();
}
private:
transaction_manager &tm_;
std::stack<frame> spine_;
};
}
//----------------------------------------------------------------
@ -348,6 +399,21 @@ namespace persistent_data {
}
}
template <typename ValueTraits>
template <typename RefCounter>
void
node_ref<ValueTraits>::dec_children(RefCounter &rc)
{
unsigned nr_entries = get_nr_entries();
for (unsigned i = 0; i < nr_entries; i++) {
typename ValueTraits::value_type v;
typename ValueTraits::disk_type d;
::memcpy(&d, value_ptr(i), sizeof(d));
ValueTraits::unpack(d, v);
rc.dec(v);
}
}
template <typename ValueTraits>
bool
node_ref<ValueTraits>::value_sizes_match() const {
@ -565,15 +631,57 @@ namespace persistent_data {
return ptr(new btree<Levels, ValueTraits>(tm_, root_, rc_));
}
#if 0
template <unsigned Levels, typename ValueTraits>
void
btree<Levels, ValueTraits>::destroy()
{
using namespace btree_detail;
btree_del_stack s(tm_);
{
read_ref blk = tm_.read_lock(root_, validator_);
internal_node n = to_node<block_traits>(blk);
s.push_frame(root_, 0, n.get_nr_entries());
}
while (!s.is_empty()) {
frame &f = s.top_frame();
if (f.current_child_ >= f.nr_entries_) {
s.pop_frame();
continue;
}
// FIXME: Cache the read_ref object in the stack to avoid temporary objects?
read_ref current = tm_.read_lock(f.blocknr_, validator_);
internal_node n = to_node<block_traits>(current);
if (n.get_type() == INTERNAL) {
// TODO: test performance penalty of prefetching
//if (!f.current_child_)
// for (unsigned i = 0; i < n.get_nr_entries(); i++)
// tm_.prefetch(n.value_at(i));
block_address b = n.value_at(f.current_child_);
read_ref leaf = tm_.read_lock(b, validator_);
internal_node o = to_node<block_traits>(leaf);
s.push_frame(b, f.level_, o.get_nr_entries());
++f.current_child_;
// internal leaf
} else if (f.level_ < Levels - 1) {
block_address b = n.value_at(f.current_child_);
read_ref leaf = tm_.read_lock(b, validator_);
internal_node o = to_node<block_traits>(leaf);
s.push_frame(b, f.level_ + 1, o.get_nr_entries());
++f.current_child_;
} else {
leaf_node o = to_node<ValueTraits>(current);
o.dec_children(rc_); // FIXME: move this into pop_frame()
s.pop_frame();
}
}
}
#endif
template <unsigned Levels, typename _>
template <typename ValueTraits, typename Search>