/* * Cursor down to child node or leaf, and update ->next. * < 0 - error * 0 - there is no further child (leaf was pushed) * 1 - there is child */ static int cursor_advance_down(struct cursor *cursor) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct btree *btree = cursor->btree; struct buffer_head *buffer; block_t child; assert(cursor->level < btree->root.depth); child = be64_to_cpu(cursor->path[cursor->level].next->block); buffer = vol_bread(btree->sb, child); if (!buffer) return -EIO; /* FIXME: stupid, it might have been NOMEM */ cursor->path[cursor->level].next++; if (cursor->level < btree->root.depth - 1) { struct bnode *node = bufdata(buffer); assert(bnode_sniff(node)); cursor_push(cursor, buffer, node->entries); cursor_check(cursor); return 1; } assert(btree->ops->leaf_sniff(btree, bufdata(buffer))); cursor_push(cursor, buffer, NULL); cursor_check(cursor); return 0; }
/* * Cursor read root node. * < 0 - error * 0 - success */ static int cursor_read_root(struct cursor *cursor) { struct btree *btree = cursor->btree; struct buffer_head *buffer; assert(has_root(btree)); buffer = vol_bread(btree->sb, btree->root.block); if (!buffer) return -EIO; /* FIXME: stupid, it might have been NOMEM */ assert(bnode_sniff(bufdata(buffer))); cursor_push(cursor, buffer, ((struct bnode *)bufdata(buffer))->entries); return 0; }
/* * Cursor read root node. * < 0 - error * 0 - success */ static int cursor_read_root(struct cursor *cursor) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct btree *btree = cursor->btree; struct buffer_head *buffer; assert(has_root(btree)); buffer = vol_bread(btree->sb, btree->root.block); if (!buffer) return -EIO; /* FIXME: stupid, it might have been NOMEM */ assert(bnode_sniff(bufdata(buffer))); cursor_push(cursor, buffer, ((struct bnode *)bufdata(buffer))->entries); return 0; }
/* * Insert new leaf to next cursor position. * keep == 1: keep current cursor position. * keep == 0, set cursor position to new leaf. */ static int insert_leaf(struct cursor *cursor, tuxkey_t childkey, struct buffer_head *leafbuf, int keep) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct btree *btree = cursor->btree; struct sb *sb = btree->sb; int level = btree->root.depth; block_t childblock = bufindex(leafbuf); if (keep) blockput(leafbuf); else { cursor_pop_blockput(cursor); cursor_push(cursor, leafbuf, NULL); } while (level--) { struct path_level *at = &cursor->path[level]; struct buffer_head *parentbuf = at->buffer; struct bnode *parent = bufdata(parentbuf); /* insert and exit if not full */ if (bcount(parent) < btree->sb->entries_per_node) { bnode_add_index(parent, at->next, childblock, childkey); if (!keep) at->next++; log_bnode_add(sb, bufindex(parentbuf), childblock, childkey); mark_buffer_unify_non(parentbuf); cursor_check(cursor); return 0; } /* split a full index node */ struct buffer_head *newbuf = new_node(btree); if (IS_ERR(newbuf)) return PTR_ERR(newbuf); struct bnode *newnode = bufdata(newbuf); unsigned half = bcount(parent) / 2; u64 newkey = be64_to_cpu(parent->entries[half].key); bnode_split(parent, half, newnode); log_bnode_split(sb, bufindex(parentbuf), half, bufindex(newbuf)); /* if the cursor is in the new node, use that as the parent */ int child_is_left = at->next <= parent->entries + half; if (!child_is_left) { struct index_entry *newnext; mark_buffer_unify_non(parentbuf); newnext = newnode->entries + (at->next - &parent->entries[half]); get_bh(newbuf); level_replace_blockput(cursor, level, newbuf, newnext); parentbuf = newbuf; parent = newnode; } else mark_buffer_unify_non(newbuf); bnode_add_index(parent, at->next, childblock, childkey); if (!keep) at->next++; log_bnode_add(sb, bufindex(parentbuf), childblock, childkey); mark_buffer_unify_non(parentbuf); childkey = newkey; childblock = bufindex(newbuf); blockput(newbuf); /* * If child is in left bnode, we should keep the * cursor position to child, otherwise adjust cursor * to new bnode. */ keep = child_is_left; } /* Make new root bnode */ trace("add tree level"); struct buffer_head *newbuf = new_node(btree); if (IS_ERR(newbuf)) return PTR_ERR(newbuf); struct bnode *newroot = bufdata(newbuf); block_t newrootblock = bufindex(newbuf); block_t oldrootblock = btree->root.block; int left_node = bufindex(cursor->path[0].buffer) != childblock; bnode_init_root(newroot, 2, oldrootblock, childblock, childkey); cursor_root_add(cursor, newbuf, newroot->entries + 1 + !left_node); log_bnode_root(sb, newrootblock, 2, oldrootblock, childblock, childkey); /* Change btree to point the new root */ btree->root.block = newrootblock; btree->root.depth++; mark_buffer_unify_non(newbuf); tux3_mark_btree_dirty(btree); cursor_check(cursor); return 0; }