⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btree.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/fs/befs/btree.c * * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> * * Licensed under the GNU GPL. See the file COPYING for details. * * 2002-02-05: Sergey S. Kostyliov added binary search withing * 		btree nodes. * * Many thanks to: * * Dominic Giampaolo, author of "Practical File System * Design with the Be File System", for such a helpful book. *  * Marcus J. Ranum, author of the b+tree package in  * comp.sources.misc volume 10. This code is not copied from that * work, but it is partially based on it. * * Makoto Kato, author of the original BeFS for linux filesystem * driver. */#include <linux/kernel.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/buffer_head.h>#include "befs.h"#include "btree.h"#include "datastream.h"/* * The btree functions in this file are built on top of the * datastream.c interface, which is in turn built on top of the * io.c interface. *//* Befs B+tree structure: *  * The first thing in the tree is the tree superblock. It tells you * all kinds of useful things about the tree, like where the rootnode * is located, and the size of the nodes (always 1024 with current version * of BeOS). * * The rest of the tree consists of a series of nodes. Nodes contain a header * (struct befs_btree_nodehead), the packed key data, an array of shorts  * containing the ending offsets for each of the keys, and an array of * befs_off_t values. In interior nodes, the keys are the ending keys for  * the childnode they point to, and the values are offsets into the  * datastream containing the tree.  *//* Note: *  * The book states 2 confusing things about befs b+trees. First,  * it states that the overflow field of node headers is used by internal nodes * to point to another node that "effectively continues this one". Here is what * I believe that means. Each key in internal nodes points to another node that * contains key values less than itself. Inspection reveals that the last key  * in the internal node is not the last key in the index. Keys that are  * greater than the last key in the internal node go into the overflow node.  * I imagine there is a performance reason for this. * * Second, it states that the header of a btree node is sufficient to  * distinguish internal nodes from leaf nodes. Without saying exactly how.  * After figuring out the first, it becomes obvious that internal nodes have * overflow nodes and leafnodes do not. *//*  * Currently, this code is only good for directory B+trees. * In order to be used for other BFS indexes, it needs to be extended to handle * duplicate keys and non-string keytypes (int32, int64, float, double). *//* * In memory structure of each btree node */typedef struct {	befs_host_btree_nodehead head;	/* head of node converted to cpu byteorder */	struct buffer_head *bh;	befs_btree_nodehead *od_node;	/* on disk node */} befs_btree_node;/* local constants */static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;/* local functions */static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,			       befs_btree_super * bt_super,			       befs_btree_node * this_node,			       befs_off_t * node_off);static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,			      befs_btree_super * sup);static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,			     befs_btree_node * node, befs_off_t node_off);static int befs_leafnode(befs_btree_node * node);static fs16 *befs_bt_keylen_index(befs_btree_node * node);static fs64 *befs_bt_valarray(befs_btree_node * node);static char *befs_bt_keydata(befs_btree_node * node);static int befs_find_key(struct super_block *sb, befs_btree_node * node,			 const char *findkey, befs_off_t * value);static char *befs_bt_get_key(struct super_block *sb, befs_btree_node * node,			     int index, u16 * keylen);static int befs_compare_strings(const void *key1, int keylen1,				const void *key2, int keylen2);/** * befs_bt_read_super - read in btree superblock convert to cpu byteorder * @sb: Filesystem superblock * @ds: Datastream to read from * @sup: Buffer in which to place the btree superblock * * Calls befs_read_datastream to read in the btree superblock and * makes sure it is in cpu byteorder, byteswapping if necessary. * * On success, returns BEFS_OK and *@sup contains the btree superblock, * in cpu byte order. * * On failure, BEFS_ERR is returned. */static intbefs_bt_read_super(struct super_block *sb, befs_data_stream * ds,		   befs_btree_super * sup){	struct buffer_head *bh = NULL;	befs_disk_btree_super *od_sup = NULL;	befs_debug(sb, "---> befs_btree_read_super()");	bh = befs_read_datastream(sb, ds, 0, NULL);	if (!bh) {		befs_error(sb, "Couldn't read index header.");		goto error;	}	od_sup = (befs_disk_btree_super *) bh->b_data;	befs_dump_index_entry(sb, od_sup);	sup->magic = fs32_to_cpu(sb, od_sup->magic);	sup->node_size = fs32_to_cpu(sb, od_sup->node_size);	sup->max_depth = fs32_to_cpu(sb, od_sup->max_depth);	sup->data_type = fs32_to_cpu(sb, od_sup->data_type);	sup->root_node_ptr = fs64_to_cpu(sb, od_sup->root_node_ptr);	sup->free_node_ptr = fs64_to_cpu(sb, od_sup->free_node_ptr);	sup->max_size = fs64_to_cpu(sb, od_sup->max_size);	brelse(bh);	if (sup->magic != BEFS_BTREE_MAGIC) {		befs_error(sb, "Index header has bad magic.");		goto error;	}	befs_debug(sb, "<--- befs_btree_read_super()");	return BEFS_OK;      error:	befs_debug(sb, "<--- befs_btree_read_super() ERROR");	return BEFS_ERR;}/** * befs_bt_read_node - read in btree node and convert to cpu byteorder * @sb: Filesystem superblock * @ds: Datastream to read from * @node: Buffer in which to place the btree node * @node_off: Starting offset (in bytes) of the node in @ds * * Calls befs_read_datastream to read in the indicated btree node and * makes sure its header fields are in cpu byteorder, byteswapping if * necessary. * Note: node->bh must be NULL when this function called first * time. Don't forget brelse(node->bh) after last call. * * On success, returns BEFS_OK and *@node contains the btree node that * starts at @node_off, with the node->head fields in cpu byte order. * * On failure, BEFS_ERR is returned. */static intbefs_bt_read_node(struct super_block *sb, befs_data_stream * ds,		  befs_btree_node * node, befs_off_t node_off){	uint off = 0;	befs_debug(sb, "---> befs_bt_read_node()");	if (node->bh)		brelse(node->bh);	node->bh = befs_read_datastream(sb, ds, node_off, &off);	if (!node->bh) {		befs_error(sb, "befs_bt_read_node() failed to read "			   "node at %Lu", node_off);		befs_debug(sb, "<--- befs_bt_read_node() ERROR");		return BEFS_ERR;	}	node->od_node =	    (befs_btree_nodehead *) ((void *) node->bh->b_data + off);	befs_dump_index_node(sb, node->od_node);	node->head.left = fs64_to_cpu(sb, node->od_node->left);	node->head.right = fs64_to_cpu(sb, node->od_node->right);	node->head.overflow = fs64_to_cpu(sb, node->od_node->overflow);	node->head.all_key_count =	    fs16_to_cpu(sb, node->od_node->all_key_count);	node->head.all_key_length =	    fs16_to_cpu(sb, node->od_node->all_key_length);	befs_debug(sb, "<--- befs_btree_read_node()");	return BEFS_OK;}/** * befs_btree_find - Find a key in a befs B+tree * @sb: Filesystem superblock * @ds: Datastream containing btree * @key: Key string to lookup in btree * @value: Value stored with @key * * On sucess, returns BEFS_OK and sets *@value to the value stored * with @key (usually the disk block number of an inode). * * On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND. *  * Algorithm:  *   Read the superblock and rootnode of the b+tree. *   Drill down through the interior nodes using befs_find_key(). *   Once at the correct leaf node, use befs_find_key() again to get the *   actuall value stored with the key. */intbefs_btree_find(struct super_block *sb, befs_data_stream * ds,		const char *key, befs_off_t * value){	befs_btree_node *this_node = NULL;	befs_btree_super bt_super;	befs_off_t node_off;	int res;	befs_debug(sb, "---> befs_btree_find() Key: %s", key);	if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {		befs_error(sb,			   "befs_btree_find() failed to read index superblock");		goto error;	}	this_node = kmalloc(sizeof (befs_btree_node),						GFP_NOFS);	if (!this_node) {		befs_error(sb, "befs_btree_find() failed to allocate %u "			   "bytes of memory", sizeof (befs_btree_node));		goto error;	}	this_node->bh = NULL;	/* read in root node */	node_off = bt_super.root_node_ptr;	if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {		befs_error(sb, "befs_btree_find() failed to read "			   "node at %Lu", node_off);		goto error_alloc;	}	while (!befs_leafnode(this_node)) {		res = befs_find_key(sb, this_node, key, &node_off);		if (res == BEFS_BT_NOT_FOUND)			node_off = this_node->head.overflow;		/* if no match, go to overflow node */		if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {			befs_error(sb, "befs_btree_find() failed to read "				   "node at %Lu", node_off);			goto error_alloc;		}	}	/* at the correct leaf node now */	res = befs_find_key(sb, this_node, key, value);	brelse(this_node->bh);	kfree(this_node);	if (res != BEFS_BT_MATCH) {		befs_debug(sb, "<--- befs_btree_find() Key %s not found", key);		*value = 0;		return BEFS_BT_NOT_FOUND;	}	befs_debug(sb, "<--- befs_btree_find() Found key %s, value %Lu",		   key, *value);	return BEFS_OK;      error_alloc:	kfree(this_node);      error:	*value = 0;	befs_debug(sb, "<--- befs_btree_find() ERROR");	return BEFS_ERR;}/** * befs_find_key - Search for a key within a node * @sb: Filesystem superblock * @node: Node to find the key within * @key: Keystring to search for * @value: If key is found, the value stored with the key is put here * * finds exact match if one exists, and returns BEFS_BT_MATCH * If no exact match, finds first key in node that is greater * (alphabetically) than the search key and returns BEFS_BT_PARMATCH * (for partial match, I guess). Can you think of something better to * call it? * * If no key was a match or greater than the search key, return * BEFS_BT_NOT_FOUND. * * Use binary search instead of a linear. */static intbefs_find_key(struct super_block *sb, befs_btree_node * node,	      const char *findkey, befs_off_t * value){	int first, last, mid;	int eq;	u16 keylen;	int findkey_len;	char *thiskey;	fs64 *valarray;	befs_debug(sb, "---> befs_find_key() %s", findkey);	*value = 0;	findkey_len = strlen(findkey);	/* if node can not contain key, just skeep this node */	last = node->head.all_key_count - 1;	thiskey = befs_bt_get_key(sb, node, last, &keylen);	eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len);	if (eq < 0) {		befs_debug(sb, "<--- befs_find_key() %s not found", findkey);		return BEFS_BT_NOT_FOUND;	}	valarray = befs_bt_valarray(node);	/* simple binary search */	first = 0;	mid = 0;	while (last >= first) {		mid = (last + first) / 2;		befs_debug(sb, "first: %d, last: %d, mid: %d", first, last,			   mid);		thiskey = befs_bt_get_key(sb, node, mid, &keylen);		eq = befs_compare_strings(thiskey, keylen, findkey,					  findkey_len);		if (eq == 0) {			befs_debug(sb, "<--- befs_find_key() found %s at %d",				   thiskey, mid);			*value = fs64_to_cpu(sb, valarray[mid]);			return BEFS_BT_MATCH;		}		if (eq > 0)			last = mid - 1;		else			first = mid + 1;	}	if (eq < 0)		*value = fs64_to_cpu(sb, valarray[mid + 1]);	else		*value = fs64_to_cpu(sb, valarray[mid]);	befs_debug(sb, "<--- befs_find_key() found %s at %d", thiskey, mid);	return BEFS_BT_PARMATCH;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -