1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1999-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/crypto.h" 13#include "dbinc/db_page.h" 14#include "dbinc/btree.h" 15#include "dbinc/hash.h" 16#include "dbinc/lock.h" 17#include "dbinc/mp.h" 18#include "dbinc/qam.h" 19#include "dbinc/txn.h" 20 21#ifdef HAVE_RPC 22#ifdef HAVE_SYSTEM_INCLUDE_FILES 23#include <rpc/rpc.h> 24#endif 25#include "db_server.h" 26#include "dbinc_auto/rpc_client_ext.h" 27#endif 28 29static int __db_get_byteswapped __P((DB *, int *)); 30static int __db_get_dbname __P((DB *, const char **, const char **)); 31static DB_ENV *__db_get_env __P((DB *)); 32static void __db_get_msgcall 33 __P((DB *, void (**)(const DB_ENV *, const char *))); 34static DB_MPOOLFILE *__db_get_mpf __P((DB *)); 35static int __db_get_multiple __P((DB *)); 36static int __db_get_transactional __P((DB *)); 37static int __db_get_type __P((DB *, DBTYPE *dbtype)); 38static int __db_init __P((DB *, u_int32_t)); 39static int __db_get_alloc __P((DB *, void *(**)(size_t), 40 void *(**)(void *, size_t), void (**)(void *))); 41static int __db_set_alloc __P((DB *, void *(*)(size_t), 42 void *(*)(void *, size_t), void (*)(void *))); 43static int __db_get_append_recno __P((DB *, 44 int (**)(DB *, DBT *, db_recno_t))); 45static int __db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t))); 46static int __db_get_cachesize __P((DB *, u_int32_t *, u_int32_t *, int *)); 47static int __db_set_cachesize __P((DB *, u_int32_t, u_int32_t, int)); 48static int __db_get_create_dir __P((DB *, const char **)); 49static int __db_set_create_dir __P((DB *, const char *)); 50static int __db_get_dup_compare 51 __P((DB *, int (**)(DB *, const DBT *, const DBT *))); 52static int __db_set_dup_compare 53 __P((DB *, int (*)(DB *, const DBT *, const DBT *))); 54static int __db_get_encrypt_flags __P((DB *, u_int32_t *)); 55static int __db_set_encrypt __P((DB *, const char *, u_int32_t)); 56static int __db_get_feedback __P((DB *, void (**)(DB *, int, int))); 57static int __db_set_feedback __P((DB *, void (*)(DB *, int, int))); 58static void __db_map_flags __P((DB *, u_int32_t *, u_int32_t *)); 59static int __db_get_pagesize __P((DB *, u_int32_t *)); 60static int __db_set_paniccall __P((DB *, void (*)(DB_ENV *, int))); 61static int __db_set_priority __P((DB *, DB_CACHE_PRIORITY)); 62static int __db_get_priority __P((DB *, DB_CACHE_PRIORITY *)); 63static void __db_get_errcall __P((DB *, 64 void (**)(const DB_ENV *, const char *, const char *))); 65static void __db_set_errcall 66 __P((DB *, void (*)(const DB_ENV *, const char *, const char *))); 67static void __db_get_errfile __P((DB *, FILE **)); 68static void __db_set_errfile __P((DB *, FILE *)); 69static void __db_get_errpfx __P((DB *, const char **)); 70static void __db_set_errpfx __P((DB *, const char *)); 71static void __db_set_msgcall 72 __P((DB *, void (*)(const DB_ENV *, const char *))); 73static void __db_get_msgfile __P((DB *, FILE **)); 74static void __db_set_msgfile __P((DB *, FILE *)); 75static void __dbh_err __P((DB *, int, const char *, ...)); 76static void __dbh_errx __P((DB *, const char *, ...)); 77 78/* 79 * db_create -- 80 * DB constructor. 81 * 82 * EXTERN: int db_create __P((DB **, DB_ENV *, u_int32_t)); 83 */ 84int 85db_create(dbpp, dbenv, flags) 86 DB **dbpp; 87 DB_ENV *dbenv; 88 u_int32_t flags; 89{ 90 DB_THREAD_INFO *ip; 91 ENV *env; 92 int ret; 93 94 ip = NULL; 95 env = dbenv == NULL ? NULL : dbenv->env; 96 97 /* Check for invalid function flags. */ 98 if (flags != 0) 99 return (__db_ferr(env, "db_create", 0)); 100 101 if (env != NULL) 102 ENV_ENTER(env, ip); 103 ret = __db_create_internal(dbpp, env, flags); 104 if (env != NULL) 105 ENV_LEAVE(env, ip); 106 107 return (ret); 108} 109 110/* 111 * __db_create_internal -- 112 * DB constructor internal routine. 113 * 114 * PUBLIC: int __db_create_internal __P((DB **, ENV *, u_int32_t)); 115 */ 116int 117__db_create_internal(dbpp, env, flags) 118 DB **dbpp; 119 ENV *env; 120 u_int32_t flags; 121{ 122 DB *dbp; 123 DB_ENV *dbenv; 124 DB_REP *db_rep; 125 int ret; 126 127 *dbpp = NULL; 128 129 /* If we don't have an environment yet, allocate a local one. */ 130 if (env == NULL) { 131 if ((ret = db_env_create(&dbenv, 0)) != 0) 132 return (ret); 133 env = dbenv->env; 134 F_SET(env, ENV_DBLOCAL); 135 } else 136 dbenv = env->dbenv; 137 138 /* Allocate and initialize the DB handle. */ 139 if ((ret = __os_calloc(env, 1, sizeof(*dbp), &dbp)) != 0) 140 goto err; 141 142 dbp->dbenv = env->dbenv; 143 dbp->env = env; 144 if ((ret = __db_init(dbp, flags)) != 0) 145 goto err; 146 147 MUTEX_LOCK(env, env->mtx_dblist); 148 ++env->db_ref; 149 MUTEX_UNLOCK(env, env->mtx_dblist); 150 151 /* 152 * Set the replication timestamp; it's 0 if we're not in a replicated 153 * environment. Don't acquire a lock to read the value, even though 154 * it's opaque: all we check later is value equality, nothing else. 155 */ 156 dbp->timestamp = REP_ON(env) ? 157 ((REGENV *)env->reginfo->primary)->rep_timestamp : 0; 158 /* 159 * Set the replication generation number for fid management; valid 160 * replication generations start at 1. Don't acquire a lock to 161 * read the value. All we check later is value equality. 162 */ 163 db_rep = env->rep_handle; 164 dbp->fid_gen = REP_ON(env) ? ((REP *)db_rep->region)->gen : 0; 165 166 /* If not RPC, open a backing DB_MPOOLFILE handle in the memory pool. */ 167 if (!RPC_ON(dbenv) && (ret = __memp_fcreate(env, &dbp->mpf)) != 0) 168 goto err; 169 170 dbp->type = DB_UNKNOWN; 171 172 *dbpp = dbp; 173 return (0); 174 175err: if (dbp != NULL) { 176 if (dbp->mpf != NULL) 177 (void)__memp_fclose(dbp->mpf, 0); 178 __os_free(env, dbp); 179 } 180 181 if (F_ISSET(env, ENV_DBLOCAL)) 182 (void)__env_close(dbp->dbenv, 0); 183 184 return (ret); 185} 186 187/* 188 * __db_init -- 189 * Initialize a DB structure. 190 */ 191static int 192__db_init(dbp, flags) 193 DB *dbp; 194 u_int32_t flags; 195{ 196 int ret; 197 198 dbp->locker = NULL; 199 LOCK_INIT(dbp->handle_lock); 200 201 TAILQ_INIT(&dbp->free_queue); 202 TAILQ_INIT(&dbp->active_queue); 203 TAILQ_INIT(&dbp->join_queue); 204 LIST_INIT(&dbp->s_secondaries); 205 206 FLD_SET(dbp->am_ok, 207 DB_OK_BTREE | DB_OK_HASH | DB_OK_QUEUE | DB_OK_RECNO); 208 209 /* DB PUBLIC HANDLE LIST BEGIN */ 210 dbp->associate = __db_associate_pp; 211 dbp->associate_foreign = __db_associate_foreign_pp; 212 dbp->close = __db_close_pp; 213 dbp->compact = __db_compact_pp; 214 dbp->cursor = __db_cursor_pp; 215 dbp->del = __db_del_pp; 216 dbp->dump = __db_dump_pp; 217 dbp->err = __dbh_err; 218 dbp->errx = __dbh_errx; 219 dbp->exists = __db_exists; 220 dbp->fd = __db_fd_pp; 221 dbp->get = __db_get_pp; 222 dbp->get_alloc = __db_get_alloc; 223 dbp->get_append_recno = __db_get_append_recno; 224 dbp->get_byteswapped = __db_get_byteswapped; 225 dbp->get_cachesize = __db_get_cachesize; 226 dbp->get_create_dir = __db_get_create_dir; 227 dbp->get_dbname = __db_get_dbname; 228 dbp->get_dup_compare = __db_get_dup_compare; 229 dbp->get_encrypt_flags = __db_get_encrypt_flags; 230 dbp->get_env = __db_get_env; 231 dbp->get_errcall = __db_get_errcall; 232 dbp->get_errfile = __db_get_errfile; 233 dbp->get_errpfx = __db_get_errpfx; 234 dbp->get_feedback = __db_get_feedback; 235 dbp->get_flags = __db_get_flags; 236 dbp->get_lorder = __db_get_lorder; 237 dbp->get_mpf = __db_get_mpf; 238 dbp->get_msgcall = __db_get_msgcall; 239 dbp->get_msgfile = __db_get_msgfile; 240 dbp->get_multiple = __db_get_multiple; 241 dbp->get_open_flags = __db_get_open_flags; 242 dbp->get_partition_dirs = __partition_get_dirs; 243 dbp->get_partition_callback = __partition_get_callback; 244 dbp->get_partition_keys = __partition_get_keys; 245 dbp->get_pagesize = __db_get_pagesize; 246 dbp->get_priority = __db_get_priority; 247 dbp->get_transactional = __db_get_transactional; 248 dbp->get_type = __db_get_type; 249 dbp->join = __db_join_pp; 250 dbp->key_range = __db_key_range_pp; 251 dbp->open = __db_open_pp; 252 dbp->pget = __db_pget_pp; 253 dbp->put = __db_put_pp; 254 dbp->remove = __db_remove_pp; 255 dbp->rename = __db_rename_pp; 256 dbp->set_alloc = __db_set_alloc; 257 dbp->set_append_recno = __db_set_append_recno; 258 dbp->set_cachesize = __db_set_cachesize; 259 dbp->set_create_dir = __db_set_create_dir; 260 dbp->set_dup_compare = __db_set_dup_compare; 261 dbp->set_encrypt = __db_set_encrypt; 262 dbp->set_errcall = __db_set_errcall; 263 dbp->set_errfile = __db_set_errfile; 264 dbp->set_errpfx = __db_set_errpfx; 265 dbp->set_feedback = __db_set_feedback; 266 dbp->set_flags = __db_set_flags; 267 dbp->set_lorder = __db_set_lorder; 268 dbp->set_msgcall = __db_set_msgcall; 269 dbp->set_msgfile = __db_set_msgfile; 270 dbp->set_pagesize = __db_set_pagesize; 271 dbp->set_paniccall = __db_set_paniccall; 272 dbp->set_partition = __partition_set; 273 dbp->set_partition_dirs = __partition_set_dirs; 274 dbp->set_priority = __db_set_priority; 275 dbp->sort_multiple = __db_sort_multiple; 276 dbp->stat = __db_stat_pp; 277 dbp->stat_print = __db_stat_print_pp; 278 dbp->sync = __db_sync_pp; 279 dbp->truncate = __db_truncate_pp; 280 dbp->upgrade = __db_upgrade_pp; 281 dbp->verify = __db_verify_pp; 282 /* DB PUBLIC HANDLE LIST END */ 283 284 /* Access method specific. */ 285 if ((ret = __bam_db_create(dbp)) != 0) 286 return (ret); 287 if ((ret = __ham_db_create(dbp)) != 0) 288 return (ret); 289 if ((ret = __qam_db_create(dbp)) != 0) 290 return (ret); 291 292#ifdef HAVE_RPC 293 /* 294 * RPC specific: must be last, as we replace methods set by the 295 * access methods. 296 */ 297 if (RPC_ON(dbp->dbenv)) { 298 __dbcl_dbp_init(dbp); 299 /* 300 * !!! 301 * We wrap the DB->open method for RPC, and the rpc.src file 302 * can't handle that. 303 */ 304 dbp->open = __dbcl_db_open_wrap; 305 if ((ret = __dbcl_db_create(dbp, dbp->dbenv, flags)) != 0) 306 return (ret); 307 } 308#else 309 COMPQUIET(flags, 0); 310#endif 311 312 return (0); 313} 314 315/* 316 * __dbh_am_chk -- 317 * Error if an unreasonable method is called. 318 * 319 * PUBLIC: int __dbh_am_chk __P((DB *, u_int32_t)); 320 */ 321int 322__dbh_am_chk(dbp, flags) 323 DB *dbp; 324 u_int32_t flags; 325{ 326 /* 327 * We start out allowing any access methods to be called, and as the 328 * application calls the methods the options become restricted. The 329 * idea is to quit as soon as an illegal method combination is called. 330 */ 331 if ((LF_ISSET(DB_OK_BTREE) && FLD_ISSET(dbp->am_ok, DB_OK_BTREE)) || 332 (LF_ISSET(DB_OK_HASH) && FLD_ISSET(dbp->am_ok, DB_OK_HASH)) || 333 (LF_ISSET(DB_OK_QUEUE) && FLD_ISSET(dbp->am_ok, DB_OK_QUEUE)) || 334 (LF_ISSET(DB_OK_RECNO) && FLD_ISSET(dbp->am_ok, DB_OK_RECNO))) { 335 FLD_CLR(dbp->am_ok, ~flags); 336 return (0); 337 } 338 339 __db_errx(dbp->env, 340 "call implies an access method which is inconsistent with previous calls"); 341 return (EINVAL); 342} 343 344/* 345 * __dbh_err -- 346 * Db.err method. 347 */ 348static void 349#ifdef STDC_HEADERS 350__dbh_err(DB *dbp, int error, const char *fmt, ...) 351#else 352__dbh_err(dbp, error, fmt, va_alist) 353 DB *dbp; 354 int error; 355 const char *fmt; 356 va_dcl 357#endif 358{ 359 /* Message with error string, to stderr by default. */ 360 DB_REAL_ERR(dbp->dbenv, error, DB_ERROR_SET, 1, fmt); 361} 362 363/* 364 * __dbh_errx -- 365 * Db.errx method. 366 */ 367static void 368#ifdef STDC_HEADERS 369__dbh_errx(DB *dbp, const char *fmt, ...) 370#else 371__dbh_errx(dbp, fmt, va_alist) 372 DB *dbp; 373 const char *fmt; 374 va_dcl 375#endif 376{ 377 /* Message without error string, to stderr by default. */ 378 DB_REAL_ERR(dbp->dbenv, 0, DB_ERROR_NOT_SET, 1, fmt); 379} 380 381/* 382 * __db_get_byteswapped -- 383 * Return if database requires byte swapping. 384 */ 385static int 386__db_get_byteswapped(dbp, isswapped) 387 DB *dbp; 388 int *isswapped; 389{ 390 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_byteswapped"); 391 392 *isswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0; 393 return (0); 394} 395 396/* 397 * __db_get_dbname -- 398 * Get the name of the database as passed to DB->open. 399 */ 400static int 401__db_get_dbname(dbp, fnamep, dnamep) 402 DB *dbp; 403 const char **fnamep, **dnamep; 404{ 405 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_dbname"); 406 407 if (fnamep != NULL) 408 *fnamep = dbp->fname; 409 if (dnamep != NULL) 410 *dnamep = dbp->dname; 411 return (0); 412} 413 414/* 415 * __db_get_env -- 416 * Get the DB_ENV handle that was passed to db_create. 417 */ 418static DB_ENV * 419__db_get_env(dbp) 420 DB *dbp; 421{ 422 return (dbp->dbenv); 423} 424 425/* 426 * __db_get_mpf -- 427 * Get the underlying DB_MPOOLFILE handle. 428 */ 429static DB_MPOOLFILE * 430__db_get_mpf(dbp) 431 DB *dbp; 432{ 433 return (dbp->mpf); 434} 435 436/* 437 * get_multiple -- 438 * Return whether this DB handle references a physical file with multiple 439 * databases. 440 */ 441static int 442__db_get_multiple(dbp) 443 DB *dbp; 444{ 445 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_multiple"); 446 447 /* 448 * Only return TRUE if the handle is for the master database, not for 449 * any subdatabase in the physical file. If it's a Btree, with the 450 * subdatabases flag set, and the meta-data page has the right value, 451 * return TRUE. (We don't need to check it's a Btree, I suppose, but 452 * it doesn't hurt.) 453 */ 454 return (dbp->type == DB_BTREE && 455 F_ISSET(dbp, DB_AM_SUBDB) && 456 dbp->meta_pgno == PGNO_BASE_MD ? 1 : 0); 457} 458 459/* 460 * get_transactional -- 461 * Return whether this database was created in a transaction. 462 */ 463static int 464__db_get_transactional(dbp) 465 DB *dbp; 466{ 467 return (F_ISSET(dbp, DB_AM_TXN) ? 1 : 0); 468} 469 470/* 471 * __db_get_type -- 472 * Return type of underlying database. 473 */ 474static int 475__db_get_type(dbp, dbtype) 476 DB *dbp; 477 DBTYPE *dbtype; 478{ 479 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_type"); 480 481 *dbtype = dbp->type; 482 return (0); 483} 484 485/* 486 * __db_get_append_recno -- 487 * Get record number append routine. 488 */ 489static int 490__db_get_append_recno(dbp, funcp) 491 DB *dbp; 492 int (**funcp) __P((DB *, DBT *, db_recno_t)); 493{ 494 DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); 495 if (funcp) 496 *funcp = dbp->db_append_recno; 497 498 return (0); 499} 500/* 501 * __db_set_append_recno -- 502 * Set record number append routine. 503 */ 504static int 505__db_set_append_recno(dbp, func) 506 DB *dbp; 507 int (*func) __P((DB *, DBT *, db_recno_t)); 508{ 509 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_append_recno"); 510 DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); 511 512 dbp->db_append_recno = func; 513 514 return (0); 515} 516 517/* 518 * __db_get_cachesize -- 519 * Get underlying cache size. 520 */ 521static int 522__db_get_cachesize(dbp, cache_gbytesp, cache_bytesp, ncachep) 523 DB *dbp; 524 u_int32_t *cache_gbytesp, *cache_bytesp; 525 int *ncachep; 526{ 527 DB_ILLEGAL_IN_ENV(dbp, "DB->get_cachesize"); 528 529 return (__memp_get_cachesize(dbp->dbenv, 530 cache_gbytesp, cache_bytesp, ncachep)); 531} 532 533/* 534 * __db_set_cachesize -- 535 * Set underlying cache size. 536 */ 537static int 538__db_set_cachesize(dbp, cache_gbytes, cache_bytes, ncache) 539 DB *dbp; 540 u_int32_t cache_gbytes, cache_bytes; 541 int ncache; 542{ 543 DB_ILLEGAL_IN_ENV(dbp, "DB->set_cachesize"); 544 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_cachesize"); 545 546 return (__memp_set_cachesize( 547 dbp->dbenv, cache_gbytes, cache_bytes, ncache)); 548} 549 550static int 551__db_set_create_dir(dbp, dir) 552 DB *dbp; 553 const char *dir; 554{ 555 DB_ENV *dbenv; 556 int i; 557 558 dbenv = dbp->dbenv; 559 560 for (i = 0; i < dbenv->data_next; i++) 561 if (strcmp(dir, dbenv->db_data_dir[i]) == 0) 562 break; 563 564 if (i == dbenv->data_next) { 565 __db_errx(dbp->env, 566 "Directory %s not in environment list.", dir); 567 return (EINVAL); 568 } 569 570 dbp->dirname = dbenv->db_data_dir[i]; 571 return (0); 572} 573 574static int 575__db_get_create_dir(dbp, dirp) 576 DB *dbp; 577 const char **dirp; 578{ 579 *dirp = dbp->dirname; 580 return (0); 581} 582 583/* 584 * __db_get_dup_compare -- 585 * Get duplicate comparison routine. 586 */ 587static int 588__db_get_dup_compare(dbp, funcp) 589 DB *dbp; 590 int (**funcp) __P((DB *, const DBT *, const DBT *)); 591{ 592 593 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); 594 595 if (funcp != NULL) { 596#ifdef HAVE_COMPRESSION 597 if (DB_IS_COMPRESSED(dbp)) { 598 *funcp = 599 ((BTREE *)dbp->bt_internal)->compress_dup_compare; 600 } else 601#endif 602 *funcp = dbp->dup_compare; 603 } 604 605 return (0); 606} 607 608/* 609 * __db_set_dup_compare -- 610 * Set duplicate comparison routine. 611 */ 612static int 613__db_set_dup_compare(dbp, func) 614 DB *dbp; 615 int (*func) __P((DB *, const DBT *, const DBT *)); 616{ 617 int ret; 618 619 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_dup_compare"); 620 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); 621 622 if ((ret = __db_set_flags(dbp, DB_DUPSORT)) != 0) 623 return (ret); 624 625#ifdef HAVE_COMPRESSION 626 if (DB_IS_COMPRESSED(dbp)) { 627 dbp->dup_compare = __bam_compress_dupcmp; 628 ((BTREE *)dbp->bt_internal)->compress_dup_compare = func; 629 } else 630#endif 631 dbp->dup_compare = func; 632 633 return (0); 634} 635 636/* 637 * __db_get_encrypt_flags -- 638 */ 639static int 640__db_get_encrypt_flags(dbp, flagsp) 641 DB *dbp; 642 u_int32_t *flagsp; 643{ 644 DB_ILLEGAL_IN_ENV(dbp, "DB->get_encrypt_flags"); 645 646 return (__env_get_encrypt_flags(dbp->dbenv, flagsp)); 647} 648 649/* 650 * __db_set_encrypt -- 651 * Set database passwd. 652 */ 653static int 654__db_set_encrypt(dbp, passwd, flags) 655 DB *dbp; 656 const char *passwd; 657 u_int32_t flags; 658{ 659 DB_CIPHER *db_cipher; 660 int ret; 661 662 DB_ILLEGAL_IN_ENV(dbp, "DB->set_encrypt"); 663 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_encrypt"); 664 665 if ((ret = __env_set_encrypt(dbp->dbenv, passwd, flags)) != 0) 666 return (ret); 667 668 /* 669 * In a real env, this gets initialized with the region. In a local 670 * env, we must do it here. 671 */ 672 db_cipher = dbp->env->crypto_handle; 673 if (!F_ISSET(db_cipher, CIPHER_ANY) && 674 (ret = db_cipher->init(dbp->env, db_cipher)) != 0) 675 return (ret); 676 677 return (__db_set_flags(dbp, DB_ENCRYPT)); 678} 679 680static void 681__db_get_errcall(dbp, errcallp) 682 DB *dbp; 683 void (**errcallp) __P((const DB_ENV *, const char *, const char *)); 684{ 685 __env_get_errcall(dbp->dbenv, errcallp); 686} 687 688static void 689__db_set_errcall(dbp, errcall) 690 DB *dbp; 691 void (*errcall) __P((const DB_ENV *, const char *, const char *)); 692{ 693 __env_set_errcall(dbp->dbenv, errcall); 694} 695 696static void 697__db_get_errfile(dbp, errfilep) 698 DB *dbp; 699 FILE **errfilep; 700{ 701 __env_get_errfile(dbp->dbenv, errfilep); 702} 703 704static void 705__db_set_errfile(dbp, errfile) 706 DB *dbp; 707 FILE *errfile; 708{ 709 __env_set_errfile(dbp->dbenv, errfile); 710} 711 712static void 713__db_get_errpfx(dbp, errpfxp) 714 DB *dbp; 715 const char **errpfxp; 716{ 717 __env_get_errpfx(dbp->dbenv, errpfxp); 718} 719 720static void 721__db_set_errpfx(dbp, errpfx) 722 DB *dbp; 723 const char *errpfx; 724{ 725 __env_set_errpfx(dbp->dbenv, errpfx); 726} 727 728static int 729__db_get_feedback(dbp, feedbackp) 730 DB *dbp; 731 void (**feedbackp) __P((DB *, int, int)); 732{ 733 if (feedbackp != NULL) 734 *feedbackp = dbp->db_feedback; 735 return (0); 736} 737 738static int 739__db_set_feedback(dbp, feedback) 740 DB *dbp; 741 void (*feedback) __P((DB *, int, int)); 742{ 743 dbp->db_feedback = feedback; 744 return (0); 745} 746 747/* 748 * __db_map_flags -- 749 * Maps between public and internal flag values. 750 * This function doesn't check for validity, so it can't fail. 751 */ 752static void 753__db_map_flags(dbp, inflagsp, outflagsp) 754 DB *dbp; 755 u_int32_t *inflagsp, *outflagsp; 756{ 757 COMPQUIET(dbp, NULL); 758 759 if (FLD_ISSET(*inflagsp, DB_CHKSUM)) { 760 FLD_SET(*outflagsp, DB_AM_CHKSUM); 761 FLD_CLR(*inflagsp, DB_CHKSUM); 762 } 763 if (FLD_ISSET(*inflagsp, DB_ENCRYPT)) { 764 FLD_SET(*outflagsp, DB_AM_ENCRYPT | DB_AM_CHKSUM); 765 FLD_CLR(*inflagsp, DB_ENCRYPT); 766 } 767 if (FLD_ISSET(*inflagsp, DB_TXN_NOT_DURABLE)) { 768 FLD_SET(*outflagsp, DB_AM_NOT_DURABLE); 769 FLD_CLR(*inflagsp, DB_TXN_NOT_DURABLE); 770 } 771} 772 773/* 774 * __db_get_flags -- 775 * The DB->get_flags method. 776 * 777 * PUBLIC: int __db_get_flags __P((DB *, u_int32_t *)); 778 */ 779int 780__db_get_flags(dbp, flagsp) 781 DB *dbp; 782 u_int32_t *flagsp; 783{ 784 static const u_int32_t db_flags[] = { 785 DB_CHKSUM, 786 DB_DUP, 787 DB_DUPSORT, 788 DB_ENCRYPT, 789#ifdef HAVE_QUEUE 790 DB_INORDER, 791#endif 792 DB_RECNUM, 793 DB_RENUMBER, 794 DB_REVSPLITOFF, 795 DB_SNAPSHOT, 796 DB_TXN_NOT_DURABLE, 797 0 798 }; 799 u_int32_t f, flags, mapped_flag; 800 int i; 801 802 flags = 0; 803 for (i = 0; (f = db_flags[i]) != 0; i++) { 804 mapped_flag = 0; 805 __db_map_flags(dbp, &f, &mapped_flag); 806 __bam_map_flags(dbp, &f, &mapped_flag); 807 __ram_map_flags(dbp, &f, &mapped_flag); 808#ifdef HAVE_QUEUE 809 __qam_map_flags(dbp, &f, &mapped_flag); 810#endif 811 DB_ASSERT(dbp->env, f == 0); 812 if (F_ISSET(dbp, mapped_flag) == mapped_flag) 813 LF_SET(db_flags[i]); 814 } 815 816 *flagsp = flags; 817 return (0); 818} 819 820/* 821 * __db_set_flags -- 822 * DB->set_flags. 823 * 824 * PUBLIC: int __db_set_flags __P((DB *, u_int32_t)); 825 */ 826int 827__db_set_flags(dbp, flags) 828 DB *dbp; 829 u_int32_t flags; 830{ 831 ENV *env; 832 int ret; 833 834 env = dbp->env; 835 836 if (LF_ISSET(DB_ENCRYPT) && !CRYPTO_ON(env)) { 837 __db_errx(env, 838 "Database environment not configured for encryption"); 839 return (EINVAL); 840 } 841 if (LF_ISSET(DB_TXN_NOT_DURABLE)) 842 ENV_REQUIRES_CONFIG(env, 843 env->tx_handle, "DB_NOT_DURABLE", DB_INIT_TXN); 844 845 __db_map_flags(dbp, &flags, &dbp->flags); 846 847 if ((ret = __bam_set_flags(dbp, &flags)) != 0) 848 return (ret); 849 if ((ret = __ram_set_flags(dbp, &flags)) != 0) 850 return (ret); 851#ifdef HAVE_QUEUE 852 if ((ret = __qam_set_flags(dbp, &flags)) != 0) 853 return (ret); 854#endif 855 856 return (flags == 0 ? 0 : __db_ferr(env, "DB->set_flags", 0)); 857} 858 859/* 860 * __db_get_lorder -- 861 * Get whether lorder is swapped or not. 862 * 863 * PUBLIC: int __db_get_lorder __P((DB *, int *)); 864 */ 865int 866__db_get_lorder(dbp, db_lorderp) 867 DB *dbp; 868 int *db_lorderp; 869{ 870 int ret; 871 872 /* Flag if the specified byte order requires swapping. */ 873 switch (ret = __db_byteorder(dbp->env, 1234)) { 874 case 0: 875 *db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 4321 : 1234; 876 break; 877 case DB_SWAPBYTES: 878 *db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 1234 : 4321; 879 break; 880 default: 881 return (ret); 882 /* NOTREACHED */ 883 } 884 885 return (0); 886} 887 888/* 889 * __db_set_lorder -- 890 * Set whether lorder is swapped or not. 891 * 892 * PUBLIC: int __db_set_lorder __P((DB *, int)); 893 */ 894int 895__db_set_lorder(dbp, db_lorder) 896 DB *dbp; 897 int db_lorder; 898{ 899 int ret; 900 901 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_lorder"); 902 903 /* Flag if the specified byte order requires swapping. */ 904 switch (ret = __db_byteorder(dbp->env, db_lorder)) { 905 case 0: 906 F_CLR(dbp, DB_AM_SWAP); 907 break; 908 case DB_SWAPBYTES: 909 F_SET(dbp, DB_AM_SWAP); 910 break; 911 default: 912 return (ret); 913 /* NOTREACHED */ 914 } 915 return (0); 916} 917 918static int 919__db_get_alloc(dbp, mal_funcp, real_funcp, free_funcp) 920 DB *dbp; 921 void *(**mal_funcp) __P((size_t)); 922 void *(**real_funcp) __P((void *, size_t)); 923 void (**free_funcp) __P((void *)); 924{ 925 DB_ILLEGAL_IN_ENV(dbp, "DB->get_alloc"); 926 927 return (__env_get_alloc(dbp->dbenv, mal_funcp, 928 real_funcp, free_funcp)); 929} 930 931static int 932__db_set_alloc(dbp, mal_func, real_func, free_func) 933 DB *dbp; 934 void *(*mal_func) __P((size_t)); 935 void *(*real_func) __P((void *, size_t)); 936 void (*free_func) __P((void *)); 937{ 938 DB_ILLEGAL_IN_ENV(dbp, "DB->set_alloc"); 939 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_alloc"); 940 941 return (__env_set_alloc(dbp->dbenv, mal_func, real_func, free_func)); 942} 943 944static void 945__db_get_msgcall(dbp, msgcallp) 946 DB *dbp; 947 void (**msgcallp) __P((const DB_ENV *, const char *)); 948{ 949 __env_get_msgcall(dbp->dbenv, msgcallp); 950} 951 952static void 953__db_set_msgcall(dbp, msgcall) 954 DB *dbp; 955 void (*msgcall) __P((const DB_ENV *, const char *)); 956{ 957 __env_set_msgcall(dbp->dbenv, msgcall); 958} 959 960static void 961__db_get_msgfile(dbp, msgfilep) 962 DB *dbp; 963 FILE **msgfilep; 964{ 965 __env_get_msgfile(dbp->dbenv, msgfilep); 966} 967 968static void 969__db_set_msgfile(dbp, msgfile) 970 DB *dbp; 971 FILE *msgfile; 972{ 973 __env_set_msgfile(dbp->dbenv, msgfile); 974} 975 976static int 977__db_get_pagesize(dbp, db_pagesizep) 978 DB *dbp; 979 u_int32_t *db_pagesizep; 980{ 981 *db_pagesizep = dbp->pgsize; 982 return (0); 983} 984 985/* 986 * __db_set_pagesize -- 987 * DB->set_pagesize 988 * 989 * PUBLIC: int __db_set_pagesize __P((DB *, u_int32_t)); 990 */ 991int 992__db_set_pagesize(dbp, db_pagesize) 993 DB *dbp; 994 u_int32_t db_pagesize; 995{ 996 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_pagesize"); 997 998 if (db_pagesize < DB_MIN_PGSIZE) { 999 __db_errx(dbp->env, "page sizes may not be smaller than %lu", 1000 (u_long)DB_MIN_PGSIZE); 1001 return (EINVAL); 1002 } 1003 if (db_pagesize > DB_MAX_PGSIZE) { 1004 __db_errx(dbp->env, "page sizes may not be larger than %lu", 1005 (u_long)DB_MAX_PGSIZE); 1006 return (EINVAL); 1007 } 1008 1009 /* 1010 * We don't want anything that's not a power-of-2, as we rely on that 1011 * for alignment of various types on the pages. 1012 */ 1013 if (!POWER_OF_TWO(db_pagesize)) { 1014 __db_errx(dbp->env, "page sizes must be a power-of-2"); 1015 return (EINVAL); 1016 } 1017 1018 /* 1019 * XXX 1020 * Should we be checking for a page size that's not a multiple of 512, 1021 * so that we never try and write less than a disk sector? 1022 */ 1023 dbp->pgsize = db_pagesize; 1024 1025 return (0); 1026} 1027 1028static int 1029__db_set_paniccall(dbp, paniccall) 1030 DB *dbp; 1031 void (*paniccall) __P((DB_ENV *, int)); 1032{ 1033 return (__env_set_paniccall(dbp->dbenv, paniccall)); 1034} 1035 1036static int 1037__db_set_priority(dbp, priority) 1038 DB *dbp; 1039 DB_CACHE_PRIORITY priority; 1040{ 1041 dbp->priority = priority; 1042 return (0); 1043} 1044 1045static int 1046__db_get_priority(dbp, priority) 1047 DB *dbp; 1048 DB_CACHE_PRIORITY *priority; 1049{ 1050 *priority = dbp->priority; 1051 return (0); 1052} 1053