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

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