00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include "db_config.h"
00046
00047 #ifndef NO_SYSTEM_INCLUDES
00048 #include <sys/types.h>
00049
00050 #include <string.h>
00051 #endif
00052
00053 #include "db_int.h"
00054 #include "dbinc/crypto.h"
00055 #include "dbinc/db_page.h"
00056 #include "dbinc/hash.h"
00057 #include "dbinc/log.h"
00058 #include "dbinc/db_shash.h"
00059 #include "dbinc/lock.h"
00060 #include "dbinc/mp.h"
00061 #include "dbinc/btree.h"
00062 #include "dbinc/fop.h"
00063
00064 static db_pgno_t __ham_init_meta __P((DB *, HMETA *, db_pgno_t, DB_LSN *));
00065
00066
00067
00068
00069
00070
00071
00072 int
00073 __ham_open(dbp, txn, name, base_pgno, flags)
00074 DB *dbp;
00075 DB_TXN *txn;
00076 const char *name;
00077 db_pgno_t base_pgno;
00078 u_int32_t flags;
00079 {
00080 DB_ENV *dbenv;
00081 DBC *dbc;
00082 HASH_CURSOR *hcp;
00083 HASH *hashp;
00084 int ret, t_ret;
00085
00086 dbenv = dbp->dbenv;
00087 dbc = NULL;
00088
00089
00090
00091
00092
00093
00094
00095 if ((ret = __db_cursor(dbp,
00096 txn, &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbenv) ?
00097 DB_WRITECURSOR : 0)) != 0)
00098 return (ret);
00099
00100 hcp = (HASH_CURSOR *)dbc->internal;
00101 hashp = dbp->h_internal;
00102 hashp->meta_pgno = base_pgno;
00103 if ((ret = __ham_get_meta(dbc)) != 0)
00104 goto err1;
00105
00106
00107 if (hcp->hdr->dbmeta.magic == DB_HASHMAGIC) {
00108
00109 if (hashp->h_hash == NULL)
00110 hashp->h_hash = hcp->hdr->dbmeta.version < 5
00111 ? __ham_func4 : __ham_func5;
00112 if (!F_ISSET(dbp, DB_AM_RDONLY) && !IS_RECOVERING(dbenv) &&
00113 hashp->h_hash(dbp,
00114 CHARKEY, sizeof(CHARKEY)) != hcp->hdr->h_charkey) {
00115 __db_err(dbp->dbenv,
00116 "hash: incompatible hash function");
00117 ret = EINVAL;
00118 goto err2;
00119 }
00120 hashp->h_nelem = hcp->hdr->nelem;
00121 if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_DUP))
00122 F_SET(dbp, DB_AM_DUP);
00123 if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_DUPSORT))
00124 F_SET(dbp, DB_AM_DUPSORT);
00125 if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_SUBDB))
00126 F_SET(dbp, DB_AM_SUBDB);
00127
00128 } else if (!IS_RECOVERING(dbenv) && !F_ISSET(dbp, DB_AM_RECOVER)) {
00129 __db_err(dbp->dbenv,
00130 "%s: Invalid hash meta page %d", name, base_pgno);
00131 ret = EINVAL;
00132 }
00133
00134 err2:
00135 if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0)
00136 ret = t_ret;
00137 err1: if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00138 ret = t_ret;
00139
00140 return (ret);
00141 }
00142
00143
00144
00145
00146
00147
00148 int
00149 __ham_metachk(dbp, name, hashm)
00150 DB *dbp;
00151 const char *name;
00152 HMETA *hashm;
00153 {
00154 DB_ENV *dbenv;
00155 u_int32_t vers;
00156 int ret;
00157
00158 dbenv = dbp->dbenv;
00159
00160
00161
00162
00163
00164 vers = hashm->dbmeta.version;
00165 if (F_ISSET(dbp, DB_AM_SWAP))
00166 M_32_SWAP(vers);
00167 switch (vers) {
00168 case 4:
00169 case 5:
00170 case 6:
00171 __db_err(dbenv,
00172 "%s: hash version %lu requires a version upgrade",
00173 name, (u_long)vers);
00174 return (DB_OLD_VERSION);
00175 case 7:
00176 case 8:
00177 break;
00178 default:
00179 __db_err(dbenv,
00180 "%s: unsupported hash version: %lu", name, (u_long)vers);
00181 return (EINVAL);
00182 }
00183
00184
00185 if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __ham_mswap((PAGE *)hashm)) != 0)
00186 return (ret);
00187
00188
00189 if (dbp->type != DB_HASH && dbp->type != DB_UNKNOWN)
00190 return (EINVAL);
00191 dbp->type = DB_HASH;
00192 DB_ILLEGAL_METHOD(dbp, DB_OK_HASH);
00193
00194
00195
00196
00197
00198 if ((ret = __db_fchk(dbenv,
00199 "DB->open", hashm->dbmeta.flags,
00200 DB_HASH_DUP | DB_HASH_SUBDB | DB_HASH_DUPSORT)) != 0)
00201 return (ret);
00202
00203 if (F_ISSET(&hashm->dbmeta, DB_HASH_DUP))
00204 F_SET(dbp, DB_AM_DUP);
00205 else
00206 if (F_ISSET(dbp, DB_AM_DUP)) {
00207 __db_err(dbenv,
00208 "%s: DB_DUP specified to open method but not set in database",
00209 name);
00210 return (EINVAL);
00211 }
00212
00213 if (F_ISSET(&hashm->dbmeta, DB_HASH_SUBDB))
00214 F_SET(dbp, DB_AM_SUBDB);
00215 else
00216 if (F_ISSET(dbp, DB_AM_SUBDB)) {
00217 __db_err(dbenv,
00218 "%s: multiple databases specified but not supported in file",
00219 name);
00220 return (EINVAL);
00221 }
00222
00223 if (F_ISSET(&hashm->dbmeta, DB_HASH_DUPSORT)) {
00224 if (dbp->dup_compare == NULL)
00225 dbp->dup_compare = __bam_defcmp;
00226 } else
00227 if (dbp->dup_compare != NULL) {
00228 __db_err(dbenv,
00229 "%s: duplicate sort function specified but not set in database",
00230 name);
00231 return (EINVAL);
00232 }
00233
00234
00235 dbp->pgsize = hashm->dbmeta.pagesize;
00236
00237
00238 memcpy(dbp->fileid, hashm->dbmeta.uid, DB_FILE_ID_LEN);
00239
00240 return (0);
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 static db_pgno_t
00252 __ham_init_meta(dbp, meta, pgno, lsnp)
00253 DB *dbp;
00254 HMETA *meta;
00255 db_pgno_t pgno;
00256 DB_LSN *lsnp;
00257 {
00258 HASH *hashp;
00259 db_pgno_t nbuckets;
00260 u_int i, l2;
00261
00262 hashp = dbp->h_internal;
00263 if (hashp->h_hash == NULL)
00264 hashp->h_hash = DB_HASHVERSION < 5 ? __ham_func4 : __ham_func5;
00265
00266 if (hashp->h_nelem != 0 && hashp->h_ffactor != 0) {
00267 hashp->h_nelem = (hashp->h_nelem - 1) / hashp->h_ffactor + 1;
00268 l2 = __db_log2(hashp->h_nelem > 2 ? hashp->h_nelem : 2);
00269 } else
00270 l2 = 1;
00271 nbuckets = (db_pgno_t)(1 << l2);
00272
00273 memset(meta, 0, sizeof(HMETA));
00274 meta->dbmeta.lsn = *lsnp;
00275 meta->dbmeta.pgno = pgno;
00276 meta->dbmeta.magic = DB_HASHMAGIC;
00277 meta->dbmeta.version = DB_HASHVERSION;
00278 meta->dbmeta.pagesize = dbp->pgsize;
00279 if (F_ISSET(dbp, DB_AM_CHKSUM))
00280 FLD_SET(meta->dbmeta.metaflags, DBMETA_CHKSUM);
00281 if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
00282 meta->dbmeta.encrypt_alg =
00283 ((DB_CIPHER *)dbp->dbenv->crypto_handle)->alg;
00284 DB_ASSERT(meta->dbmeta.encrypt_alg != 0);
00285 meta->crypto_magic = meta->dbmeta.magic;
00286 }
00287 meta->dbmeta.type = P_HASHMETA;
00288 meta->dbmeta.free = PGNO_INVALID;
00289 meta->dbmeta.last_pgno = pgno;
00290 meta->max_bucket = nbuckets - 1;
00291 meta->high_mask = nbuckets - 1;
00292 meta->low_mask = (nbuckets >> 1) - 1;
00293 meta->ffactor = hashp->h_ffactor;
00294 meta->nelem = hashp->h_nelem;
00295 meta->h_charkey = hashp->h_hash(dbp, CHARKEY, sizeof(CHARKEY));
00296 memcpy(meta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN);
00297
00298 if (F_ISSET(dbp, DB_AM_DUP))
00299 F_SET(&meta->dbmeta, DB_HASH_DUP);
00300 if (F_ISSET(dbp, DB_AM_SUBDB))
00301 F_SET(&meta->dbmeta, DB_HASH_SUBDB);
00302 if (dbp->dup_compare != NULL)
00303 F_SET(&meta->dbmeta, DB_HASH_DUPSORT);
00304
00305
00306
00307
00308
00309
00310 meta->spares[0] = pgno + 1;
00311
00312
00313 for (i = 1; i <= l2; i++)
00314 meta->spares[i] = meta->spares[0];
00315 for (; i < NCACHED; i++)
00316 meta->spares[i] = PGNO_INVALID;
00317
00318 return (nbuckets);
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 int
00338 __ham_new_file(dbp, txn, fhp, name)
00339 DB *dbp;
00340 DB_TXN *txn;
00341 DB_FH *fhp;
00342 const char *name;
00343 {
00344 DB_ENV *dbenv;
00345 DB_LSN lsn;
00346 DB_MPOOLFILE *mpf;
00347 DB_PGINFO pginfo;
00348 DBT pdbt;
00349 HMETA *meta;
00350 PAGE *page;
00351 int ret;
00352 db_pgno_t lpgno;
00353 void *buf;
00354
00355 dbenv = dbp->dbenv;
00356 mpf = dbp->mpf;
00357 meta = NULL;
00358 page = NULL;
00359 buf = NULL;
00360
00361 if (F_ISSET(dbp, DB_AM_INMEM)) {
00362
00363 lpgno = PGNO_BASE_MD;
00364 if ((ret =
00365 __memp_fget(mpf, &lpgno, DB_MPOOL_CREATE, &meta)) != 0)
00366 return (ret);
00367 LSN_NOT_LOGGED(lsn);
00368 lpgno = __ham_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
00369 meta->dbmeta.last_pgno = lpgno;
00370 if ((ret = __db_log_page(dbp,
00371 txn, &lsn, meta->dbmeta.pgno, (PAGE *)meta)) != 0)
00372 goto err;
00373 ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY);
00374 meta = NULL;
00375 if (ret != 0)
00376 goto err;
00377
00378
00379 if ((ret =
00380 __memp_fget(mpf, &lpgno, DB_MPOOL_CREATE, &page)) != 0)
00381 goto err;
00382 P_INIT(page,
00383 dbp->pgsize, lpgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
00384 LSN_NOT_LOGGED(page->lsn);
00385 if ((ret =
00386 __db_log_page(dbp, txn, &page->lsn, lpgno, page)) != 0)
00387 goto err;
00388 ret = __memp_fput(mpf, page, DB_MPOOL_DIRTY);
00389 page = NULL;
00390 if (ret != 0)
00391 goto err;
00392 } else {
00393 memset(&pdbt, 0, sizeof(pdbt));
00394
00395
00396 pginfo.db_pagesize = dbp->pgsize;
00397 pginfo.type = dbp->type;
00398 pginfo.flags =
00399 F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));
00400 pdbt.data = &pginfo;
00401 pdbt.size = sizeof(pginfo);
00402 if ((ret = __os_calloc(dbp->dbenv, 1, dbp->pgsize, &buf)) != 0)
00403 return (ret);
00404 meta = (HMETA *)buf;
00405 LSN_NOT_LOGGED(lsn);
00406 lpgno = __ham_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
00407 meta->dbmeta.last_pgno = lpgno;
00408 if ((ret = __db_pgout(dbenv, PGNO_BASE_MD, meta, &pdbt)) != 0)
00409 goto err;
00410 if ((ret = __fop_write(dbenv, txn, name, DB_APP_DATA, fhp,
00411 dbp->pgsize, 0, 0, buf, dbp->pgsize, 1, F_ISSET(
00412 dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0)) != 0)
00413 goto err;
00414 meta = NULL;
00415
00416
00417 #ifdef DIAGNOSTIC
00418 memset(buf, 0, dbp->pgsize);
00419 #endif
00420 page = (PAGE *)buf;
00421 P_INIT(page,
00422 dbp->pgsize, lpgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
00423 LSN_NOT_LOGGED(page->lsn);
00424 if ((ret = __db_pgout(dbenv, lpgno, buf, &pdbt)) != 0)
00425 goto err;
00426 if ((ret = __fop_write(dbenv, txn, name, DB_APP_DATA, fhp,
00427 dbp->pgsize, lpgno, 0, buf, dbp->pgsize, 1, F_ISSET(
00428 dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0)) != 0)
00429 goto err;
00430 page = NULL;
00431 }
00432
00433 err: if (buf != NULL)
00434 __os_free(dbenv, buf);
00435 else {
00436 if (meta != NULL)
00437 (void)__memp_fput(mpf, meta, 0);
00438 if (page != NULL)
00439 (void)__memp_fput(mpf, page, 0);
00440 }
00441 return (ret);
00442 }
00443
00444
00445
00446
00447
00448
00449
00450 int
00451 __ham_new_subdb(mdbp, dbp, txn)
00452 DB *mdbp, *dbp;
00453 DB_TXN *txn;
00454 {
00455 DBC *dbc;
00456 DB_ENV *dbenv;
00457 DB_LOCK metalock, mmlock;
00458 DB_LSN lsn;
00459 DB_MPOOLFILE *mpf;
00460 DBMETA *mmeta;
00461 HMETA *meta;
00462 PAGE *h;
00463 int i, ret, t_ret;
00464 db_pgno_t lpgno, mpgno;
00465
00466 dbenv = mdbp->dbenv;
00467 mpf = mdbp->mpf;
00468 dbc = NULL;
00469 meta = NULL;
00470 mmeta = NULL;
00471 LOCK_INIT(metalock);
00472 LOCK_INIT(mmlock);
00473
00474 if ((ret = __db_cursor(mdbp, txn,
00475 &dbc, CDB_LOCKING(dbenv) ? DB_WRITECURSOR : 0)) != 0)
00476 return (ret);
00477
00478
00479 if ((ret = __db_lget(dbc,
00480 0, dbp->meta_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
00481 goto err;
00482 if ((ret =
00483 __memp_fget(mpf, &dbp->meta_pgno, DB_MPOOL_CREATE, &meta)) != 0)
00484 goto err;
00485
00486
00487 lsn = meta->dbmeta.lsn;
00488 lpgno = __ham_init_meta(dbp, meta, dbp->meta_pgno, &lsn);
00489
00490
00491
00492
00493
00494
00495
00496 mpgno = PGNO_BASE_MD;
00497 if ((ret = __db_lget(dbc, 0, mpgno, DB_LOCK_WRITE, 0, &mmlock)) != 0)
00498 goto err;
00499 if ((ret = __memp_fget(mpf, &mpgno, 0, &mmeta)) != 0)
00500 goto err;
00501
00502
00503
00504
00505
00506 meta->spares[0] = mmeta->last_pgno + 1;
00507 for (i = 0; i < NCACHED && meta->spares[i] != PGNO_INVALID; i++)
00508 meta->spares[i] = meta->spares[0];
00509
00510
00511 if ((ret = __db_log_page(mdbp,
00512 txn, &meta->dbmeta.lsn, dbp->meta_pgno, (PAGE *)meta)) != 0)
00513 goto err;
00514
00515
00516 if (DBENV_LOGGING(dbenv))
00517 if ((ret = __ham_groupalloc_log(mdbp, txn,
00518 &LSN(mmeta), 0, &LSN(mmeta), meta->spares[0],
00519 meta->max_bucket + 1, mmeta->free, mmeta->last_pgno)) != 0)
00520 goto err;
00521
00522
00523 if ((ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY)) != 0)
00524 goto err;
00525 meta = NULL;
00526
00527 lpgno += mmeta->last_pgno;
00528
00529
00530 if ((ret = __memp_fget(mpf, &lpgno, DB_MPOOL_CREATE, &h)) != 0)
00531 goto err;
00532
00533 mmeta->last_pgno = lpgno;
00534 P_INIT(h, dbp->pgsize, lpgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
00535 LSN(h) = LSN(mmeta);
00536 if ((ret = __memp_fput(mpf, h, DB_MPOOL_DIRTY)) != 0)
00537 goto err;
00538
00539
00540 if ((ret = __memp_fput(mpf, mmeta, DB_MPOOL_DIRTY)) != 0)
00541 goto err;
00542 mmeta = NULL;
00543
00544 err:
00545 if (mmeta != NULL)
00546 if ((t_ret = __memp_fput(mpf, mmeta, 0)) != 0 && ret == 0)
00547 ret = t_ret;
00548 if ((t_ret = __LPUT(dbc, mmlock)) != 0 && ret == 0)
00549 ret = t_ret;
00550 if (meta != NULL)
00551 if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
00552 ret = t_ret;
00553 if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
00554 ret = t_ret;
00555 if (dbc != NULL)
00556 if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00557 ret = t_ret;
00558 return (ret);
00559 }