bt_search.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:13k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. /*
  8.  * Copyright (c) 1990, 1993, 1994, 1995, 1996
  9.  * Keith Bostic.  All rights reserved.
  10.  */
  11. /*
  12.  * Copyright (c) 1990, 1993, 1994, 1995
  13.  * The Regents of the University of California.  All rights reserved.
  14.  *
  15.  * This code is derived from software contributed to Berkeley by
  16.  * Mike Olson.
  17.  *
  18.  * Redistribution and use in source and binary forms, with or without
  19.  * modification, are permitted provided that the following conditions
  20.  * are met:
  21.  * 1. Redistributions of source code must retain the above copyright
  22.  *    notice, this list of conditions and the following disclaimer.
  23.  * 2. Redistributions in binary form must reproduce the above copyright
  24.  *    notice, this list of conditions and the following disclaimer in the
  25.  *    documentation and/or other materials provided with the distribution.
  26.  * 3. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  31.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  34.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  35.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  36.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  39.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  40.  * SUCH DAMAGE.
  41.  */
  42. #include "db_config.h"
  43. #ifndef lint
  44. static const char revid[] = "$Id: bt_search.c,v 11.32 2001/01/17 20:19:46 bostic Exp $";
  45. #endif /* not lint */
  46. #ifndef NO_SYSTEM_INCLUDES
  47. #include <sys/types.h>
  48. #include <string.h>
  49. #endif
  50. #include "db_int.h"
  51. #include "db_page.h"
  52. #include "db_shash.h"
  53. #include "btree.h"
  54. #include "lock.h"
  55. /*
  56.  * __bam_search --
  57.  * Search a btree for a key.
  58.  *
  59.  * PUBLIC: int __bam_search __P((DBC *,
  60.  * PUBLIC:     const DBT *, u_int32_t, int, db_recno_t *, int *));
  61.  */
  62. int
  63. __bam_search(dbc, key, flags, stop, recnop, exactp)
  64. DBC *dbc;
  65. const DBT *key;
  66. u_int32_t flags;
  67. int stop, *exactp;
  68. db_recno_t *recnop;
  69. {
  70. BTREE *t;
  71. BTREE_CURSOR *cp;
  72. DB *dbp;
  73. DB_LOCK lock;
  74. PAGE *h;
  75. db_indx_t base, i, indx, lim;
  76. db_lockmode_t lock_mode;
  77. db_pgno_t pg;
  78. db_recno_t recno;
  79. int adjust, cmp, deloffset, ret, stack;
  80. int (*func) __P((DB *, const DBT *, const DBT *));
  81. dbp = dbc->dbp;
  82. cp = (BTREE_CURSOR *)dbc->internal;
  83. t = dbp->bt_internal;
  84. recno = 0;
  85. BT_STK_CLR(cp);
  86. /*
  87.  * There are several ways we search a btree tree.  The flags argument
  88.  * specifies if we're acquiring read or write locks, if we position
  89.  * to the first or last item in a set of duplicates, if we return
  90.  * deleted items, and if we are locking pairs of pages.  In addition,
  91.  * if we're modifying record numbers, we have to lock the entire tree
  92.  * regardless.  See btree.h for more details.
  93.  *
  94.  * If write-locking pages, we need to know whether or not to acquire a
  95.  * write lock on a page before getting it.  This depends on how deep it
  96.  * is in tree, which we don't know until we acquire the root page.  So,
  97.  * if we need to lock the root page we may have to upgrade it later,
  98.  * because we won't get the correct lock initially.
  99.  *
  100.  * Retrieve the root page.
  101.  */
  102. try_again:
  103. pg = cp->root;
  104. stack = LF_ISSET(S_STACK) && F_ISSET(cp, C_RECNUM);
  105. lock_mode = stack ? DB_LOCK_WRITE : DB_LOCK_READ;
  106. if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
  107. return (ret);
  108. if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) {
  109. /* Did not read it, so we can release the lock */
  110. (void)__LPUT(dbc, lock);
  111. return (ret);
  112. }
  113. /*
  114.  * Decide if we need to save this page; if we do, write lock it.
  115.  * We deliberately don't lock-couple on this call.  If the tree
  116.  * is tiny, i.e., one page, and two threads are busily updating
  117.  * the root page, we're almost guaranteed deadlocks galore, as
  118.  * each one gets a read lock and then blocks the other's attempt
  119.  * for a write lock.
  120.  */
  121. if (!stack &&
  122.     ((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) ||
  123.     (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
  124. (void)memp_fput(dbp->mpf, h, 0);
  125. (void)__LPUT(dbc, lock);
  126. lock_mode = DB_LOCK_WRITE;
  127. if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
  128. return (ret);
  129. if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) {
  130. /* Did not read it, so we can release the lock */
  131. (void)__LPUT(dbc, lock);
  132. return (ret);
  133. }
  134. if (!((LF_ISSET(S_PARENT)
  135.     && (u_int8_t)(stop + 1) >= h->level) ||
  136.     (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
  137. /* Someone else split the root, start over. */
  138. (void)memp_fput(dbp->mpf, h, 0);
  139. (void)__LPUT(dbc, lock);
  140. goto try_again;
  141. }
  142. stack = 1;
  143. }
  144. /* Choose a comparison function. */
  145. func = F_ISSET(dbc, DBC_OPD) ?
  146.     (dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare) :
  147.     t->bt_compare;
  148. for (;;) {
  149. /*
  150.  * Do a binary search on the current page.  If we're searching
  151.  * a Btree leaf page, we have to walk the indices in groups of
  152.  * two.  If we're searching an internal page or a off-page dup
  153.  * page, they're an index per page item.  If we find an exact
  154.  * match on a leaf page, we're done.
  155.  */
  156. adjust = TYPE(h) == P_LBTREE ? P_INDX : O_INDX;
  157. for (base = 0,
  158.     lim = NUM_ENT(h) / (db_indx_t)adjust; lim != 0; lim >>= 1) {
  159. indx = base + ((lim >> 1) * adjust);
  160. if ((ret =
  161.     __bam_cmp(dbp, key, h, indx, func, &cmp)) != 0)
  162. goto err;
  163. if (cmp == 0) {
  164. if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP)
  165. goto found;
  166. goto next;
  167. }
  168. if (cmp > 0) {
  169. base = indx + adjust;
  170. --lim;
  171. }
  172. }
  173. /*
  174.  * No match found.  Base is the smallest index greater than
  175.  * key and may be zero or a last + O_INDX index.
  176.  *
  177.  * If it's a leaf page, return base as the "found" value.
  178.  * Delete only deletes exact matches.
  179.  */
  180. if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP) {
  181. *exactp = 0;
  182. if (LF_ISSET(S_EXACT))
  183. goto notfound;
  184. if (LF_ISSET(S_STK_ONLY)) {
  185. BT_STK_NUM(dbp->dbenv, cp, h, base, ret);
  186. __LPUT(dbc, lock);
  187. (void)memp_fput(dbp->mpf, h, 0);
  188. return (ret);
  189. }
  190. /*
  191.  * !!!
  192.  * Possibly returning a deleted record -- DB_SET_RANGE,
  193.  * DB_KEYFIRST and DB_KEYLAST don't require an exact
  194.  * match, and we don't want to walk multiple pages here
  195.  * to find an undeleted record.  This is handled by the
  196.  * calling routine.
  197.  */
  198. BT_STK_ENTER(dbp->dbenv,
  199.     cp, h, base, lock, lock_mode, ret);
  200. if (ret != 0)
  201. goto err;
  202. return (0);
  203. }
  204. /*
  205.  * If it's not a leaf page, record the internal page (which is
  206.  * a parent page for the key).  Decrement the base by 1 if it's
  207.  * non-zero so that if a split later occurs, the inserted page
  208.  * will be to the right of the saved page.
  209.  */
  210. indx = base > 0 ? base - O_INDX : base;
  211. /*
  212.  * If we're trying to calculate the record number, sum up
  213.  * all the record numbers on this page up to the indx point.
  214.  */
  215. next: if (recnop != NULL)
  216. for (i = 0; i < indx; ++i)
  217. recno += GET_BINTERNAL(h, i)->nrecs;
  218. pg = GET_BINTERNAL(h, indx)->pgno;
  219. if (LF_ISSET(S_STK_ONLY)) {
  220. if (stop == h->level) {
  221. BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
  222. __LPUT(dbc, lock);
  223. (void)memp_fput(dbp->mpf, h, 0);
  224. return (ret);
  225. }
  226. BT_STK_NUMPUSH(dbp->dbenv, cp, h, indx, ret);
  227. (void)memp_fput(dbp->mpf, h, 0);
  228. if ((ret = __db_lget(dbc,
  229.     LCK_COUPLE, pg, lock_mode, 0, &lock)) != 0) {
  230. /*
  231.  * Discard our lock and return on failure.  This
  232.  * is OK because it only happens when descending
  233.  * the tree holding read-locks.
  234.  */
  235. __LPUT(dbc, lock);
  236. return (ret);
  237. }
  238. } else if (stack) {
  239. /* Return if this is the lowest page wanted. */
  240. if (LF_ISSET(S_PARENT) && stop == h->level) {
  241. BT_STK_ENTER(dbp->dbenv,
  242.     cp, h, indx, lock, lock_mode, ret);
  243. if (ret != 0)
  244. goto err;
  245. return (0);
  246. }
  247. BT_STK_PUSH(dbp->dbenv,
  248.     cp, h, indx, lock, lock_mode, ret);
  249. if (ret != 0)
  250. goto err;
  251. lock_mode = DB_LOCK_WRITE;
  252. if ((ret =
  253.     __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
  254. goto err;
  255. } else {
  256. /*
  257.  * Decide if we want to return a reference to the next
  258.  * page in the return stack.  If so, lock it and never
  259.  * unlock it.
  260.  */
  261. if ((LF_ISSET(S_PARENT) &&
  262.     (u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) ||
  263.     (h->level - 1) == LEAFLEVEL)
  264. stack = 1;
  265. (void)memp_fput(dbp->mpf, h, 0);
  266. lock_mode = stack &&
  267.     LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ;
  268. if ((ret = __db_lget(dbc,
  269.     LCK_COUPLE, pg, lock_mode, 0, &lock)) != 0) {
  270. /*
  271.  * If we fail, discard the lock we held.  This
  272.  * is OK because this only happens when we are
  273.  * descending the tree holding read-locks.
  274.  */
  275. __LPUT(dbc, lock);
  276. goto err;
  277. }
  278. }
  279. if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0)
  280. goto err;
  281. }
  282. /* NOTREACHED */
  283. found: *exactp = 1;
  284. /*
  285.  * If we're trying to calculate the record number, add in the
  286.  * offset on this page and correct for the fact that records
  287.  * in the tree are 0-based.
  288.  */
  289. if (recnop != NULL)
  290. *recnop = recno + (indx / P_INDX) + 1;
  291. /*
  292.  * If we got here, we know that we have a Btree leaf or off-page
  293.  * duplicates page.  If it's a Btree leaf page, we have to handle
  294.  * on-page duplicates.
  295.  *
  296.  * If there are duplicates, go to the first/last one.  This is
  297.  * safe because we know that we're not going to leave the page,
  298.  * all duplicate sets that are not on overflow pages exist on a
  299.  * single leaf page.
  300.  */
  301. if (TYPE(h) == P_LBTREE) {
  302. if (LF_ISSET(S_DUPLAST))
  303. while (indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
  304.     h->inp[indx] == h->inp[indx + P_INDX])
  305. indx += P_INDX;
  306. else
  307. while (indx > 0 &&
  308.     h->inp[indx] == h->inp[indx - P_INDX])
  309. indx -= P_INDX;
  310. }
  311. /*
  312.  * Now check if we are allowed to return deleted items; if not, then
  313.  * find the next (or previous) non-deleted duplicate entry.  (We do
  314.  * not move from the original found key on the basis of the S_DELNO
  315.  * flag.)
  316.  */
  317. if (LF_ISSET(S_DELNO)) {
  318. deloffset = TYPE(h) == P_LBTREE ? O_INDX : 0;
  319. if (LF_ISSET(S_DUPLAST))
  320. while (B_DISSET(GET_BKEYDATA(
  321.     h, indx + deloffset)->type) && indx > 0 &&
  322.     h->inp[indx] == h->inp[indx - adjust])
  323. indx -= adjust;
  324. else
  325. while (B_DISSET(GET_BKEYDATA(
  326.     h, indx + deloffset)->type) &&
  327.     indx < (db_indx_t)(NUM_ENT(h) - adjust) &&
  328.     h->inp[indx] == h->inp[indx + adjust])
  329. indx += adjust;
  330. /*
  331.  * If we weren't able to find a non-deleted duplicate, return
  332.  * DB_NOTFOUND.
  333.  */
  334. if (B_DISSET(GET_BKEYDATA(h, indx + deloffset)->type))
  335. goto notfound;
  336. }
  337. if (LF_ISSET(S_STK_ONLY)) {
  338. BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
  339. __LPUT(dbc, lock);
  340. (void)memp_fput(dbp->mpf, h, 0);
  341. } else {
  342. BT_STK_ENTER(dbp->dbenv, cp, h, indx, lock, lock_mode, ret);
  343. if (ret != 0)
  344. goto err;
  345. }
  346. return (0);
  347. notfound:
  348. /* Keep the page locked for serializability. */
  349. (void)memp_fput(dbp->mpf, h, 0);
  350. (void)__TLPUT(dbc, lock);
  351. ret = DB_NOTFOUND;
  352. err: BT_STK_POP(cp);
  353. __bam_stkrel(dbc, 0);
  354. return (ret);
  355. }
  356. /*
  357.  * __bam_stkrel --
  358.  * Release all pages currently held in the stack.
  359.  *
  360.  * PUBLIC: int __bam_stkrel __P((DBC *, u_int32_t));
  361.  */
  362. int
  363. __bam_stkrel(dbc, flags)
  364. DBC *dbc;
  365. u_int32_t flags;
  366. {
  367. BTREE_CURSOR *cp;
  368. DB *dbp;
  369. EPG *epg;
  370. int ret, t_ret;
  371. dbp = dbc->dbp;
  372. cp = (BTREE_CURSOR *)dbc->internal;
  373. /*
  374.  * Release inner pages first.
  375.  *
  376.  * The caller must be sure that setting STK_NOLOCK will not effect
  377.  * either serializability or recoverability.
  378.  */
  379. for (ret = 0, epg = cp->sp; epg <= cp->csp; ++epg) {
  380. if (epg->page != NULL) {
  381. if (LF_ISSET(STK_CLRDBC) && cp->page == epg->page) {
  382. cp->page = NULL;
  383. cp->lock.off = LOCK_INVALID;
  384. }
  385. if ((t_ret = memp_fput(
  386.     dbp->mpf, epg->page, 0)) != 0 && ret == 0)
  387. ret = t_ret;
  388. /*
  389.  * XXX
  390.  * Temporary fix for #3243 -- under certain deadlock
  391.  * conditions we call here again and re-free the page.
  392.  * The correct fix is to never release a stack that
  393.  * doesn't hold items.
  394.  */
  395. epg->page = NULL;
  396. }
  397. if (epg->lock.off != LOCK_INVALID) {
  398. if (LF_ISSET(STK_NOLOCK))
  399. (void)__LPUT(dbc, epg->lock);
  400. else
  401. (void)__TLPUT(dbc, epg->lock);
  402. }
  403. }
  404. /* Clear the stack, all pages have been released. */
  405. BT_STK_CLR(cp);
  406. return (ret);
  407. }
  408. /*
  409.  * __bam_stkgrow --
  410.  * Grow the stack.
  411.  *
  412.  * PUBLIC: int __bam_stkgrow __P((DB_ENV *, BTREE_CURSOR *));
  413.  */
  414. int
  415. __bam_stkgrow(dbenv, cp)
  416. DB_ENV *dbenv;
  417. BTREE_CURSOR *cp;
  418. {
  419. EPG *p;
  420. size_t entries;
  421. int ret;
  422. entries = cp->esp - cp->sp;
  423. if ((ret = __os_calloc(dbenv, entries * 2, sizeof(EPG), &p)) != 0)
  424. return (ret);
  425. memcpy(p, cp->sp, entries * sizeof(EPG));
  426. if (cp->sp != cp->stack)
  427. __os_free(cp->sp, entries * sizeof(EPG));
  428. cp->sp = p;
  429. cp->csp = p + entries;
  430. cp->esp = p + entries * 2;
  431. return (0);
  432. }