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

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