db

db.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  * Sleepycat Software. All rights reserved.
00006  */
00007 /*
00008  * Copyright (c) 1990, 1993, 1994, 1995, 1996
00009  * Keith Bostic. All rights reserved.
00010  */
00011 /*
00012  * Copyright (c) 1990, 1993, 1994, 1995
00013  * The Regents of the University of California. All rights reserved.
00014  *
00015  * Redistribution and use in source and binary forms, with or without
00016  * modification, are permitted provided that the following conditions
00017  * are met:
00018  * 1. Redistributions of source code must retain the above copyright
00019  * notice, this list of conditions and the following disclaimer.
00020  * 2. Redistributions in binary form must reproduce the above copyright
00021  * notice, this list of conditions and the following disclaimer in the
00022  * documentation and/or other materials provided with the distribution.
00023  * 3. Neither the name of the University nor the names of its contributors
00024  * may be used to endorse or promote products derived from this software
00025  * without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00028  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00031  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00032  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00033  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00034  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00035  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00036  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00037  * SUCH DAMAGE.
00038  */
00039 
00040 #include "config.h"
00041 
00042 #ifndef lint
00043 static const char revid[] = "$Id: db_8c-source.html,v 1.1 2008年06月08日 10:16:30 sebdiaz Exp $";
00044 #endif /* not lint */
00045 
00046 #ifndef NO_SYSTEM_INCLUDES
00047 #include <sys/types.h>
00048 
00049 #include <errno.h>
00050 #include <stddef.h>
00051 #include <stdlib.h>
00052 #include <string.h>
00053 #endif
00054 
00055 #include "db_int.h"
00056 #include "db_page.h"
00057 #include "db_shash.h"
00058 #include "db_swap.h"
00059 #include "btree.h"
00060 #include "db_am.h"
00061 #include "hash.h"
00062 #include "lock.h"
00063 #include "log.h"
00064 #include "mp.h"
00065 #include "qam.h"
00066 #include "common_ext.h"
00067 
00068 /* Actions that __db_master_update can take. */
00069 typedef enum { MU_REMOVE, MU_RENAME, MU_OPEN } mu_action;
00070 
00071 /* Flag values that __db_file_setup can return. */
00072 #define DB_FILE_SETUP_CREATE 0x01
00073 #define DB_FILE_SETUP_ZERO 0x02
00074 
00075 static int __db_file_setup __P((DB *,
00076 const char *, u_int32_t, int, db_pgno_t, int *));
00077 static int __db_master_update __P((DB *,
00078 const char *, u_int32_t,
00079 db_pgno_t *, mu_action, const char *, u_int32_t));
00080 static int __db_metabegin __P((DB *, DB_LOCK *));
00081 static int __db_metaend __P((DB *,
00082 DB_LOCK *, int, int (*)(DB *, void *), void *));
00083 static int __db_refresh __P((DB *));
00084 static int __db_remove_callback __P((DB *, void *));
00085 static int __db_set_pgsize __P((DB *, DB_FH *, char *));
00086 static int __db_subdb_remove __P((DB *, const char *, const char *));
00087 static int __db_subdb_rename __P(( DB *,
00088 const char *, const char *, const char *));
00089 #if CONFIG_TEST
00090 static void __db_makecopy __P((const char *, const char *));
00091 #endif
00092 
00093 /*
00094  * CDB___db_open --
00095  * Main library interface to the DB access methods.
00096  *
00097  * PUBLIC: int CDB___db_open __P((DB *,
00098  * PUBLIC: const char *, const char *, DBTYPE, u_int32_t, int));
00099  */
00100 int
00101 CDB___db_open(dbp, name, subdb, type, flags, mode)
00102 DB *dbp;
00103 const char *name, *subdb;
00104 DBTYPE type;
00105 u_int32_t flags;
00106 int mode;
00107 {
00108 DB_ENV *dbenv;
00109 DB_LOCK open_lock;
00110 DB *mdbp;
00111 db_pgno_t meta_pgno;
00112 u_int32_t ok_flags;
00113 int ret, t_ret;
00114 
00115 dbenv = dbp->dbenv;
00116 mdbp = NULL;
00117 
00118 /* Validate arguments. */
00119 #define OKFLAGS \
00120  (DB_CREATE | DB_EXCL | DB_FCNTL_LOCKING | DB_COMPRESS | \
00121  DB_NOMMAP | DB_RDONLY | DB_RDWRMASTER | DB_THREAD | DB_TRUNCATE)
00122 if ((ret = CDB___db_fchk(dbenv, "DB->open", flags, OKFLAGS)) != 0)
00123 return (ret);
00124 if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE))
00125 return (CDB___db_ferr(dbenv, "DB->open", 1));
00126 if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE))
00127 return (CDB___db_ferr(dbenv, "DB->open", 1));
00128 #ifdef HAVE_VXWORKS
00129 if (LF_ISSET(DB_TRUNCATE)) {
00130 CDB___db_err(dbenv, "DB_TRUNCATE unsupported in VxWorks");
00131 return (CDB___db_eopnotsup(dbenv));
00132 }
00133 #endif
00134 switch (type) {
00135 case DB_UNKNOWN:
00136 if (LF_ISSET(DB_CREATE)) {
00137 CDB___db_err(dbenv,
00138 "%s: DB_UNKNOWN type specified with DB_CREATE",
00139 name);
00140 return (EINVAL);
00141 }
00142 ok_flags = 0;
00143 break;
00144 case DB_BTREE:
00145 ok_flags = DB_OK_BTREE;
00146 break;
00147 case DB_HASH:
00148 ok_flags = DB_OK_HASH;
00149 break;
00150 case DB_QUEUE:
00151 ok_flags = DB_OK_QUEUE;
00152 break;
00153 case DB_RECNO:
00154 ok_flags = DB_OK_RECNO;
00155 break;
00156 default:
00157 CDB___db_err(dbenv, "unknown type: %lu", type);
00158 return (EINVAL);
00159 }
00160 if (ok_flags)
00161 DB_ILLEGAL_METHOD(dbp, ok_flags);
00162 
00163 /* The environment may have been created, but never opened. */
00164 if (!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_OPEN_CALLED)) {
00165 CDB___db_err(dbenv, "environment not yet opened");
00166 return (EINVAL);
00167 }
00168 
00169 /*
00170  * Historically, you could pass in an environment that didn't have a
00171  * mpool, and DB would create a private one behind the scenes. This
00172  * no longer works.
00173  */
00174 if (!F_ISSET(dbenv, DB_ENV_DBLOCAL) && !MPOOL_ON(dbenv)) {
00175 CDB___db_err(dbenv, "environment did not include a memory pool.");
00176 return (EINVAL);
00177 }
00178 
00179 /*
00180  * You can't specify threads during DB->open if subsystems in the
00181  * environment weren't configured with them.
00182  */
00183 if (LF_ISSET(DB_THREAD) &&
00184 !F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_THREAD)) {
00185 CDB___db_err(dbenv, "environment not created using DB_THREAD");
00186 return (EINVAL);
00187 }
00188 
00189 /*
00190  * If the environment was configured with threads, the DB handle
00191  * must also be free-threaded, so we force the DB_THREAD flag on.
00192  * (See SR #2033 for why this is a requirement--recovery needs
00193  * to be able to grab a dbp using __db_fileid_to_dbp, and it has
00194  * no way of knowing which dbp goes with which thread, so whichever
00195  * one it finds has to be usable in any of them.)
00196  */
00197 if (F_ISSET(dbenv, DB_ENV_THREAD))
00198 LF_SET(DB_THREAD);
00199 
00200 /* DB_TRUNCATE is not transaction recoverable. */
00201 if (LF_ISSET(DB_TRUNCATE) && TXN_ON(dbenv)) {
00202 CDB___db_err(dbenv,
00203 "DB_TRUNCATE illegal in a transaction protected environment");
00204 return (EINVAL);
00205 }
00206 
00207 /* Subdatabase checks. */
00208 if (subdb != NULL) {
00209 /* Subdatabases must be created in named files. */
00210 if (name == NULL) {
00211 CDB___db_err(dbenv,
00212 "multiple databases cannot be created in temporary files");
00213 return (EINVAL);
00214 }
00215 
00216 /* QAM can't be done as a subdatabase. */
00217 if (type == DB_QUEUE) {
00218 CDB___db_err(dbenv, "Queue databases must be one-per-file");
00219 return (EINVAL);
00220 }
00221 }
00222 
00223 /* Convert any DB->open flags. */
00224 if (LF_ISSET(DB_RDONLY))
00225 F_SET(dbp, DB_AM_RDONLY);
00226 if (LF_ISSET(DB_COMPRESS))
00227 F_SET(dbp, DB_AM_CMPR);
00228 
00229 /* Fill in the type. */
00230 dbp->type = type;
00231 
00232 /*
00233  * If we're potentially creating a database, wrap the open inside of
00234  * a transaction.
00235  */
00236 if (TXN_ON(dbenv) && LF_ISSET(DB_CREATE))
00237 if ((ret = __db_metabegin(dbp, &open_lock)) != 0)
00238 return (ret);
00239 
00240 /*
00241  * If we're opening a subdatabase, we have to open (and potentially
00242  * create) the CDB_main database, and then get (and potentially store)
00243  * our base page number in that database. Then, we can finally open
00244  * the subdatabase.
00245  */
00246 if (subdb == NULL)
00247 meta_pgno = PGNO_BASE_MD;
00248 else {
00249 /*
00250  * Open the master database, optionally creating or updating
00251  * it, and retrieve the metadata page number.
00252  */
00253 if ((ret =
00254 CDB___db_master_open(dbp, name, flags, mode, &mdbp)) != 0)
00255 goto err;
00256 
00257 /* Copy the page size and file id from the master. */
00258 dbp->pgsize = mdbp->pgsize;
00259 F_SET(dbp, DB_AM_SUBDB);
00260 memcpy(dbp->fileid, mdbp->fileid, DB_FILE_ID_LEN);
00261 
00262 if ((ret = __db_master_update(mdbp,
00263 subdb, type, &meta_pgno, MU_OPEN, NULL, flags)) != 0)
00264 goto err;
00265 
00266 /*
00267  * Clear the exclusive open and truncation flags, they only
00268  * apply to the open of the master database.
00269  */
00270 LF_CLR(DB_EXCL | DB_TRUNCATE);
00271 }
00272 
00273 ret = CDB___db_dbopen(dbp, name, flags, mode, meta_pgno);
00274 
00275 /*
00276  * You can open the database that describes the subdatabases in the
00277  * rest of the file read-only. The content of each key's data is
00278  * unspecified and applications should never be adding new records
00279  * or updating existing records. However, during recovery, we need
00280  * to open these databases R/W so we can redo/undo changes in them.
00281  * Likewise, we need to open master databases read/write during
00282  * rename and remove so we can be sure they're fully sync'ed, so
00283  * we provide an override flag for the purpose.
00284  */
00285 if (subdb == NULL && !IS_RECOVERING(dbenv) && !LF_ISSET(DB_RDONLY) &&
00286 !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) {
00287 CDB___db_err(dbenv,
00288 "files containing multiple databases may only be opened read-only");
00289 ret = EINVAL;
00290 goto err;
00291 }
00292 
00293 err: /*
00294  * End any transaction, committing if we were successful, aborting
00295  * otherwise.
00296  */
00297 if (TXN_ON(dbenv) && LF_ISSET(DB_CREATE))
00298 if ((t_ret = __db_metaend(dbp,
00299 &open_lock, ret == 0, NULL, NULL)) != 0 && ret == 0)
00300 ret = t_ret;
00301 
00302 /* If we were successful, don't discard the file on close. */
00303 if (ret == 0)
00304 F_CLR(dbp, DB_AM_DISCARD);
00305 
00306 /* If we were unsuccessful, destroy the DB handle. */
00307 if (ret != 0) {
00308 /* In recovery we set log_fileid early. */
00309 if (IS_RECOVERING(dbenv))
00310 dbp->log_fileid = DB_LOGFILEID_INVALID;
00311 __db_refresh(dbp);
00312 }
00313 
00314 if (mdbp != NULL) {
00315 /* If we were successful, don't discard the file on close. */
00316 if (ret == 0)
00317 F_CLR(mdbp, DB_AM_DISCARD);
00318 if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0)
00319 ret = t_ret;
00320 }
00321 
00322 return (ret);
00323 }
00324 
00325 /*
00326  * CDB___db_dbopen --
00327  * Open a database.
00328  * PUBLIC: int CDB___db_dbopen __P((DB *, const char *, u_int32_t, int, db_pgno_t));
00329  */
00330 int
00331 CDB___db_dbopen(dbp, name, flags, mode, meta_pgno)
00332 DB *dbp;
00333 const char *name;
00334 u_int32_t flags;
00335 int mode;
00336 db_pgno_t meta_pgno;
00337 {
00338 DB_ENV *dbenv;
00339 int ret, retinfo;
00340 
00341 dbenv = dbp->dbenv;
00342 
00343 /* Set up the underlying file. */
00344 if ((ret = __db_file_setup(dbp,
00345 name, flags, mode, meta_pgno, &retinfo)) != 0)
00346 return (ret);
00347 
00348 /*
00349  * If we created the file, set the truncate flag for the mpool. This
00350  * isn't for anything we've done, it's protection against stupid user
00351  * tricks: if the user deleted a file behind Berkeley DB's back, we
00352  * may still have pages in the mpool that match the file's "unique" ID.
00353  */
00354 if (retinfo & DB_FILE_SETUP_CREATE)
00355 flags |= DB_TRUNCATE;
00356 
00357 /* Set up the underlying environment. */
00358 if ((ret = CDB___db_dbenv_setup(dbp, name, flags)) != 0)
00359 return (ret);
00360 
00361 /*
00362  * Do access method specific initialization.
00363  *
00364  * !!!
00365  * Set the open flag. (The underlying access method open functions
00366  * may want to do things like acquire cursors, so the open flag has
00367  * to be set before calling them.)
00368  */
00369 F_SET(dbp, DB_OPEN_CALLED);
00370 
00371 if (retinfo & DB_FILE_SETUP_ZERO)
00372 return (0);
00373 
00374 switch (dbp->type) {
00375 case DB_BTREE:
00376 ret = CDB___bam_open(dbp, name, meta_pgno, flags);
00377 break;
00378 case DB_HASH:
00379 ret = CDB___ham_open(dbp, name, meta_pgno, flags);
00380 break;
00381 case DB_RECNO:
00382 ret = CDB___ram_open(dbp, name, meta_pgno, flags);
00383 break;
00384 case DB_QUEUE:
00385 ret = CDB___qam_open(dbp, name, meta_pgno, flags);
00386 break;
00387 case DB_UNKNOWN:
00388 return (CDB___db_unknown_type(dbp->dbenv,
00389 "CDB___db_dbopen", dbp->type));
00390 break;
00391 }
00392 return (ret);
00393 }
00394 
00395 /*
00396  * CDB___db_master_open --
00397  * Open up a handle on a master database.
00398  *
00399  * PUBLIC: int CDB___db_master_open __P((DB *,
00400  * PUBLIC: const char *, u_int32_t, int, DB **));
00401  */
00402 int
00403 CDB___db_master_open(subdbp, name, flags, mode, dbpp)
00404 DB *subdbp;
00405 const char *name;
00406 u_int32_t flags;
00407 int mode;
00408 DB **dbpp;
00409 {
00410 DB *dbp;
00411 int ret;
00412 
00413 /* Open up a handle on the CDB_main database. */
00414 if ((ret = CDB_db_create(&dbp, subdbp->dbenv, 0)) != 0)
00415 return (ret);
00416 
00417 /*
00418  * It's always a btree.
00419  * Run in the transaction we've created.
00420  * Set the pagesize in case we're creating a new database.
00421  * Flag that we're creating a database with subdatabases.
00422  */
00423 dbp->type = DB_BTREE;
00424 dbp->open_txn = subdbp->open_txn;
00425 dbp->pgsize = subdbp->pgsize;
00426 F_SET(dbp, DB_AM_SUBDB);
00427 if (LF_ISSET(DB_COMPRESS)) F_SET(dbp, DB_AM_CMPR);
00428 
00429 if ((ret = CDB___db_dbopen(dbp, name, flags, mode, PGNO_BASE_MD)) != 0) {
00430 if (!F_ISSET(dbp, DB_AM_DISCARD))
00431 dbp->close(dbp, 0);
00432 return (ret);
00433 }
00434 
00435 *dbpp = dbp;
00436 return (0);
00437 }
00438 
00439 /*
00440  * __db_master_update --
00441  * Add/Remove a subdatabase from a master database.
00442  */
00443 static int
00444 __db_master_update(mdbp, subdb, type, meta_pgnop, action, newname, flags)
00445 DB *mdbp;
00446 const char *subdb;
00447 u_int32_t type;
00448 db_pgno_t *meta_pgnop; /* may be NULL on MU_RENAME */
00449 mu_action action;
00450 const char *newname;
00451 u_int32_t flags;
00452 {
00453 DB_ENV *dbenv;
00454 DBC *dbc, *ndbc;
00455 DBT key, data, ndata;
00456 PAGE *p;
00457 db_pgno_t t_pgno;
00458 int ret, t_ret;
00459 
00460 dbenv = mdbp->dbenv;
00461 dbc = ndbc = NULL;
00462 p = NULL;
00463 
00464 memset(&key, 0, sizeof(key));
00465 memset(&data, 0, sizeof(data));
00466 
00467 /* Open up a cursor. */
00468 if ((ret = mdbp->cursor(mdbp, mdbp->open_txn, &dbc, 0)) != 0)
00469 goto err;
00470 
00471 /*
00472  * Try to point the cursor at the record.
00473  *
00474  * If we're removing or potentially creating an entry, lock the page
00475  * with DB_RMW.
00476  *
00477  * !!!
00478  * We don't include the name's nul termination in the database.
00479  */
00480 key.data = (char *)subdb;
00481 key.size = strlen(subdb);
00482 /* In the rename case, we do multiple cursor ops, so MALLOC is safer. */
00483 F_SET(&data, DB_DBT_MALLOC);
00484 ret = dbc->c_get(dbc, &key, &data,
00485 DB_SET | (STD_LOCKING(dbc) &&
00486 (action == MU_RENAME || LF_ISSET(DB_CREATE)) ? DB_RMW : 0));
00487 
00488 /*
00489  * What we do next--whether or not we found a record for the
00490  * specified subdatabase--depends on what the specified action is.
00491  * Handle ret appropriately as the first statement of each case.
00492  */
00493 switch (action) {
00494 case MU_REMOVE:
00495 /*
00496  * We should have found something if we're removing it. Note
00497  * that in the common case where the DB we're asking to remove
00498  * doesn't exist, we won't get this far; __db_subdb_remove
00499  * will already have returned an error from CDB___db_open.
00500  */
00501 if (ret != 0)
00502 goto err;
00503 
00504 /*
00505  * Delete the subdatabase entry first; if this fails,
00506  * we don't want to touch the actual subdb pages.
00507  */
00508 if ((ret = dbc->c_del(dbc, 0)) != 0)
00509 goto err;
00510 
00511 /*
00512  * We're handling actual data, not on-page meta-data,
00513  * so it hasn't been converted to/from opposite
00514  * endian architectures. Do it explicitly, now.
00515  */
00516 memcpy(meta_pgnop, data.data, sizeof(db_pgno_t));
00517 DB_NTOHL(meta_pgnop);
00518 if ((ret = CDB_memp_fget(mdbp->mpf, meta_pgnop, 0, &p)) != 0)
00519 goto err;
00520 
00521 /* Free and put the page. */
00522 if ((ret = CDB___db_free(dbc, p)) != 0)
00523 goto err;
00524 p = NULL;
00525 break;
00526 case MU_RENAME:
00527 /* We should have found something if we're renaming it. */
00528 if (ret != 0)
00529 goto err;
00530 
00531 /*
00532  * Before we rename, we need to make sure we're not
00533  * overwriting another subdatabase, or else this operation
00534  * won't be undoable. Open a second cursor and check
00535  * for the existence of newname; it shouldn't appear under
00536  * us since we hold the metadata lock.
00537  */
00538 if ((ret = mdbp->cursor(mdbp, mdbp->open_txn, &ndbc, 0)) != 0)
00539 goto err;
00540 DB_ASSERT(newname != NULL);
00541 key.data = (void *) newname;
00542 key.size = strlen(newname);
00543 
00544 /*
00545  * We don't actually care what the meta page of the potentially-
00546  * overwritten DB is; we just care about existence.
00547  */
00548 memset(&ndata, 0, sizeof(ndata));
00549 F_SET(&ndata, DB_DBT_USERMEM | DB_DBT_PARTIAL);
00550 
00551 if ((ret = ndbc->c_get(ndbc, &key, &ndata, DB_SET)) == 0) {
00552 /* A subdb called newname exists. Bail. */
00553 ret = EEXIST;
00554 CDB___db_err(dbenv, "rename: database %s exists", newname);
00555 goto err;
00556 } else if (ret != DB_NOTFOUND)
00557 goto err;
00558 
00559 /*
00560  * Now do the put first; we don't want to lose our
00561  * sole reference to the subdb. Use the second cursor
00562  * so that the first one continues to point to the old record.
00563  */
00564 if ((ret = ndbc->c_put(ndbc, &key, &data, DB_KEYFIRST)) != 0)
00565 goto err;
00566 if ((ret = dbc->c_del(dbc, 0)) != 0) {
00567 /*
00568  * If the delete fails, try to delete the record
00569  * we just put, in case we're not txn-protected.
00570  */
00571 (void)ndbc->c_del(ndbc, 0);
00572 goto err;
00573 }
00574 
00575 break;
00576 case MU_OPEN:
00577 /*
00578  * Get the subdatabase information. If it already exists,
00579  * copy out the page number and we're done.
00580  */
00581 switch (ret) {
00582 case 0:
00583 memcpy(meta_pgnop, data.data, sizeof(db_pgno_t));
00584 DB_NTOHL(meta_pgnop);
00585 goto done;
00586 case DB_NOTFOUND:
00587 if (LF_ISSET(DB_CREATE))
00588 break;
00589 /*
00590  * No db_err, it is reasonable to remove a
00591  * nonexistent db.
00592  */
00593 ret = ENOENT;
00594 goto err;
00595 default:
00596 goto err;
00597 }
00598 
00599 if ((ret = CDB___db_new(dbc,
00600 type == DB_HASH ? P_HASHMETA : P_BTREEMETA, &p)) != 0)
00601 goto err;
00602 *meta_pgnop = PGNO(p);
00603 
00604 /*
00605  * XXX
00606  * We're handling actual data, not on-page meta-data, so it
00607  * hasn't been converted to/from opposite endian architectures.
00608  * Do it explicitly, now.
00609  */
00610 t_pgno = PGNO(p);
00611 DB_HTONL(&t_pgno);
00612 memset(&ndata, 0, sizeof(ndata));
00613 ndata.data = &t_pgno;
00614 ndata.size = sizeof(db_pgno_t);
00615 if ((ret = dbc->c_put(dbc, &key, &ndata, DB_KEYLAST)) != 0)
00616 goto err;
00617 break;
00618 }
00619 
00620 err:
00621 done: /*
00622  * If we allocated a page: if we're successful, mark the page dirty
00623  * and return it to the cache, otherwise, discard/free it.
00624  */
00625 if (p != NULL) {
00626 if (ret == 0) {
00627 if ((t_ret =
00628 CDB_memp_fput(mdbp->mpf, p, DB_MPOOL_DIRTY)) != 0)
00629 ret = t_ret;
00630 /*
00631  * Since we cannot close this file until after
00632  * transaction commit, we need to sync the dirty
00633  * pages, because we'll read these directly from
00634  * disk to open.
00635  */
00636 if ((t_ret = mdbp->sync(mdbp, 0)) != 0 && ret == 0)
00637 ret = t_ret;
00638 } else
00639 (void)CDB___db_free(dbc, p);
00640 }
00641 
00642 /* Discard the cursor(s) and data. */
00643 if (data.data != NULL)
00644 CDB___os_free(data.data, data.size);
00645 if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
00646 ret = t_ret;
00647 if (ndbc != NULL && (t_ret = ndbc->c_close(ndbc)) != 0 && ret == 0)
00648 ret = t_ret;
00649 
00650 return (ret);
00651 }
00652 
00653 /*
00654  * CDB___db_dbenv_setup --
00655  * Set up the underlying environment during a db_open.
00656  *
00657  * PUBLIC: int CDB___db_dbenv_setup __P((DB *, const char *, u_int32_t));
00658  */
00659 int
00660 CDB___db_dbenv_setup(dbp, name, flags)
00661 DB *dbp;
00662 const char *name;
00663 u_int32_t flags;
00664 {
00665 DB_ENV *dbenv;
00666 DBT pgcookie;
00667 DB_MPOOL_FINFO finfo;
00668 DB_PGINFO pginfo;
00669 int ret;
00670 
00671 dbenv = dbp->dbenv;
00672 
00673 /* If we don't yet have an environment, it's time to create it. */
00674 if (!F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
00675 /* Make sure we have at least DB_MINCACHE pages in our cache. */
00676 if (dbenv->mp_gbytes == 0 &&
00677 dbenv->mp_bytes < dbp->pgsize * DB_MINPAGECACHE &&
00678 (ret = dbenv->set_cachesize(
00679 dbenv, 0, dbp->pgsize * DB_MINPAGECACHE, 0)) != 0)
00680 return (ret);
00681 
00682 if ((ret = dbenv->open(dbenv, NULL, DB_CREATE |
00683 DB_INIT_MPOOL | DB_PRIVATE | LF_ISSET(DB_THREAD), 0)) != 0)
00684 return (ret);
00685 }
00686 
00687 /* Register DB's pgin/pgout functions. */
00688 if ((ret =
00689 CDB_memp_register(dbenv, DB_FTYPE_SET, CDB___db_pgin, CDB___db_pgout)) != 0)
00690 return (ret);
00691 
00692 /*
00693  * Open a backing file in the memory pool.
00694  *
00695  * If we need to pre- or post-process a file's pages on I/O, set the
00696  * file type. If it's a hash file, always call the pgin and pgout
00697  * routines. This means that hash files can never be mapped into
00698  * process memory. If it's a btree file and requires swapping, we
00699  * need to page the file in and out. This has to be right -- we can't
00700  * mmap files that are being paged in and out.
00701  */
00702 memset(&finfo, 0, sizeof(finfo));
00703 switch (dbp->type) {
00704 case DB_BTREE:
00705 case DB_RECNO:
00706 finfo.ftype =
00707 F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_SET : DB_FTYPE_NOTSET;
00708 finfo.clear_len = DB_PAGE_DB_LEN;
00709 break;
00710 case DB_HASH:
00711 finfo.ftype = DB_FTYPE_SET;
00712 finfo.clear_len = DB_PAGE_DB_LEN;
00713 break;
00714 case DB_QUEUE:
00715 finfo.ftype =
00716 F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_SET : DB_FTYPE_NOTSET;
00717 finfo.clear_len = DB_PAGE_QUEUE_LEN;
00718 break;
00719 case DB_UNKNOWN:
00720 return (CDB___db_unknown_type(dbp->dbenv,
00721 "CDB___db_dbenv_setup", dbp->type));
00722 }
00723 finfo.pgcookie = &pgcookie;
00724 finfo.fileid = dbp->fileid;
00725 finfo.lsn_offset = 0;
00726 
00727 pginfo.db_pagesize = dbp->pgsize;
00728 pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP);
00729 pgcookie.data = &pginfo;
00730 pgcookie.size = sizeof(DB_PGINFO);
00731 
00732 if ((ret = CDB_memp_fopen(dbenv, name,
00733 LF_ISSET(DB_RDONLY | DB_NOMMAP | DB_ODDFILESIZE | DB_TRUNCATE | DB_COMPRESS),
00734 0, dbp->pgsize, &finfo, &dbp->mpf)) != 0)
00735 return (ret);
00736 
00737 /*
00738  * We may need a per-thread mutex. Allocate it from the environment
00739  * region, there's supposed to be extra space there for that purpose.
00740  */
00741 if (LF_ISSET(DB_THREAD)) {
00742 if ((ret = CDB___db_mutex_alloc(
00743 dbenv, dbenv->reginfo, (MUTEX **)&dbp->mutexp)) != 0)
00744 return (ret);
00745 if ((ret = __db_mutex_init(
00746 dbenv, dbp->mutexp, 0, MUTEX_THREAD)) != 0)
00747 return (ret);
00748 }
00749 
00750 /* Get a log file id. */
00751 if (LOGGING_ON(dbenv) && !IS_RECOVERING(dbenv) &&
00752 #if !defined(DEBUG_ROP)
00753 !F_ISSET(dbp, DB_AM_RDONLY) &&
00754 #endif
00755 (ret = CDB_log_register(dbenv, dbp, name)) != 0)
00756 return (ret);
00757 
00758 return (0);
00759 }
00760 
00761 /*
00762  * __db_file_setup --
00763  * Setup the file or in-memory data.
00764  * Read the database metadata and resolve it with our arguments.
00765  */
00766 static int
00767 __db_file_setup(dbp, name, flags, mode, meta_pgno, retflags)
00768 DB *dbp;
00769 const char *name;
00770 u_int32_t flags;
00771 int mode;
00772 db_pgno_t meta_pgno;
00773 int *retflags;
00774 {
00775 DB *mdb;
00776 DBT namedbt;
00777 DB_ENV *dbenv;
00778 DB_FH *fhp, fh;
00779 DB_LSN lsn;
00780 DB_TXN *txn;
00781 size_t nr;
00782 u_int32_t magic, oflags;
00783 int ret, retry_cnt, t_ret;
00784 char *real_name, mbuf[DBMETASIZE];
00785 size_t disk_pagesize;
00786 
00787 #define IS_SUBDB_SETUP (meta_pgno != PGNO_BASE_MD)
00788 
00789 dbenv = dbp->dbenv;
00790 dbp->meta_pgno = meta_pgno;
00791 txn = NULL;
00792 *retflags = 0;
00793 
00794 /*
00795  * If we open a file handle and our caller is doing fcntl(2) locking,
00796  * we can't close it because that would discard the caller's lock.
00797  * Save it until we close the DB handle.
00798  */
00799 if (LF_ISSET(DB_FCNTL_LOCKING)) {
00800 if ((ret = CDB___os_malloc(dbenv, sizeof(*fhp), NULL, &fhp)) != 0)
00801 return (ret);
00802 } else
00803 fhp = &fh;
00804 memset(fhp, 0, sizeof(*fhp));
00805 
00806 /*
00807  * If the file is in-memory, set up is simple. Otherwise, do the
00808  * hard work of opening and reading the file.
00809  *
00810  * If we have a file name, try and read the first page, figure out
00811  * what type of file it is, and initialize everything we can based
00812  * on that file's meta-data page.
00813  *
00814  * !!!
00815  * There's a reason we don't push this code down into the buffer cache.
00816  * The problem is that there's no information external to the file that
00817  * we can use as a unique ID. UNIX has dev/inode pairs, but they are
00818  * not necessarily unique after reboot, if the file was mounted via NFS.
00819  * Windows has similar problems, as the FAT filesystem doesn't maintain
00820  * dev/inode numbers across reboot. So, we must get something from the
00821  * file we can use to ensure that, even after a reboot, the file we're
00822  * joining in the cache is the right file for us to join. The solution
00823  * we use is to maintain a file ID that's stored in the database, and
00824  * that's why we have to open and read the file before calling into the
00825  * buffer cache.
00826  *
00827  * The secondary reason is that there's additional information that
00828  * we want to have before instantiating a file in the buffer cache:
00829  * the page size, file type (btree/hash), if swapping is required,
00830  * and flags (DB_RDONLY, DB_CREATE, DB_TRUNCATE). We could handle
00831  * needing this information by allowing it to be set for a file in
00832  * the buffer cache even after the file has been opened, and, of
00833  * course, supporting the ability to flush a file from the cache as
00834  * necessary, e.g., if we guessed wrongly about the page size. Given
00835  * that we have to read the file anyway to get the file ID, we might
00836  * as well get the rest, too.
00837  *
00838  * Get the real file name.
00839  */
00840 if (name == NULL) {
00841 F_SET(dbp, DB_AM_INMEM);
00842 
00843 if (dbp->type == DB_UNKNOWN) {
00844 CDB___db_err(dbenv,
00845 "DBTYPE of unknown without existing file");
00846 return (EINVAL);
00847 }
00848 real_name = NULL;
00849 
00850 /* Set the page size if we don't have one yet. */
00851 if (dbp->pgsize == 0)
00852 dbp->pgsize = DB_DEF_IOSIZE;
00853 
00854 /*
00855  * If the file is a temporary file and we're doing locking,
00856  * then we have to create a unique file ID. We can't use our
00857  * normal dev/inode pair (or whatever this OS uses in place of
00858  * dev/inode pairs) because no backing file will be created
00859  * until the mpool cache is filled forcing the buffers to disk.
00860  * Grab a random locker ID to use as a file ID. The created
00861  * ID must never match a potential real file ID -- we know it
00862  * won't because real file IDs contain a time stamp after the
00863  * dev/inode pair, and we're simply storing a 4-byte value.
00864  *
00865  * !!!
00866  * Store the locker in the file id structure -- we can get it
00867  * from there as necessary, and it saves having two copies.
00868  */
00869 if (LOCKING_ON(dbenv) &&
00870 (ret = CDB_lock_id(dbenv, (u_int32_t *)dbp->fileid)) != 0)
00871 return (ret);
00872 
00873 return (0);
00874 }
00875 
00876 /* Get the real backing file name. */
00877 if ((ret = CDB___db_appname(dbenv,
00878 DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0)
00879 return (ret);
00880 
00881 /*
00882  * Open the backing file. We need to make sure that multiple processes
00883  * attempting to create the file at the same time are properly ordered
00884  * so that only one of them creates the "unique" file ID, so we open it
00885  * O_EXCL and O_CREAT so two simultaneous attempts to create the region
00886  * will return failure in one of the attempts. If we're the one that
00887  * fails, simply retry without the O_CREAT flag, which will require the
00888  * meta-data page exist.
00889  */
00890 
00891 /* Fill in the default file mode. */
00892 if (mode == 0)
00893 mode = CDB___db_omode("rwrw--");
00894 
00895 oflags = 0;
00896 if (LF_ISSET(DB_RDONLY))
00897 oflags |= DB_OSO_RDONLY;
00898 if (LF_ISSET(DB_TRUNCATE))
00899 oflags |= DB_OSO_TRUNC;
00900 
00901 retry_cnt = 0;
00902 open_retry:
00903 *retflags = 0;
00904 ret = 0;
00905 if (!IS_SUBDB_SETUP && LF_ISSET(DB_CREATE)) {
00906 if (dbp->open_txn != NULL) {
00907 /*
00908  * Start a child transaction to wrap this individual
00909  * create.
00910  */
00911 if ((ret =
00912 CDB_txn_begin(dbenv, dbp->open_txn, &txn, 0)) != 0)
00913 goto err_msg;
00914 
00915 memset(&namedbt, 0, sizeof(namedbt));
00916 namedbt.data = (char *)name;
00917 namedbt.size = strlen(name) + 1;
00918 if ((ret = CDB___crdel_fileopen_log(dbenv, txn,
00919 &lsn, DB_FLUSH, &namedbt, mode)) != 0)
00920 goto err_msg;
00921 }
00922 DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, name);
00923 if ((ret = CDB___os_open(dbenv, real_name,
00924 oflags | DB_OSO_CREATE | DB_OSO_EXCL, mode, fhp)) == 0) {
00925 DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, name);
00926 
00927 /* Commit the file create. */
00928 if (dbp->open_txn != NULL) {
00929 if ((ret = CDB_txn_commit(txn, DB_TXN_SYNC)) != 0)
00930 goto err_msg;
00931 txn = NULL;
00932 }
00933 
00934 /*
00935  * We created the file. This means that if we later
00936  * fail, we need to delete the file and if we're going
00937  * to do that, we need to trash any pages in the
00938  * memory pool. Since we only know here that we
00939  * created the file, we're going to set the flag here
00940  * and clear it later if we commit successfully.
00941  */
00942 F_SET(dbp, DB_AM_DISCARD);
00943 *retflags |= DB_FILE_SETUP_CREATE;
00944 } else {
00945 /*
00946  * Abort the file create. If the abort fails, report
00947  * the error returned by CDB_txn_abort(), rather than the
00948  * open error, for no particular reason.
00949  */
00950 if (dbp->open_txn != NULL) {
00951 if ((t_ret = CDB_txn_abort(txn)) != 0) {
00952 ret = t_ret;
00953 goto err_msg;
00954 }
00955 txn = NULL;
00956 }
00957 
00958 /*
00959  * If we were not doing an exclusive open, try again
00960  * without the create flag.
00961  */
00962 if (ret == EEXIST && !LF_ISSET(DB_EXCL)) {
00963 LF_CLR(DB_CREATE);
00964 DB_TEST_RECOVERY(dbp,
00965 DB_TEST_POSTOPEN, ret, name);
00966 goto open_retry;
00967 }
00968 }
00969 } else
00970 ret = CDB___os_open(dbenv, real_name, oflags, mode, fhp);
00971 
00972 /*
00973  * Be quiet if we couldn't open the file because it didn't exist
00974  * or we did not have permission,
00975  * the customers don't like those messages appearing in the logs.
00976  * Otherwise, complain loudly.
00977  */
00978 if (ret != 0) {
00979 if (ret == EACCES || ret == ENOENT)
00980 goto err;
00981 goto err_msg;
00982 }
00983 
00984 /* Set the page size if we don't have one yet. */
00985 if (dbp->pgsize == 0) {
00986 if (IS_SUBDB_SETUP) {
00987 if ((ret = CDB___db_master_open(dbp,
00988 name, flags, mode, &mdb)) != 0)
00989 goto err;
00990 dbp->pgsize = mdb->pgsize;
00991 (void) mdb->close(mdb, 0);
00992 } else if ((ret = __db_set_pgsize(dbp, fhp, real_name)) != 0)
00993 goto err;
00994 }
00995 
00996 disk_pagesize = F_ISSET(dbp, DB_AM_CMPR) ? DB_CMPR_DIVIDE(dbenv, dbp->pgsize) : dbp->pgsize;
00997 if(meta_pgno == PGNO_BASE_MD || !F_ISSET(dbp, DB_AM_CMPR)) {
00998 
00999 /*
01000  * Seek to the metadata offset; if it's a master database open or a
01001  * database without subdatabases, we're seeking to 0, but that's OK.
01002  */
01003 if ((ret = CDB___os_seek(dbenv, fhp,
01004 disk_pagesize, meta_pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
01005 goto err_msg;
01006 
01007 /*
01008  * Read the metadata page. We read DBMETASIZE bytes, which is larger
01009  * than any access method's metadata page and smaller than any disk
01010  * sector.
01011  */
01012 if ((ret = CDB___os_read(dbenv, fhp, mbuf, sizeof(mbuf), &nr)) != 0)
01013 goto err_msg;
01014 } else {
01015 if ((ret = CDB___os_seek(dbenv, fhp, disk_pagesize, 
01016 meta_pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
01017 goto err_msg;
01018 if ((ret = CDB___memp_cmpr_read_meta(dbenv, fhp, mbuf, sizeof(mbuf), &nr)) != 0)
01019 goto err_msg;
01020 }
01021 
01022 if (nr == sizeof(mbuf)) {
01023 /*
01024  * Figure out what access method we're dealing with, and then
01025  * call access method specific code to check error conditions
01026  * based on conflicts between the found file and application
01027  * arguments. A found file overrides some user information --
01028  * we don't consider it an error, for example, if the user set
01029  * an expected byte order and the found file doesn't match it.
01030  */
01031 F_CLR(dbp, DB_AM_SWAP);
01032 magic = ((DBMETA *)mbuf)->magic;
01033 
01034 swap_retry: switch (magic) {
01035 case DB_BTREEMAGIC:
01036 if ((ret =
01037 CDB___bam_metachk(dbp, name, (BTMETA *)mbuf)) != 0)
01038 goto err;
01039 break;
01040 case DB_HASHMAGIC:
01041 if ((ret =
01042 CDB___ham_metachk(dbp, name, (HMETA *)mbuf)) != 0)
01043 goto err;
01044 break;
01045 case DB_QAMMAGIC:
01046 if ((ret =
01047 CDB___qam_metachk(dbp, name, (QMETA *)mbuf)) != 0)
01048 goto err;
01049 break;
01050 case 0:
01051 /*
01052  * There are two ways we can get a 0 magic number.
01053  * If we're creating a subdatabase, then the magic
01054  * number will be 0. We allocate a page as part of
01055  * finding out what the base page number will be for
01056  * the new subdatabase, but it's not initialized in
01057  * any way.
01058  *
01059  * The second case happens if we are in recovery
01060  * and we are going to recreate a database, it's
01061  * possible that it's page was created (on systems
01062  * where pages must be created explicitly to avoid
01063  * holes in files) but is still 0.
01064  */
01065 if (IS_SUBDB_SETUP) { /* Case 1 */
01066 if ((IS_RECOVERING(dbenv)
01067 && F_ISSET((DB_LOG *)
01068 dbenv->lg_handle, DBLOG_FORCE_OPEN))
01069 || ((DBMETA *)mbuf)->pgno != PGNO_INVALID)
01070 goto empty;
01071 
01072 ret = EINVAL;
01073 goto err;
01074 }
01075 /* Case 2 */
01076 if (IS_RECOVERING(dbenv)) {
01077 *retflags |= DB_FILE_SETUP_ZERO;
01078 goto empty;
01079 }
01080 goto bad_format;
01081 default:
01082 if (F_ISSET(dbp, DB_AM_SWAP))
01083 goto bad_format;
01084 
01085 M_32_SWAP(magic);
01086 F_SET(dbp, DB_AM_SWAP);
01087 goto swap_retry;
01088 }
01089 } else {
01090 /*
01091  * Only newly created files are permitted to fail magic
01092  * number tests.
01093  */
01094 if (nr != 0 || (!IS_RECOVERING(dbenv) && IS_SUBDB_SETUP))
01095 goto bad_format;
01096 
01097 /* Let the caller know that we had a 0-length file. */
01098 if (!LF_ISSET(DB_CREATE | DB_TRUNCATE))
01099 *retflags = DB_FILE_SETUP_ZERO;
01100 
01101 /*
01102  * The only way we can reach here with the DB_CREATE flag set
01103  * is if we created the file. If that's not the case, then
01104  * either (a) someone else created the file but has not yet
01105  * written out the metadata page, or (b) we truncated the file
01106  * (DB_TRUNCATE) leaving it zero-length. In the case of (a),
01107  * we want to sleep and give the file creator time to write
01108  * the metadata page. In the case of (b), we want to continue.
01109  *
01110  * !!!
01111  * There's a race in the case of two processes opening the file
01112  * with the DB_TRUNCATE flag set at roughly the same time, and
01113  * they could theoretically hurt each other. Sure hope that's
01114  * unlikely.
01115  */
01116 if (!LF_ISSET(DB_CREATE | DB_TRUNCATE) &&
01117 !IS_RECOVERING(dbenv)) {
01118 if (retry_cnt++ < 3) {
01119 CDB___os_sleep(dbenv, 1, 0);
01120 goto open_retry;
01121 }
01122 bad_format: CDB___db_err(dbenv,
01123 "%s: unexpected file type or format", name);
01124 ret = EINVAL;
01125 goto err;
01126 }
01127 
01128 DB_ASSERT (dbp->type != DB_UNKNOWN);
01129 
01130 empty: /*
01131  * The file is empty, and that's OK. If it's not a subdatabase,
01132  * though, we do need to generate a unique file ID for it. The
01133  * unique file ID includes a timestamp so that we can't collide
01134  * with any other files, even when the file IDs (dev/inode pair)
01135  * are reused.
01136  */
01137 if (!IS_SUBDB_SETUP) {
01138 if (*retflags & DB_FILE_SETUP_ZERO)
01139 memset(dbp->fileid, 0, DB_FILE_ID_LEN);
01140 else {
01141 if ((ret = CDB___os_fileid(dbenv,
01142 real_name, 1, dbp->fileid)) != 0)
01143 goto err_msg;
01144 CDB___memp_cmpr_create(dbenv, fhp, disk_pagesize, F_ISSET(dbp, DB_AM_CMPR) ? MP_CMPR : 0);
01145 }
01146 }
01147 }
01148 
01149 if (0) {
01150 err_msg: CDB___db_err(dbenv, "%s: %s", name, CDB_db_strerror(ret));
01151 }
01152 
01153 /*
01154  * Abort any running transaction -- it can only exist if something
01155  * went wrong.
01156  */
01157 err: if (txn != NULL)
01158 (void)CDB_txn_abort(txn);
01159 
01160 DB_TEST_RECOVERY_LABEL
01161 /*
01162  * If we opened a file handle and our caller is doing fcntl(2) locking,
01163  * then we can't close it because that would discard the caller's lock.
01164  * Otherwise, close the handle.
01165  */
01166 if (F_ISSET(fhp, DB_FH_VALID)) {
01167 if (ret == 0 && LF_ISSET(DB_FCNTL_LOCKING))
01168 dbp->saved_open_fhp = fhp;
01169 else
01170 if ((t_ret = CDB___os_closehandle(fhp)) != 0 && ret == 0)
01171 ret = t_ret;
01172 }
01173 
01174 if (real_name != NULL)
01175 CDB___os_freestr(real_name);
01176 
01177 return (ret);
01178 }
01179 
01180 /*
01181  * __db_set_pgsize --
01182  * Set the page size based on file information.
01183  */
01184 static int
01185 __db_set_pgsize(dbp, fhp, name)
01186 DB *dbp;
01187 DB_FH *fhp;
01188 char *name;
01189 {
01190 DB_ENV *dbenv;
01191 u_int32_t iopsize;
01192 int ret;
01193 
01194 dbenv = dbp->dbenv;
01195 
01196 /*
01197  * Use the filesystem's optimum I/O size as the pagesize if a pagesize
01198  * not specified. Some filesystems have 64K as their optimum I/O size,
01199  * but as that results in fairly large default caches, we limit the
01200  * default pagesize to 16K.
01201  */
01202 if ((ret = CDB___os_ioinfo(dbenv, name, fhp, NULL, NULL, &iopsize)) != 0) {
01203 CDB___db_err(dbenv, "%s: %s", name, CDB_db_strerror(ret));
01204 return (ret);
01205 }
01206 if (iopsize < 512)
01207 iopsize = 512;
01208 if (iopsize > 16 * 1024)
01209 iopsize = 16 * 1024;
01210 
01211 /*
01212  * If compression is on, the minimum page size must be multiplied
01213  * by the compression factor.
01214  */
01215 if(F_ISSET(dbp, DB_AM_CMPR)) {
01216 if(iopsize < DB_CMPR_MULTIPLY(dbenv, DB_MIN_PGSIZE))
01217 iopsize = DB_CMPR_MULTIPLY(dbenv, DB_MIN_PGSIZE);
01218 }
01219 
01220 /*
01221  * Sheer paranoia, but we don't want anything that's not a power-of-2
01222  * (we rely on that for alignment of various types on the pages), and
01223  * we want a multiple of the sector size as well.
01224  */
01225 OS_ROUNDOFF(iopsize, 512);
01226 
01227 dbp->pgsize = iopsize;
01228 F_SET(dbp, DB_AM_PGDEF);
01229 
01230 return (0);
01231 }
01232 
01233 /*
01234  * CDB___db_close --
01235  * DB destructor.
01236  *
01237  * PUBLIC: int CDB___db_close __P((DB *, u_int32_t));
01238  */
01239 int
01240 CDB___db_close(dbp, flags)
01241 DB *dbp;
01242 u_int32_t flags;
01243 {
01244 DB_ENV *dbenv;
01245 DBC *dbc;
01246 int ret, t_ret;
01247 
01248 ret = 0;
01249 
01250 PANIC_CHECK(dbp->dbenv);
01251 
01252 /* Validate arguments. */
01253 if ((ret = CDB___db_closechk(dbp, flags)) != 0)
01254 return (ret);
01255 
01256 /* If never opened, or not currently open, it's easy. */
01257 if (!F_ISSET(dbp, DB_OPEN_CALLED))
01258 goto never_opened;
01259 
01260 /* Sync the underlying access method. */
01261 if (!LF_ISSET(DB_NOSYNC) && !F_ISSET(dbp, DB_AM_DISCARD) &&
01262 (t_ret = dbp->sync(dbp, 0)) != 0 && ret == 0)
01263 ret = t_ret;
01264 
01265 /*
01266  * Go through the active cursors and call the cursor recycle routine,
01267  * which resolves pending operations and moves the cursors onto the
01268  * free list. Then, walk the free list and call the cursor destroy
01269  * routine.
01270  */
01271 while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
01272 if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
01273 ret = t_ret;
01274 while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
01275 if ((t_ret = CDB___db_c_destroy(dbc)) != 0 && ret == 0)
01276 ret = t_ret;
01277 
01278 /*
01279  * Close any outstanding join cursors. Join cursors destroy
01280  * themselves on close and have no separate destroy routine.
01281  */
01282 while ((dbc = TAILQ_FIRST(&dbp->join_queue)) != NULL)
01283 if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
01284 ret = t_ret;
01285 
01286 /* Sync the memory pool. */
01287 if (!LF_ISSET(DB_NOSYNC) && !F_ISSET(dbp, DB_AM_DISCARD) &&
01288 (t_ret = CDB_memp_fsync(dbp->mpf)) != 0 &&
01289 t_ret != DB_INCOMPLETE && ret == 0)
01290 ret = t_ret;
01291 
01292 /* Close any handle we've been holding since the open. */
01293 if (dbp->saved_open_fhp != NULL &&
01294 F_ISSET(dbp->saved_open_fhp, DB_FH_VALID) &&
01295 (t_ret = CDB___os_closehandle(dbp->saved_open_fhp)) != 0 && ret == 0)
01296 ret = t_ret;
01297 
01298 never_opened:
01299 /*
01300  * Call the access specific close function.
01301  *
01302  * !!!
01303  * Because of where the function is called in the close process,
01304  * these routines can't do anything that would dirty pages or
01305  * otherwise affect closing down the database.
01306  */
01307 if ((t_ret = CDB___ham_db_close(dbp)) != 0 && ret == 0)
01308 ret = t_ret;
01309 if ((t_ret = CDB___bam_db_close(dbp)) != 0 && ret == 0)
01310 ret = t_ret;
01311 if ((t_ret = CDB___qam_db_close(dbp)) != 0 && ret == 0)
01312 ret = t_ret;
01313 
01314 /* Refresh the structure and close any local environment. */
01315 dbenv = dbp->dbenv;
01316 if ((t_ret = __db_refresh(dbp)) != 0 && ret == 0)
01317 ret = t_ret;
01318 if (F_ISSET(dbenv, DB_ENV_DBLOCAL) &&
01319 --dbenv->dblocal_ref == 0 &&
01320 (t_ret = dbenv->close(dbenv, 0)) != 0 && ret == 0)
01321 ret = t_ret;
01322 
01323 memset(dbp, CLEAR_BYTE, sizeof(*dbp));
01324 CDB___os_free(dbp, sizeof(*dbp));
01325 
01326 return (ret);
01327 }
01328 
01329 /*
01330  * __db_refresh --
01331  * Refresh the DB structure, releasing any allocated resources.
01332  */
01333 static int
01334 __db_refresh(dbp)
01335 DB *dbp;
01336 {
01337 DB_ENV *dbenv;
01338 DBC *dbc;
01339 int ret, t_ret;
01340 
01341 ret = 0;
01342 
01343 dbenv = dbp->dbenv;
01344 
01345 /*
01346  * Go through the active cursors and call the cursor recycle routine,
01347  * which resolves pending operations and moves the cursors onto the
01348  * free list. Then, walk the free list and call the cursor destroy
01349  * routine.
01350  */
01351 while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
01352 if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
01353 ret = t_ret;
01354 while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
01355 if ((t_ret = CDB___db_c_destroy(dbc)) != 0 && ret == 0)
01356 ret = t_ret;
01357 
01358 dbp->type = 0;
01359 
01360 /* Close the memory pool file handle. */
01361 if (dbp->mpf != NULL) {
01362 if (F_ISSET(dbp, DB_AM_DISCARD))
01363 (void)CDB___memp_fremove(dbp->mpf);
01364 if ((t_ret = CDB_memp_fclose(dbp->mpf)) != 0 && ret == 0)
01365 ret = t_ret;
01366 dbp->mpf = NULL;
01367 }
01368 
01369 /* Discard the thread mutex. */
01370 if (dbp->mutexp != NULL) {
01371 CDB___db_mutex_free(dbenv, dbenv->reginfo, dbp->mutexp);
01372 dbp->mutexp = NULL;
01373 }
01374 
01375 /* Discard the log file id. */
01376 if (!IS_RECOVERING(dbenv)
01377 && dbp->log_fileid != DB_LOGFILEID_INVALID)
01378 (void)CDB_log_unregister(dbenv, dbp);
01379 
01380 TAILQ_INIT(&dbp->free_queue);
01381 TAILQ_INIT(&dbp->active_queue);
01382 TAILQ_INIT(&dbp->join_queue);
01383 
01384 F_CLR(dbp, DB_AM_DISCARD);
01385 F_CLR(dbp, DB_AM_INMEM);
01386 F_CLR(dbp, DB_AM_RDONLY);
01387 F_CLR(dbp, DB_AM_SWAP);
01388 F_CLR(dbp, DB_DBM_ERROR);
01389 F_CLR(dbp, DB_OPEN_CALLED);
01390 
01391 return (ret);
01392 }
01393 
01394 /*
01395  * CDB___db_remove
01396  * Remove method for DB.
01397  *
01398  * PUBLIC: int CDB___db_remove __P((DB *, const char *, const char *, u_int32_t));
01399  */
01400 int
01401 CDB___db_remove(dbp, name, subdb, flags)
01402 DB *dbp;
01403 const char *name, *subdb;
01404 u_int32_t flags;
01405 {
01406 DBT namedbt;
01407 DB_ENV *dbenv;
01408 DB_LOCK remove_lock;
01409 DB_LSN newlsn;
01410 int ret, t_ret;
01411 char *backup, *real_back, *real_name;
01412 
01413 dbenv = dbp->dbenv;
01414 ret = 0;
01415 backup = real_back = real_name = NULL;
01416 
01417 PANIC_CHECK(dbenv);
01418 DB_ILLEGAL_AFTER_OPEN(dbp, "remove");
01419 
01420 /* Validate arguments. */
01421 if ((ret = CDB___db_removechk(dbp, flags)) != 0)
01422 return (ret);
01423 
01424 /*
01425  * Subdatabases.
01426  */
01427 if (subdb != NULL) {
01428 /* Subdatabases must be created in named files. */
01429 if (name == NULL) {
01430 CDB___db_err(dbenv,
01431 "multiple databases cannot be created in temporary files");
01432 return (EINVAL);
01433 }
01434 return (__db_subdb_remove(dbp, name, subdb));
01435 }
01436 
01437 if ((ret = dbp->open(dbp,
01438 name, NULL, DB_UNKNOWN, DB_RDWRMASTER, 0)) != 0)
01439 return (ret);
01440 
01441 if (LOGGING_ON(dbenv) && (ret = CDB___log_file_lock(dbp)) != 0)
01442 goto err_close;
01443 
01444 if ((ret = dbp->sync(dbp, 0)) != 0)
01445 goto err_close;
01446 
01447 /*
01448  * On Windows, the underlying file must be closed to perform a remove.
01449  * Nothing later in CDB___db_remove requires that it be open, and the
01450  * dbp->close closes it anyway, so we just close it early.
01451  */
01452 (void)CDB___memp_fremove(dbp->mpf);
01453 if ((ret = CDB_memp_fclose(dbp->mpf)) != 0)
01454 goto err_close;
01455 dbp->mpf = NULL;
01456 
01457 /* Start the transaction and log the delete. */
01458 if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0)
01459 goto err_close;
01460 
01461 if (LOGGING_ON(dbenv)) {
01462 memset(&namedbt, 0, sizeof(namedbt));
01463 namedbt.data = (char *)name;
01464 namedbt.size = strlen(name) + 1;
01465 
01466 if ((ret = CDB___crdel_delete_log(dbenv,
01467 dbp->open_txn, &newlsn, DB_FLUSH,
01468 dbp->log_fileid, &namedbt)) != 0) {
01469 CDB___db_err(dbenv,
01470 "%s: %s", name, CDB_db_strerror(ret));
01471 goto err;
01472 }
01473 }
01474 
01475 /* Find the real name of the file. */
01476 if ((ret = CDB___db_appname(dbenv,
01477 DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0)
01478 goto err;
01479 
01480 /*
01481  * XXX
01482  * We don't bother to open the file and call CDB___memp_fremove on the mpf.
01483  * There is a potential race here. It is at least possible that, if
01484  * the unique filesystem ID (dev/inode pair on UNIX) is reallocated
01485  * within a second (the granularity of the fileID timestamp), a new
01486  * file open will get the same fileID as the file being "removed".
01487  * We may actually want to open the file and call CDB___memp_fremove on
01488  * the mpf to get around this.
01489  */
01490 
01491 /* Create name for backup file. */
01492 if (TXN_ON(dbenv)) {
01493 if ((ret =
01494 CDB___db_backup_name(dbenv, name, &backup, &newlsn)) != 0)
01495 goto err;
01496 if ((ret = CDB___db_appname(dbenv,
01497 DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0)
01498 goto err;
01499 }
01500 
01501 DB_TEST_RECOVERY(dbp, DB_TEST_PRERENAME, ret, name);
01502 if (TXN_ON(dbenv))
01503 ret = CDB___os_rename(dbenv, real_name, real_back);
01504 else
01505 ret = CDB___os_unlink(dbenv, real_name);
01506 DB_TEST_RECOVERY(dbp, DB_TEST_POSTRENAME, ret, name);
01507 
01508 err:
01509 DB_TEST_RECOVERY_LABEL
01510 /*
01511  * End the transaction, committing the transaction if we were
01512  * successful, aborting otherwise.
01513  */
01514 if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp, &remove_lock,
01515 ret == 0, __db_remove_callback, real_back)) != 0 && ret == 0)
01516 ret = t_ret;
01517 
01518 /* FALLTHROUGH */
01519 
01520 err_close:
01521 if (real_name != NULL)
01522 CDB___os_freestr(real_name);
01523 if (backup != NULL)
01524 CDB___os_freestr(backup);
01525 
01526 /* We no longer have an mpool, so syncing would be disastrous. */
01527 if ((t_ret = dbp->close(dbp, DB_NOSYNC)) != 0 && ret == 0)
01528 ret = t_ret;
01529 
01530 return (ret);
01531 }
01532 
01533 /*
01534  * __db_subdb_remove --
01535  * Remove a subdatabase.
01536  */
01537 static int
01538 __db_subdb_remove(dbp, name, subdb)
01539 DB *dbp;
01540 const char *name, *subdb;
01541 {
01542 DB *mdbp;
01543 DBC *dbc;
01544 DB_ENV *dbenv;
01545 DB_LOCK remove_lock;
01546 db_pgno_t meta_pgno;
01547 int ret, t_ret;
01548 
01549 mdbp = NULL;
01550 dbc = NULL;
01551 dbenv = dbp->dbenv;
01552 
01553 /* Start the transaction. */
01554 if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0)
01555 return (ret);
01556 
01557 /*
01558  * Open the subdatabase. We can use the user's DB handle for this
01559  * purpose, I think.
01560  */
01561 if ((ret = CDB___db_open(dbp, name, subdb, DB_UNKNOWN, ((dbenv->flags & DB_ENV_CMPR) ? DB_COMPRESS : 0), 0)) != 0)
01562 goto err;
01563 
01564 /* Free up the pages in the subdatabase. */
01565 switch (dbp->type) {
01566 case DB_BTREE:
01567 case DB_RECNO:
01568 if ((ret = CDB___bam_reclaim(dbp, dbp->open_txn)) != 0)
01569 goto err;
01570 break;
01571 case DB_HASH:
01572 if ((ret = CDB___ham_reclaim(dbp, dbp->open_txn)) != 0)
01573 goto err;
01574 break;
01575 default:
01576 ret = CDB___db_unknown_type(dbp->dbenv,
01577 "__db_subdb_remove", dbp->type);
01578 goto err;
01579 }
01580 
01581 /*
01582  * Remove the entry from the CDB_main database and free the subdatabase
01583  * metadata page.
01584  */
01585 if ((ret = CDB___db_master_open(dbp, name, ((dbenv->flags & DB_ENV_CMPR) ? DB_COMPRESS : 0), 0, &mdbp)) != 0)
01586 goto err;
01587 
01588 if ((ret = __db_master_update(mdbp,
01589 subdb, dbp->type, &meta_pgno, MU_REMOVE, NULL, 0)) != 0)
01590 goto err;
01591 
01592 err: /*
01593  * End the transaction, committing the transaction if we were
01594  * successful, aborting otherwise.
01595  */
01596 if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp,
01597 &remove_lock, ret == 0, NULL, NULL)) != 0 && ret == 0)
01598 ret = t_ret;
01599 
01600 /*
01601  * Close the user's DB handle -- do this LAST to avoid smashing the
01602  * the transaction information.
01603  */
01604 if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
01605 ret = t_ret;
01606 
01607 if (mdbp != NULL && (t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0)
01608 ret = t_ret;
01609 
01610 return (ret);
01611 }
01612 
01613 /*
01614  * CDB___db_rename
01615  * Rename method for DB.
01616  *
01617  * PUBLIC: int CDB___db_rename __P((DB *,
01618  * PUBLIC: const char *, const char *, const char *, u_int32_t));
01619  */
01620 int
01621 CDB___db_rename(dbp, filename, subdb, newname, flags)
01622 DB *dbp;
01623 const char *filename, *subdb, *newname;
01624 u_int32_t flags;
01625 {
01626 DBT namedbt, newnamedbt;
01627 DB_ENV *dbenv;
01628 DB_LOCK remove_lock;
01629 DB_LSN newlsn;
01630 char *real_name, *real_newname;
01631 int ret, t_ret;
01632 
01633 dbenv = dbp->dbenv;
01634 ret = 0;
01635 real_name = real_newname = NULL;
01636 
01637 PANIC_CHECK(dbenv);
01638 DB_ILLEGAL_AFTER_OPEN(dbp, "rename");
01639 
01640 /* Validate arguments -- has same rules as remove. */
01641 if ((ret = CDB___db_removechk(dbp, flags)) != 0)
01642 return (ret);
01643 
01644 /*
01645  * Subdatabases.
01646  */
01647 if (subdb != NULL) {
01648 if (filename == NULL) {
01649 CDB___db_err(dbenv,
01650 "multiple databases cannot be created in temporary files");
01651 return (EINVAL);
01652 }
01653 return (__db_subdb_rename(dbp, filename, subdb, newname));
01654 }
01655 
01656 if ((ret = dbp->open(dbp,
01657 filename, NULL, DB_UNKNOWN, DB_RDWRMASTER, 0)) != 0)
01658 return (ret);
01659 
01660 if (LOGGING_ON(dbenv) && (ret = CDB___log_file_lock(dbp)) != 0)
01661 goto err_close;
01662 
01663 if ((ret = dbp->sync(dbp, 0)) != 0)
01664 goto err_close;
01665 
01666 /*
01667  * We have to flush the cache for a couple of reasons. First, the
01668  * underlying MPOOLFILE maintains a "name" that unrelated processes
01669  * can use to open the file in order to flush pages, and that name
01670  * is about to be wrong. Second, on Windows the unique file ID is
01671  * generated from the file's name, not other file information as is
01672  * the case on UNIX, and so a subsequent open of the old file name
01673  * could conceivably result in a matching "unique" file ID.
01674  */
01675 if ((ret = CDB___memp_fremove(dbp->mpf)) != 0)
01676 goto err_close;
01677 
01678 /*
01679  * On Windows, the underlying file must be closed to perform a rename.
01680  * Nothing later in CDB___db_rename requires that it be open, and the call
01681  * to dbp->close closes it anyway, so we just close it early.
01682  */
01683 if ((ret = CDB_memp_fclose(dbp->mpf)) != 0)
01684 goto err_close;
01685 dbp->mpf = NULL;
01686 
01687 /* Start the transaction and log the rename. */
01688 if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0)
01689 goto err_close;
01690 
01691 if (LOGGING_ON(dbenv)) {
01692 memset(&namedbt, 0, sizeof(namedbt));
01693 namedbt.data = (char *)filename;
01694 namedbt.size = strlen(filename) + 1;
01695 
01696 memset(&newnamedbt, 0, sizeof(namedbt));
01697 newnamedbt.data = (char *)newname;
01698 newnamedbt.size = strlen(newname) + 1;
01699 
01700 if ((ret = CDB___crdel_rename_log(dbenv, dbp->open_txn,
01701 &newlsn, 0, dbp->log_fileid, &namedbt, &newnamedbt)) != 0) {
01702 CDB___db_err(dbenv, "%s: %s", filename, CDB_db_strerror(ret));
01703 goto err;
01704 }
01705 
01706 if ((ret = CDB___log_filelist_update(dbenv, dbp,
01707 dbp->log_fileid, newname, NULL)) != 0)
01708 goto err;
01709 }
01710 
01711 /* Find the real name of the file. */
01712 if ((ret = CDB___db_appname(dbenv,
01713 DB_APP_DATA, NULL, filename, 0, NULL, &real_name)) != 0)
01714 goto err;
01715 
01716 /* Find the real newname of the file. */
01717 if ((ret = CDB___db_appname(dbenv,
01718 DB_APP_DATA, NULL, newname, 0, NULL, &real_newname)) != 0)
01719 goto err;
01720 
01721 /*
01722  * It is an error to rename a file over one that already exists,
01723  * as that wouldn't be transaction-safe.
01724  */
01725 if (CDB___os_exists(real_newname, NULL) == 0) {
01726 ret = EEXIST;
01727 CDB___db_err(dbenv, "rename: file %s exists", real_newname);
01728 goto err;
01729 }
01730 
01731 DB_TEST_RECOVERY(dbp, DB_TEST_PRERENAME, ret, filename);
01732 ret = CDB___os_rename(dbenv, real_name, real_newname);
01733 DB_TEST_RECOVERY(dbp, DB_TEST_POSTRENAME, ret, newname);
01734 
01735 DB_TEST_RECOVERY_LABEL
01736 err: if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp,
01737 &remove_lock, ret == 0, NULL, NULL)) != 0 && ret == 0)
01738 ret = t_ret;
01739 
01740 err_close:
01741 /* We no longer have an mpool, so syncing would be disastrous. */
01742 dbp->close(dbp, DB_NOSYNC);
01743 if (real_name != NULL)
01744 CDB___os_freestr(real_name);
01745 if (real_newname != NULL)
01746 CDB___os_freestr(real_newname);
01747 
01748 return (ret);
01749 }
01750 
01751 /*
01752  * __db_subdb_rename --
01753  * Rename a subdatabase.
01754  */
01755 static int
01756 __db_subdb_rename(dbp, name, subdb, newname)
01757 DB *dbp;
01758 const char *name, *subdb, *newname;
01759 {
01760 DB *mdbp;
01761 DBC *dbc;
01762 DB_ENV *dbenv;
01763 DB_LOCK remove_lock;
01764 int ret, t_ret;
01765 
01766 mdbp = NULL;
01767 dbc = NULL;
01768 dbenv = dbp->dbenv;
01769 
01770 /* Start the transaction. */
01771 if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0)
01772 return (ret);
01773 
01774 /*
01775  * Open the subdatabase. We can use the user's DB handle for this
01776  * purpose, I think.
01777  */
01778 if ((ret = CDB___db_open(dbp, name, subdb, DB_UNKNOWN, 0, 0)) != 0)
01779 goto err;
01780 
01781 /*
01782  * Rename the entry in the CDB_main database.
01783  */
01784 if ((ret = CDB___db_master_open(dbp, name, 0, 0, &mdbp)) != 0)
01785 goto err;
01786 
01787 if ((ret = __db_master_update(mdbp,
01788 subdb, dbp->type, NULL, MU_RENAME, newname, 0)) != 0)
01789 goto err;
01790 
01791 err: /*
01792  * End the transaction, committing the transaction if we were
01793  * successful, aborting otherwise.
01794  */
01795 if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp,
01796 &remove_lock, ret == 0, NULL, NULL)) != 0 && ret == 0)
01797 ret = t_ret;
01798 
01799 /*
01800  * Close the user's DB handle -- do this LAST to avoid smashing the
01801  * the transaction information.
01802  */
01803 if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
01804 ret = t_ret;
01805 
01806 if (mdbp != NULL && (t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0)
01807 ret = t_ret;
01808 
01809 return (ret);
01810 }
01811 
01812 /*
01813  * __db_metabegin --
01814  *
01815  * Begin a meta-data operation. This involves doing any required locking,
01816  * potentially beginning a transaction and then telling the caller if you
01817  * did or did not begin the transaction.
01818  *
01819  * The writing flag indicates if the caller is actually allowing creates
01820  * or doing deletes (i.e., if the caller is opening and not creating, then
01821  * we don't need to do any of this).
01822  */
01823 static int
01824 __db_metabegin(dbp, lockp)
01825 DB *dbp;
01826 DB_LOCK *lockp;
01827 {
01828 DB_ENV *dbenv;
01829 DBT dbplock;
01830 u_int32_t locker, lockval;
01831 int ret;
01832 
01833 dbenv = dbp->dbenv;
01834 
01835 lockp->off = LOCK_INVALID;
01836 
01837 /*
01838  * There is no single place where we can know that we are or are not
01839  * going to be creating any files and/or subdatabases, so we will
01840  * always begin a tranasaction when we start creating one. If we later
01841  * discover that this was unnecessary, we will abort the transaction.
01842  * Recovery is written so that if we log a file create, but then
01843  * discover that we didn't have to do it, we recover correctly. The
01844  * file recovery design document has details.
01845  *
01846  * We need to single thread all create and delete operations, so if we
01847  * are running with locking, we must obtain a lock. We use CDB_lock_id to
01848  * generate a unique locker id and use a handcrafted DBT as the object
01849  * on which we are locking.
01850  */
01851 if (LOCKING_ON(dbenv)) {
01852 if ((ret = CDB_lock_id(dbenv, &locker)) != 0)
01853 return (ret);
01854 lockval = 0;
01855 dbplock.data = &lockval;
01856 dbplock.size = sizeof(lockval);
01857 if ((ret = CDB_lock_get(dbenv,
01858 locker, 0, &dbplock, DB_LOCK_WRITE, lockp)) != 0)
01859 return(ret);
01860 }
01861 
01862 return (CDB_txn_begin(dbenv, NULL, &dbp->open_txn, 0));
01863 }
01864 
01865 /*
01866  * __db_metaend --
01867  * End a meta-data operation.
01868  */
01869 static int
01870 __db_metaend(dbp, lockp, commit, callback, cookie)
01871 DB *dbp;
01872 DB_LOCK *lockp;
01873 int commit, (*callback) __P((DB *, void *));
01874 void *cookie;
01875 {
01876 DB_ENV *dbenv;
01877 int ret, t_ret;
01878 
01879 ret = 0;
01880 dbenv = dbp->dbenv;
01881 
01882 /* End the transaction. */
01883 if (commit) {
01884 if ((ret = CDB_txn_commit(dbp->open_txn, DB_TXN_SYNC)) == 0) {
01885 /*
01886  * Unlink any underlying file, we've committed the
01887  * transaction.
01888  */
01889 if (callback != NULL)
01890 ret = callback(dbp, cookie);
01891 }
01892 } else if ((t_ret = CDB_txn_abort(dbp->open_txn)) && ret == 0)
01893 ret = t_ret;
01894 
01895 /* Release our lock. */
01896 if (lockp->off != LOCK_INVALID &&
01897 (t_ret = CDB_lock_put(dbenv, lockp)) != 0 && ret == 0)
01898 ret = t_ret;
01899 
01900 return (ret);
01901 }
01902 
01903 /*
01904  * CDB___db_log_page
01905  * Log a meta-data or root page during a create operation.
01906  *
01907  * PUBLIC: int CDB___db_log_page __P((DB *,
01908  * PUBLIC: const char *, DB_LSN *, db_pgno_t, PAGE *));
01909  */
01910 int
01911 CDB___db_log_page(dbp, name, lsn, pgno, page)
01912 DB *dbp;
01913 const char *name;
01914 DB_LSN *lsn;
01915 db_pgno_t pgno;
01916 PAGE *page;
01917 {
01918 DBT name_dbt, page_dbt;
01919 DB_LSN new_lsn;
01920 int ret;
01921 
01922 if (dbp->open_txn == NULL)
01923 return (0);
01924 
01925 memset(&page_dbt, 0, sizeof(page_dbt));
01926 page_dbt.size = dbp->pgsize;
01927 page_dbt.data = page;
01928 if (pgno == PGNO_BASE_MD) {
01929 /*
01930  * !!!
01931  * Make sure that we properly handle a null name. The old
01932  * Tcl sent us pathnames of the form ""; it may be the case
01933  * that the new Tcl doesn't do that, so we can get rid of
01934  * the second check here.
01935  */
01936 memset(&name_dbt, 0, sizeof(name_dbt));
01937 name_dbt.data = (char *)name;
01938 if (name == NULL || *name == '0円')
01939 name_dbt.size = 0;
01940 else
01941 name_dbt.size = strlen(name) + 1;
01942 
01943 ret = CDB___crdel_metapage_log(dbp->dbenv,
01944 dbp->open_txn, &new_lsn, DB_FLUSH,
01945 dbp->log_fileid, &name_dbt, pgno, &page_dbt);
01946 } else
01947 ret = CDB___crdel_metasub_log(dbp->dbenv, dbp->open_txn,
01948 &new_lsn, 0, dbp->log_fileid, pgno, &page_dbt, lsn);
01949 
01950 if (ret == 0)
01951 page->lsn = new_lsn;
01952 return (ret);
01953 }
01954 
01955 /*
01956  * CDB___db_backup_name
01957  * Create the backup file name for a given file.
01958  *
01959  * PUBLIC: int CDB___db_backup_name __P((DB_ENV *,
01960  * PUBLIC: const char *, char **, DB_LSN *));
01961  */
01962 #undef BACKUP_PREFIX
01963 #define BACKUP_PREFIX "__db."
01964 
01965 #undef MAX_LSN_TO_TEXT
01966 #define MAX_LSN_TO_TEXT 21
01967 int
01968 CDB___db_backup_name(dbenv, name, backup, lsn)
01969 DB_ENV *dbenv;
01970 const char *name;
01971 char **backup;
01972 DB_LSN *lsn;
01973 {
01974 size_t len;
01975 int plen, ret;
01976 char *p, *retp;
01977 
01978 len = strlen(name) + strlen(BACKUP_PREFIX) + MAX_LSN_TO_TEXT + 1;
01979 
01980 if ((ret = CDB___os_malloc(dbenv, len, NULL, &retp)) != 0)
01981 return (ret);
01982 
01983 /*
01984  * Create the name. Backup file names are of the form:
01985  *
01986  * __db.name.0x[lsn-file].0x[lsn-offset]
01987  *
01988  * which guarantees uniqueness.
01989  *
01990  * However, name may contain an env-relative path in it.
01991  * In that case, put the __db. after the last portion of
01992  * the pathname.
01993  */
01994 if ((p = CDB___db_rpath(name)) == NULL)
01995 snprintf(retp, len,
01996 "%s%s.0x%x0x%x", BACKUP_PREFIX, name,
01997 lsn->file, lsn->offset);
01998 else { 
01999 plen = p - name + 1;
02000 p++;
02001 snprintf(retp, len,
02002 "%.*s%s%s.0x%x0x%x", plen, name, BACKUP_PREFIX, p,
02003 lsn->file, lsn->offset);
02004 }
02005 
02006 *backup = retp;
02007 return (0);
02008 }
02009 
02010 /*
02011  * __db_remove_callback --
02012  * Callback function -- on file remove commit, it unlinks the backing
02013  * file.
02014  */
02015 static int
02016 __db_remove_callback(dbp, cookie)
02017 DB *dbp;
02018 void *cookie;
02019 {
02020 return (CDB___os_unlink(dbp->dbenv, cookie));
02021 }
02022 
02023 #if CONFIG_TEST
02024 /*
02025  * __db_testcopy
02026  * Create a copy of all backup files and our "CDB_main" DB.
02027  *
02028  * PUBLIC: int __db_testcopy __P((DB *, const char *));
02029  */
02030 int
02031 __db_testcopy(dbp, name)
02032 DB *dbp;
02033 const char *name;
02034 {
02035 size_t len;
02036 int dircnt, i, ret;
02037 char **namesp, *backup, *copy, *dir, *p, *real_name;
02038 
02039 real_name = NULL;
02040 /* Get the real backing file name. */
02041 if ((ret = CDB___db_appname(dbp->dbenv,
02042 DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0)
02043 return (ret);
02044 
02045 /*
02046  * Maximum size of file, including adding a ".afterop".
02047  */
02048 len = strlen(real_name) + strlen(BACKUP_PREFIX) + MAX_LSN_TO_TEXT + 9;
02049 
02050 if ((ret = CDB___os_malloc(dbp->dbenv, len, NULL, &copy)) != 0)
02051 goto out;
02052 
02053 if ((ret = CDB___os_malloc(dbp->dbenv, len, NULL, &backup)) != 0)
02054 goto out;
02055 
02056 /*
02057  * First copy the file itself.
02058  */
02059 snprintf(copy, len, "%s.afterop", real_name);
02060 __db_makecopy(real_name, copy);
02061 
02062 if ((ret = CDB___os_strdup(dbp->dbenv, real_name, &dir)) != 0)
02063 goto out;
02064 CDB___os_freestr(real_name);
02065 real_name = NULL;
02066 /*
02067  * Create the name. Backup file names are of the form:
02068  *
02069  * __db.name.0x[lsn-file].0x[lsn-offset]
02070  *
02071  * which guarantees uniqueness. We want to look for the
02072  * backup name, followed by a '.0x' (so that if they have
02073  * files named, say, 'a' and 'abc' we won't match 'abc' when
02074  * looking for 'a'.
02075  */
02076 snprintf(backup, len, "%s%s.0x", BACKUP_PREFIX, name);
02077 
02078 /*
02079  * We need the directory path to do the CDB___os_dirlist.
02080  */
02081 p = CDB___db_rpath(dir);
02082 if (p != NULL)
02083 *p = '0円';
02084 ret = CDB___os_dirlist(dbp->dbenv, dir, &namesp, &dircnt);
02085 #if DIAGNOSTIC
02086 /*
02087  * XXX
02088  * To get the memory guard code to work because it uses strlen and we
02089  * just moved the end of the string somewhere sooner. This causes the
02090  * guard code to fail because it looks at one byte past the end of the
02091  * string.
02092  */
02093 *p = '/';
02094 #endif
02095 CDB___os_freestr(dir);
02096 if (ret != 0)
02097 goto out;
02098 for (i = 0; i < dircnt; i++) {
02099 /*
02100  * Need to check if it is a backup file for this.
02101  * No idea what namesp[i] may be or how long, so
02102  * must use strncmp and not memcmp. We don't want
02103  * to use strcmp either because we are only matching
02104  * the first part of the real file's name. We don't
02105  * know its LSN's.
02106  */
02107 if (strncmp(namesp[i], backup, strlen(backup)) == 0) {
02108 if ((ret = CDB___db_appname(dbp->dbenv, DB_APP_DATA,
02109 NULL, namesp[i], 0, NULL, &real_name)) != 0)
02110 goto out;
02111 
02112 /*
02113  * This should not happen. Check that old
02114  * .afterop files aren't around.
02115  * If so, just move on.
02116  */
02117 if (strstr(real_name, ".afterop") != NULL) {
02118 CDB___os_freestr(real_name);
02119 real_name = NULL;
02120 continue;
02121 }
02122 snprintf(copy, len, "%s.afterop", real_name);
02123 __db_makecopy(real_name, copy);
02124 CDB___os_freestr(real_name);
02125 real_name = NULL;
02126 }
02127 }
02128 out:
02129 if (real_name)
02130 CDB___os_freestr(real_name);
02131 return (ret);
02132 }
02133 
02134 static void
02135 __db_makecopy(src, dest)
02136 const char *src, *dest;
02137 {
02138 DB_FH rfh, wfh;
02139 size_t rcnt, wcnt;
02140 char *buf;
02141 
02142 memset(&rfh, 0, sizeof(rfh));
02143 memset(&wfh, 0, sizeof(wfh));
02144 
02145 if (CDB___os_malloc(NULL, 1024, NULL, &buf) != 0)
02146 return;
02147 
02148 if (CDB___os_open(NULL,
02149 src, DB_OSO_RDONLY, CDB___db_omode("rw----"), &rfh) != 0)
02150 goto err;
02151 if (CDB___os_open(NULL, dest,
02152 DB_OSO_CREATE | DB_OSO_TRUNC, CDB___db_omode("rw----"), &wfh) != 0)
02153 goto err;
02154 
02155 for (;;)
02156 if (CDB___os_read(NULL, &rfh, buf, 1024, &rcnt) < 0 || rcnt == 0 ||
02157 CDB___os_write(NULL, &wfh, buf, rcnt, &wcnt) < 0 || wcnt != rcnt)
02158 break;
02159 
02160 err: CDB___os_free(buf, 1024);
02161 if (F_ISSET(&rfh, DB_FH_VALID))
02162 CDB___os_closehandle(&rfh);
02163 if (F_ISSET(&wfh, DB_FH_VALID))
02164 CDB___os_closehandle(&wfh);
02165 }
02166 #endif

Generated on Sun Jun 8 10:56:35 2008 for GNUmifluz by doxygen 1.5.5

AltStyle によって変換されたページ (->オリジナル) /