Btrfs: push_leaf_right
authorChris Mason <chris.mason@oracle.com>
Sat, 24 Feb 2007 17:47:20 +0000 (12:47 -0500)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Sat, 24 Feb 2007 17:47:20 +0000 (12:47 -0500)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c

index e497fd963118d7f271fbbc6e99961032f51ecf05..ef8bfa837532846cd5d9b79dd462355ed2ac22ed 100644 (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;