static void remove_index(struct cursor *cursor, int level) { struct bnode *node = cursor_node(cursor, level); int count = bcount(node), i; /* stomps the node count (if 0th key holds count) */ memmove(cursor->path[level].next - 1, cursor->path[level].next, (char *)&node->entries[count] - (char *)cursor->path[level].next); node->count = to_be_u32(count - 1); --(cursor->path[level].next); mark_buffer_dirty(cursor->path[level].buffer); /* no separator for last entry */ if (level_finished(cursor, level)) return; /* * Climb up to common parent and set separating key to deleted key. * What if index is now empty? (no deleted key) * Then some key above is going to be deleted and used to set sep * Climb the cursor while at first entry, bail out at root * find the node with the old sep, set it to deleted key */ if (cursor->path[level].next == node->entries && level) { be_u64 sep = (cursor->path[level].next)->key; for (i = level - 1; cursor->path[i].next - 1 == cursor_node(cursor, i)->entries; i--) if (!i) return; (cursor->path[i].next - 1)->key = sep; mark_buffer_dirty(cursor->path[i].buffer); } }
static void cursor_check(struct cursor *cursor) { if (cursor->len == 0) return; tuxkey_t key = 0; block_t block = cursor->btree->root.block; for (int i = 0; i < cursor->len; i++) { assert(bufindex(cursor->path[i].buffer) == block); if (!cursor->path[i].next) break; struct bnode *node = cursor_node(cursor, i); assert(node->entries < cursor->path[i].next); assert(cursor->path[i].next <= node->entries + bcount(node)); assert(from_be_u64((cursor->path[i].next - 1)->key) >= key); block = from_be_u64((cursor->path[i].next - 1)->block); key = from_be_u64((cursor->path[i].next - 1)->key); } }
/* 取得当前itor的上一结点 */ const h_rb_cursor_st *h_rbtree_prev(const h_rb_cursor_st *_itor) { rbtree_node_st *prev_node = rb_prev(cursor_node(_itor)); return prev_node == NULL ? NULL : &(prev_node->cs); }
/* 取得当前itor的下一结点 */ const h_rb_cursor_st *h_rbtree_next(const h_rb_cursor_st *_itor) { rbtree_node_st *next_node = rb_next(cursor_node(_itor)); return next_node == NULL ? NULL : &(next_node->cs); }
int tree_chop(struct btree *btree, struct delete_info *info, millisecond_t deadline) { int depth = btree->root.depth, level = depth - 1, suspend = 0; struct cursor *cursor; struct buffer_head *leafbuf, **prev, *leafprev = NULL; struct btree_ops *ops = btree->ops; struct sb *sb = btree->sb; int ret; cursor = alloc_cursor(btree, 0); prev = malloc(sizeof(*prev) * depth); memset(prev, 0, sizeof(*prev) * depth); down_write(&btree->lock); probe(btree, info->resume, cursor); leafbuf = level_pop(cursor); /* leaf walk */ while (1) { ret = (ops->leaf_chop)(btree, info->key, bufdata(leafbuf)); if (ret) { mark_buffer_dirty(leafbuf); if (ret < 0) goto error_leaf_chop; } /* try to merge this leaf with prev */ if (leafprev) { struct vleaf *this = bufdata(leafbuf); struct vleaf *that = bufdata(leafprev); /* try to merge leaf with prev */ if ((ops->leaf_need)(btree, this) <= (ops->leaf_free)(btree, that)) { trace(">>> can merge leaf %p into leaf %p", leafbuf, leafprev); (ops->leaf_merge)(btree, that, this); remove_index(cursor, level); mark_buffer_dirty(leafprev); brelse_free(btree, leafbuf); //dirty_buffer_count_check(sb); goto keep_prev_leaf; } brelse(leafprev); } leafprev = leafbuf; keep_prev_leaf: //nanosleep(&(struct timespec){ 0, 50 * 1000000 }, NULL); //printf("time remaining: %Lx\n", deadline - gettime()); // if (deadline && gettime() > deadline) // suspend = -1; if (info->blocks && info->freed >= info->blocks) suspend = -1; /* pop and try to merge finished nodes */ while (suspend || level_finished(cursor, level)) { /* try to merge node with prev */ if (prev[level]) { assert(level); /* node has no prev */ struct bnode *this = cursor_node(cursor, level); struct bnode *that = bufdata(prev[level]); trace_off("check node %p against %p", this, that); trace_off("this count = %i prev count = %i", bcount(this), bcount(that)); /* try to merge with node to left */ if (bcount(this) <= sb->entries_per_node - bcount(that)) { trace(">>> can merge node %p into node %p", this, that); merge_nodes(that, this); remove_index(cursor, level - 1); mark_buffer_dirty(prev[level]); brelse_free(btree, level_pop(cursor)); //dirty_buffer_count_check(sb); goto keep_prev_node; } brelse(prev[level]); } prev[level] = level_pop(cursor); keep_prev_node: /* deepest key in the cursor is the resume address */ if (suspend == -1 && !level_finished(cursor, level)) { suspend = 1; /* only set resume once */ info->resume = from_be_u64((cursor->path[level].next)->key); } if (!level) { /* remove depth if possible */ while (depth > 1 && bcount(bufdata(prev[0])) == 1) { trace("drop btree level"); btree->root.block = bufindex(prev[1]); mark_btree_dirty(btree); brelse_free(btree, prev[0]); //dirty_buffer_count_check(sb); depth = --btree->root.depth; vecmove(prev, prev + 1, depth); //set_sb_dirty(sb); } //sb->snapmask &= ~snapmask; delete_snapshot_from_disk(); //set_sb_dirty(sb); //save_sb(sb); ret = suspend; goto out; } level--; trace_off(printf("pop to level %i, block %Lx, %i of %i nodes\n", level, bufindex(cursor->path[level].buffer), cursor->path[level].next - cursor_node(cursor, level)->entries, bcount(cursor_node(cursor, level)));); } /* push back down to leaf level */ while (level < depth - 1) { struct buffer_head *buffer = sb_bread(vfs_sb(sb), from_be_u64(cursor->path[level++].next++->block)); if (!buffer) { ret = -EIO; goto out; } level_push(cursor, buffer, ((struct bnode *)bufdata(buffer))->entries); trace_off(printf("push to level %i, block %Lx, %i nodes\n", level, bufindex(buffer), bcount(cursor_node(cursor, level)));); }
static inline int level_finished(struct cursor *cursor, int level) { struct bnode *node = cursor_node(cursor, level); return cursor->path[level].next == node->entries + bcount(node); }