bdelete.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/bdelete.c
  3.  *
  4.  * Copyright (C) 1995-1997  Paul H. Hargrove
  5.  * This file may be distributed under the terms of the GNU General Public License.
  6.  *
  7.  * This file contains the code to delete records in a B-tree.
  8.  *
  9.  * "XXX" in a comment is a note to myself to consider changing something.
  10.  *
  11.  * In function preconditions the term "valid" applied to a pointer to
  12.  * a structure means that the pointer is non-NULL and the structure it
  13.  * points to has all fields initialized to consistent values.
  14.  */
  15. #include "hfs_btree.h"
  16. /*================ Variable-like macros ================*/
  17. #define FULL (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor))
  18. #define NO_SPACE (HFS_SECTOR_SIZE+1)
  19. /*================ File-local functions ================*/
  20. /*
  21.  * bdelete_nonempty()
  22.  *
  23.  * Description:
  24.  *   Deletes a record from a given bnode without regard to it becoming empty.
  25.  * Input Variable(s):
  26.  *   struct hfs_brec* brec: pointer to the brec for the deletion
  27.  *   struct hfs_belem* belem: which node in 'brec' to delete from
  28.  * Output Variable(s):
  29.  *   NONE
  30.  * Returns:
  31.  *   void
  32.  * Preconditions:
  33.  *   'brec' points to a valid (struct hfs_brec).
  34.  *   'belem' points to a valid (struct hfs_belem) in 'brec'.
  35.  * Postconditions:
  36.  *   The record has been inserted in the position indicated by 'brec'.
  37.  */
  38. static void bdelete_nonempty(struct hfs_brec *brec, struct hfs_belem *belem)
  39. {
  40. int i, rec, nrecs, tomove;
  41. hfs_u16 size;
  42. hfs_u8 *start;
  43. struct hfs_bnode *bnode = belem->bnr.bn;
  44. rec = belem->record;
  45. nrecs = bnode->ndNRecs;
  46. size = bnode_rsize(bnode, rec);
  47. tomove = bnode_offset(bnode, nrecs+1) - bnode_offset(bnode, rec+1);
  48. /* adjust the record table */
  49. for (i = rec+1; i <= nrecs; ++i) {
  50. hfs_put_hs(bnode_offset(bnode,i+1) - size, RECTBL(bnode,i));
  51. }
  52. /* move it down */
  53. start = bnode_key(bnode, rec);
  54. memmove(start, start + size, tomove);
  55. /* update record count */
  56. --bnode->ndNRecs;
  57. }
  58. /*
  59.  * del_root()
  60.  *
  61.  * Description:
  62.  *   Delete the current root bnode.
  63.  * Input Variable(s):
  64.  *   struct hfs_bnode_ref *root: reference to the root bnode
  65.  * Output Variable(s):
  66.  *   NONE
  67.  * Returns:
  68.  *   int: 0 on success, error code on failure
  69.  * Preconditions:
  70.  *   'root' refers to the root bnode with HFS_LOCK_WRITE access.
  71.  *   None of 'root's children are held with HFS_LOCK_WRITE access.
  72.  * Postconditions:
  73.  *   The current 'root' node is removed from the tree and the depth
  74.  *    of the tree is reduced by one.
  75.  *   If 'root' is an index node with exactly one child, then that
  76.  *    child becomes the new root of the tree.
  77.  *   If 'root' is an empty leaf node the tree becomes empty.
  78.  *   Upon return access to 'root' is relinquished.
  79.  */
  80. static int del_root(struct hfs_bnode_ref *root)
  81. {
  82. struct hfs_btree *tree = root->bn->tree;
  83. struct hfs_bnode_ref child;
  84. hfs_u32 node;
  85. if (root->bn->ndNRecs > 1) {
  86. return 0;
  87. } else if (root->bn->ndNRecs == 0) {
  88. /* tree is empty */
  89. tree->bthRoot = 0;
  90. tree->root = NULL;
  91. tree->bthRoot = 0;
  92. tree->bthFNode = 0;
  93. tree->bthLNode = 0;
  94. --tree->bthDepth;
  95. tree->dirt = 1;
  96. if (tree->bthDepth) {
  97. hfs_warn("hfs_bdelete: empty tree with bthDepth=%dn",
  98.  tree->bthDepth);
  99. goto bail;
  100. }
  101. return hfs_bnode_free(root);
  102. } else if (root->bn->ndType == ndIndxNode) {
  103. /* tree is non-empty */
  104. node = hfs_get_hl(bkey_record(bnode_datastart(root->bn)));
  105. child = hfs_bnode_find(tree, node, HFS_LOCK_READ);
  106. if (!child.bn) {
  107. hfs_warn("hfs_bdelete: can't read child node.n");
  108. goto bail;
  109. }
  110. child.bn->sticky = HFS_STICKY;
  111.          if (child.bn->next) {
  112.                  child.bn->next->prev = child.bn->prev;
  113.          }
  114.          if (child.bn->prev) {
  115.                  child.bn->prev->next = child.bn->next;
  116.          }
  117.          if (bhash(tree, child.bn->node) == child.bn) {
  118.                  bhash(tree, child.bn->node) = child.bn->next;
  119.          }
  120. child.bn->next = NULL;
  121. child.bn->prev = NULL;
  122. tree->bthRoot = child.bn->node;
  123. tree->root = child.bn;
  124. /* re-assign bthFNode and bthLNode if the new root is
  125.                    a leaf node. */
  126. if (child.bn->ndType == ndLeafNode) {
  127. tree->bthFNode = node;
  128. tree->bthLNode = node;
  129. }
  130. hfs_bnode_relse(&child);
  131. tree->bthRoot = node;
  132. --tree->bthDepth;
  133. tree->dirt = 1;
  134. if (!tree->bthDepth) {
  135. hfs_warn("hfs_bdelete: non-empty tree with "
  136.  "bthDepth == 0n");
  137. goto bail;
  138. }
  139. return hfs_bnode_free(root); /* marks tree dirty */
  140. }
  141. hfs_bnode_relse(root);
  142. return 0;
  143. bail:
  144. hfs_bnode_relse(root);
  145. return -EIO;
  146. }
  147. /*
  148.  * delete_empty_bnode()
  149.  *
  150.  * Description:
  151.  *   Removes an empty non-root bnode from between 'left' and 'right'
  152.  * Input Variable(s):
  153.  *   hfs_u32 left_node: node number of 'left' or zero if 'left' is invalid
  154.  *   struct hfs_bnode_ref *left: reference to the left neighbor of the
  155.  *    bnode to remove, or invalid if no such neighbor exists.
  156.  *   struct hfs_bnode_ref *center: reference to the bnode to remove
  157.  *   hfs_u32 right_node: node number of 'right' or zero if 'right' is invalid
  158.  *   struct hfs_bnode_ref *right: reference to the right neighbor of the
  159.  *    bnode to remove, or invalid if no such neighbor exists.
  160.  * Output Variable(s):
  161.  *   NONE
  162.  * Returns:
  163.  *   void
  164.  * Preconditions:
  165.  *   'left_node' is as described above.
  166.  *   'left' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE
  167.  *    access and referring to the left neighbor of 'center' if such a
  168.  *    neighbor exists, or invalid if no such neighbor exists.
  169.  *   'center' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE
  170.  *    access and referring to the bnode to delete.
  171.  *   'right_node' is as described above.
  172.  *   'right' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE
  173.  *    access and referring to the right neighbor of 'center' if such a
  174.  *    neighbor exists, or invalid if no such neighbor exists.
  175.  * Postconditions:
  176.  *   If 'left' is valid its 'ndFLink' field becomes 'right_node'.
  177.  *   If 'right' is valid its 'ndBLink' field becomes 'left_node'.
  178.  *   If 'center' was the first leaf node then the tree's 'bthFNode'
  179.  *    field becomes 'right_node' 
  180.  *   If 'center' was the last leaf node then the tree's 'bthLNode'
  181.  *    field becomes 'left_node' 
  182.  *   'center' is NOT freed and access to the nodes is NOT relinquished.
  183.  */
  184. static void delete_empty_bnode(hfs_u32 left_node, struct hfs_bnode_ref *left,
  185.        struct hfs_bnode_ref *center,
  186.        hfs_u32 right_node, struct hfs_bnode_ref *right)
  187. {
  188. struct hfs_bnode *bnode = center->bn;
  189. if (left_node) {
  190. left->bn->ndFLink = right_node;
  191. } else if (bnode->ndType == ndLeafNode) {
  192. bnode->tree->bthFNode = right_node;
  193. bnode->tree->dirt = 1;
  194. }
  195. if (right_node) {
  196. right->bn->ndBLink = left_node;
  197. } else if (bnode->ndType == ndLeafNode) {
  198. bnode->tree->bthLNode = left_node;
  199. bnode->tree->dirt = 1;
  200. }
  201. }
  202. /*
  203.  * balance()
  204.  *
  205.  * Description:
  206.  *   Attempt to equalize space usage in neighboring bnodes.
  207.  * Input Variable(s):
  208.  *   struct hfs_bnode *left: the left bnode.
  209.  *   struct hfs_bnode *right: the right bnode.
  210.  * Output Variable(s):
  211.  *   NONE
  212.  * Returns:
  213.  *   void
  214.  * Preconditions:
  215.  *   'left' and 'right' point to valid (struct hfs_bnode)s obtained
  216.  *    with HFS_LOCK_WRITE access, and are neighbors.
  217.  * Postconditions:
  218.  *   Records are shifted either left or right to make the space usage
  219.  *   nearly equal.  When exact equality is not possible the break
  220.  *   point is chosen to reduce data movement.
  221.  *   The key corresponding to 'right' in its parent is NOT updated.
  222.  */
  223. static void balance(struct hfs_bnode *left, struct hfs_bnode *right)
  224. {
  225. int index, left_free, right_free, half;
  226. left_free = bnode_freespace(left);
  227. right_free = bnode_freespace(right);
  228. half = (left_free + right_free)/2;
  229. if (left_free < right_free) {
  230. /* shift right to balance */
  231. index = left->ndNRecs + 1;
  232. while (right_free >= half) {
  233. --index;
  234. right_free -= bnode_rsize(left,index)+sizeof(hfs_u16);
  235. }
  236. if (index < left->ndNRecs) {
  237. #if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
  238. hfs_warn("shifting %d of %d recs right to balance: ",
  239.        left->ndNRecs - index, left->ndNRecs);
  240. #endif
  241. hfs_bnode_shift_right(left, right, index+1);
  242. #if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
  243. hfs_warn("%d,%dn", left->ndNRecs, right->ndNRecs);
  244. #endif
  245. }
  246. } else {
  247. /* shift left to balance */
  248. index = 0;
  249. while (left_free >= half) {
  250. ++index;
  251. left_free -= bnode_rsize(right,index)+sizeof(hfs_u16);
  252. }
  253. if (index > 1) {
  254. #if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
  255. hfs_warn("shifting %d of %d recs left to balance: ",
  256.        index-1, right->ndNRecs);
  257. #endif
  258. hfs_bnode_shift_left(left, right, index-1);
  259. #if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
  260. hfs_warn("%d,%dn", left->ndNRecs, right->ndNRecs);
  261. #endif
  262. }
  263. }
  264. }
  265. /*
  266.  * bdelete()
  267.  *
  268.  * Delete the given record from a B-tree.
  269.  */
  270. static int bdelete(struct hfs_brec *brec)
  271. {
  272. struct hfs_btree *tree = brec->tree;
  273. struct hfs_belem *belem = brec->bottom;
  274. struct hfs_belem *parent = (belem-1);
  275. struct hfs_bnode *bnode;
  276. hfs_u32 left_node, right_node;
  277. struct hfs_bnode_ref left, right;
  278. int left_space, right_space, min_space;
  279. int fix_right_key;
  280. int fix_key;
  281. while ((belem > brec->top) &&
  282.        (belem->flags & (HFS_BPATH_UNDERFLOW | HFS_BPATH_FIRST))) {
  283. bnode = belem->bnr.bn;
  284. fix_key = belem->flags & HFS_BPATH_FIRST;
  285. fix_right_key = 0;
  286. bdelete_nonempty(brec, belem);
  287. if (bnode->node == tree->root->node) {
  288. del_root(&belem->bnr);
  289. --brec->bottom;
  290. goto done;
  291. }
  292. /* check for btree corruption which could lead to deadlock */
  293. left_node = bnode->ndBLink;
  294. right_node = bnode->ndFLink;
  295. if ((left_node && hfs_bnode_in_brec(left_node, brec)) ||
  296.     (right_node && hfs_bnode_in_brec(right_node, brec)) ||
  297.     (left_node == right_node)) {
  298. hfs_warn("hfs_bdelete: corrupt btreen");
  299. hfs_brec_relse(brec, NULL);
  300. return -EIO;
  301. }
  302. /* grab the left neighbor if it exists */
  303. if (left_node) {
  304. hfs_bnode_lock(&belem->bnr, HFS_LOCK_RESRV);
  305. left = hfs_bnode_find(tree,left_node,HFS_LOCK_WRITE);
  306. if (!left.bn) {
  307. hfs_warn("hfs_bdelete: unable to read left "
  308.  "neighbor.n");
  309. hfs_brec_relse(brec, NULL);
  310. return -EIO;
  311. }
  312. hfs_bnode_lock(&belem->bnr, HFS_LOCK_WRITE);
  313. if (parent->record != 1) {
  314. left_space = bnode_freespace(left.bn);
  315. } else {
  316. left_space = NO_SPACE;
  317. }
  318. } else {
  319. left.bn = NULL;
  320. left_space = NO_SPACE;
  321. }
  322. /* grab the right neighbor if it exists */
  323. if (right_node) {
  324. right = hfs_bnode_find(tree,right_node,HFS_LOCK_WRITE);
  325. if (!right.bn) {
  326. hfs_warn("hfs_bdelete: unable to read right "
  327.  "neighbor.n");
  328. hfs_bnode_relse(&left);
  329. hfs_brec_relse(brec, NULL);
  330. return -EIO;
  331. }
  332. if (parent->record < parent->bnr.bn->ndNRecs) {
  333. right_space = bnode_freespace(right.bn);
  334. } else {
  335. right_space = NO_SPACE;
  336. }
  337. } else {
  338. right.bn = NULL;
  339. right_space = NO_SPACE;
  340. }
  341. if (left_space < right_space) {
  342. min_space = left_space;
  343. } else {
  344. min_space = right_space;
  345. }
  346. if (min_space == NO_SPACE) {
  347. hfs_warn("hfs_bdelete: no siblings?n");
  348. hfs_brec_relse(brec, NULL);
  349. return -EIO;
  350. }
  351. if (bnode->ndNRecs == 0) {
  352. delete_empty_bnode(left_node, &left, &belem->bnr,
  353.    right_node, &right);
  354. } else if (min_space + bnode_freespace(bnode) >= FULL) {
  355. if ((right_space == NO_SPACE) ||
  356.     ((right_space == min_space) &&
  357.      (left_space != NO_SPACE))) {
  358. hfs_bnode_shift_left(left.bn, bnode,
  359.      bnode->ndNRecs);
  360. } else {
  361. hfs_bnode_shift_right(bnode, right.bn, 1);
  362. fix_right_key = 1;
  363. }
  364. delete_empty_bnode(left_node, &left, &belem->bnr,
  365.    right_node, &right);
  366. } else if (min_space == right_space) {
  367. balance(bnode, right.bn);
  368. fix_right_key = 1;
  369. } else {
  370. balance(left.bn, bnode);
  371. fix_key = 1;
  372. }
  373. if (fix_right_key) {
  374. hfs_bnode_update_key(brec, belem, right.bn, 1);
  375. }
  376. hfs_bnode_relse(&left);
  377. hfs_bnode_relse(&right);
  378. if (bnode->ndNRecs) {
  379. if (fix_key) {
  380. hfs_bnode_update_key(brec, belem, bnode, 0);
  381. }
  382. goto done;
  383. }
  384. hfs_bnode_free(&belem->bnr);
  385. --brec->bottom;
  386. belem = parent;
  387. --parent;
  388. }
  389. if (belem < brec->top) {
  390. hfs_warn("hfs_bdelete: Missing parent.n");
  391. hfs_brec_relse(brec, NULL);
  392. return -EIO;
  393. }
  394. bdelete_nonempty(brec, belem);
  395. done:
  396. hfs_brec_relse(brec, NULL);
  397. return 0;
  398. }
  399. /*================ Global functions ================*/
  400. /*
  401.  * hfs_bdelete()
  402.  *
  403.  * Delete the requested record from a B-tree.
  404.  */
  405. int hfs_bdelete(struct hfs_btree *tree, const struct hfs_bkey *key)
  406. struct hfs_belem *belem;
  407. struct hfs_bnode *bnode;
  408. struct hfs_brec brec;
  409. int retval;
  410. if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key) {
  411. hfs_warn("hfs_bdelete: invalid arguments.n");
  412. return -EINVAL;
  413. }
  414. retval = hfs_bfind(&brec, tree, key, HFS_BFIND_DELETE);
  415. if (!retval) {
  416. belem = brec.bottom;
  417. bnode = belem->bnr.bn;
  418. belem->flags = 0;
  419.          if ((bnode->ndNRecs * sizeof(hfs_u16) + bnode_end(bnode) -
  420.      bnode_rsize(bnode, belem->record)) < FULL/2) {
  421. belem->flags |= HFS_BPATH_UNDERFLOW;
  422. }
  423. if (belem->record == 1) {
  424. belem->flags |= HFS_BPATH_FIRST;
  425. }
  426. if (!belem->flags) {
  427. hfs_brec_lock(&brec, brec.bottom);
  428. } else {
  429. hfs_brec_lock(&brec, NULL);
  430. }
  431. retval = bdelete(&brec);
  432. if (!retval) {
  433. --brec.tree->bthNRecs;
  434. brec.tree->dirt = 1;
  435. }
  436. hfs_brec_relse(&brec, NULL);
  437. }
  438. return retval;
  439. }