binsert.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/binsert.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 insert 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. /*================ File-local functions ================*/
  17. /* btree locking functions */
  18. static inline void hfs_btree_lock(struct hfs_btree *tree)
  19. {
  20.   while (tree->lock) 
  21.     hfs_sleep_on(&tree->wait);
  22.   tree->lock = 1;
  23. }
  24. static inline void hfs_btree_unlock(struct hfs_btree *tree)
  25. {
  26.   tree->lock = 0;
  27.   hfs_wake_up(&tree->wait);
  28. }
  29. /*
  30.  * binsert_nonfull()
  31.  *
  32.  * Description:
  33.  *   Inserts a record in a given bnode known to have sufficient space.
  34.  * Input Variable(s):
  35.  *   struct hfs_brec* brec: pointer to the brec for the insertion
  36.  *   struct hfs_belem* belem: the element in the search path to insert in
  37.  *   struct hfs_bkey* key: pointer to the key for the record to insert
  38.  *   void* data: pointer to the record to insert
  39.  *   hfs_u16 keysize: size of the key to insert
  40.  *   hfs_u16 datasize: size of the record to insert
  41.  * Output Variable(s):
  42.  *   NONE
  43.  * Returns:
  44.  *   NONE
  45.  * Preconditions:
  46.  *   'brec' points to a valid (struct hfs_brec).
  47.  *   'belem' points to a valid (struct hfs_belem) in 'brec', the node
  48.  *    of which has enough free space to insert 'key' and 'data'.
  49.  *   'key' is a pointer to a valid (struct hfs_bkey) of length 'keysize'
  50.  *    which, in sorted order, belongs at the location indicated by 'brec'.
  51.  *   'data' is non-NULL an points to appropriate data of length 'datasize'
  52.  * Postconditions:
  53.  *   The record has been inserted in the position indicated by 'brec'.
  54.  */
  55. static void binsert_nonfull(struct hfs_brec *brec, struct hfs_belem *belem,
  56.     const struct hfs_bkey *key, const void *data,
  57.     hfs_u8 keysize, hfs_u16 datasize)
  58. {
  59. int i, rec, nrecs, size, tomove;
  60. hfs_u8 *start;
  61. struct hfs_bnode *bnode = belem->bnr.bn;
  62. rec = ++(belem->record);
  63. size = ROUND(keysize+1) + datasize;
  64. nrecs = bnode->ndNRecs + 1;
  65. tomove = bnode_offset(bnode, nrecs) - bnode_offset(bnode, rec);
  66. /* adjust the record table */
  67. for (i = nrecs; i >= rec; --i) {
  68. hfs_put_hs(bnode_offset(bnode,i) + size, RECTBL(bnode,i+1));
  69. }
  70. /* make room */
  71. start = bnode_key(bnode, rec);
  72. memmove(start + size, start, tomove);
  73. /* copy in the key and the data*/
  74. *start = keysize;
  75. keysize = ROUND(keysize+1);
  76. memcpy(start + 1, (hfs_u8 *)key + 1, keysize-1);
  77. memcpy(start + keysize, data, datasize);
  78. /* update record count */
  79. ++bnode->ndNRecs;
  80. }
  81. /*
  82.  * add_root()
  83.  *
  84.  * Description:
  85.  *   Adds a new root to a B*-tree, increasing its height.
  86.  * Input Variable(s):
  87.  *   struct hfs_btree *tree: the tree to add a new root to
  88.  *   struct hfs_bnode *left: the new root's first child or NULL
  89.  *   struct hfs_bnode *right: the new root's second child or NULL
  90.  * Output Variable(s):
  91.  *   NONE
  92.  * Returns:
  93.  *   void
  94.  * Preconditions:
  95.  *   'tree' points to a valid (struct hfs_btree).
  96.  *   'left' and 'right' point to valid (struct hfs_bnode)s, which
  97.  *    resulted from splitting the old root node, or are both NULL
  98.  *    if there was no root node before.
  99.  * Postconditions:
  100.  *   Upon success a new root node is added to 'tree' with either
  101.  *    two children ('left' and 'right') or none.
  102.  */
  103. static void add_root(struct hfs_btree *tree,
  104.      struct hfs_bnode *left,
  105.      struct hfs_bnode *right)
  106. {
  107. struct hfs_bnode_ref bnr;
  108. struct hfs_bnode *root;
  109. struct hfs_bkey *key;
  110. int keylen = tree->bthKeyLen;
  111. if (left && !right) {
  112. hfs_warn("add_root: LEFT but no RIGHTn");
  113. return;
  114. }
  115. bnr = hfs_bnode_alloc(tree);
  116. if (!(root = bnr.bn)) {
  117. return;
  118. }
  119. root->sticky = HFS_STICKY;
  120. tree->root = root;
  121. tree->bthRoot = root->node;
  122. ++tree->bthDepth;
  123. root->ndNHeight = tree->bthDepth;
  124. root->ndFLink = 0;
  125. root->ndBLink = 0;
  126. if (!left) {
  127. /* tree was empty */
  128. root->ndType  = ndLeafNode;
  129. root->ndNRecs = 0;
  130. tree->bthFNode = root->node;
  131. tree->bthLNode = root->node;
  132. } else {
  133. root->ndType  = ndIndxNode;
  134. root->ndNRecs = 2;
  135. hfs_put_hs(sizeof(struct NodeDescriptor) + ROUND(1+keylen) +
  136.    sizeof(hfs_u32), RECTBL(root, 2));
  137. key = bnode_key(root, 1);
  138. key->KeyLen = keylen;
  139. memcpy(key->value,
  140.        ((struct hfs_bkey *)bnode_key(left, 1))->value, keylen);
  141. hfs_put_hl(left->node, bkey_record(key));
  142. hfs_put_hs(sizeof(struct NodeDescriptor) + 2*ROUND(1+keylen) +
  143.    2*sizeof(hfs_u32), RECTBL(root, 3));
  144. key = bnode_key(root, 2);
  145. key->KeyLen = keylen;
  146. memcpy(key->value,
  147.        ((struct hfs_bkey *)bnode_key(right, 1))->value, keylen);
  148. hfs_put_hl(right->node, bkey_record(key));
  149. /* the former root (left) is now just a normal node */
  150. left->sticky = HFS_NOT_STICKY;
  151. if ((left->next = bhash(tree, left->node))) {
  152. left->next->prev = left;
  153. }
  154. bhash(tree, left->node) = left;
  155. }
  156. hfs_bnode_relse(&bnr);
  157. tree->dirt = 1;
  158. }
  159. /*
  160.  * insert_empty_bnode()
  161.  *
  162.  * Description:
  163.  *   Adds an empty node to the right of 'left'.
  164.  * Input Variable(s):
  165.  *   struct hfs_btree *tree: the tree to add a node to
  166.  *   struct hfs_bnode *left: the node to add a node after
  167.  * Output Variable(s):
  168.  *   NONE
  169.  * Returns:
  170.  *   struct hfs_bnode_ref *: reference to the new bnode.
  171.  * Preconditions:
  172.  *   'tree' points to a valid (struct hfs_btree) with at least 1 free node.
  173.  *   'left' points to a valid (struct hfs_bnode) belonging to 'tree'.
  174.  * Postconditions:
  175.  *   If NULL is returned then 'tree' and 'left' are unchanged.
  176.  *   Otherwise a node with 0 records is inserted in the tree to the right
  177.  *   of the node 'left'.  The 'ndFLink' of 'left' and the 'ndBLink' of
  178.  *   the former right-neighbor of 'left' (if one existed) point to the
  179.  *   new node. If 'left' had no right neighbor and is a leaf node the
  180.  *   the 'bthLNode' of 'tree' points to the new node.  The free-count and
  181.  *   bitmap for 'tree' are kept current by hfs_bnode_alloc() which supplies
  182.  *   the required node.
  183.  */
  184. static struct hfs_bnode_ref insert_empty_bnode(struct hfs_btree *tree,
  185.        struct hfs_bnode *left)
  186. {
  187. struct hfs_bnode_ref retval;
  188. struct hfs_bnode_ref right;
  189. retval = hfs_bnode_alloc(tree);
  190. if (!retval.bn) {
  191. hfs_warn("hfs_binsert: out of bnodes?.n");
  192. goto done;
  193. }
  194. retval.bn->sticky = HFS_NOT_STICKY;
  195. if ((retval.bn->next = bhash(tree, retval.bn->node))) {
  196. retval.bn->next->prev = retval.bn;
  197. }
  198. bhash(tree, retval.bn->node) = retval.bn;
  199. if (left->ndFLink) {
  200. right = hfs_bnode_find(tree, left->ndFLink, HFS_LOCK_WRITE);
  201. if (!right.bn) {
  202. hfs_warn("hfs_binsert: corrupt btree.n");
  203. hfs_bnode_bitop(tree, retval.bn->node, 0);
  204. hfs_bnode_relse(&retval);
  205. goto done;
  206. }
  207. right.bn->ndBLink = retval.bn->node;
  208. hfs_bnode_relse(&right);
  209. } else if (left->ndType == ndLeafNode) {
  210. tree->bthLNode = retval.bn->node;
  211. tree->dirt = 1;
  212. }
  213. retval.bn->ndFLink   = left->ndFLink;
  214. retval.bn->ndBLink   = left->node;
  215. retval.bn->ndType    = left->ndType;
  216. retval.bn->ndNHeight = left->ndNHeight;
  217. retval.bn->ndNRecs   = 0;
  218. left->ndFLink = retval.bn->node;
  219.  done:
  220. return retval;
  221. }
  222. /*
  223.  * split()
  224.  *
  225.  * Description:
  226.  *   Splits an over full node during insertion.
  227.  *   Picks the split point that results in the most-nearly equal
  228.  *   space usage in the new and old nodes.
  229.  * Input Variable(s):
  230.  *   struct hfs_belem *elem: the over full node.
  231.  *   int size: the number of bytes to be used by the new record and its key.
  232.  * Output Variable(s):
  233.  *   struct hfs_belem *elem: changed to indicate where the new record
  234.  *    should be inserted.
  235.  * Returns:
  236.  *   struct hfs_bnode_ref: reference to the new bnode.
  237.  * Preconditions:
  238.  *   'elem' points to a valid path element corresponding to the over full node.
  239.  *   'size' is positive.
  240.  * Postconditions:
  241.  *   The records in the node corresponding to 'elem' are redistributed across
  242.  *   the old and new nodes so that after inserting the new record, the space
  243.  *   usage in these two nodes is as equal as possible.
  244.  *   'elem' is updated so that a call to binsert_nonfull() will insert the
  245.  *   new record in the correct location.
  246.  */
  247. static inline struct hfs_bnode_ref split(struct hfs_belem *elem, int size)
  248. {
  249. struct hfs_bnode *bnode = elem->bnr.bn;
  250. int nrecs, cutoff, index, tmp, used, in_right;
  251. struct hfs_bnode_ref right;
  252. right = insert_empty_bnode(bnode->tree, bnode);
  253. if (right.bn) {
  254. nrecs = bnode->ndNRecs;
  255. cutoff = (size + bnode_end(bnode) -
  256.       sizeof(struct NodeDescriptor) +
  257.       (nrecs+1)*sizeof(hfs_u16))/2;
  258. used = 0;
  259. in_right = 1;
  260. /* note that this only works because records sizes are even */
  261. for (index=1; index <= elem->record; ++index) {
  262. tmp = (sizeof(hfs_u16) + bnode_rsize(bnode, index))/2;
  263. used += tmp;
  264. if (used > cutoff) {
  265. goto found;
  266. }
  267. used += tmp;
  268. }
  269. tmp = (size + sizeof(hfs_u16))/2;
  270. used += tmp;
  271. if (used > cutoff) {
  272. goto found;
  273. }
  274. in_right = 0;
  275. used += tmp;
  276. for (; index <= nrecs; ++index) {
  277. tmp = (sizeof(hfs_u16) + bnode_rsize(bnode, index))/2;
  278. used += tmp;
  279. if (used > cutoff) {
  280. goto found;
  281. }
  282. used += tmp;
  283. }
  284. /* couldn't find the split point! */
  285. hfs_bnode_relse(&right);
  286. }
  287. return right;
  288. found:
  289. if (in_right) {
  290. elem->bnr = right;
  291. elem->record -= index-1;
  292. }
  293. hfs_bnode_shift_right(bnode, right.bn, index);
  294. return right;
  295. }
  296. /*
  297.  * binsert()
  298.  *
  299.  * Description:
  300.  *   Inserts a record in a tree known to have enough room, even if the
  301.  *   insertion requires the splitting of nodes.
  302.  * Input Variable(s):
  303.  *    struct hfs_brec *brec: partial path to the node to insert in
  304.  *    const struct hfs_bkey *key: key for the new record
  305.  *    const void *data: data for the new record
  306.  *    hfs_u8 keysize: size of the key
  307.  *    hfs_u16 datasize: size of the data
  308.  *    int reserve: number of nodes reserved in case of splits
  309.  * Output Variable(s):
  310.  *    *brec = NULL
  311.  * Returns:
  312.  *    int: 0 on success, error code on failure
  313.  * Preconditions:
  314.  *    'brec' points to a valid (struct hfs_brec) corresponding to a
  315.  *     record in a leaf node, after which a record is to be inserted,
  316.  *     or to "record 0" of the leaf node if the record is to be inserted
  317.  *     before all existing records in the node.  The (struct hfs_brec)
  318.  *     includes all ancestors of the leaf node that are needed to
  319.  *     complete the insertion including the parents of any nodes that
  320.  *     will be split.
  321.  *    'key' points to a valid (struct hfs_bkey) which is appropriate
  322.  *     to this tree, and which belongs at the insertion point.
  323.  *    'data' points data appropriate for the indicated node.
  324.  *    'keysize' gives the size in bytes of the key.
  325.  *    'datasize' gives the size in bytes of the data.
  326.  *    'reserve' gives the number of nodes that have been reserved in the
  327.  *     tree to allow for splitting of nodes.
  328.  * Postconditions:
  329.  *    All 'reserve'd nodes have been either used or released.
  330.  *    *brec = NULL
  331.  *    On success the key and data have been inserted at the indicated
  332.  *    location in the tree, all appropriate fields of the in-core data
  333.  *    structures have been changed and updated versions of the on-disk
  334.  *    data structures have been scheduled for write-back to disk.
  335.  *    On failure the B*-tree is probably invalid both on disk and in-core.
  336.  *
  337.  *    XXX: Some attempt at repair might be made in the event of failure,
  338.  *    or the fs should be remounted read-only so things don't get worse.
  339.  */
  340. static int binsert(struct hfs_brec *brec, const struct hfs_bkey *key,
  341.    const void *data, hfs_u8 keysize, hfs_u16 datasize,
  342.    int reserve)
  343. {
  344. struct hfs_bnode_ref left, right, other;
  345. struct hfs_btree *tree = brec->tree;
  346. struct hfs_belem *belem = brec->bottom;
  347. int tmpsize = 1 + tree->bthKeyLen;
  348. struct hfs_bkey *tmpkey = hfs_malloc(tmpsize);
  349. hfs_u32 node;
  350. while ((belem >= brec->top) && (belem->flags & HFS_BPATH_OVERFLOW)) {
  351. left = belem->bnr;
  352. if (left.bn->ndFLink &&
  353.                     hfs_bnode_in_brec(left.bn->ndFLink, brec)) {
  354. hfs_warn("hfs_binsert: corrupt btreen");
  355. tree->reserved -= reserve;
  356. hfs_free(tmpkey, tmpsize);
  357. return -EIO;
  358. }
  359. right = split(belem, ROUND(keysize+1) + ROUND(datasize));
  360. --reserve;
  361. --tree->reserved;
  362. if (!right.bn) {
  363. hfs_warn("hfs_binsert: unable to split node!n");
  364. tree->reserved -= reserve;
  365. hfs_free(tmpkey, tmpsize);
  366. return -ENOSPC;
  367. }
  368. binsert_nonfull(brec, belem, key, data, keysize, datasize);
  369. if (belem->bnr.bn == left.bn) {
  370. other = right;
  371. if (belem->record == 1) {
  372. hfs_bnode_update_key(brec, belem, left.bn, 0);
  373. }
  374. } else {
  375. other = left;
  376. }
  377. if (left.bn->node == tree->root->node) {
  378. add_root(tree, left.bn, right.bn);
  379. hfs_bnode_relse(&other);
  380. goto done;
  381. }
  382. data = &node;
  383. datasize = sizeof(node);
  384. node = htonl(right.bn->node);
  385. key = tmpkey;
  386. keysize = tree->bthKeyLen;
  387. memcpy(tmpkey, bnode_key(right.bn, 1), keysize+1);
  388. hfs_bnode_relse(&other);
  389. --belem;
  390. }
  391. if (belem < brec->top) {
  392. hfs_warn("hfs_binsert: Missing parent.n");
  393. tree->reserved -= reserve;
  394. hfs_free(tmpkey, tmpsize);
  395. return -EIO;
  396. }
  397. binsert_nonfull(brec, belem, key, data, keysize, datasize);
  398. done:
  399. tree->reserved -= reserve;
  400. hfs_free(tmpkey, tmpsize);
  401. return 0;
  402. }
  403. /*================ Global functions ================*/
  404. /*
  405.  * hfs_binsert()
  406.  *
  407.  * Description:
  408.  *   This function inserts a new record into a b-tree.
  409.  * Input Variable(s):
  410.  *   struct hfs_btree *tree: pointer to the (struct hfs_btree) to insert in
  411.  *   struct hfs_bkey *key: pointer to the (struct hfs_bkey) to insert
  412.  *   void *data: pointer to the data to associate with 'key' in the b-tree
  413.  *   unsigned int datasize: the size of the data
  414.  * Output Variable(s):
  415.  *   NONE
  416.  * Returns:
  417.  *   int: 0 on success, error code on failure
  418.  * Preconditions:
  419.  *   'tree' points to a valid (struct hfs_btree)
  420.  *   'key' points to a valid (struct hfs_bkey)
  421.  *   'data' points to valid memory of length 'datasize'
  422.  * Postconditions:
  423.  *   If zero is returned then the record has been inserted in the
  424.  *    indicated location updating all in-core data structures and
  425.  *    scheduling all on-disk data structures for write-back.
  426.  */
  427. int hfs_binsert(struct hfs_btree *tree, const struct hfs_bkey *key,
  428. const void *data, hfs_u16 datasize)
  429. struct hfs_brec brec;
  430. struct hfs_belem *belem;
  431. int err, reserve, retval;
  432. hfs_u8 keysize;
  433. if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key || !data) {
  434. hfs_warn("hfs_binsert: invalid arguments.n");
  435. return -EINVAL;
  436. }
  437. if (key->KeyLen > tree->bthKeyLen) {
  438. hfs_warn("hfs_binsert: oversized keyn");
  439. return -EINVAL;
  440. }
  441. restart:
  442. if (!tree->bthNRecs) {
  443. /* create the root bnode */
  444. add_root(tree, NULL, NULL);
  445. if (!hfs_brec_init(&brec, tree, HFS_BFIND_INSERT)) {
  446. hfs_warn("hfs_binsert: failed to create root.n");
  447. return -ENOSPC;
  448. }
  449. } else {
  450. err = hfs_bfind(&brec, tree, key, HFS_BFIND_INSERT);
  451. if (err < 0) {
  452. hfs_warn("hfs_binsert: hfs_brec_find failed.n");
  453. return err;
  454. } else if (err == 0) {
  455. hfs_brec_relse(&brec, NULL);
  456. return -EEXIST;
  457. }
  458. }
  459. keysize = key->KeyLen;
  460. datasize = ROUND(datasize);
  461. belem = brec.bottom;
  462. belem->flags = 0;
  463. if (bnode_freespace(belem->bnr.bn) <
  464.     (sizeof(hfs_u16) + ROUND(keysize+1) + datasize)) {
  465. belem->flags |= HFS_BPATH_OVERFLOW;
  466. }
  467. if (belem->record == 0) {
  468. belem->flags |= HFS_BPATH_FIRST;
  469. }
  470. if (!belem->flags) {
  471. hfs_brec_lock(&brec, brec.bottom);
  472. reserve = 0;
  473. } else {
  474. reserve = brec.bottom - brec.top;
  475. if (brec.top == 0) {
  476. ++reserve;
  477. }
  478. /* make certain we have enough nodes to proceed */
  479. if ((tree->bthFree - tree->reserved) < reserve) {
  480. hfs_brec_relse(&brec, NULL);
  481. hfs_btree_lock(tree);
  482. if ((tree->bthFree - tree->reserved) < reserve) {
  483. hfs_btree_extend(tree);
  484. }
  485. hfs_btree_unlock(tree);
  486. if ((tree->bthFree - tree->reserved) < reserve) {
  487. return -ENOSPC;
  488. } else {
  489. goto restart;
  490. }
  491. }
  492. tree->reserved += reserve;
  493. hfs_brec_lock(&brec, NULL);
  494. }
  495. retval = binsert(&brec, key, data, keysize, datasize, reserve);
  496. hfs_brec_relse(&brec, NULL);
  497. if (!retval) {
  498. ++tree->bthNRecs;
  499. tree->dirt = 1;
  500. }
  501. return retval;
  502. }