bt_search.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:13k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  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.43 2002/07/03 19:03:50 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 "dbinc/db_page.h"
  52. #include "dbinc/db_shash.h"
  53. #include "dbinc/btree.h"
  54. #include "dbinc/lock.h"
  55. /*
  56.  * __bam_search --
  57.  * Search a btree for a key.
  58.  *
  59.  * PUBLIC: int __bam_search __P((DBC *, db_pgno_t,
  60.  * PUBLIC:     const DBT *, u_int32_t, int, db_recno_t *, int *));
  61.  */
  62. int
  63. __bam_search(dbc, root_pgno, key, flags, stop, recnop, exactp)
  64. DBC *dbc;
  65. db_pgno_t root_pgno;
  66. const DBT *key;
  67. u_int32_t flags;
  68. int stop, *exactp;
  69. db_recno_t *recnop;
  70. {
  71. BTREE *t;
  72. BTREE_CURSOR *cp;
  73. DB *dbp;
  74. DB_LOCK lock;
  75. DB_MPOOLFILE *mpf;
  76. PAGE *h;
  77. db_indx_t base, i, indx, *inp, lim;
  78. db_lockmode_t lock_mode;
  79. db_pgno_t pg;
  80. db_recno_t recno;
  81. int adjust, cmp, deloffset, ret, stack;
  82. int (*func) __P((DB *, const DBT *, const DBT *));
  83. dbp = dbc->dbp;
  84. mpf = dbp->mpf;
  85. cp = (BTREE_CURSOR *)dbc->internal;
  86. t = dbp->bt_internal;
  87. recno = 0;
  88. BT_STK_CLR(cp);
  89. /*
  90.  * There are several ways we search a btree tree.  The flags argument
  91.  * specifies if we're acquiring read or write locks, if we position
  92.  * to the first or last item in a set of duplicates, if we return
  93.  * deleted items, and if we are locking pairs of pages.  In addition,
  94.  * if we're modifying record numbers, we have to lock the entire tree
  95.  * regardless.  See btree.h for more details.
  96.  *
  97.  * If write-locking pages, we need to know whether or not to acquire a
  98.  * write lock on a page before getting it.  This depends on how deep it
  99.  * is in tree, which we don't know until we acquire the root page.  So,
  100.  * if we need to lock the root page we may have to upgrade it later,
  101.  * because we won't get the correct lock initially.
  102.  *
  103.  * Retrieve the root page.
  104.  */
  105. try_again:
  106. pg = root_pgno == PGNO_INVALID ? cp->root : root_pgno;
  107. stack = LF_ISSET(S_STACK) && F_ISSET(cp, C_RECNUM);
  108. lock_mode = stack ? DB_LOCK_WRITE : DB_LOCK_READ;
  109. if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
  110. return (ret);
  111. if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0) {
  112. /* Did not read it, so we can release the lock */
  113. (void)__LPUT(dbc, lock);
  114. return (ret);
  115. }
  116. /*
  117.  * Decide if we need to save this page; if we do, write lock it.
  118.  * We deliberately don't lock-couple on this call.  If the tree
  119.  * is tiny, i.e., one page, and two threads are busily updating
  120.  * the root page, we're almost guaranteed deadlocks galore, as
  121.  * each one gets a read lock and then blocks the other's attempt
  122.  * for a write lock.
  123.  */
  124. if (!stack &&
  125.     ((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) ||
  126.     (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
  127. (void)mpf->put(mpf, h, 0);
  128. (void)__LPUT(dbc, lock);
  129. lock_mode = DB_LOCK_WRITE;
  130. if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
  131. return (ret);
  132. if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0) {
  133. /* Did not read it, so we can release the lock */
  134. (void)__LPUT(dbc, lock);
  135. return (ret);
  136. }
  137. if (!((LF_ISSET(S_PARENT) &&
  138.     (u_int8_t)(stop + 1) >= h->level) ||
  139.     (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
  140. /* Someone else split the root, start over. */
  141. (void)mpf->put(mpf, h, 0);
  142. (void)__LPUT(dbc, lock);
  143. goto try_again;
  144. }
  145. stack = 1;
  146. }
  147. /* Choose a comparison function. */
  148. func = F_ISSET(dbc, DBC_OPD) ?
  149.     (dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare) :
  150.     t->bt_compare;
  151. for (;;) {
  152. inp = P_INP(dbp, h);
  153. /*
  154.  * Do a binary search on the current page.  If we're searching
  155.  * a Btree leaf page, we have to walk the indices in groups of
  156.  * two.  If we're searching an internal page or a off-page dup
  157.  * page, they're an index per page item.  If we find an exact
  158.  * match on a leaf page, we're done.
  159.  */
  160. adjust = TYPE(h) == P_LBTREE ? P_INDX : O_INDX;
  161. for (base = 0,
  162.     lim = NUM_ENT(h) / (db_indx_t)adjust; lim != 0; lim >>= 1) {
  163. indx = base + ((lim >> 1) * adjust);
  164. if ((ret =
  165.     __bam_cmp(dbp, key, h, indx, func, &cmp)) != 0)
  166. goto err;
  167. if (cmp == 0) {
  168. if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP)
  169. goto found;
  170. goto next;
  171. }
  172. if (cmp > 0) {
  173. base = indx + adjust;
  174. --lim;
  175. }
  176. }
  177. /*
  178.  * No match found.  Base is the smallest index greater than
  179.  * key and may be zero or a last + O_INDX index.
  180.  *
  181.  * If it's a leaf page, return base as the "found" value.
  182.  * Delete only deletes exact matches.
  183.  */
  184. if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP) {
  185. *exactp = 0;
  186. if (LF_ISSET(S_EXACT))
  187. goto notfound;
  188. if (LF_ISSET(S_STK_ONLY)) {
  189. BT_STK_NUM(dbp->dbenv, cp, h, base, ret);
  190. __LPUT(dbc, lock);
  191. (void)mpf->put(mpf, h, 0);
  192. return (ret);
  193. }
  194. /*
  195.  * !!!
  196.  * Possibly returning a deleted record -- DB_SET_RANGE,
  197.  * DB_KEYFIRST and DB_KEYLAST don't require an exact
  198.  * match, and we don't want to walk multiple pages here
  199.  * to find an undeleted record.  This is handled by the
  200.  * calling routine.
  201.  */
  202. BT_STK_ENTER(dbp->dbenv,
  203.     cp, h, base, lock, lock_mode, ret);
  204. if (ret != 0)
  205. goto err;
  206. return (0);
  207. }
  208. /*
  209.  * If it's not a leaf page, record the internal page (which is
  210.  * a parent page for the key).  Decrement the base by 1 if it's
  211.  * non-zero so that if a split later occurs, the inserted page
  212.  * will be to the right of the saved page.
  213.  */
  214. indx = base > 0 ? base - O_INDX : base;
  215. /*
  216.  * If we're trying to calculate the record number, sum up
  217.  * all the record numbers on this page up to the indx point.
  218.  */
  219. next: if (recnop != NULL)
  220. for (i = 0; i < indx; ++i)
  221. recno += GET_BINTERNAL(dbp, h, i)->nrecs;
  222. pg = GET_BINTERNAL(dbp, h, indx)->pgno;
  223. if (LF_ISSET(S_STK_ONLY)) {
  224. if (stop == h->level) {
  225. BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
  226. __LPUT(dbc, lock);
  227. (void)mpf->put(mpf, h, 0);
  228. return (ret);
  229. }
  230. BT_STK_NUMPUSH(dbp->dbenv, cp, h, indx, ret);
  231. (void)mpf->put(mpf, h, 0);
  232. if ((ret = __db_lget(dbc,
  233.     LCK_COUPLE_ALWAYS, pg, lock_mode, 0, &lock)) != 0) {
  234. /*
  235.  * Discard our lock and return on failure.  This
  236.  * is OK because it only happens when descending
  237.  * the tree holding read-locks.
  238.  */
  239. __LPUT(dbc, lock);
  240. return (ret);
  241. }
  242. } else if (stack) {
  243. /* Return if this is the lowest page wanted. */
  244. if (LF_ISSET(S_PARENT) && stop == h->level) {
  245. BT_STK_ENTER(dbp->dbenv,
  246.     cp, h, indx, lock, lock_mode, ret);
  247. if (ret != 0)
  248. goto err;
  249. return (0);
  250. }
  251. BT_STK_PUSH(dbp->dbenv,
  252.     cp, h, indx, lock, lock_mode, ret);
  253. if (ret != 0)
  254. goto err;
  255. lock_mode = DB_LOCK_WRITE;
  256. if ((ret =
  257.     __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
  258. goto err;
  259. } else {
  260. /*
  261.  * Decide if we want to return a reference to the next
  262.  * page in the return stack.  If so, lock it and never
  263.  * unlock it.
  264.  */
  265. if ((LF_ISSET(S_PARENT) &&
  266.     (u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) ||
  267.     (h->level - 1) == LEAFLEVEL)
  268. stack = 1;
  269. (void)mpf->put(mpf, h, 0);
  270. lock_mode = stack &&
  271.     LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ;
  272. if ((ret = __db_lget(dbc,
  273.     LCK_COUPLE_ALWAYS, pg, lock_mode, 0, &lock)) != 0) {
  274. /*
  275.  * If we fail, discard the lock we held.  This
  276.  * is OK because this only happens when we are
  277.  * descending the tree holding read-locks.
  278.  */
  279. __LPUT(dbc, lock);
  280. goto err;
  281. }
  282. }
  283. if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0)
  284. goto err;
  285. }
  286. /* NOTREACHED */
  287. found: *exactp = 1;
  288. /*
  289.  * If we're trying to calculate the record number, add in the
  290.  * offset on this page and correct for the fact that records
  291.  * in the tree are 0-based.
  292.  */
  293. if (recnop != NULL)
  294. *recnop = recno + (indx / P_INDX) + 1;
  295. /*
  296.  * If we got here, we know that we have a Btree leaf or off-page
  297.  * duplicates page.  If it's a Btree leaf page, we have to handle
  298.  * on-page duplicates.
  299.  *
  300.  * If there are duplicates, go to the first/last one.  This is
  301.  * safe because we know that we're not going to leave the page,
  302.  * all duplicate sets that are not on overflow pages exist on a
  303.  * single leaf page.
  304.  */
  305. if (TYPE(h) == P_LBTREE) {
  306. if (LF_ISSET(S_DUPLAST))
  307. while (indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
  308.     inp[indx] == inp[indx + P_INDX])
  309. indx += P_INDX;
  310. else
  311. while (indx > 0 &&
  312.     inp[indx] == inp[indx - P_INDX])
  313. indx -= P_INDX;
  314. }
  315. /*
  316.  * Now check if we are allowed to return deleted items; if not, then
  317.  * find the next (or previous) non-deleted duplicate entry.  (We do
  318.  * not move from the original found key on the basis of the S_DELNO
  319.  * flag.)
  320.  */
  321. if (LF_ISSET(S_DELNO)) {
  322. deloffset = TYPE(h) == P_LBTREE ? O_INDX : 0;
  323. if (LF_ISSET(S_DUPLAST))
  324. while (B_DISSET(GET_BKEYDATA(dbp,
  325.     h, indx + deloffset)->type) && indx > 0 &&
  326.     inp[indx] == inp[indx - adjust])
  327. indx -= adjust;
  328. else
  329. while (B_DISSET(GET_BKEYDATA(dbp,
  330.     h, indx + deloffset)->type) &&
  331.     indx < (db_indx_t)(NUM_ENT(h) - adjust) &&
  332.     inp[indx] == inp[indx + adjust])
  333. indx += adjust;
  334. /*
  335.  * If we weren't able to find a non-deleted duplicate, return
  336.  * DB_NOTFOUND.
  337.  */
  338. if (B_DISSET(GET_BKEYDATA(dbp, h, indx + deloffset)->type))
  339. goto notfound;
  340. }
  341. if (LF_ISSET(S_STK_ONLY)) {
  342. BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
  343. __LPUT(dbc, lock);
  344. (void)mpf->put(mpf, h, 0);
  345. } else {
  346. BT_STK_ENTER(dbp->dbenv, cp, h, indx, lock, lock_mode, ret);
  347. if (ret != 0)
  348. goto err;
  349. }
  350. return (0);
  351. notfound:
  352. /* Keep the page locked for serializability. */
  353. (void)mpf->put(mpf, h, 0);
  354. (void)__TLPUT(dbc, lock);
  355. ret = DB_NOTFOUND;
  356. err: BT_STK_POP(cp);
  357. __bam_stkrel(dbc, 0);
  358. return (ret);
  359. }
  360. /*
  361.  * __bam_stkrel --
  362.  * Release all pages currently held in the stack.
  363.  *
  364.  * PUBLIC: int __bam_stkrel __P((DBC *, u_int32_t));
  365.  */
  366. int
  367. __bam_stkrel(dbc, flags)
  368. DBC *dbc;
  369. u_int32_t flags;
  370. {
  371. BTREE_CURSOR *cp;
  372. DB *dbp;
  373. DB_MPOOLFILE *mpf;
  374. EPG *epg;
  375. int ret, t_ret;
  376. dbp = dbc->dbp;
  377. mpf = dbp->mpf;
  378. cp = (BTREE_CURSOR *)dbc->internal;
  379. /*
  380.  * Release inner pages first.
  381.  *
  382.  * The caller must be sure that setting STK_NOLOCK will not effect
  383.  * either serializability or recoverability.
  384.  */
  385. for (ret = 0, epg = cp->sp; epg <= cp->csp; ++epg) {
  386. if (epg->page != NULL) {
  387. if (LF_ISSET(STK_CLRDBC) && cp->page == epg->page) {
  388. cp->page = NULL;
  389. LOCK_INIT(cp->lock);
  390. }
  391. if ((t_ret =
  392.     mpf->put(mpf, epg->page, 0)) != 0 && ret == 0)
  393. ret = t_ret;
  394. /*
  395.  * XXX
  396.  * Temporary fix for #3243 -- under certain deadlock
  397.  * conditions we call here again and re-free the page.
  398.  * The correct fix is to never release a stack that
  399.  * doesn't hold items.
  400.  */
  401. epg->page = NULL;
  402. }
  403. if (LF_ISSET(STK_NOLOCK))
  404. (void)__LPUT(dbc, epg->lock);
  405. else
  406. (void)__TLPUT(dbc, epg->lock);
  407. }
  408. /* Clear the stack, all pages have been released. */
  409. BT_STK_CLR(cp);
  410. return (ret);
  411. }
  412. /*
  413.  * __bam_stkgrow --
  414.  * Grow the stack.
  415.  *
  416.  * PUBLIC: int __bam_stkgrow __P((DB_ENV *, BTREE_CURSOR *));
  417.  */
  418. int
  419. __bam_stkgrow(dbenv, cp)
  420. DB_ENV *dbenv;
  421. BTREE_CURSOR *cp;
  422. {
  423. EPG *p;
  424. size_t entries;
  425. int ret;
  426. entries = cp->esp - cp->sp;
  427. if ((ret = __os_calloc(dbenv, entries * 2, sizeof(EPG), &p)) != 0)
  428. return (ret);
  429. memcpy(p, cp->sp, entries * sizeof(EPG));
  430. if (cp->sp != cp->stack)
  431. __os_free(dbenv, cp->sp);
  432. cp->sp = p;
  433. cp->csp = p + entries;
  434. cp->esp = p + entries * 2;
  435. return (0);
  436. }