示例#1
0
文件: btree.c 项目: poelzi/mspdebug
int btree_get(btree_t bt, const void *key, void *data)
{
	const struct btree_def *def = bt->def;
	struct btree_page *p = bt->root;
	int h;

	check_btree(bt);

	if (!key)
		return btree_select(bt, NULL, BTREE_READ, NULL, data);

	for (h = bt->root->height; h >= 0; h--) {
		int s = find_key_le(p, key);

		if (h) {
			assert (s >= 0 && s < p->num_children);
			p = *PAGE_PTR(p, s);
		} else if (s >= 0 && !def->compare(key, PAGE_KEY(p, s))) {
			memcpy(data, PAGE_DATA(p, s), def->data_size);
			return 0;
		}
	}

	return 1;
}
示例#2
0
文件: btree.c 项目: poelzi/mspdebug
void btree_clear(btree_t bt)
{
	struct btree_page *p;
	struct btree_page *path_up = 0;

	check_btree(bt);

	/* The cursor will have nothing to point to after this. */
	bt->slot[0] = -1;

	/* First, find the last leaf node, which we can re-use as an
	 * empty root.
	 */
	p = bt->root;
	while (p->height) {
		path_up = p;
		p = *PAGE_PTR(p, p->num_children - 1);
	}

	/* Unlink it from the tree and then destroy everything else. */
	if (path_up) {
		path_up->num_children--;
		destroy_page(bt->root);
	}

	/* Clear it out and make it the new root */
	p->num_children = 0;
	bt->root = p;
}
示例#3
0
文件: btree.c 项目: poelzi/mspdebug
int btree_select(btree_t bt, const void *key, btree_selmode_t mode,
		 void *key_ret, void *data_ret)
{
	const struct btree_def *def = bt->def;

	check_btree(bt);

	switch (mode) {
	case BTREE_CLEAR:
		bt->slot[0] = -1;
		break;

	case BTREE_READ:
		break;

	case BTREE_EXACT:
	case BTREE_LE:
		if (!trace_path(bt, key, bt->path, bt->slot) &&
		    mode == BTREE_EXACT)
			bt->slot[0] = -1;
		break;

	case BTREE_FIRST:
		cursor_first(bt);
		break;

	case BTREE_NEXT:
		cursor_next(bt);
		break;
	}

	/* Return the data at the cursor */
	if (bt->slot[0] >= 0) {
		if (key_ret)
			memcpy(key_ret,
			       PAGE_KEY(bt->path[0], bt->slot[0]),
			       def->key_size);
		if (data_ret)
			memcpy(data_ret,
			       PAGE_DATA(bt->path[0], bt->slot[0]),
			       def->data_size);
		return 0;
	}

	return 1;
}
示例#4
0
文件: btree.c 项目: poelzi/mspdebug
int btree_delete(btree_t bt, const void *key)
{
	const struct btree_def *def = bt->def;
	const int halfsize = def->branches / 2;
	struct btree_page *path[MAX_HEIGHT] = {0};
	int slot[MAX_HEIGHT] = {0};
	int h;

	check_btree(bt);

	/* Trace a path to the item to be deleted */
	if (!key) {
		if (bt->slot[0] < 0)
			return 1;

		memcpy(path, bt->path, sizeof(path));
		memcpy(slot, bt->slot, sizeof(slot));
	} else if (!trace_path(bt, key, path, slot)) {
		return 1;
	}

	/* Select the next item if we're deleting at the cursor */
	if (bt->slot[0] == slot[0] && bt->path[0] == path[0])
		cursor_next(bt);

	/* Delete from the leaf node. If it's still full enough, then we don't
	 * need to do anything else.
	 */
	delete_item(path[0], slot[0]);
	if (path[0]->num_children >= halfsize)
		return 0;

	/* Trace back up the tree, fixing underfull nodes. If we can fix by
	 * borrowing, do it and we're done. Otherwise, we need to fix by
	 * merging, which may result in another underfull node, and we need
	 * to continue.
	 */
	for (h = 1; h <= bt->root->height; h++) {
		struct btree_page *p = path[h];
		struct btree_page *c = path[h - 1];
		int s = slot[h];

		if (s > 0) {
			/* Borrow/merge from lower page */
			struct btree_page *d = *PAGE_PTR(p, s - 1);

			if (d->num_children > halfsize) {
				move_item(d, d->num_children - 1, c, 0);
				memcpy(PAGE_KEY(p, s), PAGE_KEY(c, 0),
				       def->key_size);
				return 0;
			}

			merge_pages(d, c);
			delete_item(p, s);
			free(c);
		} else {
			/* Borrow/merge from higher page */
			struct btree_page *d = *PAGE_PTR(p, s + 1);

			if (d->num_children > halfsize) {
				move_item(d, 0, c, c->num_children);
				memcpy(PAGE_KEY(p, s + 1),
				       PAGE_KEY(d, 0),
				       def->key_size);
				return 0;
			}

			merge_pages(c, d);
			delete_item(p, s + 1);
			free(d);
		}

		if (p->num_children >= halfsize)
			return 0;
	}

	/* If the root contains only a single pointer to another page,
	 * shrink the tree. This does not affect the cursor.
	 */
	if (bt->root->height && bt->root->num_children == 1) {
		struct btree_page *old = bt->root;

		bt->root = *PAGE_PTR(old, 0);
		free(old);
	}

	return 0;
}
示例#5
0
文件: btree.c 项目: poelzi/mspdebug
int btree_put(btree_t bt, const void *key, const void *data)
{
	const struct btree_def *def = bt->def;
	struct btree_page *new_root = NULL;
	struct btree_page *path_new[MAX_HEIGHT] = {0};
	struct btree_page *path_old[MAX_HEIGHT] = {0};
	int slot_old[MAX_HEIGHT] = {0};
	int h;

	check_btree(bt);

	/* Special case: cursor overwrite */
	if (!key) {
		if (bt->slot[0] < 0) {
			fprintf(stderr, "btree: put at invalid cursor\n");
			return -1;
		}

		memcpy(PAGE_DATA(bt->path[0], bt->slot[0]), data,
		       def->data_size);
		return 1;
	}

	/* Find a path down the tree that leads to the page which should
	 * contain this datum (though the page might be too big to hold it).
	 */
	if (trace_path(bt, key, path_old, slot_old)) {
		/* Special case: overwrite existing item */
		memcpy(PAGE_DATA(path_old[0], slot_old[0]), data,
		       def->data_size);
		return 1;
	}

	/* Trace from the leaf up. If the leaf is at its maximum size, it will
	 * need to split, and cause a pointer to be added in the parent page
	 * of the same node (which may in turn cause it to split).
	 */
	for (h = 0; h <= bt->root->height; h++) {
		if (path_old[h]->num_children < def->branches)
			break;

		path_new[h] = allocate_page(bt, h);
		if (!path_new[h])
			goto fail;
	}

	/* If the split reaches the top (i.e. the root splits), then we need
	 * to allocate a new root node.
	 */
	if (h > bt->root->height) {
		if (h >= MAX_HEIGHT) {
			fprintf(stderr, "btree: maximum height exceeded\n");
			goto fail;
		}

		new_root = allocate_page(bt, h);
		if (!new_root)
			goto fail;
	}

	/* Trace up to one page above the split. At each page that needs
	 * splitting, copy the top half of keys into the new page. Also,
	 * insert a key into one of the pages at all pages from the leaf
	 * to the page above the top of the split.
	 */
	for (h = 0; h <= bt->root->height; h++) {
		int s = slot_old[h] + 1;
		struct btree_page *p = path_old[h];

		/* If there's a split at this level, copy the top half of
		 * the keys from the old page to the new one. Check to see
		 * if the position we were going to insert into is in the
		 * old page or the new one.
		 */
		if (path_new[h]) {
			split_page(path_old[h], path_new[h]);

			if (s > p->num_children) {
				s -= p->num_children;
				p = path_new[h];
			}
		}

		/* Insert the key in the appropriate page */
		if (h)
			insert_ptr(p, s, PAGE_KEY(path_new[h - 1], 0),
				   path_new[h - 1]);
		else
			insert_data(p, s, key, data);

		/* If there was no split at this level, there's nothing to
		 * insert higher up, and we're all done.
		 */
		if (!path_new[h])
			return 0;
	}

	/* If we made it this far, the split reached the top of the tree, and
	 * we need to grow it using the extra page we allocated.
	 */
	assert (new_root);

	if (bt->slot[0] >= 0) {
		/* Fix up the cursor, if active */
		bt->slot[new_root->height] =
			bt->path[bt->root->height] == new_root ? 1 : 0;
		bt->path[new_root->height] = new_root;
	}

	memcpy(PAGE_KEY(new_root, 0), def->zero, def->key_size);
	*PAGE_PTR(new_root, 0) = path_old[h - 1];
	memcpy(PAGE_KEY(new_root, 1), PAGE_KEY(path_new[h - 1], 0),
	       def->key_size);
	*PAGE_PTR(new_root, 1) = path_new[h - 1];
	new_root->num_children = 2;
	bt->root = new_root;

	return 0;

 fail:
	for (h = 0; h <= bt->root->height; h++)
		if (path_new[h])
			free(path_new[h]);
	return -1;
}
示例#6
0
文件: btree.c 项目: poelzi/mspdebug
void btree_free(btree_t bt)
{
	check_btree(bt);
	destroy_page(bt->root);
	free(bt);
}
示例#7
0
/*===========================================
 * main -- Main procedure of dbverify command
 *=========================================*/
int
main (int argc, char **argv)
{
    char *flags, *dbname;
    char *ptr;
    char * msg;
    BOOLEAN cflag=FALSE; /* create new db if not found */
    INT writ=1; /* request write access to database */
    BOOLEAN immut=FALSE; /* immutable access to database */
    BOOLEAN allchecks=FALSE; /* if user requested all checks */
    INT returnvalue=1;
    STRING crashlog=NULL;
    INT lldberrnum=0;
    int i=0;

    /* initialize all the low-level library code */
    init_stdlib();

    validate_errs();

#if HAVE_SETLOCALE
    /* initialize locales */
    setlocale(LC_ALL, "");
#endif /* HAVE_SETLOCALE */

#if ENABLE_NLS
    ll_bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    save_original_locales();

#ifdef WIN32
    /* TO DO - research if this is necessary */
    _fmode = O_BINARY;	/* default to binary rather than TEXT mode */
#endif

    /* handle conventional arguments --version and --help */
    /* needed for help2man to synthesize manual pages */
    for (i=1; i<argc; ++i) {
        if (!strcmp(argv[i], "--version")) {
            print_version("dbverify");
            return 0;
        }
        if (!strcmp(argv[i], "--help")
                || !strcmp(argv[i], "-?")) {
            print_usage();
            return 0;
        }
    }

    if (argc != 3 || argv[1][0] != '-' || argv[1][1] == '\0') {
        print_usage();
        goto done;
    }
    flags = argv[1];
    dbname = argv[2];
    for (ptr=&flags[1]; *ptr; ++ptr) {
        switch(*ptr) {
        case 'l':
            todo.check_dbstructure=TRUE;
            break;
        case 'g':
            todo.find_ghosts=TRUE;
            break;
        case 'G':
            todo.fix_ghosts=TRUE;
            break;
        case 'i':
            todo.check_indis=TRUE;
            break;
        case 'f':
            todo.check_fams=TRUE;
            break;
        case 's':
            todo.check_sours=TRUE;
            break;
        case 'e':
            todo.check_evens=TRUE;
            break;
        case 'x':
            todo.check_othes=TRUE;
            break;
        case 'n':
            noisy=TRUE;
            break;
        case 'a':
            allchecks=TRUE;
            break;
        case 'F':
            todo.fix_alter_pointers=TRUE;
            break;
        case 'm':
            todo.check_missing_data_records=TRUE;
            break;
        case 'M':
            todo.fix_missing_data_records=TRUE;
            break;
        case 'D':
            todo.fix_deletes=TRUE;
            break;
        case 'v':
            print_version("llexec");
            goto done;
        case 'h':
        default:
            print_usage();
            goto done;
        }
    }

    /* Turn off Memory Debugging */
    /* This is unnecessary -- it is off anyway, Perry, 2001/10/28 */
    alloclog  = FALSE;

    /* Enable any checks needed for fixes selected */
    if (todo.fix_missing_data_records)
        todo.check_missing_data_records = 1;

    /* initialize options & misc. stuff */
    llgettext_set_default_localedir(LOCALEDIR);
    if (!init_lifelines_global(0, &msg, 0)) {
        printf("%s\n", msg);
        goto done;
    }

    /* setup crashlog in case init_screen fails (eg, bad menu shortcuts) */
    crashlog = getlloptstr("CrashLog_dbverify", NULL);
    if (!crashlog) {
        crashlog = "Crashlog_dbverify.log";
    }
    crash_setcrashlog(crashlog);

    /* NB: This assumes btree database */
    if (!(BTR = bt_openbtree(dbname, cflag, writ, immut, &lldberrnum))) {
        char buffer[256];
        describe_dberror(lldberrnum, buffer, ARRSIZE(buffer));
        puts(buffer);
        goto done;
    }

    /*
    Do low-level checks before initializing lifelines database layer,
    because lifelines database init traverses btree for user options
    and translation tables, and here we check the infrastructure of
    the btree itself.
    */
    if (todo.check_dbstructure || allchecks) {
        if (!check_btree(BTR))
            goto done;
    }

    if (!init_lifelines_postdb()) {
        printf(_(qSbaddb));
        goto done;
    }
    printf(_("Checking %s"), dbname);
    puts("");

    /* all checks - if any new ones, have to update this */
    if (allchecks) {
        todo.check_indis=todo.check_fams=todo.check_sours=TRUE;
        todo.check_evens=todo.check_othes=TRUE;
        todo.find_ghosts=TRUE;
    }

    if (todo.find_ghosts || todo.fix_ghosts)
        check_ghosts();


    if (!(bwrite(BTR))) {
        todo.fix_alter_pointers = FALSE;
        todo.fix_ghosts = FALSE;
    }

    if (todo.check_indis
            || todo.check_fams
            || todo.check_sours
            || todo.check_evens
            || todo.check_othes) {
        check_and_fix_records();
    }

    if (todo.check_missing_data_records) {
        check_missing_data_records();
    }

    report_results();

    closebtree(BTR);

    /* TODO: probably should call lldb_close, Perry 2005-10-07 */

    BTR = 0;
    returnvalue = 0;

done:
    return returnvalue;
}