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

📄 bdelete.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
字号:
/* * linux/fs/hfs/bdelete.c * * Copyright (C) 1995-1997  Paul H. Hargrove * This file may be distributed under the terms of the GNU General Public License. * * This file contains the code to delete records in a B-tree. * * "XXX" in a comment is a note to myself to consider changing something. * * In function preconditions the term "valid" applied to a pointer to * a structure means that the pointer is non-NULL and the structure it * points to has all fields initialized to consistent values. */#include "hfs_btree.h"/*================ Variable-like macros ================*/#define FULL (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor))#define NO_SPACE (HFS_SECTOR_SIZE+1)/*================ File-local functions ================*//* * bdelete_nonempty() * * Description: *   Deletes a record from a given bnode without regard to it becoming empty. * Input Variable(s): *   struct hfs_brec* brec: pointer to the brec for the deletion *   struct hfs_belem* belem: which node in 'brec' to delete from * Output Variable(s): *   NONE * Returns: *   void * Preconditions: *   'brec' points to a valid (struct hfs_brec). *   'belem' points to a valid (struct hfs_belem) in 'brec'. * Postconditions: *   The record has been inserted in the position indicated by 'brec'. */static void bdelete_nonempty(struct hfs_brec *brec, struct hfs_belem *belem){	int i, rec, nrecs, tomove;	hfs_u16 size;	hfs_u8 *start;	struct hfs_bnode *bnode = belem->bnr.bn;	rec = belem->record;	nrecs = bnode->ndNRecs;	size = bnode_rsize(bnode, rec);	tomove = bnode_offset(bnode, nrecs+1) - bnode_offset(bnode, rec+1);		/* adjust the record table */	for (i = rec+1; i <= nrecs; ++i) {		hfs_put_hs(bnode_offset(bnode,i+1) - size, RECTBL(bnode,i));	}	/* move it down */	start = bnode_key(bnode, rec);	memmove(start, start + size, tomove);	/* update record count */	--bnode->ndNRecs;}/* * del_root() * * Description: *   Delete the current root bnode. * Input Variable(s): *   struct hfs_bnode_ref *root: reference to the root bnode * Output Variable(s): *   NONE * Returns: *   int: 0 on success, error code on failure * Preconditions: *   'root' refers to the root bnode with HFS_LOCK_WRITE access. *   None of 'root's children are held with HFS_LOCK_WRITE access. * Postconditions: *   The current 'root' node is removed from the tree and the depth *    of the tree is reduced by one. *   If 'root' is an index node with exactly one child, then that *    child becomes the new root of the tree. *   If 'root' is an empty leaf node the tree becomes empty. *   Upon return access to 'root' is relinquished. */static int del_root(struct hfs_bnode_ref *root){	struct hfs_btree *tree = root->bn->tree;	struct hfs_bnode_ref child;	hfs_u32 node;	if (root->bn->ndNRecs > 1) {		return 0;	} else if (root->bn->ndNRecs == 0) {		/* tree is empty */		tree->bthRoot = 0;		tree->root = NULL;		tree->bthRoot = 0;		tree->bthFNode = 0;		tree->bthLNode = 0;		--tree->bthDepth;		tree->dirt = 1;		if (tree->bthDepth) {			hfs_warn("hfs_bdelete: empty tree with bthDepth=%d\n",				 tree->bthDepth);			goto bail;		}		return hfs_bnode_free(root);	} else if (root->bn->ndType == ndIndxNode) {		/* tree is non-empty */		node = hfs_get_hl(bkey_record(bnode_datastart(root->bn)));		child = hfs_bnode_find(tree, node, HFS_LOCK_READ);		if (!child.bn) {			hfs_warn("hfs_bdelete: can't read child node.\n");			goto bail;		}					child.bn->sticky = HFS_STICKY;        	if (child.bn->next) {                	child.bn->next->prev = child.bn->prev;        	}        	if (child.bn->prev) {                	child.bn->prev->next = child.bn->next;        	}        	if (bhash(tree, child.bn->node) == child.bn) {                	bhash(tree, child.bn->node) = child.bn->next;        	}		child.bn->next = NULL;		child.bn->prev = NULL;		tree->bthRoot = child.bn->node;		tree->root = child.bn;		/* re-assign bthFNode and bthLNode if the new root is                   a leaf node. */		if (child.bn->ndType == ndLeafNode) {			tree->bthFNode = node;			tree->bthLNode = node;		}		hfs_bnode_relse(&child);		tree->bthRoot = node;		--tree->bthDepth;		tree->dirt = 1;		if (!tree->bthDepth) {			hfs_warn("hfs_bdelete: non-empty tree with "				 "bthDepth == 0\n");			goto bail;		}		return hfs_bnode_free(root);	/* marks tree dirty */	}	hfs_bnode_relse(root);	return 0;bail:	hfs_bnode_relse(root);	return -EIO;}/* * delete_empty_bnode() * * Description: *   Removes an empty non-root bnode from between 'left' and 'right' * Input Variable(s): *   hfs_u32 left_node: node number of 'left' or zero if 'left' is invalid *   struct hfs_bnode_ref *left: reference to the left neighbor of the *    bnode to remove, or invalid if no such neighbor exists. *   struct hfs_bnode_ref *center: reference to the bnode to remove *   hfs_u32 right_node: node number of 'right' or zero if 'right' is invalid *   struct hfs_bnode_ref *right: reference to the right neighbor of the *    bnode to remove, or invalid if no such neighbor exists. * Output Variable(s): *   NONE * Returns: *   void * Preconditions: *   'left_node' is as described above. *   'left' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE *    access and referring to the left neighbor of 'center' if such a *    neighbor exists, or invalid if no such neighbor exists. *   'center' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE *    access and referring to the bnode to delete. *   'right_node' is as described above. *   'right' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE *    access and referring to the right neighbor of 'center' if such a *    neighbor exists, or invalid if no such neighbor exists. * Postconditions: *   If 'left' is valid its 'ndFLink' field becomes 'right_node'. *   If 'right' is valid its 'ndBLink' field becomes 'left_node'. *   If 'center' was the first leaf node then the tree's 'bthFNode' *    field becomes 'right_node'  *   If 'center' was the last leaf node then the tree's 'bthLNode' *    field becomes 'left_node'  *   'center' is NOT freed and access to the nodes is NOT relinquished. */static void delete_empty_bnode(hfs_u32 left_node, struct hfs_bnode_ref *left,			       struct hfs_bnode_ref *center,			       hfs_u32 right_node, struct hfs_bnode_ref *right){	struct hfs_bnode *bnode = center->bn;	if (left_node) {		left->bn->ndFLink = right_node;	} else if (bnode->ndType == ndLeafNode) {		bnode->tree->bthFNode = right_node;		bnode->tree->dirt = 1;	}	if (right_node) {		right->bn->ndBLink = left_node;	} else if (bnode->ndType == ndLeafNode) {		bnode->tree->bthLNode = left_node;		bnode->tree->dirt = 1;	}}/* * balance() * * Description: *   Attempt to equalize space usage in neighboring bnodes. * Input Variable(s): *   struct hfs_bnode *left: the left bnode. *   struct hfs_bnode *right: the right bnode. * Output Variable(s): *   NONE * Returns: *   void * Preconditions: *   'left' and 'right' point to valid (struct hfs_bnode)s obtained *    with HFS_LOCK_WRITE access, and are neighbors. * Postconditions: *   Records are shifted either left or right to make the space usage *   nearly equal.  When exact equality is not possible the break *   point is chosen to reduce data movement. *   The key corresponding to 'right' in its parent is NOT updated. */static void balance(struct hfs_bnode *left, struct hfs_bnode *right){	int index, left_free, right_free, half;	left_free = bnode_freespace(left);	right_free = bnode_freespace(right);	half = (left_free + right_free)/2;	if (left_free < right_free) {		/* shift right to balance */		index = left->ndNRecs + 1;		while (right_free >= half) {			--index;			right_free -= bnode_rsize(left,index)+sizeof(hfs_u16);		}		if (index < left->ndNRecs) {#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)			hfs_warn("shifting %d of %d recs right to balance: ",			       left->ndNRecs - index, left->ndNRecs);#endif			hfs_bnode_shift_right(left, right, index+1);#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)			hfs_warn("%d,%d\n", left->ndNRecs, right->ndNRecs);#endif		}	} else {		/* shift left to balance */		index = 0;		while (left_free >= half) {			++index;			left_free -= bnode_rsize(right,index)+sizeof(hfs_u16);		}		if (index > 1) {#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)			hfs_warn("shifting %d of %d recs left to balance: ",			       index-1, right->ndNRecs);#endif			hfs_bnode_shift_left(left, right, index-1);#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)			hfs_warn("%d,%d\n", left->ndNRecs, right->ndNRecs);#endif		}	}}/* * bdelete() * * Delete the given record from a B-tree. */static int bdelete(struct hfs_brec *brec){	struct hfs_btree *tree = brec->tree;	struct hfs_belem *belem = brec->bottom;	struct hfs_belem *parent = (belem-1);	struct hfs_bnode *bnode;	hfs_u32 left_node, right_node;	struct hfs_bnode_ref left, right;	int left_space, right_space, min_space;	int fix_right_key;	int fix_key;		while ((belem > brec->top) &&	       (belem->flags & (HFS_BPATH_UNDERFLOW | HFS_BPATH_FIRST))) {		bnode = belem->bnr.bn;		fix_key = belem->flags & HFS_BPATH_FIRST;		fix_right_key = 0;		bdelete_nonempty(brec, belem);		if (bnode->node == tree->root->node) {			del_root(&belem->bnr);			--brec->bottom;			goto done;		}		/* check for btree corruption which could lead to deadlock */		left_node = bnode->ndBLink;		right_node = bnode->ndFLink;		if ((left_node && hfs_bnode_in_brec(left_node, brec)) ||		    (right_node && hfs_bnode_in_brec(right_node, brec)) ||		    (left_node == right_node)) {			hfs_warn("hfs_bdelete: corrupt btree\n");			hfs_brec_relse(brec, NULL);			return -EIO;		}		/* grab the left neighbor if it exists */		if (left_node) {			hfs_bnode_lock(&belem->bnr, HFS_LOCK_RESRV);			left = hfs_bnode_find(tree,left_node,HFS_LOCK_WRITE);			if (!left.bn) {				hfs_warn("hfs_bdelete: unable to read left "					 "neighbor.\n");				hfs_brec_relse(brec, NULL);				return -EIO;			}			hfs_bnode_lock(&belem->bnr, HFS_LOCK_WRITE);			if (parent->record != 1) {				left_space = bnode_freespace(left.bn);			} else {				left_space = NO_SPACE;			}		} else {			left.bn = NULL;			left_space = NO_SPACE;		}		/* grab the right neighbor if it exists */		if (right_node) {			right = hfs_bnode_find(tree,right_node,HFS_LOCK_WRITE);			if (!right.bn) {				hfs_warn("hfs_bdelete: unable to read right "					 "neighbor.\n");				hfs_bnode_relse(&left);				hfs_brec_relse(brec, NULL);				return -EIO;			}			if (parent->record < parent->bnr.bn->ndNRecs) {				right_space = bnode_freespace(right.bn);			} else {				right_space = NO_SPACE;			}		} else {			right.bn = NULL;			right_space = NO_SPACE;		}		if (left_space < right_space) {			min_space = left_space;		} else {			min_space = right_space;		}		if (min_space == NO_SPACE) {			hfs_warn("hfs_bdelete: no siblings?\n");			hfs_brec_relse(brec, NULL);			return -EIO;		}		if (bnode->ndNRecs == 0) {			delete_empty_bnode(left_node, &left, &belem->bnr,					   right_node, &right);		} else if (min_space + bnode_freespace(bnode) >= FULL) {			if ((right_space == NO_SPACE) ||			    ((right_space == min_space) &&			     (left_space != NO_SPACE))) {				hfs_bnode_shift_left(left.bn, bnode,						     bnode->ndNRecs);			} else {				hfs_bnode_shift_right(bnode, right.bn, 1);				fix_right_key = 1;			}			delete_empty_bnode(left_node, &left, &belem->bnr,					   right_node, &right);		} else if (min_space == right_space) {			balance(bnode, right.bn);			fix_right_key = 1;		} else {			balance(left.bn, bnode);			fix_key = 1;		}		if (fix_right_key) {			hfs_bnode_update_key(brec, belem, right.bn, 1);		}		hfs_bnode_relse(&left);		hfs_bnode_relse(&right);		if (bnode->ndNRecs) {			if (fix_key) {				hfs_bnode_update_key(brec, belem, bnode, 0);			}			goto done;		}		hfs_bnode_free(&belem->bnr);		--brec->bottom;		belem = parent;		--parent;	}	if (belem < brec->top) {		hfs_warn("hfs_bdelete: Missing parent.\n");		hfs_brec_relse(brec, NULL);		return -EIO;	}	bdelete_nonempty(brec, belem);done:	hfs_brec_relse(brec, NULL);	return 0;}/*================ Global functions ================*//* * hfs_bdelete() * * Delete the requested record from a B-tree. */int hfs_bdelete(struct hfs_btree *tree, const struct hfs_bkey *key){ 	struct hfs_belem *belem;	struct hfs_bnode *bnode;	struct hfs_brec brec;	int retval;	if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key) {		hfs_warn("hfs_bdelete: invalid arguments.\n");		return -EINVAL;	}	retval = hfs_bfind(&brec, tree, key, HFS_BFIND_DELETE);	if (!retval) {		belem = brec.bottom;		bnode = belem->bnr.bn;		belem->flags = 0;        	if ((bnode->ndNRecs * sizeof(hfs_u16) + bnode_end(bnode) -		     bnode_rsize(bnode, belem->record)) < FULL/2) {			belem->flags |= HFS_BPATH_UNDERFLOW;		}		if (belem->record == 1) {			belem->flags |= HFS_BPATH_FIRST;		}		if (!belem->flags) {			hfs_brec_lock(&brec, brec.bottom);		} else {			hfs_brec_lock(&brec, NULL);		}		retval = bdelete(&brec);		if (!retval) {			--brec.tree->bthNRecs;			brec.tree->dirt = 1;		}		hfs_brec_relse(&brec, NULL);	}	return retval;}

⌨️ 快捷键说明

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