hash_open.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. /*
  8.  * Copyright (c) 1990, 1993, 1994
  9.  * Margo Seltzer.  All rights reserved.
  10.  */
  11. /*
  12.  * Copyright (c) 1990, 1993, 1994
  13.  * The Regents of the University of California.  All rights reserved.
  14.  *
  15.  * This code is derived from software contributed to Berkeley by
  16.  * Margo Seltzer.
  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: hash_open.c,v 11.175 2002/09/04 19:06:44 margo Exp $";
  45. #endif /* not lint */
  46. #ifndef NO_SYSTEM_INCLUDES
  47. #include <sys/types.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #endif
  51. #include "db_int.h"
  52. #include "dbinc/crypto.h"
  53. #include "dbinc/db_page.h"
  54. #include "dbinc/hash.h"
  55. #include "dbinc/log.h"
  56. #include "dbinc/db_shash.h"
  57. #include "dbinc/lock.h"
  58. #include "dbinc/db_swap.h"
  59. #include "dbinc/btree.h"
  60. #include "dbinc/fop.h"
  61. static db_pgno_t __ham_init_meta __P((DB *, HMETA *, db_pgno_t, DB_LSN *));
  62. /*
  63.  * __ham_open --
  64.  *
  65.  * PUBLIC: int __ham_open __P((DB *,
  66.  * PUBLIC:     DB_TXN *, const char * name, db_pgno_t, u_int32_t));
  67.  */
  68. int
  69. __ham_open(dbp, txn, name, base_pgno, flags)
  70. DB *dbp;
  71. DB_TXN *txn;
  72. const char *name;
  73. db_pgno_t base_pgno;
  74. u_int32_t flags;
  75. {
  76. DB_ENV *dbenv;
  77. DBC *dbc;
  78. DB_MPOOLFILE *mpf;
  79. HASH_CURSOR *hcp;
  80. HASH *hashp;
  81. int ret, t_ret;
  82. COMPQUIET(name, NULL);
  83. dbenv = dbp->dbenv;
  84. dbc = NULL;
  85. mpf = dbp->mpf;
  86. /* Initialize the remaining fields/methods of the DB. */
  87. dbp->stat = __ham_stat;
  88. /*
  89.  * Get a cursor.  If DB_CREATE is specified, we may be creating
  90.  * pages, and to do that safely in CDB we need a write cursor.
  91.  * In STD_LOCKING mode, we'll synchronize using the meta page
  92.  * lock instead.
  93.  */
  94. if ((ret = dbp->cursor(dbp,
  95.     txn, &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbenv) ?
  96.     DB_WRITECURSOR : 0)) != 0)
  97. return (ret);
  98. hcp = (HASH_CURSOR *)dbc->internal;
  99. hashp = dbp->h_internal;
  100. hashp->meta_pgno = base_pgno;
  101. if ((ret = __ham_get_meta(dbc)) != 0)
  102. goto err1;
  103. /* Initialize the hdr structure.  */
  104. if (hcp->hdr->dbmeta.magic == DB_HASHMAGIC) {
  105. /* File exists, verify the data in the header. */
  106. if (hashp->h_hash == NULL)
  107. hashp->h_hash = hcp->hdr->dbmeta.version < 5
  108. ? __ham_func4 : __ham_func5;
  109. if (!F_ISSET(dbp, DB_AM_RDONLY) && !IS_RECOVERING(dbenv) &&
  110.     hashp->h_hash(dbp,
  111.     CHARKEY, sizeof(CHARKEY)) != hcp->hdr->h_charkey) {
  112. __db_err(dbp->dbenv,
  113.     "hash: incompatible hash function");
  114. ret = EINVAL;
  115. goto err2;
  116. }
  117. if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_DUP))
  118. F_SET(dbp, DB_AM_DUP);
  119. if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_DUPSORT))
  120. F_SET(dbp, DB_AM_DUPSORT);
  121. if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_SUBDB))
  122. F_SET(dbp, DB_AM_SUBDB);
  123. /* We must initialize last_pgno, it could be stale. */
  124. if (!F_ISSET(dbp, DB_AM_RDONLY) &&
  125.     dbp->meta_pgno == PGNO_BASE_MD) {
  126. if ((ret = __ham_dirty_meta(dbc)) != 0)
  127. goto err2;
  128. mpf->last_pgno(mpf, &hcp->hdr->dbmeta.last_pgno);
  129. }
  130. } else if (!IS_RECOVERING(dbenv) && !F_ISSET(dbp, DB_AM_RECOVER))
  131. DB_ASSERT(0);
  132. err2: /* Release the meta data page */
  133. if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0)
  134. ret = t_ret;
  135. err1: if ((t_ret  = dbc->c_close(dbc)) != 0 && ret == 0)
  136. ret = t_ret;
  137. return (ret);
  138. }
  139. /*
  140.  * __ham_metachk --
  141.  *
  142.  * PUBLIC: int __ham_metachk __P((DB *, const char *, HMETA *));
  143.  */
  144. int
  145. __ham_metachk(dbp, name, hashm)
  146. DB *dbp;
  147. const char *name;
  148. HMETA *hashm;
  149. {
  150. DB_ENV *dbenv;
  151. u_int32_t vers;
  152. int ret;
  153. dbenv = dbp->dbenv;
  154. /*
  155.  * At this point, all we know is that the magic number is for a Hash.
  156.  * Check the version, the database may be out of date.
  157.  */
  158. vers = hashm->dbmeta.version;
  159. if (F_ISSET(dbp, DB_AM_SWAP))
  160. M_32_SWAP(vers);
  161. switch (vers) {
  162. case 4:
  163. case 5:
  164. case 6:
  165. __db_err(dbenv,
  166.     "%s: hash version %lu requires a version upgrade",
  167.     name, (u_long)vers);
  168. return (DB_OLD_VERSION);
  169. case 7:
  170. case 8:
  171. break;
  172. default:
  173. __db_err(dbenv,
  174.     "%s: unsupported hash version: %lu", name, (u_long)vers);
  175. return (EINVAL);
  176. }
  177. /* Swap the page if we need to. */
  178. if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __ham_mswap((PAGE *)hashm)) != 0)
  179. return (ret);
  180. /* Check the type. */
  181. if (dbp->type != DB_HASH && dbp->type != DB_UNKNOWN)
  182. return (EINVAL);
  183. dbp->type = DB_HASH;
  184. DB_ILLEGAL_METHOD(dbp, DB_OK_HASH);
  185. /*
  186.  * Check application info against metadata info, and set info, flags,
  187.  * and type based on metadata info.
  188.  */
  189. if ((ret = __db_fchk(dbenv,
  190.     "DB->open", hashm->dbmeta.flags,
  191.     DB_HASH_DUP | DB_HASH_SUBDB | DB_HASH_DUPSORT)) != 0)
  192. return (ret);
  193. if (F_ISSET(&hashm->dbmeta, DB_HASH_DUP))
  194. F_SET(dbp, DB_AM_DUP);
  195. else
  196. if (F_ISSET(dbp, DB_AM_DUP)) {
  197. __db_err(dbenv,
  198. "%s: DB_DUP specified to open method but not set in database",
  199.     name);
  200. return (EINVAL);
  201. }
  202. if (F_ISSET(&hashm->dbmeta, DB_HASH_SUBDB))
  203. F_SET(dbp, DB_AM_SUBDB);
  204. else
  205. if (F_ISSET(dbp, DB_AM_SUBDB)) {
  206. __db_err(dbenv,
  207.     "%s: multiple databases specified but not supported in file",
  208. name);
  209. return (EINVAL);
  210. }
  211. if (F_ISSET(&hashm->dbmeta, DB_HASH_DUPSORT)) {
  212. if (dbp->dup_compare == NULL)
  213. dbp->dup_compare = __bam_defcmp;
  214. } else
  215. if (dbp->dup_compare != NULL) {
  216. __db_err(dbenv,
  217. "%s: duplicate sort function specified but not set in database",
  218.     name);
  219. return (EINVAL);
  220. }
  221. /* Set the page size. */
  222. dbp->pgsize = hashm->dbmeta.pagesize;
  223. /* Copy the file's ID. */
  224. memcpy(dbp->fileid, hashm->dbmeta.uid, DB_FILE_ID_LEN);
  225. return (0);
  226. }
  227. /*
  228.  * __ham_init_meta --
  229.  *
  230.  * Initialize a hash meta-data page.  We assume that the meta-data page is
  231.  * contiguous with the initial buckets that we create.  If that turns out
  232.  * to be false, we'll fix it up later.  Return the initial number of buckets
  233.  * allocated.
  234.  */
  235. static db_pgno_t
  236. __ham_init_meta(dbp, meta, pgno, lsnp)
  237. DB *dbp;
  238. HMETA *meta;
  239. db_pgno_t pgno;
  240. DB_LSN *lsnp;
  241. {
  242. HASH *hashp;
  243. db_pgno_t nbuckets;
  244. int i;
  245. int32_t l2;
  246. hashp = dbp->h_internal;
  247. if (hashp->h_hash == NULL)
  248. hashp->h_hash = DB_HASHVERSION < 5 ? __ham_func4 : __ham_func5;
  249. if (hashp->h_nelem != 0 && hashp->h_ffactor != 0) {
  250. hashp->h_nelem = (hashp->h_nelem - 1) / hashp->h_ffactor + 1;
  251. l2 = __db_log2(hashp->h_nelem > 2 ? hashp->h_nelem : 2);
  252. } else
  253. l2 = 1;
  254. nbuckets = (db_pgno_t)(1 << l2);
  255. memset(meta, 0, sizeof(HMETA));
  256. meta->dbmeta.lsn = *lsnp;
  257. meta->dbmeta.pgno = pgno;
  258. meta->dbmeta.magic = DB_HASHMAGIC;
  259. meta->dbmeta.version = DB_HASHVERSION;
  260. meta->dbmeta.pagesize = dbp->pgsize;
  261. if (F_ISSET(dbp, DB_AM_CHKSUM))
  262. FLD_SET(meta->dbmeta.metaflags, DBMETA_CHKSUM);
  263. if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
  264. meta->dbmeta.encrypt_alg =
  265.    ((DB_CIPHER *)dbp->dbenv->crypto_handle)->alg;
  266. DB_ASSERT(meta->dbmeta.encrypt_alg != 0);
  267. meta->crypto_magic = meta->dbmeta.magic;
  268. }
  269. meta->dbmeta.type = P_HASHMETA;
  270. meta->dbmeta.free = PGNO_INVALID;
  271. meta->dbmeta.last_pgno = pgno;
  272. meta->max_bucket = nbuckets - 1;
  273. meta->high_mask = nbuckets - 1;
  274. meta->low_mask = (nbuckets >> 1) - 1;
  275. meta->ffactor = hashp->h_ffactor;
  276. meta->h_charkey = hashp->h_hash(dbp, CHARKEY, sizeof(CHARKEY));
  277. memcpy(meta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN);
  278. if (F_ISSET(dbp, DB_AM_DUP))
  279. F_SET(&meta->dbmeta, DB_HASH_DUP);
  280. if (F_ISSET(dbp, DB_AM_SUBDB))
  281. F_SET(&meta->dbmeta, DB_HASH_SUBDB);
  282. if (dbp->dup_compare != NULL)
  283. F_SET(&meta->dbmeta, DB_HASH_DUPSORT);
  284. /*
  285.  * Create the first and second buckets pages so that we have the
  286.  * page numbers for them and we can store that page number in the
  287.  * meta-data header (spares[0]).
  288.  */
  289. meta->spares[0] = pgno + 1;
  290. /* Fill in the last fields of the meta data page. */
  291. for (i = 1; i <= l2; i++)
  292. meta->spares[i] = meta->spares[0];
  293. for (; i < NCACHED; i++)
  294. meta->spares[i] = PGNO_INVALID;
  295. return (nbuckets);
  296. }
  297. /*
  298.  * __ham_new_file --
  299.  * Create the necessary pages to begin a new database file.  If name
  300.  * is NULL, then this is an unnamed file, the mpf has been set in the dbp
  301.  * and we simply create the pages using mpool.  In this case, we don't log
  302.  * because we never have to redo an unnamed create and the undo simply
  303.  * frees resources.
  304.  *
  305.  * This code appears more complex than it is because of the two cases (named
  306.  * and unnamed).  The way to read the code is that for each page being created,
  307.  * there are three parts: 1) a "get page" chunk (which either uses malloc'd
  308.  * memory or calls mpf->get), 2) the initialization, and 3) the "put page"
  309.  * chunk which either does a fop write or an mpf->put.
  310.  *
  311.  * PUBLIC: int __ham_new_file __P((DB *, DB_TXN *, DB_FH *, const char *));
  312.  */
  313. int
  314. __ham_new_file(dbp, txn, fhp, name)
  315. DB *dbp;
  316. DB_TXN *txn;
  317. DB_FH *fhp;
  318. const char *name;
  319. {
  320. DB_ENV *dbenv;
  321. DB_LSN lsn;
  322. DB_MPOOLFILE *mpf;
  323. DB_PGINFO pginfo;
  324. DBT pdbt;
  325. HMETA *meta;
  326. PAGE *page;
  327. int ret;
  328. db_pgno_t lpgno;
  329. void *buf;
  330. dbenv = dbp->dbenv;
  331. mpf = dbp->mpf;
  332. meta = NULL;
  333. page = NULL;
  334. memset(&pdbt, 0, sizeof(pdbt));
  335. /* Build meta-data page. */
  336. if (name == NULL) {
  337. lpgno = PGNO_BASE_MD;
  338. ret = mpf->get(mpf, &lpgno, DB_MPOOL_CREATE, &meta);
  339. } else {
  340. pginfo.db_pagesize = dbp->pgsize;
  341. pginfo.type = dbp->type;
  342. pginfo.flags =
  343.     F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));
  344. pdbt.data = &pginfo;
  345. pdbt.size = sizeof(pginfo);
  346. ret = __os_calloc(dbp->dbenv, 1, dbp->pgsize, &buf);
  347. meta = (HMETA *)buf;
  348. }
  349. if (ret != 0)
  350. return (ret);
  351. LSN_NOT_LOGGED(lsn);
  352. lpgno = __ham_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
  353. meta->dbmeta.last_pgno = lpgno;
  354. if (name == NULL)
  355. ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY);
  356. else {
  357. if ((ret = __db_pgout(dbenv, PGNO_BASE_MD, meta, &pdbt)) != 0)
  358. goto err;
  359. ret = __fop_write(dbenv, txn, name,
  360.     DB_APP_DATA, fhp, 0, buf, dbp->pgsize, 1);
  361. }
  362. if (ret != 0)
  363. goto err;
  364. meta = NULL;
  365. /* Now allocate the final hash bucket. */
  366. if (name == NULL) {
  367. if ((ret = mpf->get(mpf, &lpgno, DB_MPOOL_CREATE, &page)) != 0)
  368. goto err;
  369. } else {
  370. #ifdef DIAGNOSTIC
  371. memset(buf, 0, dbp->pgsize);
  372. #endif
  373. page = (PAGE *)buf;
  374. }
  375. P_INIT(page, dbp->pgsize, lpgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
  376. LSN_NOT_LOGGED(page->lsn);
  377. if (name == NULL)
  378. ret = mpf->put(mpf, page, DB_MPOOL_DIRTY);
  379. else {
  380. if ((ret = __db_pgout(dbenv, lpgno, buf, &pdbt)) != 0)
  381. goto err;
  382. ret = __fop_write(dbenv, txn, name,
  383.     DB_APP_DATA, fhp, lpgno * dbp->pgsize, buf, dbp->pgsize, 1);
  384. }
  385. if (ret != 0)
  386. goto err;
  387. page = NULL;
  388. err: if (name != NULL)
  389. __os_free(dbenv, buf);
  390. else {
  391. if (meta != NULL)
  392. (void)mpf->put(mpf, meta, 0);
  393. if (page != NULL)
  394. (void)mpf->put(mpf, page, 0);
  395. }
  396. return (ret);
  397. }
  398. /*
  399.  * __ham_new_subdb --
  400.  * Create the necessary pages to begin a new subdatabase.
  401.  *
  402.  * PUBLIC: int __ham_new_subdb __P((DB *, DB *, DB_TXN *));
  403.  */
  404. int
  405. __ham_new_subdb(mdbp, dbp, txn)
  406. DB *mdbp, *dbp;
  407. DB_TXN *txn;
  408. {
  409. DBC *dbc;
  410. DB_ENV *dbenv;
  411. DB_LOCK metalock, mmlock;
  412. DB_LSN lsn;
  413. DB_MPOOLFILE *mpf;
  414. DBMETA *mmeta;
  415. HMETA *meta;
  416. PAGE *h;
  417. int i, ret, t_ret;
  418. db_pgno_t lpgno, mpgno;
  419. dbenv = mdbp->dbenv;
  420. mpf = mdbp->mpf;
  421. dbc = NULL;
  422. meta = NULL;
  423. mmeta = NULL;
  424. LOCK_INIT(metalock);
  425. LOCK_INIT(mmlock);
  426. if ((ret = mdbp->cursor(mdbp, txn,
  427.     &dbc, CDB_LOCKING(dbenv) ?  DB_WRITECURSOR : 0)) != 0)
  428. return (ret);
  429. /* Get and lock the new meta data page. */
  430. if ((ret = __db_lget(dbc,
  431.     0, dbp->meta_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
  432. goto err;
  433. if ((ret = mpf->get(mpf, &dbp->meta_pgno, DB_MPOOL_CREATE, &meta)) != 0)
  434. goto err;
  435. /* Initialize the new meta-data page. */
  436. lsn = meta->dbmeta.lsn;
  437. lpgno = __ham_init_meta(dbp, meta, dbp->meta_pgno, &lsn);
  438. /*
  439.  * We are about to allocate a set of contiguous buckets (lpgno
  440.  * worth).  We need to get the master meta-data page to figure
  441.  * out where these pages are and to allocate them.  So, lock and
  442.  * get the master meta data page.
  443.  */
  444. mpgno = PGNO_BASE_MD;
  445. if ((ret = __db_lget(dbc, 0, mpgno, DB_LOCK_WRITE, 0, &mmlock)) != 0)
  446. goto err;
  447. if ((ret = mpf->get(mpf, &mpgno, 0, &mmeta)) != 0)
  448. goto err;
  449. /*
  450.  * Now update the hash meta-data page to reflect where the first
  451.  * set of buckets are actually located.
  452.  */
  453. meta->spares[0] = mmeta->last_pgno + 1;
  454. for (i = 0; i < NCACHED && meta->spares[i] != PGNO_INVALID; i++)
  455. meta->spares[i] = meta->spares[0];
  456. /* The new meta data page is now complete; log it. */
  457. if ((ret = __db_log_page(mdbp,
  458.     txn, &meta->dbmeta.lsn, dbp->meta_pgno, (PAGE *)meta)) != 0)
  459. goto err;
  460. /* Reflect the group allocation. */
  461. if (DBENV_LOGGING(dbenv))
  462. if ((ret = __ham_groupalloc_log(mdbp, txn,
  463.     &LSN(mmeta), 0, &LSN(mmeta),
  464.     meta->spares[0], meta->max_bucket + 1, mmeta->free)) != 0)
  465. goto err;
  466. /* Release the new meta-data page. */
  467. if ((ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY)) != 0)
  468. goto err;
  469. meta = NULL;
  470. mmeta->last_pgno +=lpgno;
  471. lpgno = mmeta->last_pgno;
  472. /* Now allocate the final hash bucket. */
  473. if ((ret = mpf->get(mpf, &lpgno, DB_MPOOL_CREATE, &h)) != 0)
  474. goto err;
  475. P_INIT(h, dbp->pgsize, lpgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
  476. LSN(h) = LSN(mmeta);
  477. if ((ret = mpf->put(mpf, h, DB_MPOOL_DIRTY)) != 0)
  478. goto err;
  479. /* Now put the master-metadata page back. */
  480. if ((ret = mpf->put(mpf, mmeta, DB_MPOOL_DIRTY)) != 0)
  481. goto err;
  482. mmeta = NULL;
  483. err:
  484. if (mmeta != NULL)
  485. if ((t_ret = mpf->put(mpf, mmeta, 0)) != 0 && ret == 0)
  486. ret = t_ret;
  487. if (LOCK_ISSET(mmlock))
  488. if ((t_ret = __LPUT(dbc, mmlock)) != 0 && ret == 0)
  489. ret = t_ret;
  490. if (meta != NULL)
  491. if ((t_ret = mpf->put(mpf, meta, 0)) != 0 && ret == 0)
  492. ret = t_ret;
  493. if (LOCK_ISSET(metalock))
  494. if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
  495. ret = t_ret;
  496. if (dbc != NULL)
  497. if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  498. ret = t_ret;
  499. return (ret);
  500. }