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/db_swap.h"
00057 #include "dbinc/btree.h"
00058 #include "dbinc/db_shash.h"
00059 #include "dbinc/lock.h"
00060 #include "dbinc/log.h"
00061 #include "dbinc/mp.h"
00062 #include "dbinc/fop.h"
00063
00064 static void __bam_init_meta __P((DB *, BTMETA *, db_pgno_t, DB_LSN *));
00065
00066
00067
00068
00069
00070
00071
00072
00073 int
00074 __bam_open(dbp, txn, name, base_pgno, flags)
00075 DB *dbp;
00076 DB_TXN *txn;
00077 const char *name;
00078 db_pgno_t base_pgno;
00079 u_int32_t flags;
00080 {
00081 BTREE *t;
00082
00083 COMPQUIET(name, NULL);
00084 t = dbp->bt_internal;
00085
00086
00087
00088
00089
00090
00091 if (t->bt_compare == __bam_defcmp && t->bt_prefix != __bam_defpfx) {
00092 __db_err(dbp->dbenv,
00093 "prefix comparison may not be specified for default comparison routine");
00094 return (EINVAL);
00095 }
00096
00097
00098
00099
00100
00101 if (B_MINKEY_TO_OVFLSIZE(dbp, t->bt_minkey, dbp->pgsize) >
00102 B_MINKEY_TO_OVFLSIZE(dbp, DEFMINKEYPAGE, dbp->pgsize)) {
00103 __db_err(dbp->dbenv,
00104 "bt_minkey value of %lu too high for page size of %lu",
00105 (u_long)t->bt_minkey, (u_long)dbp->pgsize);
00106 return (EINVAL);
00107 }
00108
00109
00110 return (__bam_read_root(dbp, txn, base_pgno, flags));
00111 }
00112
00113
00114
00115
00116
00117
00118 int
00119 __bam_metachk(dbp, name, btm)
00120 DB *dbp;
00121 const char *name;
00122 BTMETA *btm;
00123 {
00124 DB_ENV *dbenv;
00125 u_int32_t vers;
00126 int ret;
00127
00128 dbenv = dbp->dbenv;
00129
00130
00131
00132
00133
00134 vers = btm->dbmeta.version;
00135 if (F_ISSET(dbp, DB_AM_SWAP))
00136 M_32_SWAP(vers);
00137 switch (vers) {
00138 case 6:
00139 case 7:
00140 __db_err(dbenv,
00141 "%s: btree version %lu requires a version upgrade",
00142 name, (u_long)vers);
00143 return (DB_OLD_VERSION);
00144 case 8:
00145 case 9:
00146 break;
00147 default:
00148 __db_err(dbenv,
00149 "%s: unsupported btree version: %lu", name, (u_long)vers);
00150 return (EINVAL);
00151 }
00152
00153
00154 if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __bam_mswap((PAGE *)btm)) != 0)
00155 return (ret);
00156
00157
00158
00159
00160
00161 if ((ret =
00162 __db_fchk(dbenv, "DB->open", btm->dbmeta.flags, BTM_MASK)) != 0)
00163 return (ret);
00164
00165 if (F_ISSET(&btm->dbmeta, BTM_RECNO)) {
00166 if (dbp->type == DB_BTREE)
00167 goto wrong_type;
00168 dbp->type = DB_RECNO;
00169 DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
00170 } else {
00171 if (dbp->type == DB_RECNO)
00172 goto wrong_type;
00173 dbp->type = DB_BTREE;
00174 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
00175 }
00176
00177 if (F_ISSET(&btm->dbmeta, BTM_DUP))
00178 F_SET(dbp, DB_AM_DUP);
00179 else
00180 if (F_ISSET(dbp, DB_AM_DUP)) {
00181 __db_err(dbenv,
00182 "%s: DB_DUP specified to open method but not set in database",
00183 name);
00184 return (EINVAL);
00185 }
00186
00187 if (F_ISSET(&btm->dbmeta, BTM_RECNUM)) {
00188 if (dbp->type != DB_BTREE)
00189 goto wrong_type;
00190 F_SET(dbp, DB_AM_RECNUM);
00191
00192 if ((ret = __db_fcchk(dbenv,
00193 "DB->open", dbp->flags, DB_AM_DUP, DB_AM_RECNUM)) != 0)
00194 return (ret);
00195 } else
00196 if (F_ISSET(dbp, DB_AM_RECNUM)) {
00197 __db_err(dbenv,
00198 "%s: DB_RECNUM specified to open method but not set in database",
00199 name);
00200 return (EINVAL);
00201 }
00202
00203 if (F_ISSET(&btm->dbmeta, BTM_FIXEDLEN)) {
00204 if (dbp->type != DB_RECNO)
00205 goto wrong_type;
00206 F_SET(dbp, DB_AM_FIXEDLEN);
00207 } else
00208 if (F_ISSET(dbp, DB_AM_FIXEDLEN)) {
00209 __db_err(dbenv,
00210 "%s: DB_FIXEDLEN specified to open method but not set in database",
00211 name);
00212 return (EINVAL);
00213 }
00214
00215 if (F_ISSET(&btm->dbmeta, BTM_RENUMBER)) {
00216 if (dbp->type != DB_RECNO)
00217 goto wrong_type;
00218 F_SET(dbp, DB_AM_RENUMBER);
00219 } else
00220 if (F_ISSET(dbp, DB_AM_RENUMBER)) {
00221 __db_err(dbenv,
00222 "%s: DB_RENUMBER specified to open method but not set in database",
00223 name);
00224 return (EINVAL);
00225 }
00226
00227 if (F_ISSET(&btm->dbmeta, BTM_SUBDB))
00228 F_SET(dbp, DB_AM_SUBDB);
00229 else
00230 if (F_ISSET(dbp, DB_AM_SUBDB)) {
00231 __db_err(dbenv,
00232 "%s: multiple databases specified but not supported by file",
00233 name);
00234 return (EINVAL);
00235 }
00236
00237 if (F_ISSET(&btm->dbmeta, BTM_DUPSORT)) {
00238 if (dbp->dup_compare == NULL)
00239 dbp->dup_compare = __bam_defcmp;
00240 F_SET(dbp, DB_AM_DUPSORT);
00241 } else
00242 if (dbp->dup_compare != NULL) {
00243 __db_err(dbenv,
00244 "%s: duplicate sort specified but not supported in database",
00245 name);
00246 return (EINVAL);
00247 }
00248
00249
00250 dbp->pgsize = btm->dbmeta.pagesize;
00251
00252
00253 memcpy(dbp->fileid, btm->dbmeta.uid, DB_FILE_ID_LEN);
00254
00255 return (0);
00256
00257 wrong_type:
00258 if (dbp->type == DB_BTREE)
00259 __db_err(dbenv,
00260 "open method type is Btree, database type is Recno");
00261 else
00262 __db_err(dbenv,
00263 "open method type is Recno, database type is Btree");
00264 return (EINVAL);
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 int
00274 __bam_read_root(dbp, txn, base_pgno, flags)
00275 DB *dbp;
00276 DB_TXN *txn;
00277 db_pgno_t base_pgno;
00278 u_int32_t flags;
00279 {
00280 BTMETA *meta;
00281 BTREE *t;
00282 DBC *dbc;
00283 DB_LOCK metalock;
00284 DB_MPOOLFILE *mpf;
00285 int ret, t_ret;
00286
00287 COMPQUIET(flags, 0);
00288 meta = NULL;
00289 t = dbp->bt_internal;
00290 LOCK_INIT(metalock);
00291 mpf = dbp->mpf;
00292 ret = 0;
00293
00294
00295 if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
00296 return (ret);
00297
00298
00299 if ((ret =
00300 __db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0)
00301 goto err;
00302 if ((ret = __memp_fget(mpf, &base_pgno, 0, &meta)) != 0)
00303 goto err;
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 if (meta->dbmeta.magic == DB_BTREEMAGIC) {
00314 t->bt_minkey = meta->minkey;
00315 t->re_pad = (int)meta->re_pad;
00316 t->re_len = meta->re_len;
00317
00318 t->bt_meta = base_pgno;
00319 t->bt_root = meta->root;
00320 } else {
00321 DB_ASSERT(IS_RECOVERING(dbp->dbenv) ||
00322 F_ISSET(dbp, DB_AM_RECOVER));
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 t->bt_lpgno = PGNO_INVALID;
00335
00336 err:
00337 if (meta != NULL &&
00338 (t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
00339 ret = t_ret;
00340 if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
00341 ret = t_ret;
00342
00343 if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00344 ret = t_ret;
00345 return (ret);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354 static void
00355 __bam_init_meta(dbp, meta, pgno, lsnp)
00356 DB *dbp;
00357 BTMETA *meta;
00358 db_pgno_t pgno;
00359 DB_LSN *lsnp;
00360 {
00361 BTREE *t;
00362
00363 memset(meta, 0, sizeof(BTMETA));
00364 meta->dbmeta.lsn = *lsnp;
00365 meta->dbmeta.pgno = pgno;
00366 meta->dbmeta.magic = DB_BTREEMAGIC;
00367 meta->dbmeta.version = DB_BTREEVERSION;
00368 meta->dbmeta.pagesize = dbp->pgsize;
00369 if (F_ISSET(dbp, DB_AM_CHKSUM))
00370 FLD_SET(meta->dbmeta.metaflags, DBMETA_CHKSUM);
00371 if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
00372 meta->dbmeta.encrypt_alg =
00373 ((DB_CIPHER *)dbp->dbenv->crypto_handle)->alg;
00374 DB_ASSERT(meta->dbmeta.encrypt_alg != 0);
00375 meta->crypto_magic = meta->dbmeta.magic;
00376 }
00377 meta->dbmeta.type = P_BTREEMETA;
00378 meta->dbmeta.free = PGNO_INVALID;
00379 meta->dbmeta.last_pgno = pgno;
00380 if (F_ISSET(dbp, DB_AM_DUP))
00381 F_SET(&meta->dbmeta, BTM_DUP);
00382 if (F_ISSET(dbp, DB_AM_FIXEDLEN))
00383 F_SET(&meta->dbmeta, BTM_FIXEDLEN);
00384 if (F_ISSET(dbp, DB_AM_RECNUM))
00385 F_SET(&meta->dbmeta, BTM_RECNUM);
00386 if (F_ISSET(dbp, DB_AM_RENUMBER))
00387 F_SET(&meta->dbmeta, BTM_RENUMBER);
00388 if (F_ISSET(dbp, DB_AM_SUBDB))
00389 F_SET(&meta->dbmeta, BTM_SUBDB);
00390 if (dbp->dup_compare != NULL)
00391 F_SET(&meta->dbmeta, BTM_DUPSORT);
00392 if (dbp->type == DB_RECNO)
00393 F_SET(&meta->dbmeta, BTM_RECNO);
00394 memcpy(meta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN);
00395
00396 t = dbp->bt_internal;
00397 meta->minkey = t->bt_minkey;
00398 meta->re_len = t->re_len;
00399 meta->re_pad = (u_int32_t)t->re_pad;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 int
00415 __bam_new_file(dbp, txn, fhp, name)
00416 DB *dbp;
00417 DB_TXN *txn;
00418 DB_FH *fhp;
00419 const char *name;
00420 {
00421 BTMETA *meta;
00422 DB_ENV *dbenv;
00423 DB_LSN lsn;
00424 DB_MPOOLFILE *mpf;
00425 DB_PGINFO pginfo;
00426 DBT pdbt;
00427 PAGE *root;
00428 db_pgno_t pgno;
00429 int ret, t_ret;
00430 void *buf;
00431
00432 dbenv = dbp->dbenv;
00433 mpf = dbp->mpf;
00434 root = NULL;
00435 meta = NULL;
00436 buf = NULL;
00437
00438 if (F_ISSET(dbp, DB_AM_INMEM)) {
00439
00440 pgno = PGNO_BASE_MD;
00441 if ((ret =
00442 __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &meta)) != 0)
00443 return (ret);
00444 LSN_NOT_LOGGED(lsn);
00445 __bam_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
00446 meta->root = 1;
00447 meta->dbmeta.last_pgno = 1;
00448 if ((ret =
00449 __db_log_page(dbp, txn, &lsn, pgno, (PAGE *)meta)) != 0)
00450 goto err;
00451 ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY);
00452 meta = NULL;
00453 if (ret != 0)
00454 goto err;
00455
00456
00457 pgno = 1;
00458 if ((ret =
00459 __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &root)) != 0)
00460 goto err;
00461 P_INIT(root, dbp->pgsize, 1, PGNO_INVALID, PGNO_INVALID,
00462 LEAFLEVEL, dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE);
00463 LSN_NOT_LOGGED(root->lsn);
00464 if ((ret =
00465 __db_log_page(dbp, txn, &root->lsn, pgno, root)) != 0)
00466 goto err;
00467 ret = __memp_fput(mpf, root, DB_MPOOL_DIRTY);
00468 root = NULL;
00469 if (ret != 0)
00470 goto err;
00471 } else {
00472 memset(&pdbt, 0, sizeof(pdbt));
00473
00474
00475 pginfo.db_pagesize = dbp->pgsize;
00476 pginfo.flags =
00477 F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));
00478 pginfo.type = dbp->type;
00479 pdbt.data = &pginfo;
00480 pdbt.size = sizeof(pginfo);
00481 if ((ret = __os_calloc(dbenv, 1, dbp->pgsize, &buf)) != 0)
00482 return (ret);
00483 meta = (BTMETA *)buf;
00484 LSN_NOT_LOGGED(lsn);
00485 __bam_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
00486 meta->root = 1;
00487 meta->dbmeta.last_pgno = 1;
00488 if ((ret = __db_pgout(dbenv, PGNO_BASE_MD, meta, &pdbt)) != 0)
00489 goto err;
00490 if ((ret = __fop_write(dbenv, txn, name, DB_APP_DATA, fhp,
00491 dbp->pgsize, 0, 0, buf, dbp->pgsize, 1, F_ISSET(
00492 dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0)) != 0)
00493 goto err;
00494 meta = NULL;
00495
00496
00497 #ifdef DIAGNOSTIC
00498 memset(buf, CLEAR_BYTE, dbp->pgsize);
00499 #endif
00500 root = (PAGE *)buf;
00501 P_INIT(root, dbp->pgsize, 1, PGNO_INVALID, PGNO_INVALID,
00502 LEAFLEVEL, dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE);
00503 LSN_NOT_LOGGED(root->lsn);
00504 if ((ret = __db_pgout(dbenv, root->pgno, root, &pdbt)) != 0)
00505 goto err;
00506 if ((ret = __fop_write(dbenv, txn, name, DB_APP_DATA, fhp,
00507 dbp->pgsize, 1, 0, buf, dbp->pgsize, 1, F_ISSET(
00508 dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0)) != 0)
00509 goto err;
00510 root = NULL;
00511 }
00512
00513 err: if (buf != NULL)
00514 __os_free(dbenv, buf);
00515 else {
00516 if (meta != NULL &&
00517 (t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
00518 ret = t_ret;
00519 if (root != NULL &&
00520 (t_ret = __memp_fput(mpf, root, 0)) != 0 && ret == 0)
00521 ret = t_ret;
00522 }
00523 return (ret);
00524 }
00525
00526
00527
00528
00529
00530
00531
00532 int
00533 __bam_new_subdb(mdbp, dbp, txn)
00534 DB *mdbp, *dbp;
00535 DB_TXN *txn;
00536 {
00537 BTMETA *meta;
00538 DBC *dbc;
00539 DB_ENV *dbenv;
00540 DB_LOCK metalock;
00541 DB_LSN lsn;
00542 DB_MPOOLFILE *mpf;
00543 PAGE *root;
00544 int ret, t_ret;
00545
00546 dbenv = mdbp->dbenv;
00547 mpf = mdbp->mpf;
00548 dbc = NULL;
00549 meta = NULL;
00550 root = NULL;
00551
00552 if ((ret = __db_cursor(mdbp, txn,
00553 &dbc, CDB_LOCKING(dbenv) ? DB_WRITECURSOR : 0)) != 0)
00554 return (ret);
00555
00556
00557 if ((ret = __db_lget(dbc,
00558 0, dbp->meta_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
00559 goto err;
00560 if ((ret =
00561 __memp_fget(mpf, &dbp->meta_pgno, DB_MPOOL_CREATE, &meta)) != 0)
00562 goto err;
00563
00564
00565 lsn = meta->dbmeta.lsn;
00566 __bam_init_meta(dbp, meta, dbp->meta_pgno, &lsn);
00567 if ((ret = __db_log_page(mdbp,
00568 txn, &meta->dbmeta.lsn, dbp->meta_pgno, (PAGE *)meta)) != 0)
00569 goto err;
00570
00571
00572 if ((ret = __db_new(dbc,
00573 dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE, &root)) != 0)
00574 goto err;
00575 root->level = LEAFLEVEL;
00576
00577 if (DBENV_LOGGING(dbenv) &&
00578 (ret = __bam_root_log(mdbp, txn, &meta->dbmeta.lsn, 0,
00579 meta->dbmeta.pgno, root->pgno, &meta->dbmeta.lsn)) != 0)
00580 goto err;
00581
00582 meta->root = root->pgno;
00583 if ((ret =
00584 __db_log_page(mdbp, txn, &root->lsn, root->pgno, root)) != 0)
00585 goto err;
00586
00587
00588 if ((ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY)) != 0)
00589 goto err;
00590 meta = NULL;
00591 if ((ret = __memp_fput(mpf, root, DB_MPOOL_DIRTY)) != 0)
00592 goto err;
00593 root = NULL;
00594 err:
00595 if (meta != NULL)
00596 if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
00597 ret = t_ret;
00598 if (root != NULL)
00599 if ((t_ret = __memp_fput(mpf, root, 0)) != 0 && ret == 0)
00600 ret = t_ret;
00601 if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
00602 ret = t_ret;
00603 if (dbc != NULL)
00604 if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00605 ret = t_ret;
00606 return (ret);
00607 }