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

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: db_meta.c,v 11.61 2002/08/08 03:57:48 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/lock.h"
  54. #include "dbinc/db_am.h"
  55. static void __db_init_meta __P((void *, u_int32_t, db_pgno_t, u_int32_t));
  56. /*
  57.  * __db_init_meta --
  58.  * Helper function for __db_new that initializes the important fields in
  59.  * a meta-data page (used instead of P_INIT).  We need to make sure that we
  60.  * retain the page number and LSN of the existing page.
  61.  */
  62. static void
  63. __db_init_meta(p, pgsize, pgno, pgtype)
  64. void *p;
  65. u_int32_t pgsize;
  66. db_pgno_t pgno;
  67. u_int32_t pgtype;
  68. {
  69. DB_LSN save_lsn;
  70. DBMETA *meta;
  71. meta = (DBMETA *)p;
  72. save_lsn = meta->lsn;
  73. memset(meta, 0, sizeof(DBMETA));
  74. meta->lsn = save_lsn;
  75. meta->pagesize = pgsize;
  76. meta->pgno = pgno;
  77. meta->type = (u_int8_t)pgtype;
  78. }
  79. /*
  80.  * __db_new --
  81.  * Get a new page, preferably from the freelist.
  82.  *
  83.  * PUBLIC: int __db_new __P((DBC *, u_int32_t, PAGE **));
  84.  */
  85. int
  86. __db_new(dbc, type, pagepp)
  87. DBC *dbc;
  88. u_int32_t type;
  89. PAGE **pagepp;
  90. {
  91. DBMETA *meta;
  92. DB *dbp;
  93. DB_LOCK metalock;
  94. DB_LSN lsn;
  95. DB_MPOOLFILE *mpf;
  96. PAGE *h;
  97. db_pgno_t pgno, newnext;
  98. int meta_flags, extend, ret;
  99. meta = NULL;
  100. meta_flags = 0;
  101. dbp = dbc->dbp;
  102. mpf = dbp->mpf;
  103. h = NULL;
  104. newnext = PGNO_INVALID;
  105. pgno = PGNO_BASE_MD;
  106. if ((ret = __db_lget(dbc,
  107.     LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
  108. goto err;
  109. if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0)
  110. goto err;
  111. if (meta->free == PGNO_INVALID) {
  112. pgno = meta->last_pgno + 1;
  113. ZERO_LSN(lsn);
  114. extend = 1;
  115. } else {
  116. pgno = meta->free;
  117. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  118. goto err;
  119. /*
  120.  * We want to take the first page off the free list and
  121.  * then set meta->free to the that page's next_pgno, but
  122.  * we need to log the change first.
  123.  */
  124. newnext = h->next_pgno;
  125. lsn = h->lsn;
  126. extend = 0;
  127. }
  128. /*
  129.  * Log the allocation before fetching the new page.  If we
  130.  * don't have room in the log then we don't want to tell
  131.  * mpool to extend the file.
  132.  */
  133. if (DBC_LOGGING(dbc)) {
  134. if ((ret = __db_pg_alloc_log(dbp, dbc->txn, &LSN(meta), 0,
  135.     &LSN(meta), PGNO_BASE_MD, &lsn, pgno,
  136.     (u_int32_t)type, newnext)) != 0)
  137. goto err;
  138. } else
  139. LSN_NOT_LOGGED(LSN(meta));
  140. meta_flags = DB_MPOOL_DIRTY;
  141. meta->free = newnext;
  142. if (extend == 1) {
  143. meta->last_pgno++;
  144. if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_NEW, &h)) != 0)
  145. goto err;
  146. ZERO_LSN(h->lsn);
  147. h->pgno = pgno;
  148. DB_ASSERT(pgno == meta->last_pgno);
  149. }
  150. LSN(h) = LSN(meta);
  151. DB_ASSERT(TYPE(h) == P_INVALID);
  152. if (TYPE(h) != P_INVALID)
  153. return (__db_panic(dbp->dbenv, EINVAL));
  154. (void)mpf->put(mpf, (PAGE *)meta, DB_MPOOL_DIRTY);
  155. (void)__TLPUT(dbc, metalock);
  156. switch (type) {
  157. case P_BTREEMETA:
  158. case P_HASHMETA:
  159. case P_QAMMETA:
  160. __db_init_meta(h, dbp->pgsize, h->pgno, type);
  161. break;
  162. default:
  163. P_INIT(h, dbp->pgsize,
  164.     h->pgno, PGNO_INVALID, PGNO_INVALID, 0, type);
  165. break;
  166. }
  167. /*
  168.  * If dirty reads are enabled and we are in a transaction, we could
  169.  * abort this allocation after the page(s) pointing to this
  170.  * one have their locks downgraded.  This would permit dirty readers
  171.  * to access this page which is ok, but they must be off the
  172.  * page when we abort.  This will also prevent updates happening
  173.  * to this page until we commit.
  174.  */
  175. if (F_ISSET(dbc->dbp, DB_AM_DIRTY) && dbc->txn != NULL) {
  176. if ((ret = __db_lget(dbc, 0,
  177.     h->pgno, DB_LOCK_WWRITE, 0, &metalock)) != 0)
  178. goto err;
  179. }
  180. *pagepp = h;
  181. return (0);
  182. err: if (h != NULL)
  183. (void)mpf->put(mpf, h, 0);
  184. if (meta != NULL)
  185. (void)mpf->put(mpf, meta, meta_flags);
  186. (void)__TLPUT(dbc, metalock);
  187. return (ret);
  188. }
  189. /*
  190.  * __db_free --
  191.  * Add a page to the head of the freelist.
  192.  *
  193.  * PUBLIC: int __db_free __P((DBC *, PAGE *));
  194.  */
  195. int
  196. __db_free(dbc, h)
  197. DBC *dbc;
  198. PAGE *h;
  199. {
  200. DBMETA *meta;
  201. DB *dbp;
  202. DBT ldbt;
  203. DB_LOCK metalock;
  204. DB_MPOOLFILE *mpf;
  205. db_pgno_t pgno;
  206. u_int32_t dirty_flag;
  207. int ret, t_ret;
  208. dbp = dbc->dbp;
  209. mpf = dbp->mpf;
  210. /*
  211.  * Retrieve the metadata page and insert the page at the head of
  212.  * the free list.  If either the lock get or page get routines
  213.  * fail, then we need to put the page with which we were called
  214.  * back because our caller assumes we take care of it.
  215.  */
  216. dirty_flag = 0;
  217. pgno = PGNO_BASE_MD;
  218. if ((ret = __db_lget(dbc,
  219.     LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
  220. goto err;
  221. if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0) {
  222. (void)__TLPUT(dbc, metalock);
  223. goto err;
  224. }
  225. DB_ASSERT(h->pgno != meta->free);
  226. /* Log the change. */
  227. if (DBC_LOGGING(dbc)) {
  228. memset(&ldbt, 0, sizeof(ldbt));
  229. ldbt.data = h;
  230. ldbt.size = P_OVERHEAD(dbp);
  231. if ((ret = __db_pg_free_log(dbp,
  232.     dbc->txn, &LSN(meta), 0, h->pgno,
  233.     &LSN(meta), PGNO_BASE_MD, &ldbt, meta->free)) != 0) {
  234. (void)mpf->put(mpf, (PAGE *)meta, 0);
  235. (void)__TLPUT(dbc, metalock);
  236. goto err;
  237. }
  238. } else
  239. LSN_NOT_LOGGED(LSN(meta));
  240. LSN(h) = LSN(meta);
  241. P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, meta->free, 0, P_INVALID);
  242. meta->free = h->pgno;
  243. /* Discard the metadata page. */
  244. if ((t_ret =
  245.     mpf->put(mpf, (PAGE *)meta, DB_MPOOL_DIRTY)) != 0 && ret == 0)
  246. ret = t_ret;
  247. if ((t_ret = __TLPUT(dbc, metalock)) != 0 && ret == 0)
  248. ret = t_ret;
  249. /* Discard the caller's page reference. */
  250. dirty_flag = DB_MPOOL_DIRTY;
  251. err: if ((t_ret = mpf->put(mpf, h, dirty_flag)) != 0 && ret == 0)
  252. ret = t_ret;
  253. /*
  254.  * XXX
  255.  * We have to unlock the caller's page in the caller!
  256.  */
  257. return (ret);
  258. }
  259. #ifdef DEBUG
  260. /*
  261.  * __db_lprint --
  262.  * Print out the list of locks currently held by a cursor.
  263.  *
  264.  * PUBLIC: int __db_lprint __P((DBC *));
  265.  */
  266. int
  267. __db_lprint(dbc)
  268. DBC *dbc;
  269. {
  270. DB *dbp;
  271. DB_LOCKREQ req;
  272. dbp = dbc->dbp;
  273. if (LOCKING_ON(dbp->dbenv)) {
  274. req.op = DB_LOCK_DUMP;
  275. dbp->dbenv->lock_vec(dbp->dbenv, dbc->locker, 0, &req, 1, NULL);
  276. }
  277. return (0);
  278. }
  279. #endif
  280. /*
  281.  * Implement the rules for transactional locking.  We can release the previous
  282.  * lock if we are not in a transaction or COUPLE_ALWAYS is specifed (used in
  283.  * record locking).  If we are doing dirty reads then we can release read locks
  284.  * and down grade write locks.
  285.  */
  286. #define DB_PUT_ACTION(dbc, action, lockp)
  287.     (((action == LCK_COUPLE || action == LCK_COUPLE_ALWAYS) &&
  288.     LOCK_ISSET(*lockp)) ?
  289.     (dbc->txn == NULL || action == LCK_COUPLE_ALWAYS ||
  290.     (F_ISSET(dbc, DBC_DIRTY_READ) &&
  291.     (lockp)->mode == DB_LOCK_DIRTY)) ? LCK_COUPLE :
  292.     (F_ISSET((dbc)->dbp, DB_AM_DIRTY) &&
  293.     (lockp)->mode == DB_LOCK_WRITE) ? LCK_DOWNGRADE : 0 : 0)
  294. /*
  295.  * __db_lget --
  296.  * The standard lock get call.
  297.  *
  298.  * PUBLIC: int __db_lget __P((DBC *,
  299.  * PUBLIC:     int, db_pgno_t, db_lockmode_t, u_int32_t, DB_LOCK *));
  300.  */
  301. int
  302. __db_lget(dbc, action, pgno, mode, lkflags, lockp)
  303. DBC *dbc;
  304. int action;
  305. db_pgno_t pgno;
  306. db_lockmode_t mode;
  307. u_int32_t lkflags;
  308. DB_LOCK *lockp;
  309. {
  310. DB *dbp;
  311. DB_ENV *dbenv;
  312. DB_LOCKREQ couple[2], *reqp;
  313. DB_TXN *txn;
  314. int has_timeout, ret;
  315. dbp = dbc->dbp;
  316. dbenv = dbp->dbenv;
  317. txn = dbc->txn;
  318. /*
  319.  * We do not always check if we're configured for locking before
  320.  * calling __db_lget to acquire the lock.
  321.  */
  322. if (CDB_LOCKING(dbenv) ||
  323.     !LOCKING_ON(dbenv) || F_ISSET(dbc, DBC_COMPENSATE) ||
  324.     (F_ISSET(dbc, DBC_RECOVER) &&
  325.     (action != LCK_ROLLBACK || F_ISSET(dbenv, DB_ENV_REP_CLIENT))) ||
  326.     (action != LCK_ALWAYS && F_ISSET(dbc, DBC_OPD))) {
  327. LOCK_INIT(*lockp);
  328. return (0);
  329. }
  330. dbc->lock.pgno = pgno;
  331. if (lkflags & DB_LOCK_RECORD)
  332. dbc->lock.type = DB_RECORD_LOCK;
  333. else
  334. dbc->lock.type = DB_PAGE_LOCK;
  335. lkflags &= ~DB_LOCK_RECORD;
  336. /*
  337.  * If the transaction enclosing this cursor has DB_LOCK_NOWAIT set,
  338.  * pass that along to the lock call.
  339.  */
  340. if (DB_NONBLOCK(dbc))
  341. lkflags |= DB_LOCK_NOWAIT;
  342. if (F_ISSET(dbc, DBC_DIRTY_READ) && mode == DB_LOCK_READ)
  343. mode = DB_LOCK_DIRTY;
  344. has_timeout = txn != NULL && F_ISSET(txn, TXN_LOCKTIMEOUT);
  345. switch (DB_PUT_ACTION(dbc, action, lockp)) {
  346. case LCK_COUPLE:
  347. lck_couple: couple[0].op = has_timeout? DB_LOCK_GET_TIMEOUT : DB_LOCK_GET;
  348. couple[0].obj = &dbc->lock_dbt;
  349. couple[0].mode = mode;
  350. if (action == LCK_COUPLE_ALWAYS)
  351. action = LCK_COUPLE;
  352. UMRW_SET(couple[0].timeout);
  353. if (has_timeout)
  354. couple[0].timeout = txn->lock_timeout;
  355. if (action == LCK_COUPLE) {
  356. couple[1].op = DB_LOCK_PUT;
  357. couple[1].lock = *lockp;
  358. }
  359. ret = dbenv->lock_vec(dbenv, dbc->locker,
  360.     lkflags, couple, action == LCK_COUPLE ? 2 : 1, &reqp);
  361. if (ret == 0 || reqp == &couple[1])
  362. *lockp = couple[0].lock;
  363. break;
  364. case LCK_DOWNGRADE:
  365. if ((ret = dbenv->lock_downgrade(
  366.     dbenv, lockp, DB_LOCK_WWRITE, 0)) != 0)
  367. return (ret);
  368. /* FALL THROUGH */
  369. default:
  370. if (has_timeout)
  371. goto lck_couple;
  372. ret = dbenv->lock_get(dbenv,
  373.     dbc->locker, lkflags, &dbc->lock_dbt, mode, lockp);
  374. break;
  375. }
  376. return (ret);
  377. }
  378. /*
  379.  * __db_lput --
  380.  * The standard lock put call.
  381.  *
  382.  * PUBLIC: int __db_lput __P((DBC *, DB_LOCK *));
  383.  */
  384. int
  385. __db_lput(dbc, lockp)
  386. DBC *dbc;
  387. DB_LOCK *lockp;
  388. {
  389. DB_ENV *dbenv;
  390. int ret;
  391. dbenv = dbc->dbp->dbenv;
  392. switch (DB_PUT_ACTION(dbc, LCK_COUPLE, lockp)) {
  393. case LCK_COUPLE:
  394. ret = dbenv->lock_put(dbenv, lockp);
  395. break;
  396. case LCK_DOWNGRADE:
  397. ret = __lock_downgrade(dbenv, lockp, DB_LOCK_WWRITE, 0);
  398. break;
  399. default:
  400. ret = 0;
  401. break;
  402. }
  403. return (ret);
  404. }