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

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. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: bt_curadj.c,v 11.30 2002/07/03 19:03:48 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #endif
  14. #include "db_int.h"
  15. #include "dbinc/db_page.h"
  16. #include "dbinc/btree.h"
  17. static int __bam_opd_cursor __P((DB *, DBC *, db_pgno_t, u_int32_t, u_int32_t));
  18. #ifdef DEBUG
  19. /*
  20.  * __bam_cprint --
  21.  * Display the current internal cursor.
  22.  *
  23.  * PUBLIC: void __bam_cprint __P((DBC *));
  24.  */
  25. void
  26. __bam_cprint(dbc)
  27. DBC *dbc;
  28. {
  29. BTREE_CURSOR *cp;
  30. cp = (BTREE_CURSOR *)dbc->internal;
  31. fprintf(stderr, "tinternal: ovflsize: %lu", (u_long)cp->ovflsize);
  32. if (dbc->dbtype == DB_RECNO)
  33. fprintf(stderr, " recno: %lu", (u_long)cp->recno);
  34. if (F_ISSET(cp, C_DELETED))
  35. fprintf(stderr, " (deleted)");
  36. fprintf(stderr, "n");
  37. }
  38. #endif
  39. /*
  40.  * Cursor adjustments are logged if they are for subtransactions.  This is
  41.  * because it's possible for a subtransaction to adjust cursors which will
  42.  * still be active after the subtransaction aborts, and so which must be
  43.  * restored to their previous locations.  Cursors that can be both affected
  44.  * by our cursor adjustments and active after our transaction aborts can
  45.  * only be found in our parent transaction -- cursors in other transactions,
  46.  * including other child transactions of our parent, must have conflicting
  47.  * locker IDs, and so cannot be affected by adjustments in this transaction.
  48.  */
  49. /*
  50.  * __bam_ca_delete --
  51.  * Update the cursors when items are deleted and when already deleted
  52.  * items are overwritten.  Return the number of relevant cursors found.
  53.  *
  54.  * PUBLIC: int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int));
  55.  */
  56. int
  57. __bam_ca_delete(dbp, pgno, indx, delete)
  58. DB *dbp;
  59. db_pgno_t pgno;
  60. u_int32_t indx;
  61. int delete;
  62. {
  63. BTREE_CURSOR *cp;
  64. DB *ldbp;
  65. DB_ENV *dbenv;
  66. DBC *dbc;
  67. int count; /* !!!: Has to contain max number of cursors. */
  68. dbenv = dbp->dbenv;
  69. /*
  70.  * Adjust the cursors.  We have the page write locked, so the
  71.  * only other cursors that can be pointing at a page are
  72.  * those in the same thread of control.  Unfortunately, we don't
  73.  * know that they're using the same DB handle, so traverse
  74.  * all matching DB handles in the same DB_ENV, then all cursors
  75.  * on each matching DB handle.
  76.  *
  77.  * Each cursor is single-threaded, so we only need to lock the
  78.  * list of DBs and then the list of cursors in each DB.
  79.  */
  80. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  81. for (count = 0, ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  82.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  83.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  84. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  85. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  86.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  87. cp = (BTREE_CURSOR *)dbc->internal;
  88. if (cp->pgno == pgno && cp->indx == indx) {
  89. if (delete)
  90. F_SET(cp, C_DELETED);
  91. else
  92. F_CLR(cp, C_DELETED);
  93. ++count;
  94. }
  95. }
  96. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  97. }
  98. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  99. return (count);
  100. }
  101. /*
  102.  * __ram_ca_delete --
  103.  * Return the number of relevant cursors.
  104.  *
  105.  * PUBLIC: int __ram_ca_delete __P((DB *, db_pgno_t));
  106.  */
  107. int
  108. __ram_ca_delete(dbp, root_pgno)
  109. DB *dbp;
  110. db_pgno_t root_pgno;
  111. {
  112. DB *ldbp;
  113. DBC *dbc;
  114. DB_ENV *dbenv;
  115. int found;
  116. found = 0;
  117. dbenv = dbp->dbenv;
  118. /*
  119.  * Review the cursors.  See the comment in __bam_ca_delete().
  120.  */
  121. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  122. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  123.     found == 0 && ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  124.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  125. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  126. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  127.     found == 0 && dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
  128. if (dbc->internal->root == root_pgno)
  129. found = 1;
  130. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  131. }
  132. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  133. return (found);
  134. }
  135. /*
  136.  * __bam_ca_di --
  137.  * Adjust the cursors during a delete or insert.
  138.  *
  139.  * PUBLIC: int __bam_ca_di __P((DBC *, db_pgno_t, u_int32_t, int));
  140.  */
  141. int
  142. __bam_ca_di(my_dbc, pgno, indx, adjust)
  143. DBC *my_dbc;
  144. db_pgno_t pgno;
  145. u_int32_t indx;
  146. int adjust;
  147. {
  148. DB *dbp, *ldbp;
  149. DB_ENV *dbenv;
  150. DB_LSN lsn;
  151. DB_TXN *my_txn;
  152. DBC *dbc;
  153. DBC_INTERNAL *cp;
  154. int found, ret;
  155. dbp = my_dbc->dbp;
  156. dbenv = dbp->dbenv;
  157. my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
  158. /*
  159.  * Adjust the cursors.  See the comment in __bam_ca_delete().
  160.  */
  161. found = 0;
  162. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  163. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  164.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  165.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  166. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  167. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  168.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  169. if (dbc->dbtype == DB_RECNO)
  170. continue;
  171. cp = dbc->internal;
  172. if (cp->pgno == pgno && cp->indx >= indx) {
  173. /* Cursor indices should never be negative. */
  174. DB_ASSERT(cp->indx != 0 || adjust > 0);
  175. cp->indx += adjust;
  176. if (my_txn != NULL && dbc->txn != my_txn)
  177. found = 1;
  178. }
  179. }
  180. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  181. }
  182. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  183. if (found != 0 && DBC_LOGGING(my_dbc)) {
  184. if ((ret = __bam_curadj_log(dbp, my_dbc->txn,
  185.     &lsn, 0, DB_CA_DI, pgno, 0, 0, adjust, indx, 0)) != 0)
  186. return (ret);
  187. }
  188. return (0);
  189. }
  190. /*
  191.  * __bam_opd_cursor -- create a new opd cursor.
  192.  */
  193. static int
  194. __bam_opd_cursor(dbp, dbc, first, tpgno, ti)
  195. DB *dbp;
  196. DBC *dbc;
  197. db_pgno_t tpgno;
  198. u_int32_t first, ti;
  199. {
  200. BTREE_CURSOR *cp, *orig_cp;
  201. DBC *dbc_nopd;
  202. int ret;
  203. orig_cp = (BTREE_CURSOR *)dbc->internal;
  204. dbc_nopd = NULL;
  205. /*
  206.  * Allocate a new cursor and create the stack.  If duplicates
  207.  * are sorted, we've just created an off-page duplicate Btree.
  208.  * If duplicates aren't sorted, we've just created a Recno tree.
  209.  *
  210.  * Note that in order to get here at all, there shouldn't be
  211.  * an old off-page dup cursor--to augment the checking db_c_newopd
  212.  * will do, assert this.
  213.  */
  214. DB_ASSERT(orig_cp->opd == NULL);
  215. if ((ret = __db_c_newopd(dbc, tpgno, orig_cp->opd, &dbc_nopd)) != 0)
  216. return (ret);
  217. cp = (BTREE_CURSOR *)dbc_nopd->internal;
  218. cp->pgno = tpgno;
  219. cp->indx = ti;
  220. if (dbp->dup_compare == NULL) {
  221. /*
  222.  * Converting to off-page Recno trees is tricky.  The
  223.  * record number for the cursor is the index + 1 (to
  224.  * convert to 1-based record numbers).
  225.  */
  226. cp->recno = ti + 1;
  227. }
  228. /*
  229.  * Transfer the deleted flag from the top-level cursor to the
  230.  * created one.
  231.  */
  232. if (F_ISSET(orig_cp, C_DELETED)) {
  233. F_SET(cp, C_DELETED);
  234. F_CLR(orig_cp, C_DELETED);
  235. }
  236. /* Stack the cursors and reset the initial cursor's index. */
  237. orig_cp->opd = dbc_nopd;
  238. orig_cp->indx = first;
  239. return (0);
  240. }
  241. /*
  242.  * __bam_ca_dup --
  243.  * Adjust the cursors when moving items from a leaf page to a duplicates
  244.  * page.
  245.  *
  246.  * PUBLIC: int __bam_ca_dup __P((DBC *,
  247.  * PUBLIC:    u_int32_t, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
  248.  */
  249. int
  250. __bam_ca_dup(my_dbc, first, fpgno, fi, tpgno, ti)
  251. DBC *my_dbc;
  252. db_pgno_t fpgno, tpgno;
  253. u_int32_t first, fi, ti;
  254. {
  255. BTREE_CURSOR *orig_cp;
  256. DB *dbp, *ldbp;
  257. DBC *dbc;
  258. DB_ENV *dbenv;
  259. DB_LSN lsn;
  260. DB_TXN *my_txn;
  261. int found, ret;
  262. dbp = my_dbc->dbp;
  263. dbenv = dbp->dbenv;
  264. my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
  265. /*
  266.  * Adjust the cursors.  See the comment in __bam_ca_delete().
  267.  */
  268. found = 0;
  269. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  270. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  271.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  272.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  273. loop: MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  274. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  275.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  276. /* Find cursors pointing to this record. */
  277. orig_cp = (BTREE_CURSOR *)dbc->internal;
  278. if (orig_cp->pgno != fpgno || orig_cp->indx != fi)
  279. continue;
  280. /*
  281.  * Since we rescan the list see if this is already
  282.  * converted.
  283.  */
  284. if (orig_cp->opd != NULL)
  285. continue;
  286. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  287. if ((ret = __bam_opd_cursor(dbp,
  288.     dbc, first, tpgno, ti)) !=0)
  289. return (ret);
  290. if (my_txn != NULL && dbc->txn != my_txn)
  291. found = 1;
  292. /* We released the mutex to get a cursor, start over. */
  293. goto loop;
  294. }
  295. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  296. }
  297. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  298. if (found != 0 && DBC_LOGGING(my_dbc)) {
  299. if ((ret = __bam_curadj_log(dbp, my_dbc->txn,
  300.     &lsn, 0, DB_CA_DUP, fpgno, tpgno, 0, first, fi, ti)) != 0)
  301. return (ret);
  302. }
  303. return (0);
  304. }
  305. /*
  306.  * __bam_ca_undodup --
  307.  * Adjust the cursors when returning items to a leaf page
  308.  * from a duplicate page.
  309.  * Called only during undo processing.
  310.  *
  311.  * PUBLIC: int __bam_ca_undodup __P((DB *,
  312.  * PUBLIC:    u_int32_t, db_pgno_t, u_int32_t, u_int32_t));
  313.  */
  314. int
  315. __bam_ca_undodup(dbp, first, fpgno, fi, ti)
  316. DB *dbp;
  317. db_pgno_t fpgno;
  318. u_int32_t first, fi, ti;
  319. {
  320. BTREE_CURSOR *orig_cp;
  321. DB *ldbp;
  322. DBC *dbc;
  323. DB_ENV *dbenv;
  324. int ret;
  325. dbenv = dbp->dbenv;
  326. /*
  327.  * Adjust the cursors.  See the comment in __bam_ca_delete().
  328.  */
  329. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  330. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  331.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  332.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  333. loop: MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  334. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  335.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  336. orig_cp = (BTREE_CURSOR *)dbc->internal;
  337. /*
  338.  * A note on the orig_cp->opd != NULL requirement here:
  339.  * it's possible that there's a cursor that refers to
  340.  * the same duplicate set, but which has no opd cursor,
  341.  * because it refers to a different item and we took
  342.  * care of it while processing a previous record.
  343.  */
  344. if (orig_cp->pgno != fpgno ||
  345.     orig_cp->indx != first ||
  346.     orig_cp->opd == NULL ||
  347.     ((BTREE_CURSOR *)orig_cp->opd->internal)->indx
  348.     != ti)
  349. continue;
  350. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  351. if ((ret = orig_cp->opd->c_close(orig_cp->opd)) != 0)
  352. return (ret);
  353. orig_cp->opd = NULL;
  354. orig_cp->indx = fi;
  355. /*
  356.  * We released the mutex to free a cursor,
  357.  * start over.
  358.  */
  359. goto loop;
  360. }
  361. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  362. }
  363. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  364. return (0);
  365. }
  366. /*
  367.  * __bam_ca_rsplit --
  368.  * Adjust the cursors when doing reverse splits.
  369.  *
  370.  * PUBLIC: int __bam_ca_rsplit __P((DBC *, db_pgno_t, db_pgno_t));
  371.  */
  372. int
  373. __bam_ca_rsplit(my_dbc, fpgno, tpgno)
  374. DBC* my_dbc;
  375. db_pgno_t fpgno, tpgno;
  376. {
  377. DB *dbp, *ldbp;
  378. DBC *dbc;
  379. DB_ENV *dbenv;
  380. DB_LSN lsn;
  381. DB_TXN *my_txn;
  382. int found, ret;
  383. dbp = my_dbc->dbp;
  384. dbenv = dbp->dbenv;
  385. my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
  386. /*
  387.  * Adjust the cursors.  See the comment in __bam_ca_delete().
  388.  */
  389. found = 0;
  390. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  391. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  392.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  393.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  394. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  395. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  396.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  397. if (dbc->dbtype == DB_RECNO)
  398. continue;
  399. if (dbc->internal->pgno == fpgno) {
  400. dbc->internal->pgno = tpgno;
  401. if (my_txn != NULL && dbc->txn != my_txn)
  402. found = 1;
  403. }
  404. }
  405. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  406. }
  407. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  408. if (found != 0 && DBC_LOGGING(my_dbc)) {
  409. if ((ret = __bam_curadj_log(dbp, my_dbc->txn,
  410.     &lsn, 0, DB_CA_RSPLIT, fpgno, tpgno, 0, 0, 0, 0)) != 0)
  411. return (ret);
  412. }
  413. return (0);
  414. }
  415. /*
  416.  * __bam_ca_split --
  417.  * Adjust the cursors when splitting a page.
  418.  *
  419.  * PUBLIC: int __bam_ca_split __P((DBC *,
  420.  * PUBLIC:    db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
  421.  */
  422. int
  423. __bam_ca_split(my_dbc, ppgno, lpgno, rpgno, split_indx, cleft)
  424. DBC *my_dbc;
  425. db_pgno_t ppgno, lpgno, rpgno;
  426. u_int32_t split_indx;
  427. int cleft;
  428. {
  429. DB *dbp, *ldbp;
  430. DBC *dbc;
  431. DBC_INTERNAL *cp;
  432. DB_ENV *dbenv;
  433. DB_LSN lsn;
  434. DB_TXN *my_txn;
  435. int found, ret;
  436. dbp = my_dbc->dbp;
  437. dbenv = dbp->dbenv;
  438. my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL;
  439. /*
  440.  * Adjust the cursors.  See the comment in __bam_ca_delete().
  441.  *
  442.  * If splitting the page that a cursor was on, the cursor has to be
  443.  * adjusted to point to the same record as before the split.  Most
  444.  * of the time we don't adjust pointers to the left page, because
  445.  * we're going to copy its contents back over the original page.  If
  446.  * the cursor is on the right page, it is decremented by the number of
  447.  * records split to the left page.
  448.  */
  449. found = 0;
  450. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  451. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  452.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  453.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  454. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  455. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  456.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  457. if (dbc->dbtype == DB_RECNO)
  458. continue;
  459. cp = dbc->internal;
  460. if (cp->pgno == ppgno) {
  461. if (my_txn != NULL && dbc->txn != my_txn)
  462. found = 1;
  463. if (cp->indx < split_indx) {
  464. if (cleft)
  465. cp->pgno = lpgno;
  466. } else {
  467. cp->pgno = rpgno;
  468. cp->indx -= split_indx;
  469. }
  470. }
  471. }
  472. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  473. }
  474. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  475. if (found != 0 && DBC_LOGGING(my_dbc)) {
  476. if ((ret = __bam_curadj_log(dbp,
  477.     my_dbc->txn, &lsn, 0, DB_CA_SPLIT, ppgno, rpgno,
  478.     cleft ? lpgno : PGNO_INVALID, 0, split_indx, 0)) != 0)
  479. return (ret);
  480. }
  481. return (0);
  482. }
  483. /*
  484.  * __bam_ca_undosplit --
  485.  * Adjust the cursors when undoing a split of a page.
  486.  * If we grew a level we will execute this for both the
  487.  * left and the right pages.
  488.  * Called only during undo processing.
  489.  *
  490.  * PUBLIC: void __bam_ca_undosplit __P((DB *,
  491.  * PUBLIC:    db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t));
  492.  */
  493. void
  494. __bam_ca_undosplit(dbp, frompgno, topgno, lpgno, split_indx)
  495. DB *dbp;
  496. db_pgno_t frompgno, topgno, lpgno;
  497. u_int32_t split_indx;
  498. {
  499. DB *ldbp;
  500. DBC *dbc;
  501. DB_ENV *dbenv;
  502. DBC_INTERNAL *cp;
  503. dbenv = dbp->dbenv;
  504. /*
  505.  * Adjust the cursors.  See the comment in __bam_ca_delete().
  506.  *
  507.  * When backing out a split, we move the cursor back
  508.  * to the original offset and bump it by the split_indx.
  509.  */
  510. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  511. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  512.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  513.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  514. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  515. for (dbc = TAILQ_FIRST(&ldbp->active_queue);
  516.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  517. if (dbc->dbtype == DB_RECNO)
  518. continue;
  519. cp = dbc->internal;
  520. if (cp->pgno == topgno) {
  521. cp->pgno = frompgno;
  522. cp->indx += split_indx;
  523. } else if (cp->pgno == lpgno)
  524. cp->pgno = frompgno;
  525. }
  526. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  527. }
  528. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  529. }