1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 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 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 3. All advertising materials mentioning features or use of this software 24 * must display the following acknowledgement: 25 * This product includes software developed by the University of 26 * California, Berkeley and its contributors. 27 * 4. Neither the name of the University nor the names of its contributors 28 * may be used to endorse or promote products derived from this software 29 * without specific prior written permission. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 * SUCH DAMAGE. 42 */ 43 44 #include "config.h" 45 46 #ifndef lint 47 static const char sccsid[] = "@(#)db.c 10.75 (Sleepycat) 12/3/98"; 48 #endif /* not lint */ 49 50 #ifndef NO_SYSTEM_INCLUDES 51 #include <sys/types.h> 52 53 #include <errno.h> 54 #include <stddef.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #endif 58 59 #include "db_int.h" 60 #include "shqueue.h" 61 #include "db_page.h" 62 #include "db_shash.h" 63 #include "db_swap.h" 64 #include "btree.h" 65 #include "hash.h" 66 #include "mp.h" 67 #include "db_am.h" 68 #include "common_ext.h" 69 70 /* 71 * If the metadata page has the flag set, set the local flag. If the page 72 * does NOT have the flag set, return EINVAL if the user's dbinfo argument 73 * caused us to already set the local flag. 74 */ 75 #define DBINFO_FCHK(dbp, fn, meta_flags, m_name, dbp_name) { \ 76 if ((meta_flags) & (m_name)) \ 77 F_SET(dbp, dbp_name); \ 78 else \ 79 if (F_ISSET(dbp, dbp_name)) { \ 80 __db_err(dbenv, \ 81 "%s: %s specified in dbinfo argument but not set in file", \ 82 fname, fn); \ 83 goto einval; \ 84 } \ 85 } 86 87 /* 88 * db_open -- 89 * Main library interface to the DB access methods. 90 */ 91 int 92 db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp) 93 const char *fname; 94 DBTYPE type; 95 u_int32_t flags; 96 int mode; 97 DB_ENV *dbenv; 98 DB_INFO *dbinfo; 99 DB **dbpp; 100 { 101 BTMETA *btm; 102 DB *dbp; 103 DBT pgcookie; 104 DB_ENV *envp, t_dbenv; 105 DB_MPOOL_FINFO finfo; 106 DB_PGINFO pginfo; 107 HASHHDR *hashm; 108 size_t cachesize; 109 ssize_t nr; 110 u_int32_t iopsize; 111 int fd, ftype, need_fileid, restore, ret, retry_cnt, swapped; 112 char *real_name, mbuf[512]; 113 114 /* Validate arguments. */ 115 #ifdef HAVE_SPINLOCKS 116 #define OKFLAGS (DB_CREATE | DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_THREAD | DB_TRUNCATE) 117 #else 118 #define OKFLAGS (DB_CREATE | DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_TRUNCATE) 119 #endif 120 if ((ret = __db_fchk(dbenv, "db_open", flags, OKFLAGS)) != 0) 121 return (ret); 122 123 if (dbenv != NULL) { 124 /* 125 * You can't specify threads during the db_open() if the 126 * environment wasn't configured with them. 127 */ 128 if (LF_ISSET(DB_THREAD) && !F_ISSET(dbenv, DB_ENV_THREAD)) { 129 __db_err(dbenv, 130 "environment not created using DB_THREAD"); 131 return (EINVAL); 132 } 133 134 /* 135 * Specifying a cachesize to db_open(3), after creating an 136 * environment with DB_INIT_MPOOL, is a common mistake. 137 */ 138 if (dbenv->mp_info != NULL && 139 dbinfo != NULL && dbinfo->db_cachesize != 0) { 140 __db_err(dbenv, 141 "cachesize will be ignored if environment exists"); 142 return (EINVAL); 143 } 144 } 145 146 /* Allocate the DB structure, reference the DB_ENV structure. */ 147 if ((ret = __os_calloc(1, sizeof(DB), &dbp)) != 0) 148 return (ret); 149 dbp->dbenv = dbenv; 150 151 /* Initialize for error return. */ 152 dbp->saved_open_fd = fd = -1; 153 need_fileid = 1; 154 real_name = NULL; 155 156 /* Random initialization. */ 157 TAILQ_INIT(&dbp->free_queue); 158 TAILQ_INIT(&dbp->active_queue); 159 if ((ret = __db_init_wrapper(dbp)) != 0) 160 goto err; 161 162 /* Convert the db_open(3) flags. */ 163 if (LF_ISSET(DB_RDONLY)) 164 F_SET(dbp, DB_AM_RDONLY); 165 if (LF_ISSET(DB_THREAD)) 166 F_SET(dbp, DB_AM_THREAD); 167 168 /* Convert the dbinfo structure flags. */ 169 if (dbinfo != NULL) { 170 /* 171 * !!! 172 * We can't check for illegal flags until we know what type 173 * of open we're doing. 174 */ 175 if (F_ISSET(dbinfo, DB_DELIMITER)) 176 F_SET(dbp, DB_RE_DELIMITER); 177 if (F_ISSET(dbinfo, DB_DUP)) 178 F_SET(dbp, DB_AM_DUP); 179 if (F_ISSET(dbinfo, DB_FIXEDLEN)) 180 F_SET(dbp, DB_RE_FIXEDLEN); 181 if (F_ISSET(dbinfo, DB_PAD)) 182 F_SET(dbp, DB_RE_PAD); 183 if (F_ISSET(dbinfo, DB_RECNUM)) 184 F_SET(dbp, DB_BT_RECNUM); 185 if (F_ISSET(dbinfo, DB_RENUMBER)) 186 F_SET(dbp, DB_RE_RENUMBER); 187 if (F_ISSET(dbinfo, DB_SNAPSHOT)) 188 F_SET(dbp, DB_RE_SNAPSHOT); 189 } 190 191 /* 192 * Set based on the dbenv fields, although no logging or transactions 193 * are possible for temporary files. 194 */ 195 if (dbenv != NULL) { 196 if (dbenv->lk_info != NULL) 197 if (F_ISSET(dbenv, DB_ENV_CDB)) 198 F_SET(dbp, DB_AM_CDB); 199 else 200 F_SET(dbp, DB_AM_LOCKING); 201 if (fname != NULL && dbenv->lg_info != NULL) 202 F_SET(dbp, DB_AM_LOGGING); 203 } 204 205 /* Set the common fields. */ 206 if (dbinfo == NULL) { 207 dbp->pgsize = 0; 208 dbp->db_malloc = NULL; 209 dbp->dup_compare = NULL; 210 } else { 211 /* 212 * We don't want anything that's not a power-of-2, as we rely 213 * on that for alignment of various types on the pages. 214 */ 215 if ((dbp->pgsize = dbinfo->db_pagesize) != 0 && 216 (u_int32_t)1 << __db_log2(dbp->pgsize) != dbp->pgsize) { 217 __db_err(dbenv, "page sizes must be a power-of-2"); 218 goto einval; 219 } 220 dbp->pgsize = dbinfo->db_pagesize; 221 dbp->db_malloc = dbinfo->db_malloc; 222 if (F_ISSET(dbinfo, DB_DUPSORT)) { 223 if (F_ISSET(dbinfo, DB_DUP)) 224 dbp->dup_compare = dbinfo->dup_compare == NULL ? 225 __bam_defcmp : dbinfo->dup_compare; 226 else { 227 __db_err(dbenv, "DB_DUPSORT requires DB_DUP"); 228 goto einval; 229 } 230 F_CLR(dbinfo, DB_DUPSORT); 231 } 232 } 233 234 /* Fill in the default file mode. */ 235 if (mode == 0) 236 mode = __db_omode("rwrw--"); 237 238 /* Check if the user wants us to swap byte order. */ 239 if (dbinfo != NULL) 240 switch (ret = __db_byteorder(dbenv, dbinfo->db_lorder)) { 241 case 0: 242 break; 243 case DB_SWAPBYTES: 244 F_SET(dbp, DB_AM_SWAP); 245 break; 246 default: 247 goto err; 248 } 249 dbp->byteswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0; 250 251 /* 252 * If we have a file name, try and read the first page, figure out 253 * what type of file it is, and initialize everything we can based 254 * on that file's meta-data page. 255 * 256 * XXX 257 * We don't actually expect zero-length strings as arguments. We 258 * do the check, permitting them, because scripting languages, e.g., 259 * the Tcl test suite, doesn't know anything about passing NULL's. 260 */ 261 if (fname != NULL && fname[0] != '\0') { 262 /* Get the real file name. */ 263 if ((ret = __db_appname(dbenv, 264 DB_APP_DATA, NULL, fname, 0, NULL, &real_name)) != 0) 265 goto err; 266 267 /* 268 * Open the backing file. We need to make sure that multiple 269 * processes attempting to create the file at the same time 270 * are properly ordered so that only one of them creates the 271 * "unique" file id, so we open it O_EXCL and O_CREAT so two 272 * simultaneous attempts to create the region will return 273 * failure in one of the attempts. If we're one of the ones 274 * that fail, we simply retry without the O_CREAT flag, which 275 * will require that the meta-data page exist. 276 */ 277 retry_cnt = 0; 278 open_retry: if (LF_ISSET(DB_CREATE)) { 279 if ((ret = __db_open(real_name, flags | DB_EXCL, 280 OKFLAGS | DB_EXCL, mode, &fd)) != 0) 281 if (ret == EEXIST) { 282 LF_CLR(DB_CREATE); 283 goto open_retry; 284 } else { 285 __db_err(dbenv, 286 "%s: %s", fname, strerror(ret)); 287 goto err; 288 } 289 } else 290 if ((ret = __db_open(real_name, 291 flags, OKFLAGS, mode, &fd)) != 0) { 292 __db_err(dbenv, "%s: %s", fname, strerror(ret)); 293 goto err; 294 } 295 296 /* 297 * Use the optimum I/O size as the pagesize if a pagesize not 298 * specified. Some filesystems have 64K as their optimum I/O 299 * size, but as that results in impossibly large default cache 300 * sizes, we limit the default pagesize to 16K. 301 */ 302 if (dbp->pgsize == 0) { 303 if ((ret = __os_ioinfo(real_name, 304 fd, NULL, NULL, &iopsize)) != 0) { 305 __db_err(dbenv, 306 "%s: %s", real_name, strerror(ret)); 307 goto err; 308 } 309 if (iopsize < 512) 310 iopsize = 512; 311 if (iopsize > 16 * 1024) 312 iopsize = 16 * 1024; 313 314 /* 315 * Sheer paranoia, but we don't want anything that's 316 * not a power-of-2, as we rely on that for alignment 317 * of various types on the pages. 318 */ 319 DB_ROUNDOFF(iopsize, 512); 320 321 dbp->pgsize = iopsize; 322 F_SET(dbp, DB_AM_PGDEF); 323 } 324 325 /* 326 * Try and read the first disk sector -- this code assumes 327 * that the meta-data for all access methods fits in 512 328 * bytes, and that no database will be smaller than that. 329 */ 330 if ((ret = __os_read(fd, mbuf, sizeof(mbuf), &nr)) != 0) 331 goto err; 332 333 if (LF_ISSET(DB_FCNTL_LOCKING)) 334 dbp->saved_open_fd = fd; 335 else 336 (void)__os_close(fd); 337 fd = -1; 338 339 if (nr != sizeof(mbuf)) { 340 if (nr != 0) { 341 __db_err(dbenv, 342 "%s: unexpected file format", fname); 343 goto einval; 344 } 345 /* 346 * The only way we can reach here with the DB_CREATE 347 * flag set is if we created the file. If that's not 348 * the case, then a) someone else created the file 349 * but has not yet written out the meta-data page, or 350 * b) we truncated the file (DB_TRUNCATE) leaving it 351 * zero-length. In the case of a), we want to sleep 352 * and give the file creator some time to write the 353 * metadata page. In the case of b), charge forward. 354 * Note, there is a race in the case of two processes 355 * opening the file with the DB_TRUNCATE flag set at 356 * roughly the same time, and they could theoretically 357 * hurt each other, although it's pretty unlikely. 358 */ 359 if (retry_cnt++ < 3 && 360 !LF_ISSET(DB_CREATE | DB_TRUNCATE)) { 361 __os_sleep(1, 0); 362 goto open_retry; 363 } 364 if (type == DB_UNKNOWN) { 365 __db_err(dbenv, 366 "%s: DBTYPE of unknown with empty file", 367 fname); 368 goto einval; 369 } 370 goto empty; 371 } 372 373 /* 374 * A found file overrides some user information. We'll check 375 * for possible error conditions based on conflicts between 376 * the file and the user's arguments below. 377 */ 378 swapped = 0; 379 F_CLR(dbp, DB_AM_SWAP); 380 381 retry: switch (((BTMETA *)mbuf)->magic) { 382 case DB_BTREEMAGIC: 383 if (type != DB_BTREE && 384 type != DB_RECNO && type != DB_UNKNOWN) 385 goto einval; 386 387 btm = (BTMETA *)mbuf; 388 if (swapped && (ret = __bam_mswap((PAGE *)btm)) != 0) 389 goto err; 390 391 if (btm->version < DB_BTREEOLDVER || 392 btm->version > DB_BTREEVERSION) { 393 __db_err(dbenv, 394 "%s: unsupported btree version number %lu", 395 fname, (u_long)btm->version); 396 goto einval; 397 } 398 dbp->pgsize = btm->pagesize; 399 F_CLR(dbp, DB_AM_PGDEF); 400 401 if ((ret = __db_fchk(dbenv, 402 "db_open", btm->flags, BTM_MASK)) != 0) 403 goto err; 404 DBINFO_FCHK(dbp, "DB_DUP", 405 btm->flags, BTM_DUP, DB_AM_DUP); 406 if (F_ISSET(btm, BTM_RECNO)) { 407 DBINFO_FCHK(dbp, "DB_FIXEDLEN", 408 btm->flags, BTM_FIXEDLEN, DB_RE_FIXEDLEN); 409 DBINFO_FCHK(dbp, "DB_RENUMBER", 410 btm->flags, BTM_RENUMBER, DB_RE_RENUMBER); 411 type = DB_RECNO; 412 } else { 413 DBINFO_FCHK(dbp, "DB_RECNUM", 414 btm->flags, BTM_RECNUM, DB_BT_RECNUM); 415 type = DB_BTREE; 416 } 417 418 /* Copy the file's unique id. */ 419 need_fileid = 0; 420 memcpy(dbp->fileid, btm->uid, DB_FILE_ID_LEN); 421 break; 422 case DB_HASHMAGIC: 423 if (type != DB_HASH && type != DB_UNKNOWN) 424 goto einval; 425 426 hashm = (HASHHDR *)mbuf; 427 if (swapped && (ret = __ham_mswap((PAGE *)hashm)) != 0) 428 goto err; 429 430 if (hashm->version < DB_HASHOLDVER || 431 hashm->version > DB_HASHVERSION) { 432 __db_err(dbenv, 433 "%s: unsupported hash version number %lu", 434 fname, hashm->version); 435 goto einval; 436 } 437 dbp->pgsize = hashm->pagesize; 438 F_CLR(dbp, DB_AM_PGDEF); 439 440 if ((ret = __db_fchk(dbenv, 441 "db_open", hashm->flags, DB_HASH_DUP)) != 0) 442 goto err; 443 DBINFO_FCHK(dbp, "DB_DUP", 444 hashm->flags, DB_HASH_DUP, DB_AM_DUP); 445 type = DB_HASH; 446 447 /* Copy the file's unique id. */ 448 need_fileid = 0; 449 memcpy(dbp->fileid, hashm->uid, DB_FILE_ID_LEN); 450 break; 451 default: 452 if (swapped) { 453 __db_err(dbenv, "unrecognized file type"); 454 goto einval; 455 } 456 M_32_SWAP(((BTMETA *)mbuf)->magic); 457 F_SET(dbp, DB_AM_SWAP); 458 459 swapped = 1; 460 goto retry; 461 } 462 } else { 463 fname = real_name = NULL; 464 465 if (type == DB_UNKNOWN) { 466 __db_err(dbenv, 467 "DBTYPE of unknown without existing file"); 468 goto einval; 469 } 470 F_SET(dbp, DB_AM_INMEM); 471 } 472 473 empty: /* 474 * By the time we get here we've either set the type or we're taking 475 * it from the user. 476 */ 477 dbp->type = type; 478 479 /* 480 * Set the page size to the best value for I/O to this file. Don't 481 * overflow the page offset type. The page size must be db_indx_t 482 * aligned and >= MIN_PAGE_SIZE. 483 * 484 * XXX 485 * Should we be checking for a page size that's not a multiple of 512? 486 */ 487 if (dbp->pgsize == 0) { 488 F_SET(dbp, DB_AM_PGDEF); 489 dbp->pgsize = 8 * 1024; 490 } 491 if (dbp->pgsize < DB_MIN_PGSIZE || 492 dbp->pgsize > DB_MAX_PGSIZE || 493 dbp->pgsize & (sizeof(db_indx_t) - 1)) { 494 __db_err(dbenv, "illegal page size"); 495 goto einval; 496 } 497 498 /* 499 * If no mpool supplied by the application, attach to a local, 500 * created buffer pool. 501 * 502 * XXX 503 * If the user has a DB_ENV structure, we have to use a temporary 504 * one so that we don't step on their values. If the user doesn't, 505 * we have to create one, and keep it around until the call to the 506 * memp_close() function. This is all so the mpool functions get 507 * the error stuff right. 508 */ 509 if (dbenv == NULL || dbenv->mp_info == NULL) { 510 F_SET(dbp, DB_AM_MLOCAL); 511 512 if (dbenv == NULL) { 513 if ((ret = __os_calloc(1, 514 sizeof(DB_ENV), &dbp->mp_dbenv)) != 0) 515 goto err; 516 517 envp = dbp->mp_dbenv; 518 restore = 0; 519 } else { 520 t_dbenv = *dbenv; 521 522 envp = dbenv; 523 restore = 1; 524 } 525 526 /* 527 * Set and/or correct the cache size; must be a multiple of 528 * the page size. 529 */ 530 if (dbinfo == NULL || dbinfo->db_cachesize == 0) 531 cachesize = dbp->pgsize * DB_MINCACHE; 532 else { 533 cachesize = dbinfo->db_cachesize; 534 if (cachesize & (dbp->pgsize - 1)) 535 cachesize += 536 (~cachesize & (dbp->pgsize - 1)) + 1; 537 if (cachesize < dbp->pgsize * DB_MINCACHE) 538 cachesize = dbp->pgsize * DB_MINCACHE; 539 if (cachesize < 20 * 1024) 540 cachesize = 20 * 1024; 541 } 542 envp->mp_size = cachesize; 543 544 if ((ret = memp_open(NULL, DB_CREATE | DB_MPOOL_PRIVATE | 545 (F_ISSET(dbp, DB_AM_THREAD) ? DB_THREAD : 0), 546 __db_omode("rw----"), envp, &dbp->mp)) != 0) 547 goto err; 548 if (restore) 549 *dbenv = t_dbenv; 550 } else 551 dbp->mp = dbenv->mp_info; 552 553 /* Register DB's pgin/pgout functions. */ 554 if ((ret = memp_register(dbp->mp, 555 DB_FTYPE_BTREE, __bam_pgin, __bam_pgout)) != 0) 556 goto err; 557 if ((ret = memp_register(dbp->mp, 558 DB_FTYPE_HASH, __ham_pgin, __ham_pgout)) != 0) 559 goto err; 560 561 /* 562 * If we don't already have one, get a unique file ID. If the file 563 * is a temporary file, then we have to create a unique file ID -- 564 * no backing file will be created until the mpool cache is filled 565 * forcing it to go to disk. The created ID must never match any 566 * potential real file ID -- we know it won't because real file IDs 567 * contain a time stamp after the dev/ino pair, and we're simply 568 * storing a 4-byte locker ID. 569 * 570 * XXX 571 * Store the file id in the locker structure -- we can get it from 572 * there as necessary, and it saves having two copies. 573 */ 574 if (need_fileid) 575 if (fname == NULL) { 576 memset(dbp->fileid, 0, DB_FILE_ID_LEN); 577 if (F_ISSET(dbp, DB_AM_LOCKING) && 578 (ret = lock_id(dbenv->lk_info, 579 (u_int32_t *)dbp->fileid)) != 0) 580 goto err; 581 } else 582 if ((ret = __os_fileid(dbenv, 583 real_name, 1, dbp->fileid)) != 0) 584 goto err; 585 586 /* No further use for the real name. */ 587 if (real_name != NULL) 588 __os_freestr(real_name); 589 real_name = NULL; 590 591 /* 592 * Open a backing file in the memory pool. 593 * 594 * If we need to process the file's pages on I/O, set the file type. 595 * If it's a hash file, always call pgin and pgout routines. This 596 * means that hash files can never be mapped into process memory. If 597 * it's a btree file and requires swapping, we need to page the file 598 * in and out. This has to be right -- we can't mmap files that are 599 * being paged in and out. 600 */ 601 if (type == DB_HASH) 602 ftype = DB_FTYPE_HASH; 603 else 604 ftype = F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_BTREE : 0; 605 pginfo.db_pagesize = dbp->pgsize; 606 pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP); 607 pgcookie.data = &pginfo; 608 pgcookie.size = sizeof(DB_PGINFO); 609 610 /* 611 * Set up additional memp_fopen information. 612 */ 613 memset(&finfo, 0, sizeof(finfo)); 614 finfo.ftype = ftype; 615 finfo.pgcookie = &pgcookie; 616 finfo.fileid = dbp->fileid; 617 finfo.lsn_offset = 0; 618 finfo.clear_len = DB_PAGE_CLEAR_LEN; 619 if ((ret = memp_fopen(dbp->mp, fname, 620 F_ISSET(dbp, DB_AM_RDONLY) ? DB_RDONLY : 0, 621 0, dbp->pgsize, &finfo, &dbp->mpf)) != 0) 622 goto err; 623 624 /* 625 * XXX 626 * We need a per-thread mutex that lives in shared memory -- HP-UX 627 * can't allocate mutexes in malloc'd memory. Allocate it from the 628 * shared memory region, since it's the only one that is guaranteed 629 * to exist. 630 */ 631 if (F_ISSET(dbp, DB_AM_THREAD)) { 632 if ((ret = __memp_reg_alloc(dbp->mp, 633 sizeof(db_mutex_t), NULL, &dbp->mutexp)) != 0) 634 goto err; 635 /* 636 * Since we only get here if DB_THREAD was specified, we know 637 * we have spinlocks and no file offset argument is needed. 638 */ 639 (void)__db_mutex_init(dbp->mutexp, 0); 640 } 641 642 /* Get a log file id. */ 643 if (F_ISSET(dbp, DB_AM_LOGGING) && 644 (ret = log_register(dbenv->lg_info, 645 dbp, fname, type, &dbp->log_fileid)) != 0) 646 goto err; 647 648 /* Call the real open function. */ 649 switch (type) { 650 case DB_BTREE: 651 if (dbinfo != NULL && (ret = __db_fchk(dbenv, 652 "db_open", dbinfo->flags, DB_RECNUM | DB_DUP)) != 0) 653 goto err; 654 if (dbinfo != NULL && (ret = __db_fcchk(dbenv, 655 "db_open", dbinfo->flags, DB_DUP, DB_RECNUM)) != 0) 656 goto err; 657 if ((ret = __bam_open(dbp, dbinfo)) != 0) 658 goto err; 659 break; 660 case DB_HASH: 661 if (dbinfo != NULL && (ret = __db_fchk(dbenv, 662 "db_open", dbinfo->flags, DB_DUP)) != 0) 663 goto err; 664 if ((ret = __ham_open(dbp, dbinfo)) != 0) 665 goto err; 666 break; 667 case DB_RECNO: 668 #define DB_INFO_FLAGS \ 669 (DB_DELIMITER | DB_FIXEDLEN | DB_PAD | DB_RENUMBER | DB_SNAPSHOT) 670 if (dbinfo != NULL && (ret = __db_fchk(dbenv, 671 "db_open", dbinfo->flags, DB_INFO_FLAGS)) != 0) 672 goto err; 673 if ((ret = __ram_open(dbp, dbinfo)) != 0) 674 goto err; 675 break; 676 default: 677 abort(); 678 } 679 680 *dbpp = dbp; 681 return (0); 682 683 einval: ret = EINVAL; 684 err: /* Close the file descriptor. */ 685 if (fd != -1) 686 (void)__os_close(fd); 687 688 /* Discard the log file id. */ 689 if (dbp->log_fileid != 0) 690 (void)log_unregister(dbenv->lg_info, dbp->log_fileid); 691 692 /* Close the memory pool file. */ 693 if (dbp->mpf != NULL) 694 (void)memp_fclose(dbp->mpf); 695 696 /* If the memory pool was local, close it. */ 697 if (F_ISSET(dbp, DB_AM_MLOCAL) && dbp->mp != NULL) 698 (void)memp_close(dbp->mp); 699 700 /* If we allocated a DB_ENV, discard it. */ 701 if (dbp->mp_dbenv != NULL) 702 __os_free(dbp->mp_dbenv, sizeof(DB_ENV)); 703 704 if (real_name != NULL) 705 __os_freestr(real_name); 706 if (dbp != NULL) 707 __os_free(dbp, sizeof(DB)); 708 709 return (ret); 710 } 711 712 /* 713 * __db_close -- 714 * Close a DB tree. 715 * 716 * PUBLIC: int __db_close __P((DB *, u_int32_t)); 717 */ 718 int 719 __db_close(dbp, flags) 720 DB *dbp; 721 u_int32_t flags; 722 { 723 DBC *dbc; 724 int ret, t_ret; 725 726 DB_PANIC_CHECK(dbp); 727 728 /* Validate arguments. */ 729 if ((ret = __db_closechk(dbp, flags)) != 0) 730 return (ret); 731 732 /* Sync the underlying file. */ 733 if (flags != DB_NOSYNC && 734 (t_ret = dbp->sync(dbp, 0)) != 0 && ret == 0) 735 ret = t_ret; 736 737 /* 738 * Go through the active cursors and call the cursor recycle routine, 739 * which resolves pending operations and moves the cursors onto the 740 * free list. Then, walk the free list and call the cursor destroy 741 * routine. 742 */ 743 while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL) 744 if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) 745 ret = t_ret; 746 while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL) 747 if ((t_ret = __db_c_destroy(dbc)) != 0 && ret == 0) 748 ret = t_ret; 749 750 /* Call the access specific close function. */ 751 if ((t_ret = dbp->am_close(dbp)) != 0 && ret == 0) 752 ret = t_ret; 753 754 /* Sync the memory pool. */ 755 if (flags != DB_NOSYNC && (t_ret = memp_fsync(dbp->mpf)) != 0 && 756 t_ret != DB_INCOMPLETE && ret == 0) 757 ret = t_ret; 758 759 /* Close the memory pool file. */ 760 if ((t_ret = memp_fclose(dbp->mpf)) != 0 && ret == 0) 761 ret = t_ret; 762 763 /* If the memory pool was local, close it. */ 764 if (F_ISSET(dbp, DB_AM_MLOCAL) && 765 (t_ret = memp_close(dbp->mp)) != 0 && ret == 0) 766 ret = t_ret; 767 768 if (dbp->saved_open_fd != -1) { 769 (void)__os_close(dbp->saved_open_fd); 770 dbp->saved_open_fd = -1; 771 } 772 773 /* Discard the log file id. */ 774 if (F_ISSET(dbp, DB_AM_LOGGING)) 775 (void)log_unregister(dbp->dbenv->lg_info, dbp->log_fileid); 776 777 /* If we allocated a DB_ENV, discard it. */ 778 if (dbp->mp_dbenv != NULL) 779 __os_free(dbp->mp_dbenv, sizeof(DB_ENV)); 780 781 /* Free the DB. */ 782 __os_free(dbp, sizeof(*dbp)); 783 784 return (ret); 785 } 786