Example #1
0
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);
	}
}
Example #2
0
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);
	}
}
Example #3
0
/* 取得当前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);
}
Example #4
0
/* 取得当前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);
}
Example #5
0
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))););
		}
Example #6
0
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);
}