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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/brec.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 access records in a btree.
  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. /*
  18.  * first()
  19.  *
  20.  * returns HFS_BPATH_FIRST if elem->record == 1, 0 otherwise
  21.  */
  22. static inline int first(const struct hfs_belem *elem)
  23. {
  24. return (elem->record == 1) ? HFS_BPATH_FIRST : 0;
  25. }
  26. /*
  27.  * overflow()
  28.  *
  29.  * return HFS_BPATH_OVERFLOW if the node has no room for an 
  30.  * additional pointer record, 0 otherwise.
  31.  */
  32. static inline int overflow(const struct hfs_btree *tree,
  33.    const struct hfs_bnode *bnode)
  34. {
  35. /* there is some algebra involved in getting this form */
  36. return ((HFS_SECTOR_SIZE - sizeof(hfs_u32)) <
  37.  (bnode_end(bnode) + (2+bnode->ndNRecs)*sizeof(hfs_u16) +
  38.   ROUND(tree->bthKeyLen+1))) ?  HFS_BPATH_OVERFLOW : 0;
  39. }
  40. /*
  41.  * underflow()
  42.  *
  43.  * return HFS_BPATH_UNDERFLOW if the node will be less that 1/2 full
  44.  * upon removal of a pointer record, 0 otherwise.
  45.  */
  46. static inline int underflow(const struct hfs_btree *tree,
  47.     const struct hfs_bnode *bnode)
  48. {
  49. return ((bnode->ndNRecs * sizeof(hfs_u16) +
  50.  bnode_offset(bnode, bnode->ndNRecs)) <
  51. (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor))/2) ?
  52. HFS_BPATH_UNDERFLOW : 0;
  53. }
  54. /*================ Global functions ================*/
  55. /*
  56.  * hfs_brec_next()
  57.  *
  58.  * Description:
  59.  *   Obtain access to a child of an internal node in a B-tree.
  60.  * Input Variable(s):
  61.  *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to
  62.  *    add an element to.
  63.  * Output Variable(s):
  64.  *   NONE
  65.  * Returns:
  66.  *   struct hfs_belem *: pointer to the new path element or NULL
  67.  * Preconditions:
  68.  *   'brec' points to a "valid" (struct hfs_brec), the last element of
  69.  *   which corresponds to a record in a bnode of type ndIndxNode and the
  70.  *   'record' field indicates the index record for the desired child.
  71.  * Postconditions:
  72.  *   If the call to hfs_bnode_find() fails then 'brec' is released
  73.  *   and a NULL is returned.
  74.  *   Otherwise:
  75.  *    Any ancestors in 'brec' that are not needed (as determined by the
  76.  *     'keep_flags' field of 'brec) are released from 'brec'.
  77.  *    A new element is added to 'brec' corresponding to the desired
  78.  *     child.
  79.  *    The child is obtained with the same 'lock_type' field as its
  80.  *     parent.
  81.  *    The 'record' field is initialized to the last record.
  82.  *    A pointer to the new path element is returned.
  83.  */
  84. struct hfs_belem *hfs_brec_next(struct hfs_brec *brec)
  85. {
  86. struct hfs_belem *elem = brec->bottom;
  87. hfs_u32 node;
  88. int lock_type;
  89. /* release unneeded ancestors */
  90. elem->flags = first(elem) |
  91.       overflow(brec->tree, elem->bnr.bn) |
  92.       underflow(brec->tree, elem->bnr.bn);
  93. if (!(brec->keep_flags & elem->flags)) {
  94. hfs_brec_relse(brec, brec->bottom-1);
  95. } else if ((brec->bottom-2 >= brec->top) &&
  96.    !(elem->flags & (elem-1)->flags)) {
  97. hfs_brec_relse(brec, brec->bottom-2);
  98. }
  99. node = hfs_get_hl(belem_record(elem));
  100. lock_type = elem->bnr.lock_type;
  101. if (!node || hfs_bnode_in_brec(node, brec)) {
  102. hfs_warn("hfs_bfind: corrupt btreen");
  103. hfs_brec_relse(brec, NULL);
  104. return NULL;
  105. }
  106. ++elem;
  107. ++brec->bottom;
  108. elem->bnr = hfs_bnode_find(brec->tree, node, lock_type);
  109. if (!elem->bnr.bn) {
  110. hfs_brec_relse(brec, NULL);
  111. return NULL;
  112. }
  113. elem->record = elem->bnr.bn->ndNRecs;
  114. return elem;
  115. }
  116. /*
  117.  * hfs_brec_lock()
  118.  *
  119.  * Description:
  120.  *   This function obtains HFS_LOCK_WRITE access to the bnode
  121.  *   containing this hfs_brec. All descendents in the path from this
  122.  *   record to the leaf are given HFS_LOCK_WRITE access and all
  123.  *   ancestors in the path from the root to here are released.
  124.  * Input Variable(s):
  125.  *   struct hfs_brec *brec: pointer to the brec to obtain
  126.  *    HFS_LOCK_WRITE access to some of the nodes of.
  127.  *   struct hfs_belem *elem: the first node to lock or NULL for all
  128.  * Output Variable(s):
  129.  *   NONE
  130.  * Returns:
  131.  *   void
  132.  * Preconditions:
  133.  *   'brec' points to a "valid" (struct hfs_brec)
  134.  * Postconditions: 
  135.  *   All nodes between the indicated node and the beginning of the path
  136.  *    are released.  hfs_bnode_lock() is called in turn on each node
  137.  *    from the indicated node to the leaf node of the path, with a
  138.  *    lock_type argument of HFS_LOCK_WRITE.  If one of those calls
  139.  *    results in deadlock, then this function will never return.
  140.  */
  141. void hfs_brec_lock(struct hfs_brec *brec, struct hfs_belem *elem) 
  142. {
  143. if (!elem) {
  144. elem = brec->top;
  145. } else if (elem > brec->top) {
  146. hfs_brec_relse(brec, elem-1);
  147. }
  148. while (elem <= brec->bottom) {
  149. hfs_bnode_lock(&elem->bnr, HFS_LOCK_WRITE);
  150. ++elem;
  151. }
  152. }
  153. /*
  154.  * hfs_brec_init()
  155.  *
  156.  * Description:
  157.  *   Obtain access to the root node of a B-tree.
  158.  *   Note that this first must obtain access to the header node.
  159.  * Input Variable(s):
  160.  *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to
  161.  *    initialize
  162.  *   struct hfs_btree *btree: pointer to the (struct hfs_btree)
  163.  *   int lock_type: the type of access to get to the nodes.
  164.  * Output Variable(s):
  165.  *   NONE
  166.  * Returns:
  167.  *   struct hfs_belem *: pointer to the root path element or NULL
  168.  * Preconditions:
  169.  *   'brec' points to a (struct hfs_brec).
  170.  *   'tree' points to a valid (struct hfs_btree).
  171.  * Postconditions:
  172.  *   If the two calls to brec_bnode_find() succeed then the return value
  173.  *   points to a (struct hfs_belem) which corresponds to the root node
  174.  *   of 'brec->tree'.
  175.  *   Both the root and header nodes are obtained with the type of lock
  176.  *   given by (flags & HFS_LOCK_MASK).
  177.  *   The fields 'record' field of the root is set to its last record.
  178.  *   If the header node is not needed to complete the appropriate
  179.  *   operation (as determined by the 'keep_flags' field of 'brec') then
  180.  *   it is released before this function returns.
  181.  *   If either call to brec_bnode_find() fails, NULL is returned and the
  182.  *   (struct hfs_brec) pointed to by 'brec' is invalid.
  183.  */
  184. struct hfs_belem *hfs_brec_init(struct hfs_brec *brec, struct hfs_btree *tree,
  185. int flags)
  186. {
  187. struct hfs_belem *head = &brec->elem[0];
  188. struct hfs_belem *root = &brec->elem[1];
  189. int lock_type = flags & HFS_LOCK_MASK;
  190. brec->tree = tree;
  191. head->bnr = hfs_bnode_find(tree, 0, lock_type);
  192. if (!head->bnr.bn) {
  193. return NULL;
  194. }
  195. root->bnr = hfs_bnode_find(tree, tree->bthRoot, lock_type);
  196. if (!root->bnr.bn) {
  197. hfs_bnode_relse(&head->bnr);
  198. return NULL;
  199. }
  200. root->record = root->bnr.bn->ndNRecs;
  201. brec->top = head;
  202. brec->bottom = root;
  203. brec->keep_flags = flags & HFS_BPATH_MASK;
  204. /* HFS_BPATH_FIRST not applicable for root */
  205. /* and HFS_BPATH_UNDERFLOW is different */
  206. root->flags = overflow(tree, root->bnr.bn);
  207. if (root->record < 3) {
  208. root->flags |= HFS_BPATH_UNDERFLOW;
  209. }
  210. if (!(root->flags & brec->keep_flags)) {
  211. hfs_brec_relse(brec, head);
  212. }
  213. return root;
  214. }