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

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_delete.c,v 11.31 2001/01/17 18:48: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_delete --
  57.  * Delete the items referenced by a key.
  58.  *
  59.  * PUBLIC: int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
  60.  */
  61. int
  62. __bam_delete(dbp, txn, key, flags)
  63. DB *dbp;
  64. DB_TXN *txn;
  65. DBT *key;
  66. u_int32_t flags;
  67. {
  68. DBC *dbc;
  69. DBT lkey;
  70. DBT data;
  71. u_int32_t f_init, f_next;
  72. int ret, t_ret;
  73. PANIC_CHECK(dbp->dbenv);
  74. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del");
  75. DB_CHECK_TXN(dbp, txn);
  76. /* Check for invalid flags. */
  77. if ((ret =
  78.     __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0)
  79. return (ret);
  80. /* Allocate a cursor. */
  81. if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
  82. return (ret);
  83. DEBUG_LWRITE(dbc, txn, "bam_delete", key, NULL, flags);
  84. /*
  85.  * Walk a cursor through the key/data pairs, deleting as we go.  Set
  86.  * the DB_DBT_USERMEM flag, as this might be a threaded application
  87.  * and the flags checking will catch us.  We don't actually want the
  88.  * keys or data, so request a partial of length 0.
  89.  */
  90. memset(&lkey, 0, sizeof(lkey));
  91. F_SET(&lkey, DB_DBT_USERMEM | DB_DBT_PARTIAL);
  92. memset(&data, 0, sizeof(data));
  93. F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL);
  94. /*
  95.  * If locking (and we haven't already acquired CDB locks), set the
  96.  * read-modify-write flag.
  97.  */
  98. f_init = DB_SET;
  99. f_next = DB_NEXT_DUP;
  100. if (STD_LOCKING(dbc)) {
  101. f_init |= DB_RMW;
  102. f_next |= DB_RMW;
  103. }
  104. /* Walk through the set of key/data pairs, deleting as we go. */
  105. if ((ret = dbc->c_get(dbc, key, &data, f_init)) != 0)
  106. goto err;
  107. for (;;) {
  108. if ((ret = dbc->c_del(dbc, 0)) != 0)
  109. goto err;
  110. if ((ret = dbc->c_get(dbc, &lkey, &data, f_next)) != 0) {
  111. if (ret == DB_NOTFOUND) {
  112. ret = 0;
  113. break;
  114. }
  115. goto err;
  116. }
  117. }
  118. err: /* Discard the cursor. */
  119. if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  120. ret = t_ret;
  121. return (ret);
  122. }
  123. /*
  124.  * __bam_ditem --
  125.  * Delete one or more entries from a page.
  126.  *
  127.  * PUBLIC: int __bam_ditem __P((DBC *, PAGE *, u_int32_t));
  128.  */
  129. int
  130. __bam_ditem(dbc, h, indx)
  131. DBC *dbc;
  132. PAGE *h;
  133. u_int32_t indx;
  134. {
  135. BINTERNAL *bi;
  136. BKEYDATA *bk;
  137. DB *dbp;
  138. u_int32_t nbytes;
  139. int ret;
  140. dbp = dbc->dbp;
  141. switch (TYPE(h)) {
  142. case P_IBTREE:
  143. bi = GET_BINTERNAL(h, indx);
  144. switch (B_TYPE(bi->type)) {
  145. case B_DUPLICATE:
  146. case B_KEYDATA:
  147. nbytes = BINTERNAL_SIZE(bi->len);
  148. break;
  149. case B_OVERFLOW:
  150. nbytes = BINTERNAL_SIZE(bi->len);
  151. if ((ret =
  152.     __db_doff(dbc, ((BOVERFLOW *)bi->data)->pgno)) != 0)
  153. return (ret);
  154. break;
  155. default:
  156. return (__db_pgfmt(dbp, PGNO(h)));
  157. }
  158. break;
  159. case P_IRECNO:
  160. nbytes = RINTERNAL_SIZE;
  161. break;
  162. case P_LBTREE:
  163. /*
  164.  * If it's a duplicate key, discard the index and don't touch
  165.  * the actual page item.
  166.  *
  167.  * !!!
  168.  * This works because no data item can have an index matching
  169.  * any other index so even if the data item is in a key "slot",
  170.  * it won't match any other index.
  171.  */
  172. if ((indx % 2) == 0) {
  173. /*
  174.  * Check for a duplicate after us on the page.  NOTE:
  175.  * we have to delete the key item before deleting the
  176.  * data item, otherwise the "indx + P_INDX" calculation
  177.  * won't work!
  178.  */
  179. if (indx + P_INDX < (u_int32_t)NUM_ENT(h) &&
  180.     h->inp[indx] == h->inp[indx + P_INDX])
  181. return (__bam_adjindx(dbc,
  182.     h, indx, indx + O_INDX, 0));
  183. /*
  184.  * Check for a duplicate before us on the page.  It
  185.  * doesn't matter if we delete the key item before or
  186.  * after the data item for the purposes of this one.
  187.  */
  188. if (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX])
  189. return (__bam_adjindx(dbc,
  190.     h, indx, indx - P_INDX, 0));
  191. }
  192. /* FALLTHROUGH */
  193. case P_LDUP:
  194. case P_LRECNO:
  195. bk = GET_BKEYDATA(h, indx);
  196. switch (B_TYPE(bk->type)) {
  197. case B_DUPLICATE:
  198. nbytes = BOVERFLOW_SIZE;
  199. break;
  200. case B_OVERFLOW:
  201. nbytes = BOVERFLOW_SIZE;
  202. if ((ret = __db_doff(
  203.     dbc, (GET_BOVERFLOW(h, indx))->pgno)) != 0)
  204. return (ret);
  205. break;
  206. case B_KEYDATA:
  207. nbytes = BKEYDATA_SIZE(bk->len);
  208. break;
  209. default:
  210. return (__db_pgfmt(dbp, PGNO(h)));
  211. }
  212. break;
  213. default:
  214. return (__db_pgfmt(dbp, PGNO(h)));
  215. }
  216. /* Delete the item and mark the page dirty. */
  217. if ((ret = __db_ditem(dbc, h, indx, nbytes)) != 0)
  218. return (ret);
  219. if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0)
  220. return (ret);
  221. return (0);
  222. }
  223. /*
  224.  * __bam_adjindx --
  225.  * Adjust an index on the page.
  226.  *
  227.  * PUBLIC: int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int));
  228.  */
  229. int
  230. __bam_adjindx(dbc, h, indx, indx_copy, is_insert)
  231. DBC *dbc;
  232. PAGE *h;
  233. u_int32_t indx, indx_copy;
  234. int is_insert;
  235. {
  236. DB *dbp;
  237. db_indx_t copy;
  238. int ret;
  239. dbp = dbc->dbp;
  240. /* Log the change. */
  241. if (DB_LOGGING(dbc) &&
  242.     (ret = __bam_adj_log(dbp->dbenv, dbc->txn, &LSN(h),
  243.     0, dbp->log_fileid, PGNO(h), &LSN(h), indx, indx_copy,
  244.     (u_int32_t)is_insert)) != 0)
  245. return (ret);
  246. /* Shuffle the indices and mark the page dirty. */
  247. if (is_insert) {
  248. copy = h->inp[indx_copy];
  249. if (indx != NUM_ENT(h))
  250. memmove(&h->inp[indx + O_INDX], &h->inp[indx],
  251.     sizeof(db_indx_t) * (NUM_ENT(h) - indx));
  252. h->inp[indx] = copy;
  253. ++NUM_ENT(h);
  254. } else {
  255. --NUM_ENT(h);
  256. if (indx != NUM_ENT(h))
  257. memmove(&h->inp[indx], &h->inp[indx + O_INDX],
  258.     sizeof(db_indx_t) * (NUM_ENT(h) - indx));
  259. }
  260. if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0)
  261. return (ret);
  262. return (0);
  263. }
  264. /*
  265.  * __bam_dpages --
  266.  * Delete a set of locked pages.
  267.  *
  268.  * PUBLIC: int __bam_dpages __P((DBC *, EPG *));
  269.  */
  270. int
  271. __bam_dpages(dbc, stack_epg)
  272. DBC *dbc;
  273. EPG *stack_epg;
  274. {
  275. BTREE_CURSOR *cp;
  276. BINTERNAL *bi;
  277. DB *dbp;
  278. DBT a, b;
  279. DB_LOCK c_lock, p_lock;
  280. EPG *epg;
  281. PAGE *child, *parent;
  282. db_indx_t nitems;
  283. db_pgno_t pgno, root_pgno;
  284. db_recno_t rcnt;
  285. int done, ret, t_ret;
  286. dbp = dbc->dbp;
  287. cp = (BTREE_CURSOR *)dbc->internal;
  288. /*
  289.  * We have the entire stack of deletable pages locked.
  290.  *
  291.  * Btree calls us with a pointer to the beginning of a stack, where
  292.  * the first page in the stack is to have a single item deleted, and
  293.  * the rest of the pages are to be removed.
  294.  *
  295.  * Recno calls us with a pointer into the middle of the stack, where
  296.  * the referenced page is to have a single item deleted, and pages
  297.  * after the stack reference are to be removed.
  298.  *
  299.  * First, discard any pages that we don't care about.
  300.  */
  301. ret = 0;
  302. for (epg = cp->sp; epg < stack_epg; ++epg) {
  303. if ((t_ret =
  304.     memp_fput(dbp->mpf, epg->page, 0)) != 0 && ret == 0)
  305. ret = t_ret;
  306. (void)__TLPUT(dbc, epg->lock);
  307. }
  308. if (ret != 0)
  309. goto err;
  310. /*
  311.  * !!!
  312.  * There is an interesting deadlock situation here.  We have to relink
  313.  * the leaf page chain around the leaf page being deleted.  Consider
  314.  * a cursor walking through the leaf pages, that has the previous page
  315.  * read-locked and is waiting on a lock for the page we're deleting.
  316.  * It will deadlock here.  Before we unlink the subtree, we relink the
  317.  * leaf page chain.
  318.  */
  319. if ((ret = __db_relink(dbc, DB_REM_PAGE, cp->csp->page, NULL, 1)) != 0)
  320. goto err;
  321. /*
  322.  * Delete the last item that references the underlying pages that are
  323.  * to be deleted, and adjust cursors that reference that page.  Then,
  324.  * save that page's page number and item count and release it.  If
  325.  * the application isn't retaining locks because it's running without
  326.  * transactions, this lets the rest of the tree get back to business
  327.  * immediately.
  328.  */
  329. if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0)
  330. goto err;
  331. if ((ret = __bam_ca_di(dbc, PGNO(epg->page), epg->indx, -1)) != 0)
  332. goto err;
  333. pgno = PGNO(epg->page);
  334. nitems = NUM_ENT(epg->page);
  335. if ((ret = memp_fput(dbp->mpf, epg->page, 0)) != 0)
  336. goto err_inc;
  337. (void)__TLPUT(dbc, epg->lock);
  338. /* Free the rest of the pages in the stack. */
  339. while (++epg <= cp->csp) {
  340. /*
  341.  * Delete page entries so they will be restored as part of
  342.  * recovery.  We don't need to do cursor adjustment here as
  343.  * the pages are being emptied by definition and so cannot
  344.  * be referenced by a cursor.
  345.  */
  346. if (NUM_ENT(epg->page) != 0) {
  347. DB_ASSERT(NUM_ENT(epg->page) == 1);
  348. if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0)
  349. goto err;
  350. }
  351. if ((ret = __db_free(dbc, epg->page)) != 0) {
  352. epg->page = NULL;
  353. goto err_inc;
  354. }
  355. (void)__TLPUT(dbc, epg->lock);
  356. }
  357. if (0) {
  358. err_inc: ++epg;
  359. err: for (; epg <= cp->csp; ++epg) {
  360. if (epg->page != NULL)
  361. (void)memp_fput(dbp->mpf, epg->page, 0);
  362. (void)__TLPUT(dbc, epg->lock);
  363. }
  364. BT_STK_CLR(cp);
  365. return (ret);
  366. }
  367. BT_STK_CLR(cp);
  368. /*
  369.  * If we just deleted the next-to-last item from the root page, the
  370.  * tree can collapse one or more levels.  While there remains only a
  371.  * single item on the root page, write lock the last page referenced
  372.  * by the root page and copy it over the root page.
  373.  */
  374. root_pgno = cp->root;
  375. if (pgno != root_pgno || nitems != 1)
  376. return (0);
  377. for (done = 0; !done;) {
  378. /* Initialize. */
  379. parent = child = NULL;
  380. p_lock.off = c_lock.off = LOCK_INVALID;
  381. /* Lock the root. */
  382. pgno = root_pgno;
  383. if ((ret =
  384.     __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &p_lock)) != 0)
  385. goto stop;
  386. if ((ret = memp_fget(dbp->mpf, &pgno, 0, &parent)) != 0)
  387. goto stop;
  388. if (NUM_ENT(parent) != 1)
  389. goto stop;
  390. switch (TYPE(parent)) {
  391. case P_IBTREE:
  392. /*
  393.  * If this is overflow, then try to delete it.
  394.  * The child may or may not still point at it.
  395.  */
  396. bi = GET_BINTERNAL(parent, 0);
  397. if (B_TYPE(bi->type) == B_OVERFLOW)
  398. if ((ret = __db_doff(dbc,
  399.     ((BOVERFLOW *)bi->data)->pgno)) != 0)
  400. goto stop;
  401. pgno = bi->pgno;
  402. break;
  403. case P_IRECNO:
  404. pgno = GET_RINTERNAL(parent, 0)->pgno;
  405. break;
  406. default:
  407. goto stop;
  408. }
  409. /* Lock the child page. */
  410. if ((ret =
  411.     __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &c_lock)) != 0)
  412. goto stop;
  413. if ((ret = memp_fget(dbp->mpf, &pgno, 0, &child)) != 0)
  414. goto stop;
  415. /* Log the change. */
  416. if (DB_LOGGING(dbc)) {
  417. memset(&a, 0, sizeof(a));
  418. a.data = child;
  419. a.size = dbp->pgsize;
  420. memset(&b, 0, sizeof(b));
  421. b.data = P_ENTRY(parent, 0);
  422. b.size = TYPE(parent) == P_IRECNO ? RINTERNAL_SIZE :
  423.     BINTERNAL_SIZE(((BINTERNAL *)b.data)->len);
  424. if ((ret =
  425.    __bam_rsplit_log(dbp->dbenv, dbc->txn, &child->lsn,
  426.    0, dbp->log_fileid, PGNO(child), &a, PGNO(parent),
  427.    RE_NREC(parent), &b, &parent->lsn)) != 0)
  428. goto stop;
  429. }
  430. /*
  431.  * Make the switch.
  432.  *
  433.  * One fixup -- internal pages below the top level do not store
  434.  * a record count, so we have to preserve it if we're not
  435.  * converting to a leaf page.  Note also that we are about to
  436.  * overwrite the parent page, including its LSN.  This is OK
  437.  * because the log message we wrote describing this update
  438.  * stores its LSN on the child page.  When the child is copied
  439.  * onto the parent, the correct LSN is copied into place.
  440.  */
  441. COMPQUIET(rcnt, 0);
  442. if (F_ISSET(cp, C_RECNUM) && LEVEL(child) > LEAFLEVEL)
  443. rcnt = RE_NREC(parent);
  444. memcpy(parent, child, dbp->pgsize);
  445. PGNO(parent) = root_pgno;
  446. if (F_ISSET(cp, C_RECNUM) && LEVEL(child) > LEAFLEVEL)
  447. RE_NREC_SET(parent, rcnt);
  448. /* Mark the pages dirty. */
  449. if ((ret = memp_fset(dbp->mpf, parent, DB_MPOOL_DIRTY)) != 0)
  450. goto stop;
  451. if ((ret = memp_fset(dbp->mpf, child, DB_MPOOL_DIRTY)) != 0)
  452. goto stop;
  453. /* Adjust the cursors. */
  454. if ((ret = __bam_ca_rsplit(dbc, PGNO(child), root_pgno)) != 0)
  455. goto stop;
  456. /*
  457.  * Free the page copied onto the root page and discard its
  458.  * lock.  (The call to __db_free() discards our reference
  459.  * to the page.)
  460.  */
  461. if ((ret = __db_free(dbc, child)) != 0) {
  462. child = NULL;
  463. goto stop;
  464. }
  465. child = NULL;
  466. if (0) {
  467. stop: done = 1;
  468. }
  469. if (p_lock.off != LOCK_INVALID)
  470. (void)__TLPUT(dbc, p_lock);
  471. if (parent != NULL &&
  472.     (t_ret = memp_fput(dbp->mpf, parent, 0)) != 0 && ret == 0)
  473. ret = t_ret;
  474. if (c_lock.off != LOCK_INVALID)
  475. (void)__TLPUT(dbc, c_lock);
  476. if (child != NULL &&
  477.     (t_ret = memp_fput(dbp->mpf, child, 0)) != 0 && ret == 0)
  478. ret = t_ret;
  479. }
  480. return (ret);
  481. }