blob: 9c382399b5d548a22bcb77f9de9331c202a52907 [file] [log] [blame]
/*
* Copyright 2002-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#include "debugreiserfs.h"
#include <search.h>
#include <obstack.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
/* try to find blocks which contain only items which are */
/* read blocks marked in debug_bitmap and collect statistic of it:
number of stat data */
struct {
unsigned long all;
unsigned long items [5];
unsigned long unique_keys; /* keys of stat datas */
unsigned long unique_entry_keys; /* keys which appear in directory entries */
unsigned long names; /* dir entries but "." and ".." */
unsigned long dir_blocks; /* block containing only one directory item */
unsigned long unique_items;
unsigned long leaves;
unsigned long blocks_to_skip;
} fs_stat;
/* store unique item heads */
struct obstack items;
/* tree sorting item heades by comp_items_1 */
void * items_tree;
static int comp_items_1 (const void * p1, const void * p2)
{
int retval;
struct item_head * ih1, * ih2;
/*
if (*(int *)p1 != *(int *)p2)
retval = 1;
else
retval = 0;
*/
retval = comp_keys (p1, p2);
/*retval = comp_short_keys (p1, p2);*/
if (retval)
return retval;
ih1 = (struct item_head *)p1;
ih2 = (struct item_head *)p2;
if (get_ih_item_len (ih1) < get_ih_item_len (ih2))
return -1;
if (get_ih_item_len (ih1) > get_ih_item_len (ih2))
return 1;
if (get_ih_entry_count (ih1) < get_ih_entry_count (ih2))
return -1;
if (get_ih_entry_count (ih1) > get_ih_entry_count (ih2))
return 1;
return 0;
}
/*
static void print_node (const void *nodep, VISIT value, int level)
{
int i;
if (value == leaf) {
for (i = 0; i < level; i ++)
reiserfs_warning (stdout, "\t");
reiserfs_warning (stdout, "%H\n", *(struct item_head **)nodep);
return;
}
if (value == postorder) {
for (i = 0; i < level; i ++)
reiserfs_warning (stdout, "\t");
reiserfs_warning (stdout, "%H\n", *(struct item_head **)nodep);
}
}
*/
static int is_unique_item (struct obstack * ostack, void ** tree, void * ih)
{
void * res;
void * key1;
key1 = obstack_copy (ostack, ih, IH_SIZE);
res = tsearch (key1, tree, comp_items_1);
if (!res)
reiserfs_panic ("Too many keys found");
/* twalk (*tree, print_node);*/
/* reiserfs_warning (stderr, "\n\n");*/
if (*(void **)res != key1) {
/* key is in tree already, remove it from obstack */
/*reiserfs_warning (stdout, "%H is skipped\n", ih);fflush (stdout);*/
obstack_free (ostack, key1);
return 0;
}
/*reiserfs_warning (stdout, "%k is added\n", ih);fflush (stdout);*/
return 1;
}
static void stat1_the_leaf (reiserfs_filsys_t * fs, struct buffer_head * bh)
{
int i, i_num;
struct item_head * ih;
int is_there_unique_item;
ih = B_N_PITEM_HEAD (bh, 0);
is_there_unique_item = 0;
i_num = leaf_item_number_estimate(bh);
for (i = 0; i < i_num; i ++, ih ++) {
/* count all items */
fs_stat.all ++;
if (is_unique_item (&items, &items_tree, ih)) {
/* this is item we have not seen yet */
fs_stat.unique_items ++;
is_there_unique_item ++;
}
}
if (!is_there_unique_item) {
/* the node contains only items we have seen already. so we will skip
it */
fs_stat.blocks_to_skip ++;
reiserfs_bitmap_clear_bit (input_bitmap (fs), bh->b_blocknr);
} else {
ih = B_N_PITEM_HEAD (bh, 0);
/* node contains at least one unique item. We will put it in, count items of each type */
for (i = 0; i < i_num; i ++, ih ++) {
fs_stat.items [get_type (&ih->ih_key)] ++;
}
}
}
/*
static void stat2_the_leaf (struct buffer_head * bh)
{
int i;
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, 0);
for (i = 0; i < node_item_number (bh); i ++, ih ++) {
}
}
*/
void do_stat (reiserfs_filsys_t * fs)
{
unsigned long i;
unsigned long done, total;
struct buffer_head * bh;
int type;
FILE * fp;
obstack_init (&items);
items_tree = 0;
/*
bh = bread (fs->s_dev, 8211, fs->s_blocksize);
stat1_the_leaf (fs, bh);
return;
*/
/* pass 0 of stating */
total = reiserfs_bitmap_ones (input_bitmap (fs));
done = 0;
for (i = 0; i < get_sb_block_count (fs->fs_ondisk_sb); i ++) {
if (!reiserfs_bitmap_test_bit (input_bitmap (fs), i))
continue;
print_how_far (stderr, &done, total, 1, be_quiet (fs));
bh = bread (fs->fs_dev, i, fs->fs_blocksize);
if (!bh) {
printf ("could not read block %lu\n", i);
continue;
}
type = who_is_this (bh->b_data, bh->b_size);
if (type != THE_LEAF && type != HAS_IH_ARRAY) {
reiserfs_bitmap_clear_bit (input_bitmap (fs), i);
brelse (bh);
continue;
}
fs_stat.leaves ++;
stat1_the_leaf (fs, bh);
brelse (bh);
}
reiserfs_warning (stderr, "\nThere were found on the '%s' device:\n"
"\tleaves %lu\n"
"\ttotal number of items %lu\n"
"\tblocks containing at least one unique item %lu\n"
"\tblocks which can be skipped %lu\n"
"\t\tstat data %lu\n"
"\t\tindirect %lu\n"
"\t\tdirect %lu\n"
"\t\tdirectory items %lu\n"
"\tunique items %lu\n",
/*
"\tnames there (but \".\" and \"..\") %lu\n"
"\tpointing to unique keys %lu\n"
"other items %lu\n"
"blocks containing only 1 dir item %lu\n",
*/
fs->fs_file_name,
fs_stat.leaves,
fs_stat.all,
fs_stat.leaves - fs_stat.blocks_to_skip,
fs_stat.blocks_to_skip,
fs_stat.items [TYPE_STAT_DATA],
fs_stat.items [TYPE_INDIRECT],
fs_stat.items [TYPE_DIRECT],
fs_stat.items [TYPE_DIRENTRY],
fs_stat.unique_items);
/*
fs_stat.names,
fs_stat.unique_keys,
fs_stat.items [4],
fs_stat.dir_blocks);
*/
if (!input_bitmap_file_name(fs))
return;
fp = fopen (input_bitmap_file_name(fs), "w");
if (!fp) {
reiserfs_exit (1, "could not open %s to save bitmap: %m\n",
input_bitmap_file_name(fs));
}
reiserfs_warning (stderr, "Updated bitmap contains %u blocks marked\n",
reiserfs_bitmap_ones (input_bitmap (fs)));
reiserfs_bitmap_save (fp, input_bitmap (fs));
fclose (fp);
return;
/* pass 2 of stating */
reiserfs_warning (stderr, "Looking for blocks containing only keys not pointed by any of entries\n");
total = reiserfs_bitmap_ones (input_bitmap (fs));
done = 0;
for (i = 0; i < get_sb_block_count (fs->fs_ondisk_sb); i ++) {
if (!reiserfs_bitmap_test_bit (input_bitmap (fs), i))
continue;
print_how_far (stderr, &done, total, 1, be_quiet (fs));
bh = bread (fs->fs_dev, i, fs->fs_blocksize);
if (!bh) {
printf ("could not read block %lu\n", i);
continue;
}
/*stat2_the_leaf (bh);*/
}
}