2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 1996-2004
5
* Sleepycat Software. All rights reserved.
7
* $Id: db_open.c,v 11.240 2004/09/22 20:53:19 margo Exp $
10
#include "db_config.h"
12
#ifndef NO_SYSTEM_INCLUDES
13
#include <sys/types.h>
20
#include "dbinc/db_page.h"
21
#include "dbinc/db_shash.h"
22
#include "dbinc/db_swap.h"
23
#include "dbinc/btree.h"
24
#include "dbinc/crypto.h"
25
#include "dbinc/hmac.h"
26
#include "dbinc/fop.h"
27
#include "dbinc/hash.h"
28
#include "dbinc/lock.h"
29
#include "dbinc/log.h"
31
#include "dbinc/qam.h"
32
#include "dbinc/txn.h"
38
* This routine gets called in three different ways:
40
* 1. It can be called to open a file/database. In this case, subdb will
41
* be NULL and meta_pgno will be PGNO_BASE_MD.
42
* 2. It can be called to open a subdatabase during normal operation. In
43
* this case, name and subname will both be non-NULL and meta_pgno will
44
* be PGNO_BASE_MD (also PGNO_INVALID).
45
* 3. It can be called during recovery to open a file/database, in which case
46
* name will be non-NULL, subname will be NULL, and meta-pgno will be
48
* 4. It can be called during recovery to open a subdatabase, in which case
49
* name will be non-NULL, subname may be NULL and meta-pgno will be
50
* a valid pgno (i.e., not PGNO_BASE_MD).
52
* PUBLIC: int __db_open __P((DB *, DB_TXN *,
53
* PUBLIC: const char *, const char *, DBTYPE, u_int32_t, int, db_pgno_t));
56
__db_open(dbp, txn, fname, dname, type, flags, mode, meta_pgno)
59
const char *fname, *dname;
72
DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, fname);
75
* If the environment was configured with threads, the DB handle
76
* must also be free-threaded, so we force the DB_THREAD flag on.
77
* (See SR #2033 for why this is a requirement--recovery needs
78
* to be able to grab a dbp using __db_fileid_to_dbp, and it has
79
* no way of knowing which dbp goes with which thread, so whichever
80
* one it finds has to be usable in any of them.)
82
if (F_ISSET(dbenv, DB_ENV_THREAD))
85
/* Convert any DB->open flags. */
86
if (LF_ISSET(DB_RDONLY))
87
F_SET(dbp, DB_AM_RDONLY);
88
if (LF_ISSET(DB_DIRTY_READ))
89
F_SET(dbp, DB_AM_DIRTY);
92
F_SET(dbp, DB_AM_TXN);
94
/* Fill in the type. */
98
* If fname is NULL, it's always a create, so make sure that we
99
* have a type specified. It would be nice if this checking
100
* were done in __db_open where most of the interface checking
101
* is done, but this interface (__db_dbopen) is used by the
102
* recovery and limbo system, so we need to safeguard this
106
F_SET(dbp, DB_AM_INMEM);
108
if (dbp->type == DB_UNKNOWN) {
110
"DBTYPE of unknown without existing file");
114
if (dbp->pgsize == 0)
115
dbp->pgsize = DB_DEF_IOSIZE;
118
* If the file is a temporary file and we're doing locking,
119
* then we have to create a unique file ID. We can't use our
120
* normal dev/inode pair (or whatever this OS uses in place of
121
* dev/inode pairs) because no backing file will be created
122
* until the mpool cache is filled forcing the buffers to disk.
123
* Grab a random locker ID to use as a file ID. The created
124
* ID must never match a potential real file ID -- we know it
125
* won't because real file IDs contain a time stamp after the
126
* dev/inode pair, and we're simply storing a 4-byte value.
129
* Store the locker in the file id structure -- we can get it
130
* from there as necessary, and it saves having two copies.
132
if (LOCKING_ON(dbenv) &&
133
(ret = __lock_id(dbenv, (u_int32_t *)dbp->fileid)) != 0)
135
} else if (dname == NULL && meta_pgno == PGNO_BASE_MD) {
136
/* Open/create the underlying file. Acquire locks. */
138
__fop_file_setup(dbp, txn, fname, mode, flags, &id)) != 0)
141
if ((ret = __fop_subdb_setup(dbp,
142
txn, fname, dname, mode, flags)) != 0)
144
meta_pgno = dbp->meta_pgno;
148
* If we created the file, set the truncate flag for the mpool. This
149
* isn't for anything we've done, it's protection against stupid user
150
* tricks: if the user deleted a file behind Berkeley DB's back, we
151
* may still have pages in the mpool that match the file's "unique" ID.
153
* Note that if we're opening a subdatabase, we don't want to set
154
* the TRUNCATE flag even if we just created the file--we already
155
* opened and updated the master using access method interfaces,
156
* so we don't want to get rid of any pages that are in the mpool.
157
* If we created the file when we opened the master, we already hit
158
* this check in a non-subdatabase context then.
160
if (dname == NULL && F_ISSET(dbp, DB_AM_CREATED))
163
/* Set up the underlying environment. */
164
if ((ret = __db_dbenv_setup(dbp, txn, fname, id, flags)) != 0)
168
* Set the open flag. We use it to mean that the dbp has gone
169
* through mpf setup, including dbreg_register. Also, below,
170
* the underlying access method open functions may want to do
171
* things like acquire cursors, so the open flag has to be set
172
* before calling them.
174
F_SET(dbp, DB_AM_OPEN_CALLED);
177
* For unnamed files, we need to actually create the file now
178
* that the mpool is open.
180
if (fname == NULL && (ret = __db_new_file(dbp, txn, NULL, NULL)) != 0)
185
ret = __bam_open(dbp, txn, fname, meta_pgno, flags);
188
ret = __ham_open(dbp, txn, fname, meta_pgno, flags);
191
ret = __ram_open(dbp, txn, fname, meta_pgno, flags);
194
ret = __qam_open(dbp, txn, fname, meta_pgno, mode, flags);
197
return (__db_unknown_type(dbenv, "__db_dbopen", dbp->type));
202
DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, fname);
205
* Unnamed files don't need handle locks, so we only have to check
206
* for a handle lock downgrade or lockevent in the case of named
209
if (!F_ISSET(dbp, DB_AM_RECOVER) &&
210
fname != NULL && LOCK_ISSET(dbp->handle_lock)) {
212
ret = __txn_lockevent(dbenv,
213
txn, dbp, &dbp->handle_lock, dbp->lid);
214
} else if (LOCKING_ON(dbenv))
215
/* Trade write handle lock for read handle lock. */
216
ret = __lock_downgrade(dbenv,
217
&dbp->handle_lock, DB_LOCK_READ, 0);
219
DB_TEST_RECOVERY_LABEL
225
* __db_get_open_flags --
226
* Accessor for flags passed into DB->open call
228
* PUBLIC: int __db_get_open_flags __P((DB *, u_int32_t *));
231
__db_get_open_flags(dbp, flagsp)
235
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_open_flags");
237
*flagsp = dbp->open_flags;
243
* Create a new database file.
245
* PUBLIC: int __db_new_file __P((DB *, DB_TXN *, DB_FH *, const char *));
248
__db_new_file(dbp, txn, fhp, name)
259
ret = __bam_new_file(dbp, txn, fhp, name);
262
ret = __ham_new_file(dbp, txn, fhp, name);
265
ret = __qam_new_file(dbp, txn, fhp, name);
270
"%s: Invalid type %d specified", name, dbp->type);
275
DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name);
276
/* Sync the file in preparation for moving it into place. */
277
if (ret == 0 && fhp != NULL)
278
ret = __os_fsync(dbp->dbenv, fhp);
280
DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
282
DB_TEST_RECOVERY_LABEL
288
* Initialize the dbp for a subdb.
290
* PUBLIC: int __db_init_subdb __P((DB *, DB *, const char *, DB_TXN *));
293
__db_init_subdb(mdbp, dbp, name, txn)
303
if (!F_ISSET(dbp, DB_AM_CREATED)) {
304
/* Subdb exists; read meta-data page and initialize. */
306
if ((ret = __memp_fget(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
308
ret = __db_meta_setup(mdbp->dbenv, dbp, name, meta, 0, 0);
309
if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
312
* If __db_meta_setup found that the meta-page hadn't
313
* been written out during recovery, we can just return.
320
/* Handle the create case here. */
324
ret = __bam_new_subdb(mdbp, dbp, txn);
327
ret = __ham_new_subdb(mdbp, dbp, txn);
335
"Invalid subdatabase type %d specified", dbp->type);
344
* Take a buffer containing a meta-data page and check it for a checksum
345
* (and verify the checksum if necessary) and possibly decrypt it.
347
* Return 0 on success, >0 (errno) on error, -1 on checksum mismatch.
349
* PUBLIC: int __db_chk_meta __P((DB_ENV *, DB *, DBMETA *, int));
352
__db_chk_meta(dbenv, dbp, meta, do_metachk)
358
int is_hmac, ret, swapped;
364
if (FLD_ISSET(meta->metaflags, DBMETA_CHKSUM)) {
366
F_SET(dbp, DB_AM_CHKSUM);
368
is_hmac = meta->encrypt_alg == 0 ? 0 : 1;
369
chksum = ((BTMETA *)meta)->chksum;
372
* If we need to swap, the checksum function overwrites the
373
* original checksum with 0, so we need to save a copy of the
374
* original for swapping later.
376
orig_chk = *(u_int32_t *)chksum;
379
* We cannot add this to __db_metaswap because that gets done
380
* later after we've verified the checksum or decrypted.
384
chk_retry: if ((ret = __db_check_chksum(dbenv,
385
(DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
386
DBMETASIZE, is_hmac)) != 0) {
387
if (is_hmac || swapped)
392
*(u_int32_t *)chksum = orig_chk;
396
} else if (dbp != NULL)
397
F_CLR(dbp, DB_AM_CHKSUM);
400
ret = __crypto_decrypt_meta(dbenv, dbp, (u_int8_t *)meta, do_metachk);
408
* Take a buffer containing a meta-data page and figure out if it's
409
* valid, and if so, initialize the dbp from the meta-data page.
411
* PUBLIC: int __db_meta_setup __P((DB_ENV *,
412
* PUBLIC: DB *, const char *, DBMETA *, u_int32_t, int));
415
__db_meta_setup(dbenv, dbp, name, meta, oflags, do_metachk)
423
u_int32_t flags, magic;
429
* Figure out what access method we're dealing with, and then
430
* call access method specific code to check error conditions
431
* based on conflicts between the found file and application
432
* arguments. A found file overrides some user information --
433
* we don't consider it an error, for example, if the user set
434
* an expected byte order and the found file doesn't match it.
436
F_CLR(dbp, DB_AM_SWAP);
448
* The only time this should be 0 is if we're in the
449
* midst of opening a subdb during recovery and that
450
* subdatabase had its meta-data page allocated, but
451
* not yet initialized.
453
if (F_ISSET(dbp, DB_AM_SUBDB) && ((IS_RECOVERING(dbenv) &&
454
F_ISSET((DB_LOG *) dbenv->lg_handle, DBLOG_FORCE_OPEN)) ||
455
meta->pgno != PGNO_INVALID))
460
if (F_ISSET(dbp, DB_AM_SWAP))
464
F_SET(dbp, DB_AM_SWAP);
469
* We can only check the meta page if we are sure we have a meta page.
470
* If it is random data, then this check can fail. So only now can we
471
* checksum and decrypt. Don't distinguish between configuration and
472
* checksum match errors here, because we haven't opened the database
473
* and even a checksum error isn't a reason to panic the environment.
475
if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) {
478
"%s: metadata page checksum error", name);
484
if (dbp->type != DB_UNKNOWN &&
485
dbp->type != DB_RECNO && dbp->type != DB_BTREE)
489
if (F_ISSET(dbp, DB_AM_SWAP))
491
if (LF_ISSET(BTM_RECNO))
492
dbp->type = DB_RECNO;
494
dbp->type = DB_BTREE;
495
if ((oflags & DB_TRUNCATE) == 0 && (ret =
496
__bam_metachk(dbp, name, (BTMETA *)meta)) != 0)
500
if (dbp->type != DB_UNKNOWN && dbp->type != DB_HASH)
504
if ((oflags & DB_TRUNCATE) == 0 && (ret =
505
__ham_metachk(dbp, name, (HMETA *)meta)) != 0)
509
if (dbp->type != DB_UNKNOWN && dbp->type != DB_QUEUE)
511
dbp->type = DB_QUEUE;
512
if ((oflags & DB_TRUNCATE) == 0 && (ret =
513
__qam_metachk(dbp, name, (QMETA *)meta)) != 0)
517
F_SET(dbp, DB_AM_IN_RENAME);
519
/* Copy the file's ID. */
520
memcpy(dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
529
if (F_ISSET(dbp, DB_AM_RECOVER))
532
__db_err(dbenv, "%s: unexpected file type or format", name);
533
return (ret == 0 ? EINVAL : ret);