errval_t mdb_remove(struct cte *target) { MDB_TRACE_ENTER(mdb_root, "%p", target); errval_t err = mdb_subtree_remove(target, &mdb_root, NULL); MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, mdb_root); }
errval_t mdb_insert(struct cte *new_node) { MDB_TRACE_ENTER(mdb_root, "%p", new_node); errval_t ret = mdb_sub_insert(new_node, &mdb_root); MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, ret, mdb_root); }
errval_t mdb_insert(struct cte *new_node) { MDB_TRACE_ENTER(mdb_root, "%p", new_node); #ifdef IN_KERNEL #ifdef MDB_TRACE_NO_RECURSIVE char prefix[50]; snprintf(prefix, 50, "mdb_insert.%d: ", my_core_id); print_cte(new_node, prefix); #endif #endif errval_t ret = mdb_sub_insert(new_node, &mdb_root); CHECK_INVARIANTS(mdb_root, new_node, true); MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, ret, mdb_root); }
errval_t mdb_remove(struct cte *target) { MDB_TRACE_ENTER(mdb_root, "%p", target); CHECK_INVARIANTS(mdb_root, target, true); #ifdef IN_KERNEL #ifdef MDB_TRACE_NO_RECURSIVE char prefix[50]; snprintf(prefix, 50, "mdb_remove.%d: ", my_core_id); print_cte(target, prefix); #endif #endif errval_t err = mdb_subtree_remove(target, &mdb_root, NULL); CHECK_INVARIANTS(mdb_root, target, false); MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, mdb_root); }
static errval_t mdb_sub_insert(struct cte *new_node, struct cte **current) { errval_t err; assert(new_node); assert(current); MDB_TRACE_ENTER(*current, "%p, %p (*%p)", new_node, *current, current); struct cte *current_ = *current; if (!current_) { // we've reached an empty leaf, insert here *current = new_node; mdb_update_end(new_node); return SYS_ERR_OK; } int compare = compare_caps(C(new_node), C(current_), true); if (compare < 0) { // new_node < current err = mdb_sub_insert(new_node, &N(current_)->left); if (err_is_fail(err)) { return err; } } else if (compare > 0) { // new_node > current err = mdb_sub_insert(new_node, &N(current_)->right); if (err_is_fail(err)) { return err; } } else { return CAPS_ERR_MDB_DUPLICATE_ENTRY; } mdb_update_end(current_); current_ = mdb_skew(current_); current_ = mdb_split(current_); *current = current_; err = SYS_ERR_OK; MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, current_); }
static errval_t mdb_subtree_remove(struct cte *target, struct cte **current, struct cte *parent) { assert(current); MDB_TRACE_ENTER(*current, "%p, %p (*%p), %p", target, *current, current, parent); errval_t err; struct cte *current_ = *current; if (!current_) { err = CAPS_ERR_MDB_ENTRY_NOTFOUND; MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, current_); } int compare = compare_caps(C(target), C(current_), true); if (compare > 0) { err = mdb_subtree_remove(target, &N(current_)->right, current_); if (err != SYS_ERR_OK) { MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, current_); return err; } } else if (compare < 0) { err = mdb_subtree_remove(target, &N(current_)->left, current_); if (err != SYS_ERR_OK) { MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, current_); } } else { assert(current_ == target); if (!N(current_)->left && !N(current_)->right) { // target is leaf, just remove *current = NULL; err = SYS_ERR_OK; MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, NULL); } else if (!N(current_)->left) { // move to right child then go left (dir=-1) // curr, new_right = xchg_rm(elem, parent, current.right, current, -1) struct cte *new_current = NULL; struct cte *new_right = N(current_)->right; mdb_exchange_remove(target, parent, &new_right, current_, -1, &new_current); assert(new_current); current_ = new_current; N(current_)->right = new_right; assert(!mdb_is_reachable(mdb_root, target)); } else { // move to left child then go right (dir=1) // curr, new_left = xchg_rm(elem, parent, current.left, current, 1) struct cte *new_current = NULL; struct cte *new_left = N(current_)->left; mdb_exchange_remove(target, parent, &new_left, current_, 1, &new_current); assert(new_current); current_ = new_current; N(current_)->left = new_left; assert(!mdb_is_reachable(mdb_root, target)); } } // rebalance after remove from subtree current_ = mdb_rebalance(current_); *current = current_; assert(C(target)->type != 0); assert(!*current || C(*current)->type != 0); err = SYS_ERR_OK; MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, current_); }
static void mdb_exchange_remove(struct cte *target, struct cte *target_parent, struct cte **current, struct cte *parent, int dir, struct cte **ret_target) { assert(current); MDB_TRACE_ENTER(*current, "%p, %p, %p (*%p), %p, %d", target, target_parent, *current, current, parent, dir); assert(target); assert(*current); assert(parent); assert(C(target)->type != 0); assert(C(*current)->type != 0); assert(C(parent)->type != 0); assert(ret_target); assert(!*ret_target); assert(dir != 0); assert(compare_caps(C(target), C(*current), true) != 0); assert(mdb_is_child(target, target_parent)); assert(mdb_is_child(*current, parent)); assert(mdb_is_reachable(mdb_root, target)); struct cte *current_ = *current; if (dir > 0) { if (parent == target) { assert(N(parent)->left == current_); } else { assert(N(parent)->right == current_); } if (N(current_)->right) { mdb_exchange_remove(target, target_parent, &N(current_)->right, current_, dir, ret_target); } } else if (dir < 0) { if (parent == target) { assert(N(parent)->right == current_); } else { assert(N(parent)->left == current_); } if (N(current_)->left) { mdb_exchange_remove(target, target_parent, &N(current_)->left, current_, dir, ret_target); } else if (N(current_)->right) { assert(N(current_)->level == 0); // right is non-null, left null -> current is level 0 node with // horizontal right link, and is also the successor of the target. // in this case, exchange current and current right, then current // (at its new position) and the target. struct cte *new_current = N(current_)->right; mdb_exchange_nodes(current_, parent, N(current_)->right, current_); mdb_exchange_nodes(target, target_parent, current_, new_current); // "current" is now located where the target was, further up in the // tree. "new_current" is the node where current was. "target" is // where current->right was, and is a leaf, so can be dropped. assert(N(new_current)->right == target); N(new_current)->right = NULL; *ret_target = current_; *current = new_current; assert(!mdb_is_reachable(mdb_root, target)); MDB_TRACE_LEAVE_SUB(NULL); } } if (*ret_target) { assert(!mdb_is_reachable(mdb_root, target)); // implies we recursed further down to find a leaf. need to rebalance. current_ = mdb_rebalance(current_); *current = current_; MDB_TRACE_LEAVE_SUB(current_); } else { //printf("found leaf %p\n", current_); // found successor/predecessor leaf, exchange with target assert(!N(current_)->right && !N(current_)->left); mdb_exchange_nodes(target, target_parent, current_, parent); // "current" is now where target was, so set as ret_target *ret_target = current_; // target would be the new current, but we're removing it, so set // current to null. This also sets parent's corresponding child to // null by recursion. *current = NULL; MDB_TRACE_LEAVE_SUB(NULL); } }