Btrfs: push_leaf_right

Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Chris Mason 2007-02-24 12:47:20 -05:00 committed by David Woodhouse
parent 5de08d7d50
commit 00ec4c5161
1 changed files with 102 additions and 7 deletions

View File

@ -517,6 +517,97 @@ int leaf_space_used(struct leaf *l, int start, int nr)
return data_len;
}
/*
* push some data in the path leaf to the right, trying to free up at
* least data_size bytes. returns zero if the push worked, nonzero otherwise
*/
int push_leaf_right(struct ctree_root *root, struct ctree_path *path,
int data_size)
{
struct tree_buffer *left_buf = path->nodes[0];
struct leaf *left = &left_buf->leaf;
struct leaf *right;
struct tree_buffer *right_buf;
struct tree_buffer *upper;
int slot;
int i;
int free_space;
int push_space = 0;
int push_items = 0;
struct item *item;
slot = path->slots[1];
if (!path->nodes[1]) {
return 1;
}
upper = path->nodes[1];
if (slot >= upper->node.header.nritems - 1) {
return 1;
}
right_buf = read_tree_block(root, upper->node.blockptrs[slot + 1]);
right = &right_buf->leaf;
free_space = leaf_free_space(right);
if (free_space < data_size + sizeof(struct item)) {
tree_block_release(root, right_buf);
return 1;
}
for (i = left->header.nritems - 1; i >= 0; i--) {
item = left->items + i;
if (path->slots[0] == i)
push_space += data_size + sizeof(*item);
if (item->size + sizeof(*item) + push_space > free_space)
break;
push_items++;
push_space += item->size + sizeof(*item);
}
if (push_items == 0) {
tree_block_release(root, right_buf);
return 1;
}
/* push left to right */
push_space = left->items[left->header.nritems - push_items].offset +
left->items[left->header.nritems - push_items].size;
push_space -= leaf_data_end(left);
/* make room in the right data area */
memmove(right->data + leaf_data_end(right) - push_space,
right->data + leaf_data_end(right),
LEAF_DATA_SIZE - leaf_data_end(right));
/* copy from the left data area */
memcpy(right->data + LEAF_DATA_SIZE - push_space,
left->data + leaf_data_end(left),
push_space);
memmove(right->items + push_items, right->items,
right->header.nritems * sizeof(struct item));
/* copy the items from left to right */
memcpy(right->items, left->items + left->header.nritems - push_items,
push_items * sizeof(struct item));
/* update the item pointers */
right->header.nritems += push_items;
push_space = LEAF_DATA_SIZE;
for (i = 0; i < right->header.nritems; i++) {
right->items[i].offset = push_space - right->items[i].size;
push_space = right->items[i].offset;
}
left->header.nritems -= push_items;
write_tree_block(root, left_buf);
write_tree_block(root, right_buf);
memcpy(upper->node.keys + slot + 1,
&right->items[0].key, sizeof(struct key));
write_tree_block(root, upper);
/* then fixup the leaf pointer in the path */
// FIXME use nritems in here somehow
if (path->slots[0] >= left->header.nritems) {
path->slots[0] -= left->header.nritems;
tree_block_release(root, path->nodes[0]);
path->nodes[0] = right_buf;
path->slots[1] += 1;
} else {
tree_block_release(root, right_buf);
}
return 0;
}
/*
* push some data in the path leaf to the left, trying to free up at
* least data_size bytes. returns zero if the push worked, nonzero otherwise
@ -631,7 +722,8 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size)
int i;
int ret;
if (push_leaf_left(root, path, data_size) == 0) {
if (push_leaf_left(root, path, data_size) == 0 ||
push_leaf_right(root, path, data_size) == 0) {
l_buf = path->nodes[0];
l = &l_buf->leaf;
if (leaf_free_space(l) >= sizeof(struct item) + data_size)
@ -875,6 +967,8 @@ int del_item(struct ctree_root *root, struct ctree_path *path)
slot = path->slots[1];
leaf_buf->count++;
push_leaf_left(root, path, 1);
if (leaf->header.nritems)
push_leaf_right(root, path, 1);
if (leaf->header.nritems == 0) {
u64 blocknr = leaf_buf->blocknr;
path->slots[1] = slot;
@ -929,7 +1023,7 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path)
/* for testing only */
int next_key(int i, int max_key) {
return rand() % max_key;
// return i;
//return i;
}
int main() {
@ -958,7 +1052,7 @@ int main() {
// num = i;
sprintf(buf, "string-%d", num);
if (i % 10000 == 0)
printf("insert %d:%d\n", num, i);
fprintf(stderr, "insert %d:%d\n", num, i);
ins.objectid = num;
ins.offset = 0;
ins.flags = 0;
@ -978,7 +1072,7 @@ int main() {
ins.objectid = num;
init_path(&path);
if (i % 10000 == 0)
printf("search %d:%d\n", num, i);
fprintf(stderr, "search %d:%d\n", num, i);
ret = search_slot(root, &ins, &path, 0);
if (ret) {
print_tree(root, root->node);
@ -1004,7 +1098,7 @@ int main() {
ret = search_slot(root, &ins, &path, -1);
if (!ret) {
if (i % 10000 == 0)
printf("del %d:%d\n", num, i);
fprintf(stderr, "del %d:%d\n", num, i);
ret = del_item(root, &path);
if (ret != 0)
BUG();
@ -1022,7 +1116,7 @@ int main() {
sprintf(buf, "string-%d", num);
ins.objectid = num;
if (i % 10000 == 0)
printf("insert %d:%d\n", num, i);
fprintf(stderr, "insert %d:%d\n", num, i);
ret = insert_item(root, &ins, buf, strlen(buf));
if (!ret)
tree_size++;
@ -1038,7 +1132,7 @@ int main() {
ins.objectid = num;
init_path(&path);
if (i % 10000 == 0)
printf("search %d:%d\n", num, i);
fprintf(stderr, "search %d:%d\n", num, i);
ret = search_slot(root, &ins, &path, 0);
if (ret) {
print_tree(root, root->node);
@ -1082,6 +1176,7 @@ int main() {
}
printf("tree size is now %d\n", tree_size);
printf("map tree\n");
print_tree(root->extent_root, root->extent_root->node);
write_ctree_super(root, &super);
close_ctree(root);
return 0;