blob: 5ef053eb13802fb2174df8873c58d5ab98f104ae [file] [log] [blame]
/*
* Copyright 2000-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "reiserfs/libreiserfs.h"
/* Make empty node */
void reiserfs_tb_attach_new (reiserfs_bufinfo_t * bi)
{
reiserfs_leaf_mkempty (bi->bi_bh);
if (bi->bi_parent)
reiserfs_dc_set_size (reiserfs_int_at (bi->bi_parent, bi->bi_position), 0);
}
/* Get first empty buffer */
reiserfs_bh_t * reiserfs_tb_FEB (reiserfs_tb_t * tb) {
int i;
reiserfs_bh_t * first_b;
reiserfs_bufinfo_t bi;
for (i = 0; i < TB_FEB_MAX; i ++)
if (tb->FEB[i] != 0)
break;
if (i == TB_FEB_MAX)
reiserfs_panic("vs-12300: reiserfs_tb_FEB: FEB list is empty");
bi.bi_bh = first_b = tb->FEB[i];
bi.bi_parent = 0;
bi.bi_position = 0;
reiserfs_tb_attach_new (&bi);
misc_set_bit(BH_Uptodate, &first_b->b_state);
tb->FEB[i] = 0;
tb->used[i] = first_b;
return(first_b);
}
int reiserfs_tb_lpos (reiserfs_tb_t * tb, int h)
{
int Sh_position = REISERFS_PATH_UPPOS (tb->tb_path, h + 1);
if (Sh_position == 0)
return reiserfs_node_items (tb->FL[h]);
else
return Sh_position - 1;
}
int reiserfs_tb_rpos (reiserfs_tb_t * tb, int h)
{
int Sh_position = REISERFS_PATH_UPPOS (tb->tb_path, h + 1);
if (Sh_position == reiserfs_node_items (REISERFS_PATH_UPPARENT (tb->tb_path, h)))
return 0;
else
return Sh_position + 1;
}
/* Now we have all of the buffers that must be used in balancing of the tree.
We rely on the assumption that schedule() will not occur while reiserfs_tb_balance
works. ( Only interrupt handlers are acceptable.) We balance the tree
according to the analysis made before this, using buffers already obtained.
For SMP support it will someday be necessary to add ordered locking of
tb. */
/* Some interesting rules of balancing:
we delete a maximum of two nodes per level per balancing: we never delete R, when we delete two
of three nodes L, S, R then we move them into R.
we only delete L if we are deleting two nodes, if we delete only one node we delete S
if we shift leaves then we shift as much as we can: this is a deliberate policy of extremism in
node packing which results in higher average utilization after repeated random balance
operations at the cost of more memory copies and more balancing as a result of small insertions
to full nodes.
if we shift internal nodes we try to evenly balance the node utilization, with consequent less
balancing at the cost of lower utilization.
one could argue that the policy for directories in leaves should be that of internal nodes, but
we will wait until another day to evaluate this.... It would be nice to someday measure and
prove these assumptions as to what is optimal....
*/
void reiserfs_tb_balance (
reiserfs_tb_t * tb, /* tree_balance structure */
reiserfs_ih_t * ih, /* item header of inserted item */
const char * body, /* body of inserted item or bytes to paste */
int flag, /* i - insert, d - delete
c - cut, p - paste
Cut means delete part of an item (includes
removing an entry from a directory).
Delete means delete whole item.
Insert means add a new item into the tree.
Paste means to append to the end of an existing
file or to insert a directory entry. */
int zeros_num)
{
//int pos_in_item = tb->tb_path->pos_in_item;
int child_pos, /* position of a child node in its parent */
h; /* level of the tree being processed */
reiserfs_ih_t insert_key[2]; /* in our processing of one level we
sometimes determine what must be
inserted into the next higher level.
This insertion consists of a key or two
keys and their corresponding pointers */
reiserfs_bh_t *insert_ptr[2]; /* inserted node-ptrs for the next
level */
/* if we have no real work to do */
if ( ! tb->insert_size[0] ) {
reiserfs_unfix_nodes(/*th,*/ tb);
return;
}
if (flag == M_INTERNAL) {
insert_ptr[0] = (reiserfs_bh_t *)body;
/* we must prepare insert_key */
if (REISERFS_PATH_UPPARENT_POS (tb->tb_path, 0)
/*LAST_POSITION (tb->tb_path)*//*item_pos*/ == -1)
{
/* get delimiting key from buffer in tree */
reiserfs_key_copy (&insert_key[0].ih_key,
reiserfs_ih_key_at (REISERFS_PATH_LEAF (tb->tb_path), 0));
/*insert_ptr[0]->b_item_order = 0;*/
} else {
/* get delimiting key from new buffer */
reiserfs_key_copy (&insert_key[0].ih_key,
reiserfs_ih_key_at((reiserfs_bh_t *)body,0));
/*insert_ptr[0]->b_item_order = item_pos;*/
}
/* and insert_ptr instead of reiserfs_lb_balance */
child_pos = REISERFS_PATH_UPPARENT_POS (tb->tb_path, 0)/*item_pos*/;
} else
/* balance leaf returns 0 except if combining L R and S into
one node. see reiserfs_ib_balance() for explanation
of this line of code.*/
child_pos = REISERFS_PATH_UPPARENT_POS (tb->tb_path, 0) +
reiserfs_lb_balance (tb, ih, body, flag, zeros_num,
insert_key, insert_ptr);
/* Balance internal level of the tree. */
for ( h = 1; h < REISERFS_TREE_HEIGHT_MAX && tb->insert_size[h]; h++ )
child_pos = reiserfs_ib_balance (tb, h, child_pos,
insert_key, insert_ptr);
/* Release all (except for S[0]) non NULL buffers fixed by reiserfs_fix_nodes() */
reiserfs_unfix_nodes(/*th,*/ tb);
}
void reiserfs_tb_init (reiserfs_tb_t * tb,
reiserfs_filsys_t * fs,
reiserfs_path_t * path,
int size)
{
memset (tb, '\0', sizeof(reiserfs_tb_t));
tb->tb_fs = fs;
tb->tb_path = path;
REISERFS_PATH_BUFFER(path, REISERFS_PATH_OFFILL) = NULL;
REISERFS_PATH_POS(path, REISERFS_PATH_OFFILL) = 0;
tb->insert_size[0] = size;
}
void reiserfs_tb_print_path (reiserfs_tb_t * tb, reiserfs_path_t * path)
{
int offset = path->path_length;
reiserfs_bh_t * bh;
printf ("Offset Bh (b_blocknr, b_count) Position Nr_item\n");
while ( offset > REISERFS_PATH_OFFILL ) {
bh = REISERFS_PATH_BUFFER (path, offset);
printf ("%6d %10p (%9lu, %7d) %8d %7d\n", offset,
bh, bh ? bh->b_blocknr : 0, bh ? bh->b_count : 0,
REISERFS_PATH_POS (path, offset), bh ? reiserfs_node_items (bh) : -1);
offset --;
}
}