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

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_open.c,v 11.42 2000/11/30 00:58:28 ubell Exp $";
  45. #endif /* not lint */
  46. #ifndef NO_SYSTEM_INCLUDES
  47. #include <sys/types.h>
  48. #include <limits.h>
  49. #include <string.h>
  50. #endif
  51. #include "db_int.h"
  52. #include "db_page.h"
  53. #include "db_swap.h"
  54. #include "btree.h"
  55. #include "db_shash.h"
  56. #include "lock.h"
  57. #include "log.h"
  58. #include "mp.h"
  59. /*
  60.  * __bam_open --
  61.  * Open a btree.
  62.  *
  63.  * PUBLIC: int __bam_open __P((DB *, const char *, db_pgno_t, u_int32_t));
  64.  */
  65. int
  66. __bam_open(dbp, name, base_pgno, flags)
  67. DB *dbp;
  68. const char *name;
  69. db_pgno_t base_pgno;
  70. u_int32_t flags;
  71. {
  72. BTREE *t;
  73. t = dbp->bt_internal;
  74. /* Initialize the remaining fields/methods of the DB. */
  75. dbp->del = __bam_delete;
  76. dbp->key_range = __bam_key_range;
  77. dbp->stat = __bam_stat;
  78. /*
  79.  * We don't permit the user to specify a prefix routine if they didn't
  80.  * also specify a comparison routine, they can't know enough about our
  81.  * comparison routine to get it right.
  82.  */
  83. if (t->bt_compare == __bam_defcmp && t->bt_prefix != __bam_defpfx) {
  84. __db_err(dbp->dbenv,
  85. "prefix comparison may not be specified for default comparison routine");
  86. return (EINVAL);
  87. }
  88. /*
  89.  * Verify that the bt_minkey value specified won't cause the
  90.  * calculation of ovflsize to underflow [#2406] for this pagesize.
  91.  */
  92. if (B_MINKEY_TO_OVFLSIZE(t->bt_minkey, dbp->pgsize) >
  93.     B_MINKEY_TO_OVFLSIZE(DEFMINKEYPAGE, dbp->pgsize)) {
  94. __db_err(dbp->dbenv,
  95.     "bt_minkey value of %lu too high for page size of %lu",
  96.     (u_long)t->bt_minkey, (u_long)dbp->pgsize);
  97. return (EINVAL);
  98. }
  99. /* Start up the tree. */
  100. return (__bam_read_root(dbp, name, base_pgno, flags));
  101. }
  102. /*
  103.  * __bam_metachk --
  104.  *
  105.  * PUBLIC: int __bam_metachk __P((DB *, const char *, BTMETA *));
  106.  */
  107. int
  108. __bam_metachk(dbp, name, btm)
  109. DB *dbp;
  110. const char *name;
  111. BTMETA *btm;
  112. {
  113. DB_ENV *dbenv;
  114. u_int32_t vers;
  115. int ret;
  116. dbenv = dbp->dbenv;
  117. /*
  118.  * At this point, all we know is that the magic number is for a Btree.
  119.  * Check the version, the database may be out of date.
  120.  */
  121. vers = btm->dbmeta.version;
  122. if (F_ISSET(dbp, DB_AM_SWAP))
  123. M_32_SWAP(vers);
  124. switch (vers) {
  125. case 6:
  126. case 7:
  127. __db_err(dbenv,
  128.     "%s: btree version %lu requires a version upgrade",
  129.     name, (u_long)vers);
  130. return (DB_OLD_VERSION);
  131. case 8:
  132. break;
  133. default:
  134. __db_err(dbenv,
  135.     "%s: unsupported btree version: %lu", name, (u_long)vers);
  136. return (EINVAL);
  137. }
  138. /* Swap the page if we need to. */
  139. if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __bam_mswap((PAGE *)btm)) != 0)
  140. return (ret);
  141. /*
  142.  * Check application info against metadata info, and set info, flags,
  143.  * and type based on metadata info.
  144.  */
  145. if ((ret =
  146.     __db_fchk(dbenv, "DB->open", btm->dbmeta.flags, BTM_MASK)) != 0)
  147. return (ret);
  148. if (F_ISSET(&btm->dbmeta, BTM_RECNO)) {
  149. if (dbp->type == DB_BTREE)
  150. goto wrong_type;
  151. dbp->type = DB_RECNO;
  152. DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
  153. } else {
  154. if (dbp->type == DB_RECNO)
  155. goto wrong_type;
  156. dbp->type = DB_BTREE;
  157. DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
  158. }
  159. if (F_ISSET(&btm->dbmeta, BTM_DUP))
  160. F_SET(dbp, DB_AM_DUP);
  161. else
  162. if (F_ISSET(dbp, DB_AM_DUP)) {
  163. __db_err(dbenv,
  164. "%s: DB_DUP specified to open method but not set in database",
  165.     name);
  166. return (EINVAL);
  167. }
  168. if (F_ISSET(&btm->dbmeta, BTM_RECNUM)) {
  169. if (dbp->type != DB_BTREE)
  170. goto wrong_type;
  171. F_SET(dbp, DB_BT_RECNUM);
  172. if ((ret = __db_fcchk(dbenv,
  173.     "DB->open", dbp->flags, DB_AM_DUP, DB_BT_RECNUM)) != 0)
  174. return (ret);
  175. } else
  176. if (F_ISSET(dbp, DB_BT_RECNUM)) {
  177. __db_err(dbenv,
  178.     "%s: DB_RECNUM specified to open method but not set in database",
  179.     name);
  180. return (EINVAL);
  181. }
  182. if (F_ISSET(&btm->dbmeta, BTM_FIXEDLEN)) {
  183. if (dbp->type != DB_RECNO)
  184. goto wrong_type;
  185. F_SET(dbp, DB_RE_FIXEDLEN);
  186. } else
  187. if (F_ISSET(dbp, DB_RE_FIXEDLEN)) {
  188. __db_err(dbenv,
  189. "%s: DB_FIXEDLEN specified to open method but not set in database",
  190.     name);
  191. return (EINVAL);
  192. }
  193. if (F_ISSET(&btm->dbmeta, BTM_RENUMBER)) {
  194. if (dbp->type != DB_RECNO)
  195. goto wrong_type;
  196. F_SET(dbp, DB_RE_RENUMBER);
  197. } else
  198. if (F_ISSET(dbp, DB_RE_RENUMBER)) {
  199. __db_err(dbenv,
  200.     "%s: DB_RENUMBER specified to open method but not set in database",
  201.     name);
  202. return (EINVAL);
  203. }
  204. if (F_ISSET(&btm->dbmeta, BTM_SUBDB))
  205. F_SET(dbp, DB_AM_SUBDB);
  206. else
  207. if (F_ISSET(dbp, DB_AM_SUBDB)) {
  208. __db_err(dbenv,
  209.     "%s: multiple databases specified but not supported by file",
  210.     name);
  211. return (EINVAL);
  212. }
  213. if (F_ISSET(&btm->dbmeta, BTM_DUPSORT)) {
  214. if (dbp->dup_compare == NULL)
  215. dbp->dup_compare = __bam_defcmp;
  216. F_SET(dbp, DB_AM_DUPSORT);
  217. } else
  218. if (dbp->dup_compare != NULL) {
  219. __db_err(dbenv,
  220. "%s: duplicate sort specified but not supported in database",
  221.     name);
  222. return (EINVAL);
  223. }
  224. /* Set the page size. */
  225. dbp->pgsize = btm->dbmeta.pagesize;
  226. /* Copy the file's ID. */
  227. memcpy(dbp->fileid, btm->dbmeta.uid, DB_FILE_ID_LEN);
  228. return (0);
  229. wrong_type:
  230. if (dbp->type == DB_BTREE)
  231. __db_err(dbenv,
  232.     "open method type is Btree, database type is Recno");
  233. else
  234. __db_err(dbenv,
  235.     "open method type is Recno, database type is Btree");
  236. return (EINVAL);
  237. }
  238. /*
  239.  * __bam_read_root --
  240.  * Check (and optionally create) a tree.
  241.  *
  242.  * PUBLIC: int __bam_read_root __P((DB *, const char *, db_pgno_t, u_int32_t));
  243.  */
  244. int
  245. __bam_read_root(dbp, name, base_pgno, flags)
  246. DB *dbp;
  247. const char *name;
  248. db_pgno_t base_pgno;
  249. u_int32_t flags;
  250. {
  251. BTMETA *meta;
  252. BTREE *t;
  253. DBC *dbc;
  254. DB_LSN orig_lsn;
  255. DB_LOCK metalock;
  256. PAGE *root;
  257. int locked, ret, t_ret;
  258. ret = 0;
  259. t = dbp->bt_internal;
  260. meta = NULL;
  261. root = NULL;
  262. locked = 0;
  263. /*
  264.  * Get a cursor.  If DB_CREATE is specified, we may be creating
  265.  * the root page, and to do that safely in CDB we need a write
  266.  * cursor.  In STD_LOCKING mode, we'll synchronize using the
  267.  * meta page lock instead.
  268.  */
  269. if ((ret = dbp->cursor(dbp, dbp->open_txn,
  270.     &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbp->dbenv) ?
  271.     DB_WRITECURSOR : 0)) != 0)
  272. return (ret);
  273. /* Get, and optionally create the metadata page. */
  274. if ((ret =
  275.     __db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0)
  276. goto err;
  277. if ((ret = memp_fget(
  278.     dbp->mpf, &base_pgno, DB_MPOOL_CREATE, (PAGE **)&meta)) != 0)
  279. goto err;
  280. /*
  281.  * If the magic number is correct, we're not creating the tree.
  282.  * Correct any fields that may not be right.  Note, all of the
  283.  * local flags were set by DB->open.
  284.  */
  285. again: if (meta->dbmeta.magic != 0) {
  286. t->bt_maxkey = meta->maxkey;
  287. t->bt_minkey = meta->minkey;
  288. t->re_pad = meta->re_pad;
  289. t->re_len = meta->re_len;
  290. t->bt_meta = base_pgno;
  291. t->bt_root = meta->root;
  292. (void)memp_fput(dbp->mpf, meta, 0);
  293. meta = NULL;
  294. goto done;
  295. }
  296. /* In recovery if it's not there it will be created elsewhere.*/
  297. if (IS_RECOVERING(dbp->dbenv))
  298. goto done;
  299. /* If we're doing CDB; we now have to get the write lock. */
  300. if (CDB_LOCKING(dbp->dbenv)) {
  301. /*
  302.  * We'd better have DB_CREATE set if we're actually doing
  303.  * the create.
  304.  */
  305. DB_ASSERT(LF_ISSET(DB_CREATE));
  306. if ((ret = lock_get(dbp->dbenv, dbc->locker, DB_LOCK_UPGRADE,
  307.     &dbc->lock_dbt, DB_LOCK_WRITE, &dbc->mylock)) != 0)
  308. goto err;
  309. }
  310. /*
  311.  * If we are doing locking, relase the read lock and get a write lock.
  312.  * We want to avoid deadlock.
  313.  */
  314. if (locked == 0 && STD_LOCKING(dbc)) {
  315. if ((ret = __LPUT(dbc, metalock)) != 0)
  316. goto err;
  317. if ((ret = __db_lget(dbc,
  318.      0, base_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
  319. goto err;
  320. locked = 1;
  321. goto again;
  322. }
  323. /* Initialize the tree structure metadata information. */
  324. orig_lsn = meta->dbmeta.lsn;
  325. memset(meta, 0, sizeof(BTMETA));
  326. meta->dbmeta.lsn = orig_lsn;
  327. meta->dbmeta.pgno = base_pgno;
  328. meta->dbmeta.magic = DB_BTREEMAGIC;
  329. meta->dbmeta.version = DB_BTREEVERSION;
  330. meta->dbmeta.pagesize = dbp->pgsize;
  331. meta->dbmeta.type = P_BTREEMETA;
  332. meta->dbmeta.free = PGNO_INVALID;
  333. if (F_ISSET(dbp, DB_AM_DUP))
  334. F_SET(&meta->dbmeta, BTM_DUP);
  335. if (F_ISSET(dbp, DB_RE_FIXEDLEN))
  336. F_SET(&meta->dbmeta, BTM_FIXEDLEN);
  337. if (F_ISSET(dbp, DB_BT_RECNUM))
  338. F_SET(&meta->dbmeta, BTM_RECNUM);
  339. if (F_ISSET(dbp, DB_RE_RENUMBER))
  340. F_SET(&meta->dbmeta, BTM_RENUMBER);
  341. if (F_ISSET(dbp, DB_AM_SUBDB))
  342. F_SET(&meta->dbmeta, BTM_SUBDB);
  343. if (dbp->dup_compare != NULL)
  344. F_SET(&meta->dbmeta, BTM_DUPSORT);
  345. if (dbp->type == DB_RECNO)
  346. F_SET(&meta->dbmeta, BTM_RECNO);
  347. memcpy(meta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN);
  348. meta->maxkey = t->bt_maxkey;
  349. meta->minkey = t->bt_minkey;
  350. meta->re_len = t->re_len;
  351. meta->re_pad = t->re_pad;
  352. /* If necessary, log the meta-data and root page creates.  */
  353. if ((ret = __db_log_page(dbp,
  354.     name, &orig_lsn, base_pgno, (PAGE *)meta)) != 0)
  355. goto err;
  356. /* Create and initialize a root page. */
  357. if ((ret = __db_new(dbc,
  358.     dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE, &root)) != 0)
  359. goto err;
  360. root->level = LEAFLEVEL;
  361. if (dbp->open_txn != NULL && (ret = __bam_root_log(dbp->dbenv,
  362.     dbp->open_txn, &meta->dbmeta.lsn, 0, dbp->log_fileid,
  363.     meta->dbmeta.pgno, root->pgno, &meta->dbmeta.lsn)) != 0)
  364. goto err;
  365. meta->root = root->pgno;
  366. DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name);
  367. if ((ret = __db_log_page(dbp,
  368.     name, &root->lsn, root->pgno, root)) != 0)
  369. goto err;
  370. DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, name);
  371. t->bt_meta = base_pgno;
  372. t->bt_root = root->pgno;
  373. /* Release the metadata and root pages. */
  374. if ((ret = memp_fput(dbp->mpf, meta, DB_MPOOL_DIRTY)) != 0)
  375. goto err;
  376. meta = NULL;
  377. if ((ret = memp_fput(dbp->mpf, root, DB_MPOOL_DIRTY)) != 0)
  378. goto err;
  379. root = NULL;
  380. /*
  381.  * Flush the metadata and root pages to disk.
  382.  *
  383.  * !!!
  384.  * It's not useful to return not-yet-flushed here -- convert it to
  385.  * an error.
  386.  */
  387. if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE) {
  388. __db_err(dbp->dbenv, "Metapage flush failed");
  389. ret = EINVAL;
  390. }
  391. DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
  392. done: /*
  393.  * !!!
  394.  * We already did an insert and so the last-page-inserted has been
  395.  * set.  I'm not sure where the *right* place to clear this value
  396.  * is, it's not intuitively obvious that it belongs here.
  397.  */
  398. t->bt_lpgno = PGNO_INVALID;
  399. err:
  400. DB_TEST_RECOVERY_LABEL
  401. /* Put any remaining pages back. */
  402. if (meta != NULL)
  403. if ((t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 &&
  404.     ret == 0)
  405. ret = t_ret;
  406. if (root != NULL)
  407. if ((t_ret = memp_fput(dbp->mpf, root, 0)) != 0 &&
  408.     ret == 0)
  409. ret = t_ret;
  410. /* We can release the metapage lock when we are done. */
  411. if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
  412. ret = t_ret;
  413. if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  414. ret = t_ret;
  415. return (ret);
  416. }