1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Merge mysql.com:/home/jimw/my/mysql-5.1-bdb

into  mysql.com:/home/jimw/my/mysql-5.1-clean


VC++Files/storage/bdb/bdb.dsp:
  Auto merged
sql/ha_berkeley.cc:
  Auto merged
This commit is contained in:
unknown
2005-09-21 10:35:19 -07:00
767 changed files with 98264 additions and 36928 deletions

View File

@@ -158,6 +158,26 @@ SOURCE=.\btree\btree_auto.c
# End Source File
# Begin Source File
SOURCE=.\crypto\aes_method.c
# End Source File
# Begin Source File
SOURCE=.\crypto\crypto.c
# End Source File
# Begin Source File
SOURCE=.\crypto\mersenne\mt19937db.c
# End Source File
# Begin Source File
SOURCE=.\crypto\rijndael\rijndael-alg-fst.c
# End Source File
# Begin Source File
SOURCE=.\crypto\rijndael\rijndael-api-fst.c
# End Source File
# Begin Source File
SOURCE=.\db\crdel_auto.c
# End Source File
# Begin Source File
@@ -238,6 +258,10 @@ SOURCE=.\db\db_overflow.c
# End Source File
# Begin Source File
SOURCE=.\db\db_ovfl_vrfy.c
# End Source File
# Begin Source File
SOURCE=.\db\db_pr.c
# End Source File
# Begin Source File
@@ -262,6 +286,18 @@ SOURCE=.\db\db_ret.c
# End Source File
# Begin Source File
SOURCE=.\db\db_setid.c
# End Source File
# Begin Source File
SOURCE=.\db\db_setlsn.c
# End Source File
# Begin Source File
SOURCE=.\db\db_stati.c
# End Source File
# Begin Source File
SOURCE=.\env\db_salloc.c
# End Source File
# Begin Source File
@@ -306,6 +342,10 @@ SOURCE=.\dbreg\dbreg_rec.c
# End Source File
# Begin Source File
SOURCE=.\dbreg\dbreg_stat.c
# End Source File
# Begin Source File
SOURCE=.\dbreg\dbreg_util.c
# End Source File
# Begin Source File
@@ -330,6 +370,10 @@ SOURCE=.\env\env_region.c
# End Source File
# Begin Source File
SOURCE=.\env\env_stat.c
# End Source File
# Begin Source File
SOURCE=.\fileops\fileops_auto.c
# End Source File
# Begin Source File
@@ -418,6 +462,14 @@ SOURCE=.\lock\lock_deadlock.c
# End Source File
# Begin Source File
SOURCE=.\lock\lock_id.c
# End Source File
# Begin Source File
SOURCE=.\lock\lock_list.c
# End Source File
# Begin Source File
SOURCE=.\lock\lock_method.c
# End Source File
# Begin Source File
@@ -430,6 +482,10 @@ SOURCE=.\lock\lock_stat.c
# End Source File
# Begin Source File
SOURCE=.\lock\lock_timer.c
# End Source File
# Begin Source File
SOURCE=.\lock\lock_util.c
# End Source File
# Begin Source File
@@ -458,6 +514,10 @@ SOURCE=.\log\log_put.c
# End Source File
# Begin Source File
SOURCE=.\log\log_stat.c
# End Source File
# Begin Source File
SOURCE=.\mp\mp_alloc.c
# End Source File
# Begin Source File
@@ -470,6 +530,10 @@ SOURCE=.\mp\mp_fget.c
# End Source File
# Begin Source File
SOURCE=.\mp\mp_fmethod.c
# End Source File
# Begin Source File
SOURCE=.\mp\mp_fopen.c
# End Source File
# Begin Source File
@@ -614,6 +678,10 @@ SOURCE=.\os\os_tmpdir.c
# End Source File
# Begin Source File
SOURCE=.\os_win32\os_truncate.c
# End Source File
# Begin Source File
SOURCE=.\os_win32\os_type.c
# End Source File
# Begin Source File
@@ -662,6 +730,14 @@ SOURCE=.\qam\qam_verify.c
# End Source File
# Begin Source File
SOURCE=.\rep\rep_auto.c
# End Source File
# Begin Source File
SOURCE=.\rep\rep_backup.c
# End Source File
# Begin Source File
SOURCE=.\rep\rep_method.c
# End Source File
# Begin Source File
@@ -674,6 +750,10 @@ SOURCE=.\rep\rep_region.c
# End Source File
# Begin Source File
SOURCE=.\rep\rep_stat.c
# End Source File
# Begin Source File
SOURCE=.\rep\rep_util.c
# End Source File
# Begin Source File

View File

@@ -93,7 +93,8 @@ u_int32_t berkeley_lock_types[]=
TYPELIB berkeley_lock_typelib= {array_elements(berkeley_lock_names)-1,"",
berkeley_lock_names, NULL};
static void berkeley_print_error(const char *db_errpfx, char *buffer);
static void berkeley_print_error(const DB_ENV *db_env, const char *db_errpfx,
const char *buffer);
static byte* bdb_get_key(BDB_SHARE *share,uint *length,
my_bool not_used __attribute__((unused)));
static BDB_SHARE *get_share(const char *table_name, TABLE *table);
@@ -176,7 +177,7 @@ handlerton *berkeley_init(void)
if (opt_endinfo)
db_env->set_verbose(db_env,
DB_VERB_CHKPOINT | DB_VERB_DEADLOCK | DB_VERB_RECOVERY,
DB_VERB_DEADLOCK | DB_VERB_RECOVERY,
1);
db_env->set_cachesize(db_env, 0, berkeley_cache_size, 0);
@@ -248,7 +249,7 @@ static int berkeley_commit(THD *thd, bool all)
DBUG_PRINT("trans",("ending transaction %s", all ? "all" : "stmt"));
berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
DB_TXN **txn= all ? &trx->all : &trx->stmt;
int error=txn_commit(*txn,0);
int error= (*txn)->commit(*txn,0);
*txn=0;
#ifndef DBUG_OFF
if (error)
@@ -263,7 +264,7 @@ static int berkeley_rollback(THD *thd, bool all)
DBUG_PRINT("trans",("aborting transaction %s", all ? "all" : "stmt"));
berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
DB_TXN **txn= all ? &trx->all : &trx->stmt;
int error=txn_abort(*txn);
int error= (*txn)->abort(*txn);
*txn=0;
DBUG_RETURN(error);
}
@@ -321,7 +322,8 @@ err:
}
static void berkeley_print_error(const char *db_errpfx, char *buffer)
static void berkeley_print_error(const DB_ENV *db_env, const char *db_errpfx,
const char *buffer)
{
sql_print_error("%s: %s",db_errpfx,buffer); /* purecov: tested */
}
@@ -612,7 +614,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
berkeley_cmp_packed_key));
if (!hidden_primary_key)
file->app_private= (void*) (table->key_info + table_share->primary_key);
if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
if ((error= db_env->txn_begin(db_env, NULL, (DB_TXN**) &transaction, 0)) ||
(error= (file->open(file, transaction,
fn_format(name_buff, name, "", ha_berkeley_ext,
2 | 4),
@@ -651,7 +653,8 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
DBUG_PRINT("bdb",("Setting DB_DUP for key %u", i));
(*ptr)->set_flags(*ptr, DB_DUP);
}
if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
if ((error= db_env->txn_begin(db_env, NULL, (DB_TXN**) &transaction,
0)) ||
(error=((*ptr)->open(*ptr, transaction, name_buff, part, DB_BTREE,
open_mode, 0))) ||
(error= transaction->commit(transaction, 0)))
@@ -1844,7 +1847,7 @@ int ha_berkeley::external_lock(THD *thd, int lock_type)
/* We have to start a master transaction */
DBUG_PRINT("trans",("starting transaction all: options: 0x%lx",
(ulong) thd->options));
if ((error=txn_begin(db_env, 0, &trx->all, 0)))
if ((error= db_env->txn_begin(db_env, NULL, &trx->all, 0)))
{
trx->bdb_lock_count--; // We didn't get the lock
DBUG_RETURN(error);
@@ -1854,7 +1857,7 @@ int ha_berkeley::external_lock(THD *thd, int lock_type)
DBUG_RETURN(0); // Don't create stmt trans
}
DBUG_PRINT("trans",("starting transaction stmt"));
if ((error=txn_begin(db_env, trx->all, &trx->stmt, 0)))
if ((error= db_env->txn_begin(db_env, trx->all, &trx->stmt, 0)))
{
/* We leave the possible master transaction open */
trx->bdb_lock_count--; // We didn't get the lock
@@ -1879,7 +1882,7 @@ int ha_berkeley::external_lock(THD *thd, int lock_type)
We must in this case commit the work to keep the row locks
*/
DBUG_PRINT("trans",("commiting non-updating transaction"));
error= txn_commit(trx->stmt,0);
error= trx->stmt->commit(trx->stmt,0);
trx->stmt= transaction= 0;
}
}
@@ -1908,7 +1911,7 @@ int ha_berkeley::start_stmt(THD *thd)
if (!trx->stmt)
{
DBUG_PRINT("trans",("starting transaction stmt"));
error=txn_begin(db_env, trx->all, &trx->stmt, 0);
error= db_env->txn_begin(db_env, trx->all, &trx->stmt, 0);
trans_register_ha(thd, FALSE, &berkeley_hton);
}
transaction= trx->stmt;
@@ -2289,7 +2292,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
free(stat);
stat=0;
}
if ((key_file[i]->stat)(key_file[i], (void*) &stat, 0))
if ((key_file[i]->stat)(key_file[i], NULL, (void*) &stat, 0))
goto err; /* purecov: inspected */
share->rec_per_key[i]= (stat->bt_ndata /
(stat->bt_nkeys ? stat->bt_nkeys : 1));
@@ -2302,7 +2305,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
free(stat);
stat=0;
}
if ((file->stat)(file, (void*) &stat, 0))
if ((file->stat)(file, NULL, (void*) &stat, 0))
goto err; /* purecov: inspected */
}
pthread_mutex_lock(&share->mutex);

View File

@@ -1,16 +1,16 @@
/*-
* $Id: LICENSE,v 11.9 2002/01/11 15:51:10 bostic Exp $
* $Id: LICENSE,v 11.12 2004/03/30 20:49:44 bostic Exp $
*/
The following is the license that applies to this copy of the Berkeley DB
software. For a license to use the Berkeley DB software under conditions
other than those described here, or to purchase support for this software,
please contact Sleepycat Software by email at db@sleepycat.com, or on the
Web at http://www.sleepycat.com.
please contact Sleepycat Software by email at info@sleepycat.com, or on
the Web at http://www.sleepycat.com.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/*
* Copyright (c) 1990-2002
* Copyright (c) 1990-2004
* Sleepycat Software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,14 +38,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_compare.c,v 11.20 2004/02/21 15:54:44 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_compare.c,v 11.17 2002/03/27 04:30:42 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif
@@ -204,8 +202,12 @@ __bam_defpfx(dbp, a, b)
return (cnt);
/*
* We know that a->size must be <= b->size, or they wouldn't be
* in this order.
* They match up to the smaller of the two sizes.
* Collate the longer after the shorter.
*/
return (a->size < b->size ? a->size + 1 : a->size);
if (a->size < b->size)
return (a->size + 1);
if (b->size < a->size)
return (b->size + 1);
return (b->size);
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_conv.c,v 11.15 2004/01/28 03:35:48 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_conv.c,v 11.13 2002/08/06 06:11:12 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_curadj.c,v 11.37 2004/03/13 14:11:33 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_curadj.c,v 11.30 2002/07/03 19:03:48 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif
@@ -21,30 +19,6 @@ static const char revid[] = "$Id: bt_curadj.c,v 11.30 2002/07/03 19:03:48 bostic
static int __bam_opd_cursor __P((DB *, DBC *, db_pgno_t, u_int32_t, u_int32_t));
#ifdef DEBUG
/*
* __bam_cprint --
* Display the current internal cursor.
*
* PUBLIC: void __bam_cprint __P((DBC *));
*/
void
__bam_cprint(dbc)
DBC *dbc;
{
BTREE_CURSOR *cp;
cp = (BTREE_CURSOR *)dbc->internal;
fprintf(stderr, "\tinternal: ovflsize: %lu", (u_long)cp->ovflsize);
if (dbc->dbtype == DB_RECNO)
fprintf(stderr, " recno: %lu", (u_long)cp->recno);
if (F_ISSET(cp, C_DELETED))
fprintf(stderr, " (deleted)");
fprintf(stderr, "\n");
}
#endif
/*
* Cursor adjustments are logged if they are for subtransactions. This is
* because it's possible for a subtransaction to adjust cursors which will
@@ -98,6 +72,19 @@ __bam_ca_delete(dbp, pgno, indx, delete)
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
cp = (BTREE_CURSOR *)dbc->internal;
if (cp->pgno == pgno && cp->indx == indx) {
/*
* [#8032] This assert is checking
* for possible race conditions where we
* hold a cursor position without a lock.
* Unfortunately, there are paths in the
* Btree code that do not satisfy these
* conditions. None of them are known to
* be a problem, but this assert should
* be re-activated when the Btree stack
* code is re-written.
DB_ASSERT(!STD_LOCKING(dbc) ||
cp->lock_mode != DB_LOCK_NG);
*/
if (delete)
F_SET(cp, C_DELETED);
else
@@ -192,7 +179,10 @@ __bam_ca_di(my_dbc, pgno, indx, adjust)
if (cp->pgno == pgno && cp->indx >= indx) {
/* Cursor indices should never be negative. */
DB_ASSERT(cp->indx != 0 || adjust > 0);
/* [#8032]
DB_ASSERT(!STD_LOCKING(dbc) ||
cp->lock_mode != DB_LOCK_NG);
*/
cp->indx += adjust;
if (my_txn != NULL && dbc->txn != my_txn)
found = 1;
@@ -203,8 +193,8 @@ __bam_ca_di(my_dbc, pgno, indx, adjust)
MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
if (found != 0 && DBC_LOGGING(my_dbc)) {
if ((ret = __bam_curadj_log(dbp, my_dbc->txn,
&lsn, 0, DB_CA_DI, pgno, 0, 0, adjust, indx, 0)) != 0)
if ((ret = __bam_curadj_log(dbp, my_dbc->txn, &lsn, 0,
DB_CA_DI, pgno, 0, 0, (u_int32_t)adjust, indx, 0)) != 0)
return (ret);
}
@@ -319,6 +309,10 @@ loop: MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
continue;
MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
/* [#8032]
DB_ASSERT(!STD_LOCKING(dbc) ||
orig_cp->lock_mode != DB_LOCK_NG);
*/
if ((ret = __bam_opd_cursor(dbp,
dbc, first, tpgno, ti)) !=0)
return (ret);
@@ -388,7 +382,7 @@ loop: MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
!= ti)
continue;
MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
if ((ret = orig_cp->opd->c_close(orig_cp->opd)) != 0)
if ((ret = __db_c_close(orig_cp->opd)) != 0)
return (ret);
orig_cp->opd = NULL;
orig_cp->indx = fi;
@@ -442,6 +436,10 @@ __bam_ca_rsplit(my_dbc, fpgno, tpgno)
continue;
if (dbc->internal->pgno == fpgno) {
dbc->internal->pgno = tpgno;
/* [#8032]
DB_ASSERT(!STD_LOCKING(dbc) ||
dbc->internal->lock_mode != DB_LOCK_NG);
*/
if (my_txn != NULL && dbc->txn != my_txn)
found = 1;
}
@@ -506,6 +504,10 @@ __bam_ca_split(my_dbc, ppgno, lpgno, rpgno, split_indx, cleft)
continue;
cp = dbc->internal;
if (cp->pgno == ppgno) {
/* [#8032]
DB_ASSERT(!STD_LOCKING(dbc) ||
cp->lock_mode != DB_LOCK_NG);
*/
if (my_txn != NULL && dbc->txn != my_txn)
found = 1;
if (cp->indx < split_indx) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,14 +38,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_delete.c,v 11.49 2004/02/27 12:38:28 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_delete.c,v 11.44 2002/07/03 19:03:49 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -57,6 +55,7 @@ static const char revid[] = "$Id: bt_delete.c,v 11.44 2002/07/03 19:03:49 bostic
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
/*
* __bam_ditem --
@@ -161,7 +160,7 @@ __bam_ditem(dbc, h, indx)
/* Delete the item and mark the page dirty. */
if ((ret = __db_ditem(dbc, h, indx, nbytes)) != 0)
return (ret);
if ((ret = mpf->set(mpf, h, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fset(mpf, h, DB_MPOOL_DIRTY)) != 0)
return (ret);
return (0);
@@ -211,7 +210,7 @@ __bam_adjindx(dbc, h, indx, indx_copy, is_insert)
memmove(&inp[indx], &inp[indx + O_INDX],
sizeof(db_indx_t) * (NUM_ENT(h) - indx));
}
if ((ret = mpf->set(mpf, h, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fset(mpf, h, DB_MPOOL_DIRTY)) != 0)
return (ret);
return (0);
@@ -260,9 +259,10 @@ __bam_dpages(dbc, stack_epg)
*/
ret = 0;
for (epg = cp->sp; epg < stack_epg; ++epg) {
if ((t_ret = mpf->put(mpf, epg->page, 0)) != 0 && ret == 0)
if ((t_ret = __memp_fput(mpf, epg->page, 0)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
ret = t_ret;
(void)__TLPUT(dbc, epg->lock);
}
if (ret != 0)
goto err;
@@ -276,7 +276,7 @@ __bam_dpages(dbc, stack_epg)
* It will deadlock here. Before we unlink the subtree, we relink the
* leaf page chain.
*/
if ((ret = __db_relink(dbc, DB_REM_PAGE, cp->csp->page, NULL, 1)) != 0)
if ((ret = __bam_relink(dbc, cp->csp->page, NULL)) != 0)
goto err;
/*
@@ -295,9 +295,11 @@ __bam_dpages(dbc, stack_epg)
pgno = PGNO(epg->page);
nitems = NUM_ENT(epg->page);
if ((ret = mpf->put(mpf, epg->page, 0)) != 0)
ret = __memp_fput(mpf, epg->page, 0);
if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err_inc;
(void)__TLPUT(dbc, epg->lock);
/* Free the rest of the pages in the stack. */
while (++epg <= cp->csp) {
@@ -314,18 +316,19 @@ __bam_dpages(dbc, stack_epg)
goto err;
}
if ((ret = __db_free(dbc, epg->page)) != 0) {
epg->page = NULL;
ret = __db_free(dbc, epg->page);
epg->page = NULL;
if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err_inc;
}
(void)__TLPUT(dbc, epg->lock);
}
if (0) {
err_inc: ++epg;
err: for (; epg <= cp->csp; ++epg) {
if (epg->page != NULL)
(void)mpf->put(mpf, epg->page, 0);
(void)__memp_fput(mpf, epg->page, 0);
(void)__TLPUT(dbc, epg->lock);
}
BT_STK_CLR(cp);
@@ -354,7 +357,7 @@ err: for (; epg <= cp->csp; ++epg) {
if ((ret =
__db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &p_lock)) != 0)
goto stop;
if ((ret = mpf->get(mpf, &pgno, 0, &parent)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &parent)) != 0)
goto stop;
if (NUM_ENT(parent) != 1)
@@ -384,7 +387,7 @@ err: for (; epg <= cp->csp; ++epg) {
if ((ret =
__db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &c_lock)) != 0)
goto stop;
if ((ret = mpf->get(mpf, &pgno, 0, &child)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &child)) != 0)
goto stop;
/* Log the change. */
@@ -423,9 +426,9 @@ err: for (; epg <= cp->csp; ++epg) {
RE_NREC_SET(parent, rcnt);
/* Mark the pages dirty. */
if ((ret = mpf->set(mpf, parent, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fset(mpf, parent, DB_MPOOL_DIRTY)) != 0)
goto stop;
if ((ret = mpf->set(mpf, child, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fset(mpf, child, DB_MPOOL_DIRTY)) != 0)
goto stop;
/* Adjust the cursors. */
@@ -446,15 +449,125 @@ err: for (; epg <= cp->csp; ++epg) {
if (0) {
stop: done = 1;
}
(void)__TLPUT(dbc, p_lock);
if (parent != NULL &&
(t_ret = mpf->put(mpf, parent, 0)) != 0 && ret == 0)
if ((t_ret = __TLPUT(dbc, p_lock)) != 0 && ret == 0)
ret = t_ret;
if (parent != NULL &&
(t_ret = __memp_fput(mpf, parent, 0)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, c_lock)) != 0 && ret == 0)
ret = t_ret;
(void)__TLPUT(dbc, c_lock);
if (child != NULL &&
(t_ret = mpf->put(mpf, child, 0)) != 0 && ret == 0)
(t_ret = __memp_fput(mpf, child, 0)) != 0 && ret == 0)
ret = t_ret;
}
return (ret);
}
/*
* __bam_relink --
* Relink around a deleted page.
*
* PUBLIC: int __bam_relink __P((DBC *, PAGE *, PAGE **));
*/
int
__bam_relink(dbc, pagep, new_next)
DBC *dbc;
PAGE *pagep, **new_next;
{
DB *dbp;
PAGE *np, *pp;
DB_LOCK npl, ppl;
DB_LSN *nlsnp, *plsnp, ret_lsn;
DB_MPOOLFILE *mpf;
int ret, t_ret;
dbp = dbc->dbp;
np = pp = NULL;
LOCK_INIT(npl);
LOCK_INIT(ppl);
nlsnp = plsnp = NULL;
mpf = dbp->mpf;
ret = 0;
/*
* Retrieve and lock the one/two pages. For a remove, we may need
* two pages (the before and after). For an add, we only need one
* because, the split took care of the prev.
*/
if (pagep->next_pgno != PGNO_INVALID) {
if ((ret = __db_lget(dbc,
0, pagep->next_pgno, DB_LOCK_WRITE, 0, &npl)) != 0)
goto err;
if ((ret = __memp_fget(mpf, &pagep->next_pgno, 0, &np)) != 0) {
ret = __db_pgerr(dbp, pagep->next_pgno, ret);
goto err;
}
nlsnp = &np->lsn;
}
if (pagep->prev_pgno != PGNO_INVALID) {
if ((ret = __db_lget(dbc,
0, pagep->prev_pgno, DB_LOCK_WRITE, 0, &ppl)) != 0)
goto err;
if ((ret = __memp_fget(mpf, &pagep->prev_pgno, 0, &pp)) != 0) {
ret = __db_pgerr(dbp, pagep->prev_pgno, ret);
goto err;
}
plsnp = &pp->lsn;
}
/* Log the change. */
if (DBC_LOGGING(dbc)) {
if ((ret = __bam_relink_log(dbp, dbc->txn, &ret_lsn, 0,
pagep->pgno, &pagep->lsn, pagep->prev_pgno, plsnp,
pagep->next_pgno, nlsnp)) != 0)
goto err;
} else
LSN_NOT_LOGGED(ret_lsn);
if (np != NULL)
np->lsn = ret_lsn;
if (pp != NULL)
pp->lsn = ret_lsn;
pagep->lsn = ret_lsn;
/*
* Modify and release the two pages.
*
* !!!
* The parameter new_next gets set to the page following the page we
* are removing. If there is no following page, then new_next gets
* set to NULL.
*/
if (np != NULL) {
np->prev_pgno = pagep->prev_pgno;
if (new_next == NULL)
ret = __memp_fput(mpf, np, DB_MPOOL_DIRTY);
else {
*new_next = np;
ret = __memp_fset(mpf, np, DB_MPOOL_DIRTY);
}
if ((t_ret = __TLPUT(dbc, npl)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
} else if (new_next != NULL)
*new_next = NULL;
if (pp != NULL) {
pp->next_pgno = pagep->next_pgno;
ret = __memp_fput(mpf, pp, DB_MPOOL_DIRTY);
if ((t_ret = __TLPUT(dbc, ppl)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
}
return (0);
err: if (np != NULL)
(void)__memp_fput(mpf, np, 0);
(void)__TLPUT(dbc, npl);
if (pp != NULL)
(void)__memp_fput(mpf, pp, 0);
(void)__TLPUT(dbc, ppl);
return (ret);
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Copyright (c) 1999-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_method.c,v 11.38 2004/09/22 03:31:26 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_method.c,v 11.29 2002/04/21 13:17:04 margo Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif
@@ -20,15 +18,15 @@ static const char revid[] = "$Id: bt_method.c,v 11.29 2002/04/21 13:17:04 margo
#include "dbinc/btree.h"
#include "dbinc/qam.h"
static int __bam_set_bt_compare
__P((DB *, int (*)(DB *, const DBT *, const DBT *)));
static int __bam_set_bt_maxkey __P((DB *, u_int32_t));
static int __bam_set_bt_minkey __P((DB *, u_int32_t));
static int __bam_set_bt_prefix
__P((DB *, size_t(*)(DB *, const DBT *, const DBT *)));
static int __ram_get_re_delim __P((DB *, int *));
static int __ram_set_re_delim __P((DB *, int));
static int __ram_set_re_len __P((DB *, u_int32_t));
static int __ram_set_re_pad __P((DB *, int));
static int __ram_get_re_source __P((DB *, const char **));
static int __ram_set_re_source __P((DB *, const char *));
/*
@@ -55,6 +53,7 @@ __bam_db_create(dbp)
dbp->set_bt_compare = __bam_set_bt_compare;
dbp->set_bt_maxkey = __bam_set_bt_maxkey;
dbp->get_bt_minkey = __bam_get_bt_minkey;
dbp->set_bt_minkey = __bam_set_bt_minkey;
dbp->set_bt_prefix = __bam_set_bt_prefix;
@@ -62,9 +61,13 @@ __bam_db_create(dbp)
t->re_delim = '\n';
t->re_eof = 1;
dbp->get_re_delim = __ram_get_re_delim;
dbp->set_re_delim = __ram_set_re_delim;
dbp->get_re_len = __ram_get_re_len;
dbp->set_re_len = __ram_set_re_len;
dbp->get_re_pad = __ram_get_re_pad;
dbp->set_re_pad = __ram_set_re_pad;
dbp->get_re_source = __ram_get_re_source;
dbp->set_re_source = __ram_set_re_source;
return (0);
@@ -99,6 +102,37 @@ __bam_db_close(dbp)
return (0);
}
/*
* __bam_map_flags --
* Map Btree specific flags from public to the internal values.
*
* PUBLIC: void __bam_map_flags __P((DB *, u_int32_t *, u_int32_t *));
*/
void
__bam_map_flags(dbp, inflagsp, outflagsp)
DB *dbp;
u_int32_t *inflagsp, *outflagsp;
{
COMPQUIET(dbp, NULL);
if (FLD_ISSET(*inflagsp, DB_DUP)) {
FLD_SET(*outflagsp, DB_AM_DUP);
FLD_CLR(*inflagsp, DB_DUP);
}
if (FLD_ISSET(*inflagsp, DB_DUPSORT)) {
FLD_SET(*outflagsp, DB_AM_DUP | DB_AM_DUPSORT);
FLD_CLR(*inflagsp, DB_DUPSORT);
}
if (FLD_ISSET(*inflagsp, DB_RECNUM)) {
FLD_SET(*outflagsp, DB_AM_RECNUM);
FLD_CLR(*inflagsp, DB_RECNUM);
}
if (FLD_ISSET(*inflagsp, DB_REVSPLITOFF)) {
FLD_SET(*outflagsp, DB_AM_REVSPLITOFF);
FLD_CLR(*inflagsp, DB_REVSPLITOFF);
}
}
/*
* __bam_set_flags --
* Set Btree specific flags.
@@ -113,50 +147,31 @@ __bam_set_flags(dbp, flagsp)
u_int32_t flags;
flags = *flagsp;
if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF)) {
if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF))
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags");
/*
* The DB_DUP and DB_DUPSORT flags are shared by the Hash
* and Btree access methods.
*/
if (LF_ISSET(DB_DUP | DB_DUPSORT))
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
/*
* The DB_DUP and DB_DUPSORT flags are shared by the Hash
* and Btree access methods.
*/
if (LF_ISSET(DB_DUP | DB_DUPSORT))
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF))
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF))
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
if (LF_ISSET(DB_DUP | DB_DUPSORT)) {
/* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */
if (F_ISSET(dbp, DB_AM_RECNUM))
goto incompat;
/* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */
if (LF_ISSET(DB_DUP | DB_DUPSORT) && F_ISSET(dbp, DB_AM_RECNUM))
goto incompat;
if (LF_ISSET(DB_DUPSORT)) {
if (dbp->dup_compare == NULL)
dbp->dup_compare = __bam_defcmp;
F_SET(dbp, DB_AM_DUPSORT);
}
/* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */
if (LF_ISSET(DB_RECNUM) && F_ISSET(dbp, DB_AM_DUP))
goto incompat;
F_SET(dbp, DB_AM_DUP);
LF_CLR(DB_DUP | DB_DUPSORT);
}
if (LF_ISSET(DB_DUPSORT) && dbp->dup_compare == NULL)
dbp->dup_compare = __bam_defcmp;
if (LF_ISSET(DB_RECNUM)) {
/* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */
if (F_ISSET(dbp, DB_AM_DUP))
goto incompat;
F_SET(dbp, DB_AM_RECNUM);
LF_CLR(DB_RECNUM);
}
if (LF_ISSET(DB_REVSPLITOFF)) {
F_SET(dbp, DB_AM_REVSPLITOFF);
LF_CLR(DB_REVSPLITOFF);
}
*flagsp = flags;
}
__bam_map_flags(dbp, flagsp, &dbp->flags);
return (0);
incompat:
@@ -166,15 +181,18 @@ incompat:
/*
* __bam_set_bt_compare --
* Set the comparison function.
*
* PUBLIC: int __bam_set_bt_compare
* PUBLIC: __P((DB *, int (*)(DB *, const DBT *, const DBT *)));
*/
static int
int
__bam_set_bt_compare(dbp, func)
DB *dbp;
int (*func) __P((DB *, const DBT *, const DBT *));
{
BTREE *t;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_compare");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compare");
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
t = dbp->bt_internal;
@@ -201,7 +219,7 @@ __bam_set_bt_maxkey(dbp, bt_maxkey)
{
BTREE *t;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_maxkey");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_maxkey");
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
t = dbp->bt_internal;
@@ -215,6 +233,26 @@ __bam_set_bt_maxkey(dbp, bt_maxkey)
return (0);
}
/*
* __db_get_bt_minkey --
* Get the minimum keys per page.
*
* PUBLIC: int __bam_get_bt_minkey __P((DB *, u_int32_t *));
*/
int
__bam_get_bt_minkey(dbp, bt_minkeyp)
DB *dbp;
u_int32_t *bt_minkeyp;
{
BTREE *t;
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
t = dbp->bt_internal;
*bt_minkeyp = t->bt_minkey;
return (0);
}
/*
* __bam_set_bt_minkey --
* Set the minimum keys per page.
@@ -226,7 +264,7 @@ __bam_set_bt_minkey(dbp, bt_minkey)
{
BTREE *t;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_minkey");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_minkey");
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
t = dbp->bt_internal;
@@ -251,7 +289,7 @@ __bam_set_bt_prefix(dbp, func)
{
BTREE *t;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_prefix");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_prefix");
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
t = dbp->bt_internal;
@@ -260,6 +298,29 @@ __bam_set_bt_prefix(dbp, func)
return (0);
}
/*
* __ram_map_flags --
* Map Recno specific flags from public to the internal values.
*
* PUBLIC: void __ram_map_flags __P((DB *, u_int32_t *, u_int32_t *));
*/
void
__ram_map_flags(dbp, inflagsp, outflagsp)
DB *dbp;
u_int32_t *inflagsp, *outflagsp;
{
COMPQUIET(dbp, NULL);
if (FLD_ISSET(*inflagsp, DB_RENUMBER)) {
FLD_SET(*outflagsp, DB_AM_RENUMBER);
FLD_CLR(*inflagsp, DB_RENUMBER);
}
if (FLD_ISSET(*inflagsp, DB_SNAPSHOT)) {
FLD_SET(*outflagsp, DB_AM_SNAPSHOT);
FLD_CLR(*inflagsp, DB_SNAPSHOT);
}
}
/*
* __ram_set_flags --
* Set Recno specific flags.
@@ -276,21 +337,27 @@ __ram_set_flags(dbp, flagsp)
flags = *flagsp;
if (LF_ISSET(DB_RENUMBER | DB_SNAPSHOT)) {
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags");
DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
if (LF_ISSET(DB_RENUMBER)) {
F_SET(dbp, DB_AM_RENUMBER);
LF_CLR(DB_RENUMBER);
}
if (LF_ISSET(DB_SNAPSHOT)) {
F_SET(dbp, DB_AM_SNAPSHOT);
LF_CLR(DB_SNAPSHOT);
}
*flagsp = flags;
}
__ram_map_flags(dbp, flagsp, &dbp->flags);
return (0);
}
/*
* __db_get_re_delim --
* Get the variable-length input record delimiter.
*/
static int
__ram_get_re_delim(dbp, re_delimp)
DB *dbp;
int *re_delimp;
{
BTREE *t;
DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
t = dbp->bt_internal;
*re_delimp = t->re_delim;
return (0);
}
@@ -305,7 +372,7 @@ __ram_set_re_delim(dbp, re_delim)
{
BTREE *t;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_delim");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_delim");
DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
t = dbp->bt_internal;
@@ -316,6 +383,40 @@ __ram_set_re_delim(dbp, re_delim)
return (0);
}
/*
* __db_get_re_len --
* Get the variable-length input record length.
*
* PUBLIC: int __ram_get_re_len __P((DB *, u_int32_t *));
*/
int
__ram_get_re_len(dbp, re_lenp)
DB *dbp;
u_int32_t *re_lenp;
{
BTREE *t;
QUEUE *q;
DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
/*
* This has to work for all access methods, before or after opening the
* database. When the record length is set with __ram_set_re_len, the
* value in both the BTREE and QUEUE structs will be correct.
* Otherwise, this only makes sense after the database in opened, in
* which case we know the type.
*/
if (dbp->type == DB_QUEUE) {
q = dbp->q_internal;
*re_lenp = q->re_len;
} else {
t = dbp->bt_internal;
*re_lenp = t->re_len;
}
return (0);
}
/*
* __ram_set_re_len --
* Set the variable-length input record length.
@@ -328,7 +429,7 @@ __ram_set_re_len(dbp, re_len)
BTREE *t;
QUEUE *q;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_len");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_len");
DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
t = dbp->bt_internal;
@@ -342,6 +443,40 @@ __ram_set_re_len(dbp, re_len)
return (0);
}
/*
* __db_get_re_pad --
* Get the fixed-length record pad character.
*
* PUBLIC: int __ram_get_re_pad __P((DB *, int *));
*/
int
__ram_get_re_pad(dbp, re_padp)
DB *dbp;
int *re_padp;
{
BTREE *t;
QUEUE *q;
DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
/*
* This has to work for all access methods, before or after opening the
* database. When the record length is set with __ram_set_re_pad, the
* value in both the BTREE and QUEUE structs will be correct.
* Otherwise, this only makes sense after the database in opened, in
* which case we know the type.
*/
if (dbp->type == DB_QUEUE) {
q = dbp->q_internal;
*re_padp = q->re_pad;
} else {
t = dbp->bt_internal;
*re_padp = t->re_pad;
}
return (0);
}
/*
* __ram_set_re_pad --
* Set the fixed-length record pad character.
@@ -354,7 +489,7 @@ __ram_set_re_pad(dbp, re_pad)
BTREE *t;
QUEUE *q;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_pad");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_pad");
DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
t = dbp->bt_internal;
@@ -368,6 +503,24 @@ __ram_set_re_pad(dbp, re_pad)
return (0);
}
/*
* __db_get_re_source --
* Get the backing source file name.
*/
static int
__ram_get_re_source(dbp, re_sourcep)
DB *dbp;
const char **re_sourcep;
{
BTREE *t;
DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
t = dbp->bt_internal;
*re_sourcep = t->re_source;
return (0);
}
/*
* __ram_set_re_source --
* Set the backing source file name.
@@ -379,7 +532,7 @@ __ram_set_re_source(dbp, re_source)
{
BTREE *t;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_source");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_source");
DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
t = dbp->bt_internal;

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,18 +38,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_open.c,v 11.92 2004/04/29 14:39:47 ubell Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_open.c,v 11.76 2002/09/04 19:06:42 margo Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <limits.h>
#include <string.h>
#endif
@@ -61,6 +58,7 @@ static const char revid[] = "$Id: bt_open.c,v 11.76 2002/09/04 19:06:42 margo Ex
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#include "dbinc/fop.h"
static void __bam_init_meta __P((DB *, BTMETA *, db_pgno_t, DB_LSN *));
@@ -85,10 +83,6 @@ __bam_open(dbp, txn, name, base_pgno, flags)
COMPQUIET(name, NULL);
t = dbp->bt_internal;
/* Initialize the remaining fields/methods of the DB. */
dbp->key_range = __bam_key_range;
dbp->stat = __bam_stat;
/*
* We don't permit the user to specify a prefix routine if they didn't
* also specify a comparison routine, they can't know enough about our
@@ -290,6 +284,7 @@ __bam_read_root(dbp, txn, base_pgno, flags)
DB_MPOOLFILE *mpf;
int ret, t_ret;
COMPQUIET(flags, 0);
meta = NULL;
t = dbp->bt_internal;
LOCK_INIT(metalock);
@@ -297,14 +292,14 @@ __bam_read_root(dbp, txn, base_pgno, flags)
ret = 0;
/* Get a cursor. */
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
return (ret);
/* Get the metadata page. */
if ((ret =
__db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &base_pgno, 0, (PAGE **)&meta)) != 0)
if ((ret = __memp_fget(mpf, &base_pgno, 0, &meta)) != 0)
goto err;
/*
@@ -315,16 +310,18 @@ __bam_read_root(dbp, txn, base_pgno, flags)
* Otherwise, we'd better be in recovery or abort, in which case the
* metadata page will be created/initialized elsewhere.
*/
DB_ASSERT(meta->dbmeta.magic != 0 ||
IS_RECOVERING(dbp->dbenv) || F_ISSET(dbp, DB_AM_RECOVER));
if (meta->dbmeta.magic == DB_BTREEMAGIC) {
t->bt_maxkey = meta->maxkey;
t->bt_minkey = meta->minkey;
t->re_pad = (int)meta->re_pad;
t->re_len = meta->re_len;
t->bt_maxkey = meta->maxkey;
t->bt_minkey = meta->minkey;
t->re_pad = meta->re_pad;
t->re_len = meta->re_len;
t->bt_meta = base_pgno;
t->bt_root = meta->root;
t->bt_meta = base_pgno;
t->bt_root = meta->root;
} else {
DB_ASSERT(IS_RECOVERING(dbp->dbenv) ||
F_ISSET(dbp, DB_AM_RECOVER));
}
/*
* !!!
@@ -337,21 +334,14 @@ __bam_read_root(dbp, txn, base_pgno, flags)
*/
t->bt_lpgno = PGNO_INVALID;
/* We must initialize last_pgno, it could be stale. */
if (!LF_ISSET(DB_RDONLY) && dbp->meta_pgno == PGNO_BASE_MD) {
mpf->last_pgno(mpf, &meta->dbmeta.last_pgno);
ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY);
} else
ret = mpf->put(mpf, meta, 0);
meta = NULL;
err: /* Put the metadata page back. */
if (meta != NULL && (t_ret = mpf->put(mpf, meta, 0)) != 0 && ret == 0)
if (meta != NULL &&
(t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
@@ -408,7 +398,7 @@ __bam_init_meta(dbp, meta, pgno, lsnp)
meta->maxkey = t->bt_maxkey;
meta->minkey = t->bt_minkey;
meta->re_len = t->re_len;
meta->re_pad = t->re_pad;
meta->re_pad = (u_int32_t)t->re_pad;
}
/*
@@ -418,8 +408,8 @@ __bam_init_meta(dbp, meta, pgno, lsnp)
* This code appears more complex than it is because of the two cases (named
* and unnamed). The way to read the code is that for each page being created,
* there are three parts: 1) a "get page" chunk (which either uses malloc'd
* memory or calls mpf->get), 2) the initialization, and 3) the "put page"
* chunk which either does a fop write or an mpf->put.
* memory or calls __memp_fget), 2) the initialization, and 3) the "put page"
* chunk which either does a fop write or an __memp_fput.
*
* PUBLIC: int __bam_new_file __P((DB *, DB_TXN *, DB_FH *, const char *));
*/
@@ -445,78 +435,84 @@ __bam_new_file(dbp, txn, fhp, name)
mpf = dbp->mpf;
root = NULL;
meta = NULL;
memset(&pdbt, 0, sizeof(pdbt));
/* Build meta-data page. */
buf = NULL;
if (name == NULL) {
/* Build the meta-data page. */
pgno = PGNO_BASE_MD;
ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &meta);
if ((ret =
__memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &meta)) != 0)
return (ret);
LSN_NOT_LOGGED(lsn);
__bam_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
meta->root = 1;
meta->dbmeta.last_pgno = 1;
ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY);
meta = NULL;
if (ret != 0)
goto err;
/* Build the root page. */
pgno = 1;
if ((ret =
__memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &root)) != 0)
goto err;
P_INIT(root, dbp->pgsize, 1, PGNO_INVALID, PGNO_INVALID,
LEAFLEVEL, dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE);
LSN_NOT_LOGGED(root->lsn);
ret = __memp_fput(mpf, root, DB_MPOOL_DIRTY);
root = NULL;
if (ret != 0)
goto err;
} else {
memset(&pdbt, 0, sizeof(pdbt));
/* Build the meta-data page. */
pginfo.db_pagesize = dbp->pgsize;
pginfo.flags =
F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));
pginfo.type = dbp->type;
pdbt.data = &pginfo;
pdbt.size = sizeof(pginfo);
ret = __os_calloc(dbp->dbenv, 1, dbp->pgsize, &buf);
if ((ret = __os_calloc(dbenv, 1, dbp->pgsize, &buf)) != 0)
return (ret);
meta = (BTMETA *)buf;
}
if (ret != 0)
return (ret);
LSN_NOT_LOGGED(lsn);
__bam_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
meta->root = 1;
meta->dbmeta.last_pgno = 1;
if (name == NULL)
ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY);
else {
LSN_NOT_LOGGED(lsn);
__bam_init_meta(dbp, meta, PGNO_BASE_MD, &lsn);
meta->root = 1;
meta->dbmeta.last_pgno = 1;
if ((ret = __db_pgout(dbenv, PGNO_BASE_MD, meta, &pdbt)) != 0)
goto err;
ret = __fop_write(dbenv,
txn, name, DB_APP_DATA, fhp, 0, buf, dbp->pgsize, 1);
}
if (ret != 0)
goto err;
meta = NULL;
/* Now build root page. */
if (name == NULL) {
pgno = 1;
if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &root)) != 0)
if ((ret = __fop_write(dbenv, txn, name, DB_APP_DATA, fhp,
dbp->pgsize, 0, 0, buf, dbp->pgsize, 1, F_ISSET(
dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0)) != 0)
goto err;
} else {
meta = NULL;
/* Build the root page. */
#ifdef DIAGNOSTIC
memset(buf, 0, dbp->pgsize);
memset(buf, CLEAR_BYTE, dbp->pgsize);
#endif
root = (PAGE *)buf;
}
P_INIT(root, dbp->pgsize, 1, PGNO_INVALID, PGNO_INVALID,
LEAFLEVEL, dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE);
LSN_NOT_LOGGED(root->lsn);
if (name == NULL)
ret = mpf->put(mpf, root, DB_MPOOL_DIRTY);
else {
P_INIT(root, dbp->pgsize, 1, PGNO_INVALID, PGNO_INVALID,
LEAFLEVEL, dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE);
LSN_NOT_LOGGED(root->lsn);
if ((ret = __db_pgout(dbenv, root->pgno, root, &pdbt)) != 0)
goto err;
ret = __fop_write(dbenv, txn,
name, DB_APP_DATA, fhp, dbp->pgsize, buf, dbp->pgsize, 1);
if ((ret = __fop_write(dbenv, txn, name, DB_APP_DATA, fhp,
dbp->pgsize, 1, 0, buf, dbp->pgsize, 1, F_ISSET(
dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0)) != 0)
goto err;
root = NULL;
}
if (ret != 0)
goto err;
root = NULL;
err: if (name != NULL)
err: if (buf != NULL)
__os_free(dbenv, buf);
else {
if (meta != NULL)
(void)mpf->put(mpf, meta, 0);
(void)__memp_fput(mpf, meta, 0);
if (root != NULL)
(void)mpf->put(mpf, root, 0);
(void)__memp_fput(mpf, root, 0);
}
return (ret);
}
@@ -547,7 +543,7 @@ __bam_new_subdb(mdbp, dbp, txn)
meta = NULL;
root = NULL;
if ((ret = mdbp->cursor(mdbp, txn,
if ((ret = __db_cursor(mdbp, txn,
&dbc, CDB_LOCKING(dbenv) ? DB_WRITECURSOR : 0)) != 0)
return (ret);
@@ -555,7 +551,8 @@ __bam_new_subdb(mdbp, dbp, txn)
if ((ret = __db_lget(dbc,
0, dbp->meta_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &dbp->meta_pgno, DB_MPOOL_CREATE, &meta)) != 0)
if ((ret =
__memp_fget(mpf, &dbp->meta_pgno, DB_MPOOL_CREATE, &meta)) != 0)
goto err;
/* Build meta-data page. */
@@ -582,24 +579,23 @@ __bam_new_subdb(mdbp, dbp, txn)
goto err;
/* Release the metadata and root pages. */
if ((ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY)) != 0)
goto err;
meta = NULL;
if ((ret = mpf->put(mpf, root, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, root, DB_MPOOL_DIRTY)) != 0)
goto err;
root = NULL;
err:
if (meta != NULL)
if ((t_ret = mpf->put(mpf, meta, 0)) != 0 && ret == 0)
if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
ret = t_ret;
if (root != NULL)
if ((t_ret = mpf->put(mpf, root, 0)) != 0 && ret == 0)
ret = t_ret;
if (LOCK_ISSET(metalock))
if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
if ((t_ret = __memp_fput(mpf, root, 0)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
ret = t_ret;
if (dbc != NULL)
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,14 +38,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_put.c,v 11.80 2004/10/29 17:33:25 ubell Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_put.c,v 11.69 2002/08/06 06:11:12 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -54,7 +52,9 @@ static const char revid[] = "$Id: bt_put.c,v 11.69 2002/08/06 06:11:12 bostic Ex
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/mp.h"
static int __bam_build
__P((DBC *, u_int32_t, DBT *, PAGE *, u_int32_t, u_int32_t));
@@ -76,6 +76,7 @@ __bam_iitem(dbc, key, data, op, flags)
DBT *key, *data;
u_int32_t op, flags;
{
DB_ENV *dbenv;
BKEYDATA *bk, bk_tmp;
BTREE *t;
BTREE_CURSOR *cp;
@@ -90,6 +91,7 @@ __bam_iitem(dbc, key, data, op, flags)
COMPQUIET(bk, NULL);
dbp = dbc->dbp;
dbenv = dbp->dbenv;
mpf = dbp->mpf;
cp = (BTREE_CURSOR *)dbc->internal;
t = dbp->bt_internal;
@@ -102,10 +104,8 @@ __bam_iitem(dbc, key, data, op, flags)
* anything other simple overwrite.
*/
if (F_ISSET(dbp, DB_AM_FIXEDLEN) &&
F_ISSET(data, DB_DBT_PARTIAL) && data->dlen != data->size) {
data_size = data->size;
goto len_err;
}
F_ISSET(data, DB_DBT_PARTIAL) && data->size != data->dlen)
return (__db_rec_repl(dbenv, data->size, data->dlen));
/*
* Figure out how much space the data will take, including if it's a
@@ -119,12 +119,8 @@ __bam_iitem(dbc, key, data, op, flags)
__bam_partsize(dbp, op, data, h, indx) : data->size;
padrec = 0;
if (F_ISSET(dbp, DB_AM_FIXEDLEN)) {
if (data_size > t->re_len) {
len_err: __db_err(dbp->dbenv,
"Length improper for fixed length record %lu",
(u_long)data_size);
return (EINVAL);
}
if (data_size > t->re_len)
return (__db_rec_toobig(dbenv, data_size, t->re_len));
/* Records that are deleted anyway needn't be padded out. */
if (!LF_ISSET(BI_DELETED) && data_size < t->re_len) {
@@ -158,8 +154,8 @@ len_err: __db_err(dbp->dbenv,
dbp->dup_compare, &cmp)) != 0)
return (ret);
if (cmp != 0) {
__db_err(dbp->dbenv,
"Current data differs from put data");
__db_err(dbenv,
"Existing data sorts differently from put data");
return (EINVAL);
}
}
@@ -218,19 +214,14 @@ len_err: __db_err(dbp->dbenv,
needed += need_bytes - have_bytes;
break;
default:
return (__db_unknown_flag(dbp->dbenv, "__bam_iitem", op));
return (__db_unknown_flag(dbenv, "DB->put", op));
}
/*
* If there's not enough room, or the user has put a ceiling on the
* number of keys permitted in the page, split the page.
*
* XXX
* The t->bt_maxkey test here may be insufficient -- do we have to
* check in the btree split code, so we don't undo it there!?!?
*/
if (P_FREESPACE(dbp, h) < needed ||
(t->bt_maxkey != 0 && NUM_ENT(h) > t->bt_maxkey))
if (P_FREESPACE(dbp, h) < needed)
return (DB_NEEDSPLIT);
/*
@@ -294,24 +285,25 @@ len_err: __db_err(dbp->dbenv,
* we deadlock or fail while deleting the overflow item or
* replacing the non-overflow item, a subsequent cursor close
* will try and remove the item because the cursor's delete
* flag is set
* flag is set.
*/
(void)__bam_ca_delete(dbp, PGNO(h), indx, 0);
if (TYPE(h) == P_LBTREE) {
++indx;
dupadjust = 1;
/*
* In a Btree deleted records aren't counted (deleted
* records are counted in a Recno because all accesses
* are based on record number). If it's a Btree and
* it's a DB_CURRENT operation overwriting a previously
* deleted record, increment the record count.
*/
was_deleted = B_DISSET(bk->type);
}
/*
* In a Btree deleted records aren't counted (deleted records
* are counted in a Recno because all accesses are based on
* record number). If it's a Btree and it's a DB_CURRENT
* operation overwriting a previously deleted record, increment
* the record count.
*/
if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP)
was_deleted = B_DISSET(bk->type);
/*
* 4. Delete and re-add the data item.
*
@@ -331,7 +323,7 @@ len_err: __db_err(dbp->dbenv,
replace = 1;
break;
default:
return (__db_unknown_flag(dbp->dbenv, "__bam_iitem", op));
return (__db_unknown_flag(dbenv, "DB->put", op));
}
/* Add the data. */
@@ -360,7 +352,7 @@ len_err: __db_err(dbp->dbenv,
if (ret != 0)
return (ret);
}
if ((ret = mpf->set(mpf, h, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fset(mpf, h, DB_MPOOL_DIRTY)) != 0)
return (ret);
/*
@@ -648,7 +640,7 @@ __bam_ritem(dbc, h, indx, data)
if (p == t) /* First index is fast. */
inp[indx] += nbytes;
else { /* Else, shift the page. */
memmove(p + nbytes, p, t - p);
memmove(p + nbytes, p, (size_t)(t - p));
/* Adjust the indices' offsets. */
off = inp[indx];
@@ -700,12 +692,16 @@ __bam_dup_convert(dbc, h, indx)
*/
while (indx > 0 && inp[indx] == inp[indx - P_INDX])
indx -= P_INDX;
for (cnt = 0, sz = 0, first = indx;; ++cnt, indx += P_INDX) {
if (indx >= NUM_ENT(h) || inp[first] != inp[indx])
break;
bk = GET_BKEYDATA(dbp, h, indx);
sz += B_TYPE(bk->type) == B_KEYDATA ?
BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
/* Count the key once. */
bk = GET_BKEYDATA(dbp, h, indx);
sz = B_TYPE(bk->type) == B_KEYDATA ?
BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
/* Sum up all the data items. */
for (cnt = 0, first = indx;
indx < NUM_ENT(h) && inp[first] == inp[indx];
++cnt, indx += P_INDX) {
bk = GET_BKEYDATA(dbp, h, indx + O_INDX);
sz += B_TYPE(bk->type) == B_KEYDATA ?
BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
@@ -800,14 +796,14 @@ __bam_dup_convert(dbc, h, indx)
B_DUPLICATE, dp->pgno, h, first + 1, NULL)) != 0)
goto err;
/* Adjust cursors for all the above movments. */
/* Adjust cursors for all the above movements. */
if ((ret = __bam_ca_di(dbc,
PGNO(h), first + P_INDX, first + P_INDX - indx)) != 0)
PGNO(h), first + P_INDX, (int)(first + P_INDX - indx))) != 0)
goto err;
return (mpf->put(mpf, dp, DB_MPOOL_DIRTY));
return (__memp_fput(mpf, dp, DB_MPOOL_DIRTY));
err: (void)mpf->put(mpf, dp, 0);
err: (void)__memp_fput(mpf, dp, 0);
return (ret);
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_rec.c,v 11.70 2004/09/24 00:43:12 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_rec.c,v 11.57 2002/08/06 16:53:53 ubell Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -23,6 +21,7 @@ static const char revid[] = "$Id: bt_rec.c,v 11.57 2002/08/06 16:53:53 ubell Exp
#include "dbinc/btree.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#define IS_BTREE_PAGE(pagep) \
(TYPE(pagep) == P_IBTREE || \
@@ -50,7 +49,7 @@ __bam_split_recover(dbenv, dbtp, lsnp, op, info)
PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
db_pgno_t pgno, root_pgno;
u_int32_t ptype;
int cmp, l_update, p_update, r_update, rc, ret, ret_l, rootsplit, t_ret;
int cmp, l_update, p_update, r_update, rc, ret, rootsplit, t_ret;
COMPQUIET(info, NULL);
REC_PRINT(__bam_split_print);
@@ -82,50 +81,40 @@ __bam_split_recover(dbenv, dbtp, lsnp, op, info)
pgno = PGNO(sp);
root_pgno = argp->root_pgno;
rootsplit = root_pgno != PGNO_INVALID;
if ((ret_l = mpf->get(mpf, &argp->left, 0, &lp)) != 0)
lp = NULL;
if (mpf->get(mpf, &argp->right, 0, &rp) != 0)
rp = NULL;
REC_FGET(mpf, argp->left, &lp, right);
right: REC_FGET(mpf, argp->right, &rp, redo);
if (DB_REDO(op)) {
redo: if (DB_REDO(op)) {
l_update = r_update = p_update = 0;
/*
* Decide if we need to resplit the page.
*
* If this is a root split, then the root has to exist, it's
* the page we're splitting and it gets modified. If this is
* not a root split, then the left page has to exist, for the
* same reason.
* If this is a root split, then the root has to exist unless
* we have truncated it due to a future deallocation.
*/
if (rootsplit) {
if ((ret = mpf->get(mpf, &pgno, 0, &pp)) != 0) {
__db_pgerr(file_dbp, pgno, ret);
pp = NULL;
goto out;
}
cmp = log_compare(&LSN(pp), &LSN(argp->pg.data));
CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data));
REC_FGET(mpf, root_pgno, &pp, do_left);
cmp =
log_compare(&LSN(pp), &LSN(argp->pg.data));
CHECK_LSN(op,
cmp, &LSN(pp), &LSN(argp->pg.data));
p_update = cmp == 0;
} else if (lp == NULL) {
__db_pgerr(file_dbp, argp->left, ret_l);
goto out;
}
if (lp != NULL) {
do_left: if (lp != NULL) {
cmp = log_compare(&LSN(lp), &argp->llsn);
CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn);
if (cmp == 0)
l_update = 1;
} else
l_update = 1;
}
if (rp != NULL) {
cmp = log_compare(&LSN(rp), &argp->rlsn);
CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn);
if (cmp == 0)
r_update = 1;
} else
r_update = 1;
}
if (!p_update && !l_update && !r_update)
goto check_next;
@@ -158,32 +147,18 @@ __bam_split_recover(dbenv, dbtp, lsnp, op, info)
NUM_ENT(sp))) != 0)
goto out;
/* If the left child is wrong, update it. */
if (lp == NULL && (ret = mpf->get(
mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) {
__db_pgerr(file_dbp, argp->left, ret);
lp = NULL;
goto out;
}
if (l_update) {
memcpy(lp, _lp, file_dbp->pgsize);
lp->lsn = *lsnp;
if ((ret = mpf->put(mpf, lp, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
goto out;
lp = NULL;
}
/* If the right child is wrong, update it. */
if (rp == NULL && (ret = mpf->get(
mpf, &argp->right, DB_MPOOL_CREATE, &rp)) != 0) {
__db_pgerr(file_dbp, argp->right, ret);
rp = NULL;
goto out;
}
if (r_update) {
memcpy(rp, _rp, file_dbp->pgsize);
rp->lsn = *lsnp;
if ((ret = mpf->put(mpf, rp, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
goto out;
rp = NULL;
}
@@ -205,11 +180,11 @@ __bam_split_recover(dbenv, dbtp, lsnp, op, info)
P_INIT(pp, file_dbp->pgsize, root_pgno,
PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype);
RE_NREC_SET(pp, rc ? __bam_total(file_dbp, _lp) +
RE_NREC_SET(pp, rc ? __bam_total(file_dbp, _lp) +
__bam_total(file_dbp, _rp) : 0);
pp->lsn = *lsnp;
if ((ret = mpf->put(mpf, pp, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
goto out;
pp = NULL;
}
@@ -221,11 +196,19 @@ check_next: /*
* previous-page pointer updated to our new page. The next
* page must exist because we're redoing the operation.
*/
if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
if ((ret = mpf->get(mpf, &argp->npgno, 0, &np)) != 0) {
__db_pgerr(file_dbp, argp->npgno, ret);
np = NULL;
goto out;
if (!rootsplit && argp->npgno != PGNO_INVALID) {
if ((ret =
__memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(
file_dbp, argp->npgno, ret);
goto out;
} else
goto done;
}
cmp = log_compare(&LSN(np), &argp->nlsn);
CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn);
@@ -233,7 +216,7 @@ check_next: /*
PREV_PGNO(np) = argp->right;
np->lsn = *lsnp;
if ((ret =
mpf->put(mpf, np, DB_MPOOL_DIRTY)) != 0)
__memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0)
goto out;
np = NULL;
}
@@ -246,13 +229,13 @@ check_next: /*
* the adds onto the page that caused the split, and there's
* really no undo-ing to be done.
*/
if ((ret = mpf->get(mpf, &pgno, 0, &pp)) != 0) {
if ((ret = __memp_fget(mpf, &pgno, 0, &pp)) != 0) {
pp = NULL;
goto lrundo;
}
if (log_compare(lsnp, &LSN(pp)) == 0) {
memcpy(pp, argp->pg.data, argp->pg.size);
if ((ret = mpf->put(mpf, pp, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
goto out;
pp = NULL;
}
@@ -270,7 +253,7 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
log_compare(lsnp, &LSN(lp)) == 0) {
lp->lsn = argp->llsn;
if ((ret =
mpf->put(mpf, lp, DB_MPOOL_DIRTY)) != 0)
__memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
goto out;
lp = NULL;
}
@@ -278,7 +261,7 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
log_compare(lsnp, &LSN(rp)) == 0) {
rp->lsn = argp->rlsn;
if ((ret =
mpf->put(mpf, rp, DB_MPOOL_DIRTY)) != 0)
__memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
goto out;
rp = NULL;
}
@@ -292,15 +275,16 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
* possible that the next-page never existed, we ignore it as
* if there's nothing to undo.
*/
if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
if ((ret = mpf->get(mpf, &argp->npgno, 0, &np)) != 0) {
if (!rootsplit && argp->npgno != PGNO_INVALID) {
if ((ret =
__memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
np = NULL;
goto done;
}
if (log_compare(lsnp, &LSN(np)) == 0) {
PREV_PGNO(np) = argp->left;
np->lsn = argp->nlsn;
if (mpf->put(mpf, np, DB_MPOOL_DIRTY))
if (__memp_fput(mpf, np, DB_MPOOL_DIRTY))
goto out;
np = NULL;
}
@@ -311,13 +295,13 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: /* Free any pages that weren't dirtied. */
if (pp != NULL && (t_ret = mpf->put(mpf, pp, 0)) != 0 && ret == 0)
if (pp != NULL && (t_ret = __memp_fput(mpf, pp, 0)) != 0 && ret == 0)
ret = t_ret;
if (lp != NULL && (t_ret = mpf->put(mpf, lp, 0)) != 0 && ret == 0)
if (lp != NULL && (t_ret = __memp_fput(mpf, lp, 0)) != 0 && ret == 0)
ret = t_ret;
if (np != NULL && (t_ret = mpf->put(mpf, np, 0)) != 0 && ret == 0)
if (np != NULL && (t_ret = __memp_fput(mpf, np, 0)) != 0 && ret == 0)
ret = t_ret;
if (rp != NULL && (t_ret = mpf->put(mpf, rp, 0)) != 0 && ret == 0)
if (rp != NULL && (t_ret = __memp_fput(mpf, rp, 0)) != 0 && ret == 0)
ret = t_ret;
/* Free any allocated space. */
@@ -362,18 +346,18 @@ __bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
/* Fix the root page. */
pgno = root_pgno = argp->root_pgno;
if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) {
/* The root page must always exist if we are going forward. */
if (DB_REDO(op)) {
__db_pgerr(file_dbp, pgno, ret);
if ((ret = __memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, pgno, ret);
goto out;
}
/* This must be the root of an OPD tree. */
DB_ASSERT(root_pgno !=
((BTREE *)file_dbp->bt_internal)->bt_root);
ret = 0;
goto do_page;
} else
goto do_page;
}
modified = 0;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->rootlsn);
@@ -395,7 +379,7 @@ __bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
pagep->lsn = argp->rootlsn;
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
do_page:
@@ -404,11 +388,16 @@ do_page:
* page never made it to disk, so if we're undo-ing and the page
* doesn't exist, it's okay and there's nothing further to do.
*/
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (DB_UNDO(op))
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->pgno, ret);
goto out;
} else
goto done;
__db_pgerr(file_dbp, argp->pgno, ret);
goto out;
}
modified = 0;
(void)__ua_memcpy(&copy_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN));
@@ -424,7 +413,7 @@ do_page:
memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
@@ -432,7 +421,7 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}
@@ -464,11 +453,16 @@ __bam_adj_recover(dbenv, dbtp, lsnp, op, info)
REC_INTRO(__bam_adj_read, 1);
/* Get the page; if it never existed and we're undoing, we're done. */
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (DB_UNDO(op))
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->pgno, ret);
goto out;
} else
goto done;
__db_pgerr(file_dbp, argp->pgno, ret);
goto out;
}
modified = 0;
@@ -492,7 +486,7 @@ __bam_adj_recover(dbenv, dbtp, lsnp, op, info)
LSN(pagep) = argp->lsn;
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
@@ -500,7 +494,7 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}
@@ -533,11 +527,16 @@ __bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
REC_INTRO(__bam_cadjust_read, 1);
/* Get the page; if it never existed and we're undoing, we're done. */
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (DB_UNDO(op))
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->pgno, ret);
goto out;
} else
goto done;
__db_pgerr(file_dbp, argp->pgno, ret);
goto out;
}
modified = 0;
@@ -576,7 +575,7 @@ __bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
LSN(pagep) = argp->lsn;
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
@@ -584,7 +583,7 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}
@@ -617,11 +616,16 @@ __bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
REC_INTRO(__bam_cdel_read, 1);
/* Get the page; if it never existed and we're undoing, we're done. */
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (DB_UNDO(op))
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->pgno, ret);
goto out;
} else
goto done;
__db_pgerr(file_dbp, argp->pgno, ret);
goto out;
}
modified = 0;
@@ -645,7 +649,7 @@ __bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
LSN(pagep) = argp->lsn;
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
@@ -653,7 +657,7 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}
@@ -688,11 +692,16 @@ __bam_repl_recover(dbenv, dbtp, lsnp, op, info)
REC_INTRO(__bam_repl_read, 1);
/* Get the page; if it never existed and we're undoing, we're done. */
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (DB_UNDO(op))
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->pgno, ret);
goto out;
} else
goto done;
__db_pgerr(file_dbp, argp->pgno, ret);
goto out;
}
bk = GET_BKEYDATA(file_dbp, pagep, argp->indx);
@@ -753,7 +762,7 @@ __bam_repl_recover(dbenv, dbtp, lsnp, op, info)
LSN(pagep) = argp->lsn;
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
@@ -761,7 +770,7 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}
@@ -792,10 +801,13 @@ __bam_root_recover(dbenv, dbtp, lsnp, op, info)
REC_PRINT(__bam_root_print);
REC_INTRO(__bam_root_read, 0);
if ((ret = mpf->get(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
/* The metadata page must always exist on redo. */
if (DB_REDO(op)) {
__db_pgerr(file_dbp, argp->meta_pgno, ret);
if ((ret = __memp_fget(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->meta_pgno, ret);
goto out;
} else
goto done;
@@ -816,7 +828,7 @@ __bam_root_recover(dbenv, dbtp, lsnp, op, info)
meta->dbmeta.lsn = argp->meta_lsn;
modified = 1;
}
if ((ret = mpf->put(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
meta = NULL;
@@ -824,7 +836,7 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (meta != NULL)
(void)mpf->put(mpf, meta, 0);
(void)__memp_fput(mpf, meta, 0);
REC_CLOSE;
}
@@ -851,6 +863,7 @@ __bam_curadj_recover(dbenv, dbtp, lsnp, op, info)
int ret;
COMPQUIET(info, NULL);
COMPQUIET(mpf, NULL);
REC_PRINT(__bam_curadj_print);
REC_INTRO(__bam_curadj_read, 0);
@@ -859,7 +872,7 @@ __bam_curadj_recover(dbenv, dbtp, lsnp, op, info)
if (op != DB_TXN_ABORT)
goto done;
switch(argp->mode) {
switch (argp->mode) {
case DB_CA_DI:
if ((ret = __bam_ca_di(dbc, argp->from_pgno,
argp->from_indx, -(int)argp->first_indx)) != 0)
@@ -911,6 +924,7 @@ __bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
int ret, t_ret;
COMPQUIET(info, NULL);
COMPQUIET(mpf, NULL);
rdbc = NULL;
REC_PRINT(__bam_rcuradj_print);
@@ -931,8 +945,7 @@ __bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
* state into __ram_ca, and this way we don't need to make
* this function know anything about how offpage dups work.
*/
if ((ret =
__db_icursor(file_dbp,
if ((ret = __db_cursor_int(file_dbp,
NULL, DB_RECNO, argp->root, 0, DB_LOCK_INVALIDID, &rdbc)) != 0)
goto out;
@@ -940,7 +953,7 @@ __bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
F_SET(cp, C_RENUMBER);
cp->recno = argp->recno;
switch(argp->mode) {
switch (argp->mode) {
case CA_DELETE:
/*
* The way to undo a delete is with an insert. Since
@@ -949,7 +962,7 @@ __bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
F_SET(cp, C_DELETED);
F_SET(cp, C_RENUMBER); /* Just in case. */
cp->order = argp->order;
__ram_ca(rdbc, CA_ICURRENT);
(void)__ram_ca(rdbc, CA_ICURRENT);
break;
case CA_IAFTER:
case CA_IBEFORE:
@@ -960,12 +973,157 @@ __bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
*/
F_CLR(cp, C_DELETED);
cp->order = INVALID_ORDER;
__ram_ca(rdbc, CA_DELETE);
(void)__ram_ca(rdbc, CA_DELETE);
break;
}
done: *lsnp = argp->prev_lsn;
out: if (rdbc != NULL && (t_ret = rdbc->c_close(rdbc)) != 0 && ret == 0)
out: if (rdbc != NULL && (t_ret = __db_c_close(rdbc)) != 0 && ret == 0)
ret = t_ret;
REC_CLOSE;
}
/*
* __bam_relink_recover --
* Recovery function for relink.
*
* PUBLIC: int __bam_relink_recover
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
*/
int
__bam_relink_recover(dbenv, dbtp, lsnp, op, info)
DB_ENV *dbenv;
DBT *dbtp;
DB_LSN *lsnp;
db_recops op;
void *info;
{
__bam_relink_args *argp;
DB *file_dbp;
DBC *dbc;
DB_MPOOLFILE *mpf;
PAGE *pagep;
int cmp_n, cmp_p, modified, ret;
pagep = NULL;
COMPQUIET(info, NULL);
REC_PRINT(__bam_relink_print);
REC_INTRO(__bam_relink_read, 1);
/*
* There are up to three pages we need to check -- the page, and the
* previous and next pages, if they existed. For a page add operation,
* the current page is the result of a split and is being recovered
* elsewhere, so all we need do is recover the next page.
*/
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->pgno, ret);
goto out;
} else
goto next2;
}
modified = 0;
cmp_p = log_compare(&LSN(pagep), &argp->lsn);
CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
if (cmp_p == 0 && DB_REDO(op)) {
/* Redo the relink. */
pagep->lsn = *lsnp;
modified = 1;
} else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
/* Undo the relink. */
pagep->next_pgno = argp->next;
pagep->prev_pgno = argp->prev;
pagep->lsn = argp->lsn;
modified = 1;
}
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
next2: if ((ret = __memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->next, ret);
goto out;
} else
goto prev;
}
modified = 0;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->lsn_next);
CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_next);
if (cmp_p == 0 && DB_REDO(op)) {
/* Redo the remove or undo the add. */
pagep->prev_pgno = argp->prev;
modified = 1;
} else if (cmp_n == 0 && DB_UNDO(op)) {
/* Undo the remove or redo the add. */
pagep->prev_pgno = argp->pgno;
modified = 1;
}
if (modified == 1) {
if (DB_UNDO(op))
pagep->lsn = argp->lsn_next;
else
pagep->lsn = *lsnp;
}
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
prev: if ((ret = __memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
if (ret != DB_PAGE_NOTFOUND
#ifndef HAVE_FTRUNCATE
|| DB_REDO(op)
#endif
) {
ret = __db_pgerr(file_dbp, argp->prev, ret);
goto out;
} else
goto done;
}
modified = 0;
cmp_p = log_compare(&LSN(pagep), &argp->lsn_prev);
CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_prev);
if (cmp_p == 0 && DB_REDO(op)) {
/* Redo the relink. */
pagep->next_pgno = argp->next;
modified = 1;
} else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
/* Undo the relink. */
pagep->next_pgno = argp->pgno;
modified = 1;
}
if (modified == 1) {
if (DB_UNDO(op))
pagep->lsn = argp->lsn_prev;
else
pagep->lsn = *lsnp;
}
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998-2002
* Copyright (c) 1998-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_reclaim.c,v 11.15 2004/01/28 03:35:49 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_reclaim.c,v 11.11 2002/03/29 20:46:26 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -36,7 +34,7 @@ __bam_reclaim(dbp, txn)
int ret, t_ret;
/* Acquire a cursor. */
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
return (ret);
/* Walk the tree, freeing pages. */
@@ -44,7 +42,7 @@ __bam_reclaim(dbp, txn)
DB_LOCK_WRITE, dbc->internal->root, __db_reclaim_callback, dbc);
/* Discard the cursor. */
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
@@ -54,32 +52,23 @@ __bam_reclaim(dbp, txn)
* __bam_truncate --
* Truncate a database.
*
* PUBLIC: int __bam_truncate __P((DB *, DB_TXN *, u_int32_t *));
* PUBLIC: int __bam_truncate __P((DBC *, u_int32_t *));
*/
int
__bam_truncate(dbp, txn, countp)
DB *dbp;
DB_TXN *txn;
__bam_truncate(dbc, countp)
DBC *dbc;
u_int32_t *countp;
{
DBC *dbc;
db_trunc_param trunc;
int ret, t_ret;
/* Acquire a cursor. */
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
return (ret);
int ret;
trunc.count = 0;
trunc.dbc = dbc;
/* Walk the tree, freeing pages. */
ret = __bam_traverse(dbc,
DB_LOCK_WRITE, dbc->internal->root, __db_truncate_callback, &trunc);
/* Discard the cursor. */
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
*countp = trunc.count;
return (ret);

View File

@@ -1,21 +1,17 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_recno.c,v 11.117 2004/03/28 17:01:01 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_recno.c,v 11.106 2002/08/16 04:56:30 ubell Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#endif
@@ -58,7 +54,7 @@ static int __ram_update __P((DBC *, db_recno_t, int));
} \
}
#define CD_ISSET(cp) \
(F_ISSET(cp, C_RENUMBER) && F_ISSET(cp, C_DELETED))
(F_ISSET(cp, C_RENUMBER) && F_ISSET(cp, C_DELETED) ? 1 : 0)
/*
* Macros for comparing the ordering of two cursors.
@@ -91,11 +87,13 @@ static int __ram_update __P((DBC *, db_recno_t, int));
* After a search, copy the found page into the cursor, discarding any
* currently held lock.
*/
#define STACK_TO_CURSOR(cp) { \
#define STACK_TO_CURSOR(cp, ret) { \
int __t_ret; \
(cp)->page = (cp)->csp->page; \
(cp)->pgno = (cp)->csp->page->pgno; \
(cp)->indx = (cp)->csp->indx; \
(void)__TLPUT(dbc, (cp)->lock); \
if ((__t_ret = __TLPUT(dbc, (cp)->lock)) != 0 && (ret) == 0) \
ret = __t_ret; \
(cp)->lock = (cp)->csp->lock; \
(cp)->lock_mode = (cp)->csp->lock_mode; \
}
@@ -122,9 +120,6 @@ __ram_open(dbp, txn, name, base_pgno, flags)
COMPQUIET(name, NULL);
t = dbp->bt_internal;
/* Initialize the remaining fields/methods of the DB. */
dbp->stat = __bam_stat;
/* Start up the tree. */
if ((ret = __bam_read_root(dbp, txn, base_pgno, flags)) != 0)
return (ret);
@@ -143,7 +138,7 @@ __ram_open(dbp, txn, name, base_pgno, flags)
/* If we're snapshotting an underlying source file, do it now. */
if (F_ISSET(dbp, DB_AM_SNAPSHOT)) {
/* Allocate a cursor. */
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
if ((ret = __db_cursor(dbp, NULL, &dbc, 0)) != 0)
return (ret);
/* Do the snapshot. */
@@ -152,7 +147,7 @@ __ram_open(dbp, txn, name, base_pgno, flags)
ret = 0;
/* Discard the cursor. */
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
}
@@ -209,7 +204,7 @@ __ram_c_del(dbc)
DB_LSN lsn;
DBT hdr, data;
EPG *epg;
int exact, ret, stack;
int exact, ret, stack, t_ret;
dbp = dbc->dbp;
cp = (BTREE_CURSOR *)dbc->internal;
@@ -240,7 +235,9 @@ __ram_c_del(dbc)
stack = 1;
/* Copy the page into the cursor. */
STACK_TO_CURSOR(cp);
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
/*
* If re-numbering records, the on-page deleted flag can only mean
@@ -262,7 +259,8 @@ __ram_c_del(dbc)
/* Delete the item, adjust the counts, adjust the cursors. */
if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0)
goto err;
__bam_adjust(dbc, -1);
if ((ret = __bam_adjust(dbc, -1)) != 0)
goto err;
if (__ram_ca(dbc, CA_DELETE) > 0 &&
CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp, dbc->txn,
&lsn, 0, CA_DELETE, cp->root, cp->recno, cp->order)) != 0)
@@ -325,8 +323,8 @@ __ram_c_del(dbc)
t->re_modified = 1;
err: if (stack)
__bam_stkrel(dbc, STK_CLRDBC);
err: if (stack && (t_ret = __bam_stkrel(dbc, STK_CLRDBC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
@@ -388,8 +386,13 @@ retry: switch (flags) {
* we have to avoid incrementing the record number so that we
* return the right record by virtue of renumbering the tree.
*/
if (CD_ISSET(cp))
if (CD_ISSET(cp)) {
/*
* Clear the flag, we've moved off the deleted record.
*/
CD_CLR(cp);
break;
}
if (cp->recno != RECNO_OOB) {
++cp->recno;
@@ -494,7 +497,9 @@ retry: switch (flags) {
}
/* Copy the page into the cursor. */
STACK_TO_CURSOR(cp);
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
/*
* If re-numbering records, the on-page deleted flag means this
@@ -607,9 +612,11 @@ __ram_c_put(dbc, key, data, flags, pgnop)
return (ret);
if (CURADJ_LOG(dbc) &&
(ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0,
CA_ICURRENT, cp->root, cp->recno, cp->order)))
CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0)
return (ret);
return (0);
default:
break;
}
/*
@@ -650,7 +657,9 @@ split: if ((ret = __bam_rsearch(dbc, &cp->recno, S_INSERT, 1, &exact)) != 0)
DB_ASSERT(exact || CD_ISSET(cp));
/* Copy the page into the cursor. */
STACK_TO_CURSOR(cp);
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
ret = __bam_iitem(dbc, key, data, iiflags, 0);
t_ret = __bam_stkrel(dbc, STK_CLRDBC);
@@ -708,6 +717,8 @@ split: if ((ret = __bam_rsearch(dbc, &cp->recno, S_INSERT, 1, &exact)) != 0)
CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0)
goto err;
break;
default:
break;
}
/* Return the key if we've created a new record. */
@@ -983,7 +994,7 @@ __ram_source(dbp)
* when it comes time to write the database back to the source.
*/
if ((t->re_fp = fopen(t->re_source, "r")) == NULL) {
ret = errno;
ret = __os_get_errno();
__db_err(dbp->dbenv, "%s: %s", t->re_source, db_strerror(ret));
return (ret);
}
@@ -1027,7 +1038,7 @@ __ram_writeback(dbp)
}
/* Allocate a cursor. */
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
if ((ret = __db_cursor(dbp, NULL, &dbc, 0)) != 0)
return (ret);
/*
@@ -1060,13 +1071,13 @@ __ram_writeback(dbp)
*/
if (t->re_fp != NULL) {
if (fclose(t->re_fp) != 0) {
ret = errno;
ret = __os_get_errno();
goto err;
}
t->re_fp = NULL;
}
if ((fp = fopen(t->re_source, "w")) == NULL) {
ret = errno;
ret = __os_get_errno();
__db_err(dbenv, "%s: %s", t->re_source, db_strerror(ret));
goto err;
}
@@ -1088,23 +1099,24 @@ __ram_writeback(dbp)
* and the pad character if we're doing fixed-length records.
*/
delim = t->re_delim;
if (F_ISSET(dbp, DB_AM_FIXEDLEN)) {
if ((ret = __os_malloc(dbenv, t->re_len, &pad)) != 0)
goto err;
memset(pad, t->re_pad, t->re_len);
}
for (keyno = 1;; ++keyno) {
switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
switch (ret = __db_get(dbp, NULL, &key, &data, 0)) {
case 0:
if (data.size != 0 && (u_int32_t)fwrite(
data.data, 1, data.size, fp) != data.size)
if (data.size != 0 &&
fwrite(data.data, 1, data.size, fp) != data.size)
goto write_err;
break;
case DB_KEYEMPTY:
if (F_ISSET(dbp, DB_AM_FIXEDLEN) &&
(u_int32_t)fwrite(pad, 1, t->re_len, fp) !=
t->re_len)
goto write_err;
if (F_ISSET(dbp, DB_AM_FIXEDLEN)) {
if (pad == NULL) {
if ((ret = __os_malloc(
dbenv, t->re_len, &pad)) != 0)
goto err;
memset(pad, t->re_pad, t->re_len);
}
if (fwrite(pad, 1, t->re_len, fp) != t->re_len)
goto write_err;
}
break;
case DB_NOTFOUND:
ret = 0;
@@ -1114,8 +1126,8 @@ __ram_writeback(dbp)
}
if (!F_ISSET(dbp, DB_AM_FIXEDLEN) &&
fwrite(&delim, 1, 1, fp) != 1) {
write_err: ret = errno;
__db_err(dbp->dbenv,
write_err: ret = __os_get_errno();
__db_err(dbenv,
"%s: write failed to backing file: %s",
t->re_source, strerror(ret));
goto err;
@@ -1125,13 +1137,14 @@ write_err: ret = errno;
err:
done: /* Close the file descriptor. */
if (fp != NULL && fclose(fp) != 0) {
t_ret = __os_get_errno();
if (ret == 0)
ret = errno;
__db_err(dbenv, "%s: %s", t->re_source, db_strerror(errno));
ret = t_ret;
__db_err(dbenv, "%s: %s", t->re_source, db_strerror(t_ret));
}
/* Discard the cursor. */
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
/* Discard memory allocated to hold the data items. */
@@ -1259,7 +1272,7 @@ __ram_add(dbc, recnop, data, flags, bi_flags)
u_int32_t flags, bi_flags;
{
BTREE_CURSOR *cp;
int exact, ret, stack;
int exact, ret, stack, t_ret;
cp = (BTREE_CURSOR *)dbc->internal;
@@ -1270,7 +1283,9 @@ retry: /* Find the slot for insertion. */
stack = 1;
/* Copy the page into the cursor. */
STACK_TO_CURSOR(cp);
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
/*
* The application may modify the data based on the selected record
@@ -1320,8 +1335,8 @@ retry: /* Find the slot for insertion. */
goto err;
}
err: if (stack)
__bam_stkrel(dbc, STK_CLRDBC);
err: if (stack && (t_ret = __bam_stkrel(dbc, STK_CLRDBC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -35,14 +35,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_rsearch.c,v 11.40 2004/07/23 17:21:09 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_rsearch.c,v 11.34 2002/07/03 19:03:50 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif
@@ -52,6 +50,7 @@ static const char revid[] = "$Id: bt_rsearch.c,v 11.34 2002/07/03 19:03:50 bosti
#include "dbinc/btree.h"
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
/*
* __bam_rsearch --
@@ -77,11 +76,12 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
db_lockmode_t lock_mode;
db_pgno_t pg;
db_recno_t recno, t_recno, total;
int ret, stack;
int ret, stack, t_ret;
dbp = dbc->dbp;
mpf = dbp->mpf;
cp = (BTREE_CURSOR *)dbc->internal;
h = NULL;
BT_STK_CLR(cp);
@@ -105,7 +105,7 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
lock_mode = stack ? DB_LOCK_WRITE : DB_LOCK_READ;
if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
return (ret);
if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0) {
if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0) {
/* Did not read it, so we can release the lock */
(void)__LPUT(dbc, lock);
return (ret);
@@ -122,12 +122,15 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
if (!stack &&
((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) ||
(LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
(void)mpf->put(mpf, h, 0);
(void)__LPUT(dbc, lock);
ret = __memp_fput(mpf, h, 0);
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
return (ret);
lock_mode = DB_LOCK_WRITE;
if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
return (ret);
if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0) {
if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0) {
/* Did not read it, so we can release the lock */
(void)__LPUT(dbc, lock);
return (ret);
@@ -166,9 +169,11 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
* eliminate any concurrency. A possible fix
* would be to lock the last leaf page instead.
*/
(void)mpf->put(mpf, h, 0);
(void)__TLPUT(dbc, lock);
return (DB_NOTFOUND);
ret = __memp_fput(mpf, h, 0);
if ((t_ret =
__TLPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
return (ret == 0 ? DB_NOTFOUND : ret);
}
}
}
@@ -200,7 +205,13 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
*exactp = 0;
if (!LF_ISSET(S_PAST_EOF) ||
recno > t_recno + 1) {
ret = DB_NOTFOUND;
ret = __memp_fput(mpf, h, 0);
h = NULL;
if ((t_ret = __TLPUT(dbc,
lock)) != 0 && ret == 0)
ret = t_ret;
if (ret == 0)
ret = DB_NOTFOUND;
goto err;
}
}
@@ -262,6 +273,7 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
cp, h, indx, lock, lock_mode, ret);
if (ret != 0)
goto err;
h = NULL;
lock_mode = DB_LOCK_WRITE;
if ((ret =
@@ -278,7 +290,9 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
(h->level - 1) == LEAFLEVEL)
stack = 1;
(void)mpf->put(mpf, h, 0);
if ((ret = __memp_fput(mpf, h, 0)) != 0)
goto err;
h = NULL;
lock_mode = stack &&
LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ;
@@ -289,18 +303,22 @@ __bam_rsearch(dbc, recnop, flags, stop, exactp)
* is OK because this only happens when we are
* descending the tree holding read-locks.
*/
__LPUT(dbc, lock);
(void)__LPUT(dbc, lock);
goto err;
}
}
if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0)
goto err;
}
/* NOTREACHED */
err: BT_STK_POP(cp);
err: if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
BT_STK_POP(cp);
__bam_stkrel(dbc, 0);
return (ret);
}
@@ -352,7 +370,7 @@ __bam_adjust(dbc, adjust)
if (PGNO(h) == root_pgno)
RE_NREC_ADJ(h, adjust);
if ((ret = mpf->set(mpf, h, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fset(mpf, h, DB_MPOOL_DIRTY)) != 0)
return (ret);
}
}
@@ -375,7 +393,7 @@ __bam_nrecs(dbc, rep)
DB_MPOOLFILE *mpf;
PAGE *h;
db_pgno_t pgno;
int ret;
int ret, t_ret;
dbp = dbc->dbp;
mpf = dbp->mpf;
@@ -383,15 +401,16 @@ __bam_nrecs(dbc, rep)
pgno = dbc->internal->root;
if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0)
return (ret);
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
return (ret);
*rep = RE_NREC(h);
(void)mpf->put(mpf, h, 0);
(void)__TLPUT(dbc, lock);
ret = __memp_fput(mpf, h, 0);
if ((t_ret = __TLPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
return (0);
return (ret);
}
/*

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,14 +38,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_search.c,v 11.50 2004/07/23 17:21:09 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_search.c,v 11.43 2002/07/03 19:03:50 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -57,6 +55,7 @@ static const char revid[] = "$Id: bt_search.c,v 11.43 2002/07/03 19:03:50 bostic
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
/*
* __bam_search --
@@ -84,12 +83,13 @@ __bam_search(dbc, root_pgno, key, flags, stop, recnop, exactp)
db_lockmode_t lock_mode;
db_pgno_t pg;
db_recno_t recno;
int adjust, cmp, deloffset, ret, stack;
int adjust, cmp, deloffset, ret, stack, t_ret;
int (*func) __P((DB *, const DBT *, const DBT *));
dbp = dbc->dbp;
mpf = dbp->mpf;
cp = (BTREE_CURSOR *)dbc->internal;
h = NULL;
t = dbp->bt_internal;
recno = 0;
@@ -117,7 +117,7 @@ try_again:
lock_mode = stack ? DB_LOCK_WRITE : DB_LOCK_READ;
if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
return (ret);
if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0) {
if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0) {
/* Did not read it, so we can release the lock */
(void)__LPUT(dbc, lock);
return (ret);
@@ -134,12 +134,15 @@ try_again:
if (!stack &&
((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) ||
(LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
(void)mpf->put(mpf, h, 0);
(void)__LPUT(dbc, lock);
ret = __memp_fput(mpf, h, 0);
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
return (ret);
lock_mode = DB_LOCK_WRITE;
if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
return (ret);
if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0) {
if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0) {
/* Did not read it, so we can release the lock */
(void)__LPUT(dbc, lock);
return (ret);
@@ -148,8 +151,11 @@ try_again:
(u_int8_t)(stop + 1) >= h->level) ||
(LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
/* Someone else split the root, start over. */
(void)mpf->put(mpf, h, 0);
(void)__LPUT(dbc, lock);
ret = __memp_fput(mpf, h, 0);
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
return (ret);
goto try_again;
}
stack = 1;
@@ -197,13 +203,19 @@ try_again:
if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP) {
*exactp = 0;
if (LF_ISSET(S_EXACT))
goto notfound;
if (LF_ISSET(S_EXACT)) {
ret = DB_NOTFOUND;
goto err;
}
if (LF_ISSET(S_STK_ONLY)) {
BT_STK_NUM(dbp->dbenv, cp, h, base, ret);
__LPUT(dbc, lock);
(void)mpf->put(mpf, h, 0);
if ((t_ret =
__LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret =
__memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
@@ -243,12 +255,17 @@ next: if (recnop != NULL)
if (LF_ISSET(S_STK_ONLY)) {
if (stop == h->level) {
BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
__LPUT(dbc, lock);
(void)mpf->put(mpf, h, 0);
if ((t_ret =
__LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret =
__memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
BT_STK_NUMPUSH(dbp->dbenv, cp, h, indx, ret);
(void)mpf->put(mpf, h, 0);
(void)__memp_fput(mpf, h, 0);
h = NULL;
if ((ret = __db_lget(dbc,
LCK_COUPLE_ALWAYS, pg, lock_mode, 0, &lock)) != 0) {
/*
@@ -256,7 +273,7 @@ next: if (recnop != NULL)
* is OK because it only happens when descending
* the tree holding read-locks.
*/
__LPUT(dbc, lock);
(void)__LPUT(dbc, lock);
return (ret);
}
} else if (stack) {
@@ -272,6 +289,7 @@ next: if (recnop != NULL)
cp, h, indx, lock, lock_mode, ret);
if (ret != 0)
goto err;
h = NULL;
lock_mode = DB_LOCK_WRITE;
if ((ret =
@@ -288,7 +306,9 @@ next: if (recnop != NULL)
(h->level - 1) == LEAFLEVEL)
stack = 1;
(void)mpf->put(mpf, h, 0);
if ((ret = __memp_fput(mpf, h, 0)) != 0)
goto err;
h = NULL;
lock_mode = stack &&
LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ;
@@ -299,25 +319,17 @@ next: if (recnop != NULL)
* is OK because this only happens when we are
* descending the tree holding read-locks.
*/
__LPUT(dbc, lock);
(void)__LPUT(dbc, lock);
goto err;
}
}
if ((ret = mpf->get(mpf, &pg, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0)
goto err;
}
/* NOTREACHED */
found: *exactp = 1;
/*
* If we're trying to calculate the record number, add in the
* offset on this page and correct for the fact that records
* in the tree are 0-based.
*/
if (recnop != NULL)
*recnop = recno + (indx / P_INDX) + 1;
/*
* If we got here, we know that we have a Btree leaf or off-page
* duplicates page. If it's a Btree leaf page, we have to handle
@@ -345,6 +357,7 @@ found: *exactp = 1;
* not move from the original found key on the basis of the S_DELNO
* flag.)
*/
DB_ASSERT(recnop == NULL || LF_ISSET(S_DELNO));
if (LF_ISSET(S_DELNO)) {
deloffset = TYPE(h) == P_LBTREE ? O_INDX : 0;
if (LF_ISSET(S_DUPLAST))
@@ -363,29 +376,53 @@ found: *exactp = 1;
* If we weren't able to find a non-deleted duplicate, return
* DB_NOTFOUND.
*/
if (B_DISSET(GET_BKEYDATA(dbp, h, indx + deloffset)->type))
goto notfound;
if (B_DISSET(GET_BKEYDATA(dbp, h, indx + deloffset)->type)) {
ret = DB_NOTFOUND;
goto err;
}
/*
* Increment the record counter to point to the found element.
* Ignore any deleted key/data pairs. There doesn't need to
* be any correction for duplicates, as Btree doesn't support
* duplicates and record numbers in the same tree.
*/
if (recnop != NULL) {
DB_ASSERT(TYPE(h) == P_LBTREE);
for (i = 0; i < indx; i += P_INDX)
if (!B_DISSET(
GET_BKEYDATA(dbp, h, i + O_INDX)->type))
++recno;
/* Correct the number for a 0-base. */
*recnop = recno + 1;
}
}
if (LF_ISSET(S_STK_ONLY)) {
BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
__LPUT(dbc, lock);
(void)mpf->put(mpf, h, 0);
} else {
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
} else
BT_STK_ENTER(dbp->dbenv, cp, h, indx, lock, lock_mode, ret);
if (ret != 0)
goto err;
}
if (ret != 0)
goto err;
return (0);
notfound:
/* Keep the page locked for serializability. */
(void)mpf->put(mpf, h, 0);
(void)__TLPUT(dbc, lock);
ret = DB_NOTFOUND;
err: if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
err: BT_STK_POP(cp);
/* Keep any not-found page locked for serializability. */
if ((t_ret = __TLPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
BT_STK_POP(cp);
__bam_stkrel(dbc, 0);
return (ret);
}
@@ -423,7 +460,7 @@ __bam_stkrel(dbc, flags)
LOCK_INIT(cp->lock);
}
if ((t_ret =
mpf->put(mpf, epg->page, 0)) != 0 && ret == 0)
__memp_fput(mpf, epg->page, 0)) != 0 && ret == 0)
ret = t_ret;
/*
* XXX
@@ -434,10 +471,12 @@ __bam_stkrel(dbc, flags)
*/
epg->page = NULL;
}
if (LF_ISSET(STK_NOLOCK))
(void)__LPUT(dbc, epg->lock);
else
(void)__TLPUT(dbc, epg->lock);
if (LF_ISSET(STK_NOLOCK)) {
if ((t_ret = __LPUT(dbc, epg->lock)) != 0 && ret == 0)
ret = t_ret;
} else
if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
ret = t_ret;
}
/* Clear the stack, all pages have been released. */

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -35,18 +35,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bt_split.c,v 11.66 2004/10/01 13:00:21 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_split.c,v 11.58 2002/07/03 19:03:50 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <limits.h>
#include <string.h>
#endif
@@ -54,6 +51,7 @@ static const char revid[] = "$Id: bt_split.c,v 11.58 2002/07/03 19:03:50 bostic
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
#include "dbinc/btree.h"
static int __bam_broot __P((DBC *, PAGE *, PAGE *, PAGE *));
@@ -119,7 +117,7 @@ __bam_split(dbc, arg, root_pgnop)
arg, S_WRPAIR, level, NULL, &exact) :
__bam_rsearch(dbc,
(db_recno_t *)arg, S_WRPAIR, level, &exact))) != 0)
return (ret);
break;
if (root_pgnop != NULL)
*root_pgnop = cp->csp[0].page->pgno == root_pgno ?
@@ -133,7 +131,7 @@ __bam_split(dbc, arg, root_pgnop)
if (2 * B_MAXSIZEONPAGE(cp->ovflsize)
<= (db_indx_t)P_FREESPACE(dbc->dbp, cp->csp[0].page)) {
__bam_stkrel(dbc, STK_NOLOCK);
return (0);
break;
}
ret = cp->csp[0].page->pgno == root_pgno ?
__bam_root(dbc, &cp->csp[0]) :
@@ -161,10 +159,13 @@ __bam_split(dbc, arg, root_pgnop)
dir = UP;
break;
default:
return (ret);
goto err;
}
}
/* NOTREACHED */
err: if (root_pgnop != NULL)
*root_pgnop = cp->root;
return (ret);
}
/*
@@ -183,10 +184,11 @@ __bam_root(dbc, cp)
PAGE *lp, *rp;
db_indx_t split;
u_int32_t opflags;
int ret;
int ret, t_ret;
dbp = dbc->dbp;
mpf = dbp->mpf;
lp = rp = NULL;
/* Yeah, right. */
if (cp->page->level >= MAXBTREELEVEL) {
@@ -197,7 +199,6 @@ __bam_root(dbc, cp)
}
/* Create new left and right pages for the split. */
lp = rp = NULL;
if ((ret = __db_new(dbc, TYPE(cp->page), &lp)) != 0 ||
(ret = __db_new(dbc, TYPE(cp->page), &rp)) != 0)
goto err;
@@ -237,24 +238,21 @@ __bam_root(dbc, cp)
goto err;
/* Adjust any cursors. */
if ((ret = __bam_ca_split(dbc,
cp->page->pgno, lp->pgno, rp->pgno, split, 1)) != 0)
goto err;
ret = __bam_ca_split(dbc, cp->page->pgno, lp->pgno, rp->pgno, split, 1);
/* Success -- write the real pages back to the store. */
(void)mpf->put(mpf, cp->page, DB_MPOOL_DIRTY);
(void)__TLPUT(dbc, cp->lock);
(void)mpf->put(mpf, lp, DB_MPOOL_DIRTY);
(void)mpf->put(mpf, rp, DB_MPOOL_DIRTY);
/* Success or error: release pages and locks. */
err: if ((t_ret =
__memp_fput(mpf, cp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, cp->lock)) != 0 && ret == 0)
ret = t_ret;
if (lp != NULL &&
(t_ret = __memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if (rp != NULL &&
(t_ret = __memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
return (0);
err: if (lp != NULL)
(void)mpf->put(mpf, lp, 0);
if (rp != NULL)
(void)mpf->put(mpf, rp, 0);
(void)mpf->put(mpf, cp->page, 0);
(void)__TLPUT(dbc, cp->lock);
return (ret);
}
@@ -358,7 +356,7 @@ __bam_page(dbc, pp, cp)
if ((ret = __db_lget(dbc,
0, NEXT_PGNO(cp->page), DB_LOCK_WRITE, 0, &tplock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &NEXT_PGNO(cp->page), 0, &tp)) != 0)
if ((ret = __memp_fget(mpf, &NEXT_PGNO(cp->page), 0, &tp)) != 0)
goto err;
}
@@ -370,9 +368,13 @@ __bam_page(dbc, pp, cp)
goto err;
/*
* Lock the new page. We need to do this because someone
* could get here through bt_lpgno if this page was recently
* dealocated. They can't look at it before we commit.
* Lock the new page. We need to do this for two reasons: first, the
* fast-lookup code might have a reference to this page in bt_lpgno if
* the page was recently deleted from the tree, and that code doesn't
* walk the tree and so won't encounter the parent's page lock.
* Second, a dirty reader could get to this page via the parent or old
* page after the split is done but before the transaction is committed
* or aborted.
*/
if ((ret = __db_lget(dbc,
0, PGNO(alloc_rp), DB_LOCK_WRITE, 0, &rplock)) != 0)
@@ -456,20 +458,27 @@ __bam_page(dbc, pp, cp)
* releasing locks on the pages that reference it. We're finished
* modifying the page so it's not really necessary, but it's neater.
*/
if ((t_ret = mpf->put(mpf, alloc_rp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
if ((t_ret =
__memp_fput(mpf, alloc_rp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
(void)__TLPUT(dbc, rplock);
if ((t_ret = mpf->put(mpf, pp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
if ((t_ret = __TLPUT(dbc, rplock)) != 0 && ret == 0)
ret = t_ret;
(void)__TLPUT(dbc, pp->lock);
if ((t_ret = mpf->put(mpf, cp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
if ((t_ret =
__memp_fput(mpf, pp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, pp->lock)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret =
__memp_fput(mpf, cp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, cp->lock)) != 0 && ret == 0)
ret = t_ret;
(void)__TLPUT(dbc, cp->lock);
if (tp != NULL) {
if ((t_ret =
mpf->put(mpf, tp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
__memp_fput(mpf, tp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, tplock)) != 0 && ret == 0)
ret = t_ret;
(void)__TLPUT(dbc, tplock);
}
return (ret);
@@ -478,21 +487,21 @@ err: if (lp != NULL)
if (rp != NULL)
__os_free(dbp->dbenv, rp);
if (alloc_rp != NULL)
(void)mpf->put(mpf, alloc_rp, 0);
(void)__memp_fput(mpf, alloc_rp, 0);
if (tp != NULL)
(void)mpf->put(mpf, tp, 0);
(void)__memp_fput(mpf, tp, 0);
/* We never updated the new or next pages, we can release them. */
(void)__LPUT(dbc, rplock);
(void)__LPUT(dbc, tplock);
(void)mpf->put(mpf, pp->page, 0);
(void)__memp_fput(mpf, pp->page, 0);
if (ret == DB_NEEDSPLIT)
(void)__LPUT(dbc, pp->lock);
else
(void)__TLPUT(dbc, pp->lock);
(void)mpf->put(mpf, cp->page, 0);
(void)__memp_fput(mpf, cp->page, 0);
if (ret == DB_NEEDSPLIT)
(void)__LPUT(dbc, cp->lock);
else

View File

@@ -1,19 +1,18 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_stat.c,v 11.78 2004/09/22 03:31:26 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_stat.c,v 11.52 2002/05/30 15:40:27 krinsky Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <ctype.h>
#include <string.h>
#endif
@@ -22,33 +21,35 @@ static const char revid[] = "$Id: bt_stat.c,v 11.52 2002/05/30 15:40:27 krinsky
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#ifdef HAVE_STATISTICS
/*
* __bam_stat --
* Gather/print the btree statistics
*
* PUBLIC: int __bam_stat __P((DB *, void *, u_int32_t));
* PUBLIC: int __bam_stat __P((DBC *, void *, u_int32_t));
*/
int
__bam_stat(dbp, spp, flags)
DB *dbp;
__bam_stat(dbc, spp, flags)
DBC *dbc;
void *spp;
u_int32_t flags;
{
BTMETA *meta;
BTREE *t;
BTREE_CURSOR *cp;
DBC *dbc;
DB *dbp;
DB_BTREE_STAT *sp;
DB_ENV *dbenv;
DB_LOCK lock, metalock;
DB_MPOOLFILE *mpf;
PAGE *h;
db_pgno_t pgno;
int ret, t_ret, write_meta;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
dbp = dbc->dbp;
dbenv = dbp->dbenv;
meta = NULL;
t = dbp->bt_internal;
@@ -57,22 +58,12 @@ __bam_stat(dbp, spp, flags)
LOCK_INIT(lock);
mpf = dbp->mpf;
h = NULL;
ret = 0;
write_meta = 0;
ret = write_meta = 0;
/* Check for invalid flags. */
if ((ret = __db_statchk(dbp, flags)) != 0)
return (ret);
/* Acquire a cursor. */
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
return (ret);
cp = (BTREE_CURSOR *)dbc->internal;
DEBUG_LWRITE(dbc, NULL, "bam_stat", NULL, NULL, flags);
/* Allocate and clear the structure. */
if ((ret = __os_umalloc(dbp->dbenv, sizeof(*sp), &sp)) != 0)
if ((ret = __os_umalloc(dbenv, sizeof(*sp), &sp)) != 0)
goto err;
memset(sp, 0, sizeof(*sp));
@@ -80,7 +71,7 @@ __bam_stat(dbp, spp, flags)
pgno = PGNO_BASE_MD;
if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &metalock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &meta)) != 0)
goto err;
if (flags == DB_RECORDCOUNT || flags == DB_CACHED_COUNTS)
@@ -92,11 +83,11 @@ __bam_stat(dbp, spp, flags)
for (sp->bt_free = 0, pgno = meta->dbmeta.free; pgno != PGNO_INVALID;) {
++sp->bt_free;
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
goto err;
pgno = h->next_pgno;
if ((ret = mpf->put(mpf, h, 0)) != 0)
if ((ret = __memp_fput(mpf, h, 0)) != 0)
goto err;
h = NULL;
}
@@ -105,17 +96,19 @@ __bam_stat(dbp, spp, flags)
pgno = cp->root;
if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
goto err;
/* Get the levels from the root page. */
sp->bt_levels = h->level;
/* Discard the root page. */
if ((ret = mpf->put(mpf, h, 0)) != 0)
goto err;
ret = __memp_fput(mpf, h, 0);
h = NULL;
__LPUT(dbc, lock);
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
/* Walk the tree. */
if ((ret = __bam_traverse(dbc,
@@ -129,16 +122,18 @@ __bam_stat(dbp, spp, flags)
write_meta = !F_ISSET(dbp, DB_AM_RDONLY);
meta_only:
if (t->bt_meta != PGNO_BASE_MD || write_meta != 0) {
if ((ret = mpf->put(mpf, meta, 0)) != 0)
goto err;
ret = __memp_fput(mpf, meta, 0);
meta = NULL;
__LPUT(dbc, metalock);
if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
if ((ret = __db_lget(dbc,
0, t->bt_meta, write_meta == 0 ?
DB_LOCK_READ : DB_LOCK_WRITE, 0, &metalock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &t->bt_meta, 0, (PAGE **)&meta)) != 0)
if ((ret = __memp_fget(mpf, &t->bt_meta, 0, &meta)) != 0)
goto err;
}
if (flags == DB_FAST_STAT) {
@@ -147,14 +142,15 @@ meta_only:
if ((ret = __db_lget(dbc, 0,
cp->root, DB_LOCK_READ, 0, &lock)) != 0)
goto err;
if ((ret =
mpf->get(mpf, &cp->root, 0, (PAGE **)&h)) != 0)
if ((ret = __memp_fget(mpf, &cp->root, 0, &h)) != 0)
goto err;
sp->bt_nkeys = RE_NREC(h);
} else
sp->bt_nkeys = meta->dbmeta.key_count;
sp->bt_ndata = meta->dbmeta.record_count;
sp->bt_ndata = dbp->type == DB_RECNO ?
sp->bt_nkeys : meta->dbmeta.record_count;
}
/* Get metadata page statistics. */
@@ -175,21 +171,20 @@ meta_only:
*(DB_BTREE_STAT **)spp = sp;
err: /* Discard the second page. */
__LPUT(dbc, lock);
if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret == 0)
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
/* Discard the metadata page. */
__LPUT(dbc, metalock);
if (meta != NULL && (t_ret = mpf->put(
if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
ret = t_ret;
if (meta != NULL && (t_ret = __memp_fput(
mpf, meta, write_meta == 0 ? 0 : DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0 && sp != NULL) {
__os_ufree(dbp->dbenv, sp);
__os_ufree(dbenv, sp);
*(DB_BTREE_STAT **)spp = NULL;
}
@@ -197,104 +192,113 @@ err: /* Discard the second page. */
}
/*
* __bam_traverse --
* Walk a Btree database.
* __bam_stat_print --
* Display btree/recno statistics.
*
* PUBLIC: int __bam_traverse __P((DBC *, db_lockmode_t,
* PUBLIC: db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *));
* PUBLIC: int __bam_stat_print __P((DBC *, u_int32_t));
*/
int
__bam_traverse(dbc, mode, root_pgno, callback, cookie)
__bam_stat_print(dbc, flags)
DBC *dbc;
db_lockmode_t mode;
db_pgno_t root_pgno;
int (*callback)__P((DB *, PAGE *, void *, int *));
void *cookie;
u_int32_t flags;
{
BINTERNAL *bi;
BKEYDATA *bk;
static const FN fn[] = {
{ BTM_DUP, "duplicates" },
{ BTM_RECNO, "recno" },
{ BTM_RECNUM, "record-numbers" },
{ BTM_FIXEDLEN, "fixed-length" },
{ BTM_RENUMBER, "renumber" },
{ BTM_SUBDB, "multiple-databases" },
{ BTM_DUPSORT, "sorted duplicates" },
{ 0, NULL }
};
DB *dbp;
DB_LOCK lock;
DB_MPOOLFILE *mpf;
PAGE *h;
RINTERNAL *ri;
db_indx_t indx;
int already_put, ret, t_ret;
DB_BTREE_STAT *sp;
DB_ENV *dbenv;
int lorder, ret;
const char *s;
dbp = dbc->dbp;
mpf = dbp->mpf;
already_put = 0;
dbenv = dbp->dbenv;
if ((ret = __db_lget(dbc, 0, root_pgno, mode, 0, &lock)) != 0)
return (ret);
if ((ret = mpf->get(mpf, &root_pgno, 0, &h)) != 0) {
__LPUT(dbc, lock);
if ((ret = __bam_stat(dbc, &sp, 0)) != 0)
return (ret);
if (LF_ISSET(DB_STAT_ALL)) {
__db_msg(dbenv, "%s", DB_GLOBAL(db_line));
__db_msg(dbenv, "Default Btree/Recno database information:");
}
switch (TYPE(h)) {
case P_IBTREE:
for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
bi = GET_BINTERNAL(dbp, h, indx);
if (B_TYPE(bi->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
((BOVERFLOW *)bi->data)->pgno,
callback, cookie)) != 0)
goto err;
if ((ret = __bam_traverse(
dbc, mode, bi->pgno, callback, cookie)) != 0)
goto err;
}
__db_msg(dbenv, "%lx\tBtree magic number", (u_long)sp->bt_magic);
__db_msg(dbenv, "%lu\tBtree version number", (u_long)sp->bt_version);
(void)__db_get_lorder(dbp, &lorder);
switch (lorder) {
case 1234:
s = "Little-endian";
break;
case P_IRECNO:
for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
ri = GET_RINTERNAL(dbp, h, indx);
if ((ret = __bam_traverse(
dbc, mode, ri->pgno, callback, cookie)) != 0)
goto err;
}
case 4321:
s = "Big-endian";
break;
case P_LBTREE:
for (indx = 0; indx < NUM_ENT(h); indx += P_INDX) {
bk = GET_BKEYDATA(dbp, h, indx);
if (B_TYPE(bk->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
GET_BOVERFLOW(dbp, h, indx)->pgno,
callback, cookie)) != 0)
goto err;
bk = GET_BKEYDATA(dbp, h, indx + O_INDX);
if (B_TYPE(bk->type) == B_DUPLICATE &&
(ret = __bam_traverse(dbc, mode,
GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
callback, cookie)) != 0)
goto err;
if (B_TYPE(bk->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
callback, cookie)) != 0)
goto err;
}
break;
case P_LDUP:
case P_LRECNO:
for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
bk = GET_BKEYDATA(dbp, h, indx);
if (B_TYPE(bk->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
GET_BOVERFLOW(dbp, h, indx)->pgno,
callback, cookie)) != 0)
goto err;
}
default:
s = "Unrecognized byte order";
break;
}
__db_msg(dbenv, "%s\tByte order", s);
__db_prflags(dbenv, NULL, sp->bt_metaflags, fn, NULL, "\tFlags");
if (dbp->type == DB_BTREE) {
#ifdef NOT_IMPLEMENTED
__db_dl(dbenv, "Maximum keys per-page", (u_long)sp->bt_maxkey);
#endif
__db_dl(dbenv, "Minimum keys per-page", (u_long)sp->bt_minkey);
}
if (dbp->type == DB_RECNO) {
__db_dl(dbenv,
"Fixed-length record size", (u_long)sp->bt_re_len);
__db_dl(dbenv,
"%#x\tFixed-length record pad", (u_int)sp->bt_re_pad);
}
__db_dl(dbenv,
"Underlying database page size", (u_long)sp->bt_pagesize);
__db_dl(dbenv, "Number of levels in the tree", (u_long)sp->bt_levels);
__db_dl(dbenv, dbp->type == DB_BTREE ?
"Number of unique keys in the tree" :
"Number of records in the tree", (u_long)sp->bt_nkeys);
__db_dl(dbenv,
"Number of data items in the tree", (u_long)sp->bt_ndata);
ret = callback(dbp, h, cookie, &already_put);
__db_dl(dbenv,
"Number of tree internal pages", (u_long)sp->bt_int_pg);
__db_dl_pct(dbenv,
"Number of bytes free in tree internal pages",
(u_long)sp->bt_int_pgfree,
DB_PCT_PG(sp->bt_int_pgfree, sp->bt_int_pg, sp->bt_pagesize), "ff");
err: if (!already_put && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret != 0)
ret = t_ret;
__LPUT(dbc, lock);
__db_dl(dbenv,
"Number of tree leaf pages", (u_long)sp->bt_leaf_pg);
__db_dl_pct(dbenv, "Number of bytes free in tree leaf pages",
(u_long)sp->bt_leaf_pgfree, DB_PCT_PG(
sp->bt_leaf_pgfree, sp->bt_leaf_pg, sp->bt_pagesize), "ff");
return (ret);
__db_dl(dbenv,
"Number of tree duplicate pages", (u_long)sp->bt_dup_pg);
__db_dl_pct(dbenv,
"Number of bytes free in tree duplicate pages",
(u_long)sp->bt_dup_pgfree,
DB_PCT_PG(sp->bt_dup_pgfree, sp->bt_dup_pg, sp->bt_pagesize), "ff");
__db_dl(dbenv,
"Number of tree overflow pages", (u_long)sp->bt_over_pg);
__db_dl_pct(dbenv, "Number of bytes free in tree overflow pages",
(u_long)sp->bt_over_pgfree, DB_PCT_PG(
sp->bt_over_pgfree, sp->bt_over_pg, sp->bt_pagesize), "ff");
__db_dl(dbenv, "Number of empty pages", (u_long)sp->bt_empty_pg);
__db_dl(dbenv, "Number of pages on the free list", (u_long)sp->bt_free);
__os_ufree(dbenv, sp);
return (0);
}
/*
@@ -326,14 +330,23 @@ __bam_stat_callback(dbp, h, cookie, putp)
sp->bt_int_pgfree += P_FREESPACE(dbp, h);
break;
case P_LBTREE:
if (top == 0)
++sp->bt_empty_pg;
/* Correct for on-page duplicates and deleted items. */
for (indx = 0; indx < top; indx += P_INDX) {
type = GET_BKEYDATA(dbp, h, indx + O_INDX)->type;
/* Ignore deleted items. */
if (B_DISSET(type))
continue;
/* Ignore duplicate keys. */
if (indx + P_INDX >= top ||
inp[indx] != inp[indx + P_INDX])
++sp->bt_nkeys;
type = GET_BKEYDATA(dbp, h, indx + O_INDX)->type;
if (!B_DISSET(type) && B_TYPE(type) != B_DUPLICATE)
/* Ignore off-page duplicates. */
if (B_TYPE(type) != B_DUPLICATE)
++sp->bt_ndata;
}
@@ -341,24 +354,28 @@ __bam_stat_callback(dbp, h, cookie, putp)
sp->bt_leaf_pgfree += P_FREESPACE(dbp, h);
break;
case P_LRECNO:
if (top == 0)
++sp->bt_empty_pg;
/*
* If walking a recno tree, then each of these items is a key.
* Otherwise, we're walking an off-page duplicate set.
*/
if (dbp->type == DB_RECNO) {
sp->bt_nkeys += top;
/*
* Correct for deleted items in non-renumbering
* Recno databases.
* Correct for deleted items in non-renumbering Recno
* databases.
*/
if (F_ISSET(dbp, DB_AM_RENUMBER))
if (F_ISSET(dbp, DB_AM_RENUMBER)) {
sp->bt_nkeys += top;
sp->bt_ndata += top;
else
} else
for (indx = 0; indx < top; indx += O_INDX) {
type = GET_BKEYDATA(dbp, h, indx)->type;
if (!B_DISSET(type))
if (!B_DISSET(type)) {
++sp->bt_ndata;
++sp->bt_nkeys;
}
}
++sp->bt_leaf_pg;
@@ -371,6 +388,9 @@ __bam_stat_callback(dbp, h, cookie, putp)
}
break;
case P_LDUP:
if (top == 0)
++sp->bt_empty_pg;
/* Correct for deleted items. */
for (indx = 0; indx < top; indx += O_INDX)
if (!B_DISSET(GET_BKEYDATA(dbp, h, indx)->type))
@@ -389,47 +409,84 @@ __bam_stat_callback(dbp, h, cookie, putp)
return (0);
}
/*
* __bam_print_cursor --
* Display the current internal cursor.
*
* PUBLIC: void __bam_print_cursor __P((DBC *));
*/
void
__bam_print_cursor(dbc)
DBC *dbc;
{
static const FN fn[] = {
{ C_DELETED, "C_DELETED" },
{ C_RECNUM, "C_RECNUM" },
{ C_RENUMBER, "C_RENUMBER" },
{ 0, NULL }
};
DB_ENV *dbenv;
BTREE_CURSOR *cp;
dbenv = dbc->dbp->dbenv;
cp = (BTREE_CURSOR *)dbc->internal;
STAT_ULONG("Overflow size", cp->ovflsize);
if (dbc->dbtype == DB_RECNO)
STAT_ULONG("Recno", cp->recno);
STAT_ULONG("Order", cp->order);
__db_prflags(dbenv, NULL, cp->flags, fn, NULL, "\tInternal Flags");
}
#else /* !HAVE_STATISTICS */
int
__bam_stat(dbc, spp, flags)
DBC *dbc;
void *spp;
u_int32_t flags;
{
COMPQUIET(spp, NULL);
COMPQUIET(flags, 0);
return (__db_stat_not_built(dbc->dbp->dbenv));
}
int
__bam_stat_print(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
COMPQUIET(flags, 0);
return (__db_stat_not_built(dbc->dbp->dbenv));
}
#endif
/*
* __bam_key_range --
* Return proportion of keys relative to given key. The numbers are
* slightly skewed due to on page duplicates.
*
* PUBLIC: int __bam_key_range __P((DB *,
* PUBLIC: DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
* PUBLIC: int __bam_key_range __P((DBC *, DBT *, DB_KEY_RANGE *, u_int32_t));
*/
int
__bam_key_range(dbp, txn, dbt, kp, flags)
DB *dbp;
DB_TXN *txn;
__bam_key_range(dbc, dbt, kp, flags)
DBC *dbc;
DBT *dbt;
DB_KEY_RANGE *kp;
u_int32_t flags;
{
BTREE_CURSOR *cp;
DBC *dbc;
EPG *sp;
double factor;
int exact, ret, t_ret;
int exact, ret;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range");
if (flags != 0)
return (__db_ferr(dbp->dbenv, "DB->key_range", 0));
/* Check for consistent transaction usage. */
if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
return (ret);
/* Acquire a cursor. */
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
return (ret);
DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0);
COMPQUIET(flags, 0);
if ((ret = __bam_search(dbc, PGNO_INVALID,
dbt, S_STK_ONLY, 1, NULL, &exact)) != 0)
goto err;
return (ret);
cp = (BTREE_CURSOR *)dbc->internal;
kp->less = kp->greater = 0.0;
@@ -454,7 +511,7 @@ __bam_key_range(dbp, txn, dbt, kp, flags)
else {
kp->less += factor * sp->indx / sp->entries;
kp->greater += factor *
(sp->entries - sp->indx - 1) / sp->entries;
((sp->entries - sp->indx) - 1) / sp->entries;
}
factor *= 1.0/sp->entries;
}
@@ -474,7 +531,112 @@ __bam_key_range(dbp, txn, dbt, kp, flags)
BT_STK_CLR(cp);
err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
return (0);
}
/*
* __bam_traverse --
* Walk a Btree database.
*
* PUBLIC: int __bam_traverse __P((DBC *, db_lockmode_t,
* PUBLIC: db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *));
*/
int
__bam_traverse(dbc, mode, root_pgno, callback, cookie)
DBC *dbc;
db_lockmode_t mode;
db_pgno_t root_pgno;
int (*callback)__P((DB *, PAGE *, void *, int *));
void *cookie;
{
BINTERNAL *bi;
BKEYDATA *bk;
DB *dbp;
DB_LOCK lock;
DB_MPOOLFILE *mpf;
PAGE *h;
RINTERNAL *ri;
db_indx_t indx, *inp;
int already_put, ret, t_ret;
dbp = dbc->dbp;
mpf = dbp->mpf;
already_put = 0;
if ((ret = __db_lget(dbc, 0, root_pgno, mode, 0, &lock)) != 0)
return (ret);
if ((ret = __memp_fget(mpf, &root_pgno, 0, &h)) != 0) {
(void)__TLPUT(dbc, lock);
return (ret);
}
switch (TYPE(h)) {
case P_IBTREE:
for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
bi = GET_BINTERNAL(dbp, h, indx);
if (B_TYPE(bi->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
((BOVERFLOW *)bi->data)->pgno,
callback, cookie)) != 0)
goto err;
if ((ret = __bam_traverse(
dbc, mode, bi->pgno, callback, cookie)) != 0)
goto err;
}
break;
case P_IRECNO:
for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
ri = GET_RINTERNAL(dbp, h, indx);
if ((ret = __bam_traverse(
dbc, mode, ri->pgno, callback, cookie)) != 0)
goto err;
}
break;
case P_LBTREE:
inp = P_INP(dbp, h);
for (indx = 0; indx < NUM_ENT(h); indx += P_INDX) {
bk = GET_BKEYDATA(dbp, h, indx);
if (B_TYPE(bk->type) == B_OVERFLOW &&
(indx + P_INDX >= NUM_ENT(h) ||
inp[indx] != inp[indx + P_INDX])) {
if ((ret = __db_traverse_big(dbp,
GET_BOVERFLOW(dbp, h, indx)->pgno,
callback, cookie)) != 0)
goto err;
}
bk = GET_BKEYDATA(dbp, h, indx + O_INDX);
if (B_TYPE(bk->type) == B_DUPLICATE &&
(ret = __bam_traverse(dbc, mode,
GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
callback, cookie)) != 0)
goto err;
if (B_TYPE(bk->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
callback, cookie)) != 0)
goto err;
}
break;
case P_LDUP:
case P_LRECNO:
for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
bk = GET_BKEYDATA(dbp, h, indx);
if (B_TYPE(bk->type) == B_OVERFLOW &&
(ret = __db_traverse_big(dbp,
GET_BOVERFLOW(dbp, h, indx)->pgno,
callback, cookie)) != 0)
goto err;
}
break;
default:
return (__db_pgfmt(dbp->dbenv, h->pgno));
}
ret = callback(dbp, h, cookie, &already_put);
err: if (!already_put && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, lock)) != 0 && ret == 0)
ret = t_ret;
return (ret);

View File

@@ -1,26 +1,23 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: bt_upgrade.c,v 11.30 2004/01/28 03:35:49 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: bt_upgrade.c,v 11.25 2002/08/06 06:11:13 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <limits.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_am.h"
#include "dbinc/db_upgrade.h"
#include "dbinc/btree.h"
/*
* __bam_30_btreemeta --

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,15 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: btree.src,v 10.35 2002/04/17 19:02:56 krinsky Exp $
* $Id: btree.src,v 10.42 2004/06/17 17:35:12 bostic Exp $
*/
PREFIX __bam
DBPRIVATE
INCLUDE #include "db_config.h"
INCLUDE
INCLUDE #ifndef NO_SYSTEM_INCLUDES
INCLUDE #include <sys/types.h>
INCLUDE
@@ -26,14 +24,9 @@ INCLUDE #include "dbinc/db_dispatch.h"
INCLUDE #include "dbinc/db_am.h"
INCLUDE #include "dbinc/btree.h"
INCLUDE #include "dbinc/log.h"
INCLUDE #include "dbinc/rep.h"
INCLUDE #include "dbinc/txn.h"
INCLUDE
/*
* NOTE: pg_alloc and pg_free have been moved to db.src, where they belong.
*/
/*
* BTREE-split: used to log a page split.
*
@@ -50,14 +43,14 @@ INCLUDE
*/
BEGIN split 62
DB fileid int32_t ld
WRLOCK left db_pgno_t lu
ARG left db_pgno_t lu
POINTER llsn DB_LSN * lu
WRLOCK right db_pgno_t lu
ARG right db_pgno_t lu
POINTER rlsn DB_LSN * lu
ARG indx u_int32_t lu
ARG npgno db_pgno_t lu
POINTER nlsn DB_LSN * lu
WRLOCKNZ root_pgno db_pgno_t lu
ARG root_pgno db_pgno_t lu
PGDBT pg DBT s
ARG opflags u_int32_t lu
END
@@ -74,9 +67,9 @@ END
*/
BEGIN rsplit 63
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
PGDBT pgdbt DBT s
WRLOCK root_pgno db_pgno_t lu
ARG root_pgno db_pgno_t lu
ARG nrec db_pgno_t lu
DBT rootent DBT s
POINTER rootlsn DB_LSN * lu
@@ -93,7 +86,7 @@ END
*/
BEGIN adj 55
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
POINTER lsn DB_LSN * lu
ARG indx u_int32_t lu
ARG indx_copy u_int32_t lu
@@ -111,7 +104,7 @@ END
*/
BEGIN cadjust 56
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
POINTER lsn DB_LSN * lu
ARG indx u_int32_t lu
ARG adjust int32_t ld
@@ -127,7 +120,7 @@ END
*/
BEGIN cdel 57
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
POINTER lsn DB_LSN * lu
ARG indx u_int32_t lu
END
@@ -137,13 +130,16 @@ END
*
* pgno: the page modified.
* lsn: the page's original lsn.
* indx: the index to be replaced.
* isdeleted: set if the record was previously deleted.
* orig: the original data.
* new: the replacement data.
* duplicate: the prefix of the replacement that matches the original.
* repl: the replacement data.
* prefix: the prefix of the replacement that matches the original.
* suffix: the suffix of the replacement that matches the original.
*/
BEGIN repl 58
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
POINTER lsn DB_LSN * lu
ARG indx u_int32_t lu
ARG isdeleted u_int32_t lu
@@ -158,8 +154,8 @@ END
*/
BEGIN root 59
DB fileid int32_t ld
WRLOCK meta_pgno db_pgno_t lu
WRLOCK root_pgno db_pgno_t lu
ARG meta_pgno db_pgno_t lu
ARG root_pgno db_pgno_t lu
POINTER meta_lsn DB_LSN * lu
END
@@ -206,3 +202,24 @@ ARG recno db_recno_t ld
/* Order number of the adjustment. */
ARG order u_int32_t ld
END
/*
* BTREE-relink -- Handles relinking around a deleted leaf page.
*
*/
BEGIN relink 147
/* Fileid of db affected. */
DB fileid int32_t ld
/* The page being changed. */
ARG pgno db_pgno_t lu
/* The page's original lsn. */
POINTER lsn DB_LSN * lu
/* The previous page. */
ARG prev db_pgno_t lu
/* The previous page's original lsn. */
POINTER lsn_prev DB_LSN * lu
/* The next page. */
ARG next db_pgno_t lu
/* The previous page's original lsn. */
POINTER lsn_next DB_LSN * lu
END

View File

@@ -0,0 +1,251 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_deadlock.c,v 11.45 2004/03/24 15:13:12 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char copyright[] =
"Copyright (c) 1996-2004\nSleepycat Software Inc. All rights reserved.\n";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif
#include "db_int.h"
int db_deadlock_main __P((int, char *[]));
int db_deadlock_usage __P((void));
int db_deadlock_version_check __P((const char *));
int
db_deadlock(args)
char *args;
{
int argc;
char **argv;
__db_util_arg("db_deadlock", args, &argc, &argv);
return (db_deadlock_main(argc, argv) ? EXIT_FAILURE : EXIT_SUCCESS);
}
#include <stdio.h>
#define ERROR_RETURN ERROR
int
db_deadlock_main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind, __db_getopt_reset;
const char *progname = "db_deadlock";
DB_ENV *dbenv;
u_int32_t atype;
time_t now;
u_long secs, usecs;
int ch, exitval, ret, verbose;
char *home, *logfile, *str;
if ((ret = db_deadlock_version_check(progname)) != 0)
return (ret);
dbenv = NULL;
atype = DB_LOCK_DEFAULT;
home = logfile = NULL;
secs = usecs = 0;
exitval = verbose = 0;
__db_getopt_reset = 1;
while ((ch = getopt(argc, argv, "a:h:L:t:Vvw")) != EOF)
switch (ch) {
case 'a':
switch (optarg[0]) {
case 'e':
atype = DB_LOCK_EXPIRE;
break;
case 'm':
atype = DB_LOCK_MAXLOCKS;
break;
case 'n':
atype = DB_LOCK_MINLOCKS;
break;
case 'o':
atype = DB_LOCK_OLDEST;
break;
case 'W':
atype = DB_LOCK_MAXWRITE;
break;
case 'w':
atype = DB_LOCK_MINWRITE;
break;
case 'y':
atype = DB_LOCK_YOUNGEST;
break;
default:
return (db_deadlock_usage());
/* NOTREACHED */
}
if (optarg[1] != '\0')
return (db_deadlock_usage());
break;
case 'h':
home = optarg;
break;
case 'L':
logfile = optarg;
break;
case 't':
if ((str = strchr(optarg, '.')) != NULL) {
*str++ = '\0';
if (*str != '\0' && __db_getulong(
NULL, progname, str, 0, LONG_MAX, &usecs))
return (EXIT_FAILURE);
}
if (*optarg != '\0' && __db_getulong(
NULL, progname, optarg, 0, LONG_MAX, &secs))
return (EXIT_FAILURE);
if (secs == 0 && usecs == 0)
return (db_deadlock_usage());
break;
case 'V':
printf("%s\n", db_version(NULL, NULL, NULL));
return (EXIT_SUCCESS);
case 'v':
verbose = 1;
break;
case 'w': /* Undocumented. */
/* Detect every 100ms (100000 us) when polling. */
secs = 0;
usecs = 100000;
break;
case '?':
default:
return (db_deadlock_usage());
}
argc -= optind;
argv += optind;
if (argc != 0)
return (db_deadlock_usage());
/* Handle possible interruptions. */
__db_util_siginit();
/* Log our process ID. */
if (logfile != NULL && __db_util_logset(progname, logfile))
goto shutdown;
/*
* Create an environment object and initialize it for error
* reporting.
*/
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(stderr,
"%s: db_env_create: %s\n", progname, db_strerror(ret));
goto shutdown;
}
dbenv->set_errfile(dbenv, stderr);
dbenv->set_errpfx(dbenv, progname);
if (verbose) {
(void)dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 1);
(void)dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, 1);
}
/* An environment is required. */
if ((ret =
dbenv->open(dbenv, home, DB_INIT_LOCK | DB_USE_ENVIRON, 0)) != 0) {
dbenv->err(dbenv, ret, "open");
goto shutdown;
}
while (!__db_util_interrupted()) {
if (verbose) {
(void)time(&now);
dbenv->errx(dbenv, "running at %.24s", ctime(&now));
}
if ((ret = dbenv->lock_detect(dbenv, 0, atype, NULL)) != 0) {
dbenv->err(dbenv, ret, "DB_ENV->lock_detect");
goto shutdown;
}
/* Make a pass every "secs" secs and "usecs" usecs. */
if (secs == 0 && usecs == 0)
break;
__os_sleep(dbenv, secs, usecs);
}
if (0) {
shutdown: exitval = 1;
}
/* Clean up the logfile. */
if (logfile != NULL)
(void)remove(logfile);
/* Clean up the environment. */
if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
exitval = 1;
fprintf(stderr,
"%s: dbenv->close: %s\n", progname, db_strerror(ret));
}
/* Resend any caught signal. */
__db_util_sigresend();
return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
int
db_deadlock_usage()
{
(void)fprintf(stderr, "%s\n\t%s\n",
"usage: db_deadlock [-Vv]",
"[-a e | m | n | o | W | w | y] [-h home] [-L file] [-t sec.usec]");
return (EXIT_FAILURE);
}
int
db_deadlock_version_check(progname)
const char *progname;
{
int v_major, v_minor, v_patch;
/* Make sure we're loaded with the right version of the DB library. */
(void)db_version(&v_major, &v_minor, &v_patch);
if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
fprintf(stderr,
"%s: version %d.%d doesn't match library version %d.%d\n",
progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
v_major, v_minor);
return (EXIT_FAILURE);
}
return (0);
}

View File

@@ -1,51 +1,9 @@
Microsoft Developer Studio Workspace File, Format Version 5.00
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "DB_DLL"=.\db_dll.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "DB_Static"=.\db_static.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "db_archive"=.\db_archive.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
End Project Dependency
}}}
###############################################################################
Project: "db_buildall"=.\db_buildall.dsp - Package Owner=<4>
Project: "build_all"=.\build_all.dsp - Package Owner=<4>
Package=<5>
{{{
@@ -125,6 +83,24 @@ Package=<4>
Begin Project Dependency
Project_Dep_Name excxx_tpcb
End Project Dependency
Begin Project Dependency
Project_Dep_Name db_lib
End Project Dependency
}}}
###############################################################################
Project: "db_archive"=.\db_archive.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name db_lib
End Project Dependency
}}}
###############################################################################
@@ -138,10 +114,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -158,9 +131,18 @@ Package=<4>
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
End Project Dependency
}}}
###############################################################################
Project: "db_dll"=.\db_dll.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
@@ -174,10 +156,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -198,6 +177,24 @@ Package=<4>
###############################################################################
Project: "db_lib"=.\db_lib.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name db_dll
End Project Dependency
Begin Project Dependency
Project_Dep_Name db_static
End Project Dependency
}}}
###############################################################################
Project: "db_load"=.\db_load.dsp - Package Owner=<4>
Package=<5>
@@ -207,10 +204,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -225,10 +219,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -243,10 +234,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -261,15 +249,24 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
###############################################################################
Project: "db_static"=.\db_static.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "db_tcl"=.\db_tcl.dsp - Package Owner=<4>
Package=<5>
@@ -294,7 +291,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name db_buildall
Project_Dep_Name build_all
End Project Dependency
Begin Project Dependency
Project_Dep_Name db_tcl
@@ -312,10 +309,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -330,10 +324,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -348,10 +339,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -366,10 +354,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_Static
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_DLL
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -384,10 +369,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -402,10 +384,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -420,10 +399,22 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
Project_Dep_Name db_lib
End Project Dependency
}}}
###############################################################################
Project: "ex_repquote"=.\ex_repquote.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -438,10 +429,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -456,10 +444,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -474,10 +459,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -492,10 +474,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -510,10 +489,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -528,10 +504,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -546,10 +519,7 @@ Package=<5>
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name DB_DLL
End Project Dependency
Begin Project Dependency
Project_Dep_Name DB_Static
Project_Dep_Name db_lib
End Project Dependency
}}}
@@ -566,3 +536,4 @@ Package=<3>
}}}
###############################################################################

View File

@@ -44,7 +44,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -68,7 +68,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
@@ -92,8 +92,8 @@ LINK32=link.exe
# PROP Intermediate_Dir "Release_static"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -117,8 +117,8 @@ LINK32=link.exe
# PROP Intermediate_Dir "Debug_static"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe

View File

@@ -42,7 +42,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -71,7 +71,7 @@ PostBuild_Cmds=copy Release\*.exe .
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe

View File

@@ -1,10 +1,10 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Copyright (c) 1999-2004
* Sleepycat Software. All rights reserved.
*
* $Id: dbkill.cpp,v 11.7 2002/01/11 15:51:27 bostic Exp $
* $Id: dbkill.cpp,v 11.9 2004/01/28 03:35:52 bostic Exp $
*/
/*
* Kill -

View File

@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I ".." /I "../dbinc" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I ".." /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -69,7 +69,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c
# SUBTRACT CPP /Fr
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32

View File

@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -60,15 +60,15 @@ InputPath=.\Release\libdb_java@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll
SOURCE="$(InputPath)"
"force_compilation.txt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
mkdir $(ProjDir)\Release\classes
echo compiling Berkeley DB classes
javac -g -d $(ProjDir)/Release/classes -classpath "$(CLASSPATH);$(ProjDir)/Release/classes" ..\java\src\com\sleepycat\db\*.java
mkdir "$(OUTDIR)\classes"
javac -O -d "$(OUTDIR)\classes" -classpath "$(OUTDIR)/classes" ..\java\src\com\sleepycat\db\*.java ..\java\src\com\sleepycat\db\internal\*.java ..\java\src\com\sleepycat\bind\*.java ..\java\src\com\sleepycat\bind\serial\*.java ..\java\src\com\sleepycat\bind\tuple\*.java ..\java\src\com\sleepycat\collections\*.java ..\java\src\com\sleepycat\compat\*.java ..\java\src\com\sleepycat\util\*.java
echo compiling examples
javac -g -d $(ProjDir)/Release/classes -classpath "$(CLASSPATH);$(ProjDir)/Release/classes" ..\java\src\com\sleepycat\examples\*.java
mkdir "$(OUTDIR)\classes.ex"
javac -O -d "$(OUTDIR)\classes.ex" -classpath "$(OUTDIR)\classes;$(OUTDIR)\classes.ex" ..\examples_java\src\com\sleepycat\examples\db\*.java ..\examples_java\src\com\sleepycat\examples\db\GettingStarted\*.java ..\examples_java\src\com\sleepycat\examples\collections\access\*.java ..\examples_java\src\com\sleepycat\examples\collections\hello\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\basic\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\entity\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\tuple\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\sentity\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\marshal\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\factory\*.java
echo creating jar files
cd $(ProjDir)\Release\classes
jar cf ../db.jar com\sleepycat\db\*.class
jar cf ../dbexamples.jar com\sleepycat\examples\*.class
jar cf "$(OUTDIR)\db.jar" -C "$(OUTDIR)\classes" .
jar cf "$(OUTDIR)\dbexamples.jar" -C "$(OUTDIR)\classes.ex" .
echo Java build finished
# End Custom Build
@@ -87,7 +87,7 @@ SOURCE="$(InputPath)"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c
# SUBTRACT CPP /Fr
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
@@ -105,17 +105,17 @@ InputPath=.\Debug\libdb_java@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll
SOURCE="$(InputPath)"
"force_compilation.txt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
mkdir $(ProjDir)\Debug\classes
echo compiling Berkeley DB classes
javac -g -d $(ProjDir)/Debug/classes -classpath "$(CLASSPATH);$(ProjDir)/Debug/classes" ..\java\src\com\sleepycat\db\*.java
mkdir "$(OUTDIR)\classes"
javac -g -d "$(OUTDIR)\classes" -classpath "$(OUTDIR)/classes" ..\java\src\com\sleepycat\db\*.java ..\java\src\com\sleepycat\db\internal\*.java ..\java\src\com\sleepycat\bind\*.java ..\java\src\com\sleepycat\bind\serial\*.java ..\java\src\com\sleepycat\bind\tuple\*.java ..\java\src\com\sleepycat\collections\*.java ..\java\src\com\sleepycat\compat\*.java ..\java\src\com\sleepycat\util\*.java
echo compiling examples
javac -g -d $(ProjDir)/Debug/classes -classpath "$(CLASSPATH);$(ProjDir)/Debug/classes" ..\java\src\com\sleepycat\examples\*.java
mkdir "$(OUTDIR)\classes.ex"
javac -g -d "$(OUTDIR)\classes.ex" -classpath "$(OUTDIR)\classes;$(OUTDIR)\classes.ex" ..\examples_java\src\com\sleepycat\examples\db\*.java ..\examples_java\src\com\sleepycat\examples\db\GettingStarted\*.java ..\examples_java\src\com\sleepycat\examples\collections\access\*.java ..\examples_java\src\com\sleepycat\examples\collections\hello\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\basic\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\entity\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\tuple\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\sentity\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\marshal\*.java ..\examples_java\src\com\sleepycat\examples\collections\ship\factory\*.java
echo creating jar files
cd $(ProjDir)\Debug\classes
jar cf ../db.jar com\sleepycat\db\*.class
jar cf ../dbexamples.jar com\sleepycat\examples\*.class
jar cf "$(OUTDIR)\db.jar" -C "$(OUTDIR)\classes" .
jar cf "$(OUTDIR)\dbexamples.jar" -C "$(OUTDIR)\classes.ex" .
echo Java build finished
# End Custom Build
!ENDIF

View File

@@ -1,27 +1,7 @@
; $Id: libdb_tcl.def,v 11.5 2002/04/03 12:01:27 mjc Exp $
; $Id: libdb_tcl.def,v 11.7 2002/10/14 23:44:20 mjc Exp $
DESCRIPTION 'Berkeley DB TCL interface Library'
EXPORTS
Db_tcl_Init
db_Cmd
dbc_Cmd
env_Cmd
tcl_EnvRemove
tcl_LockDetect
tcl_LockGet
tcl_LockStat
tcl_LockVec
tcl_LogArchive
tcl_LogCompare
tcl_LogFile
tcl_LogFlush
tcl_LogGet
tcl_LogPut
tcl_LogStat
tcl_Mp
tcl_MpStat
tcl_MpSync
tcl_MpTrickle
tcl_Txn
tcl_TxnCheckpoint
tcl_TxnStat
_NameToPtr

View File

@@ -20,7 +20,7 @@ BEGIN
VALUE "FileDescription", "Berkeley DB 3.0 DLL\0"
VALUE "FileVersion", "%MAJOR%.%MINOR%.%PATCH%\0"
VALUE "InternalName", "libdb.dll\0"
VALUE "LegalCopyright", "Copyright <20> Sleepycat Software Inc. 1997-2002\0"
VALUE "LegalCopyright", "Copyright <20> Sleepycat Software Inc. 1997-2004\0"
VALUE "OriginalFilename", "libdb.dll\0"
VALUE "ProductName", "Sleepycat Software libdb\0"
VALUE "ProductVersion", "%MAJOR%.%MINOR%.%PATCH%\0"

View File

@@ -40,8 +40,8 @@ RSC=rc.exe
# PROP Output_Dir "Release_static"
# PROP Intermediate_Dir "Release_static"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX"config.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I ".." /I "../dbinc" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX"config.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I ".." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c
# ADD BASE RSC /l 0xc09
# ADD RSC /l 0xc09
BSC32=bscmake.exe
@@ -63,8 +63,8 @@ LIB32=link.exe -lib
# PROP Output_Dir "Debug_static"
# PROP Intermediate_Dir "Debug_static"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX"config.h" /FD /c
# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c
# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I ".." /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX"config.h" /FD /c
# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I ".." /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c
# ADD BASE RSC /l 0xc09
# ADD RSC /l 0xc09
BSC32=bscmake.exe

View File

@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I ".." /I "../dbinc" /D "DB_TCL_SUPPORT" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I ".." /D "DB_TCL_SUPPORT" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -53,7 +53,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.lib tcl83.lib /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb_tcl@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll"
# ADD LINK32 Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.lib tcl84.lib /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb_tcl@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll"
!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug"
@@ -69,7 +69,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /I "../dbinc" /D "DB_TCL_SUPPORT" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c
# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I ".." /D "DB_TCL_SUPPORT" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c
# SUBTRACT CPP /Fr
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
@@ -80,7 +80,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.lib tcl83d.lib /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb_tcl@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no
# ADD LINK32 Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.lib tcl84g.lib /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb_tcl@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no
!ENDIF

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -31,14 +31,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: getcwd.c,v 11.15 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: getcwd.c,v 11.13 2002/02/28 21:27:18 ubell Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <sys/stat.h>

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -31,14 +31,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: getopt.c,v 11.9 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: getopt.c,v 11.7 2002/01/11 15:51:28 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <stdio.h>
#include <stdlib.h>

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -31,14 +31,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: memcmp.c,v 11.9 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: memcmp.c,v 11.7 2002/01/11 15:51:28 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -31,14 +31,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: memmove.c,v 11.8 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: memmove.c,v 11.6 2002/01/11 15:51:28 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: raise.c,v 11.8 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: raise.c,v 11.6 2002/01/11 15:51:28 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <signal.h>
#include <unistd.h>

View File

@@ -1,24 +1,30 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: snprintf.c,v 11.18 2004/09/22 03:32:43 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: snprintf.c,v 11.10 2002/01/11 15:51:28 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* Declare STDERR_FILENO. */
#endif
#include "db_int.h"
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
static void sprintf_overflow __P((void));
static int sprintf_retcharpnt __P((void));
#endif
/*
* snprintf --
* Bounded version of sprintf.
@@ -29,7 +35,7 @@ static const char revid[] = "$Id: snprintf.c,v 11.10 2002/01/11 15:51:28 bostic
*/
#ifndef HAVE_SNPRINTF
int
#ifdef __STDC__
#ifdef STDC_HEADERS
snprintf(char *str, size_t n, const char *fmt, ...)
#else
snprintf(str, n, fmt, va_alist)
@@ -41,9 +47,98 @@ snprintf(str, n, fmt, va_alist)
{
static int ret_charpnt = -1;
va_list ap;
int len;
size_t len;
COMPQUIET(n, 0);
if (ret_charpnt == -1)
ret_charpnt = sprintf_retcharpnt();
#ifdef STDC_HEADERS
va_start(ap, fmt);
#else
va_start(ap);
#endif
len = (size_t)vsprintf(str, fmt, ap);
if (ret_charpnt)
len = strlen(str);
va_end(ap);
if (len >= n) {
sprintf_overflow();
/* NOTREACHED */
}
return ((int)len);
}
#endif
/*
* vsnprintf --
* Bounded version of vsprintf.
*
* PUBLIC: #ifndef HAVE_VSNPRINTF
* PUBLIC: int vsnprintf __P((char *, size_t, const char *, va_list));
* PUBLIC: #endif
*/
#ifndef HAVE_VSNPRINTF
int
vsnprintf(str, n, fmt, ap)
char *str;
size_t n;
const char *fmt;
va_list ap;
{
static int ret_charpnt = -1;
size_t len;
if (ret_charpnt == -1)
ret_charpnt = sprintf_retcharpnt();
len = (size_t)vsprintf(str, fmt, ap);
if (ret_charpnt)
len = strlen(str);
if (len >= n) {
sprintf_overflow();
/* NOTREACHED */
}
return ((int)len);
}
#endif
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
static void
sprintf_overflow()
{
/*
* !!!
* We're potentially manipulating strings handed us by the application,
* and on systems without a real snprintf() the sprintf() calls could
* have overflowed the buffer. We can't do anything about it now, but
* we don't want to return control to the application, we might have
* overwritten the stack with a Trojan horse. We're not trying to do
* anything recoverable here because systems without snprintf support
* are pretty rare anymore.
*/
#define OVERFLOW_ERROR "internal buffer overflow, process ended\n"
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
(void)write(STDERR_FILENO, OVERFLOW_ERROR, sizeof(OVERFLOW_ERROR) - 1);
/* Be polite. */
exit(1);
/* But firm. */
abort();
/* NOTREACHED */
}
static int
sprintf_retcharpnt()
{
int ret_charpnt;
char buf[10];
/*
* Some old versions of sprintf return a pointer to the first argument
@@ -53,22 +148,12 @@ snprintf(str, n, fmt, va_alist)
* We do this test at run-time because it's not a test we can do in a
* cross-compilation environment.
*/
if (ret_charpnt == -1) {
char buf[10];
ret_charpnt =
sprintf(buf, "123") != 3 ||
sprintf(buf, "123456789") != 9 ||
sprintf(buf, "1234") != 4;
}
ret_charpnt =
(int)sprintf(buf, "123") != 3 ||
(int)sprintf(buf, "123456789") != 9 ||
(int)sprintf(buf, "1234") != 4;
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
len = vsprintf(str, fmt, ap);
va_end(ap);
return (ret_charpnt ? (int)strlen(str) : len);
return (ret_charpnt);
}
#endif

View File

@@ -29,14 +29,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: strcasecmp.c,v 1.8 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: strcasecmp.c,v 1.7 2001/11/15 17:51:38 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <string.h>
#endif

View File

@@ -29,14 +29,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: strdup.c,v 1.6 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: strdup.c,v 1.5 2002/05/01 18:40:05 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -31,14 +31,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: strerror.c,v 11.8 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: strerror.c,v 11.6 2002/01/11 15:51:29 bostic Exp $";
#endif /* not lint */
/*
* strerror --
* Return the string associated with an errno.

144
storage/bdb/clib/strtol.c Normal file
View File

@@ -0,0 +1,144 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: strtol.c,v 1.3 2004/10/28 19:27:19 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#endif
/*
* Convert a string to a long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
long
strtol(nptr, endptr, base)
const char * nptr;
char ** endptr;
int base;
{
const char *s;
unsigned long acc;
char c;
unsigned long cutoff;
int neg, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
s = nptr;
do {
c = *s++;
} while (isspace((unsigned char)c));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
: LONG_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}

123
storage/bdb/clib/strtoul.c Normal file
View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: strtoul.c,v 1.3 2004/10/28 19:27:19 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#endif
/*
* Convert a string to an unsigned long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long
strtoul(nptr, endptr, base)
const char * nptr;
char ** endptr;
int base;
{
const char *s;
unsigned long acc;
char c;
unsigned long cutoff;
int neg, any, cutlim;
/*
* See strtol for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (isspace((unsigned char)c));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = ULONG_MAX / base;
cutlim = ULONG_MAX % base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}

View File

@@ -0,0 +1,45 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: crypto_stub.c,v 1.4 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#include "db_int.h"
/*
* __crypto_region_init --
* Initialize crypto.
*
*
* !!!
* We don't put this stub file in the crypto/ directory of the distribution
* because that entire directory is removed for non-crypto distributions.
*
* PUBLIC: int __crypto_region_init __P((DB_ENV *));
*/
int
__crypto_region_init(dbenv)
DB_ENV *dbenv;
{
REGENV *renv;
REGINFO *infop;
int ret;
infop = dbenv->reginfo;
renv = infop->primary;
MUTEX_LOCK(dbenv, &renv->mutex);
ret = !(renv->cipher_off == INVALID_ROFF);
MUTEX_UNLOCK(dbenv, &renv->mutex);
if (ret == 0)
return (0);
__db_err(dbenv,
"Encrypted environment: library build did not include cryptography support");
return (DB_OPNOTSUP);
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_byteorder.c,v 11.10 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_byteorder.c,v 11.8 2002/02/01 18:15:29 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

View File

@@ -1,20 +1,17 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_err.c,v 11.123 2004/09/22 03:07:50 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_err.c,v 11.80 2002/07/30 01:21:53 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
@@ -27,6 +24,9 @@ static const char revid[] = "$Id: db_err.c,v 11.80 2002/07/30 01:21:53 bostic Ex
#include "dbinc/log.h"
#include "dbinc/txn.h"
static void __db_msgcall __P((const DB_ENV *, const char *, va_list));
static void __db_msgfile __P((const DB_ENV *, const char *, va_list));
/*
* __db_fchk --
* General flags checking routine.
@@ -76,13 +76,30 @@ __db_ferr(dbenv, name, iscombo)
return (EINVAL);
}
/*
* __db_fnl --
* Common flag-needs-locking message.
*
* PUBLIC: int __db_fnl __P((const DB_ENV *, const char *));
*/
int
__db_fnl(dbenv, name)
const DB_ENV *dbenv;
const char *name;
{
__db_err(dbenv,
"%s: the DB_DIRTY_READ, DB_DEGREE_2 and DB_RMW flags require locking",
name);
return (EINVAL);
}
/*
* __db_pgerr --
* Error when unable to retrieve a specified page.
*
* PUBLIC: void __db_pgerr __P((DB *, db_pgno_t, int));
* PUBLIC: int __db_pgerr __P((DB *, db_pgno_t, int));
*/
void
int
__db_pgerr(dbp, pgno, errval)
DB *dbp;
db_pgno_t pgno;
@@ -95,7 +112,7 @@ __db_pgerr(dbp, pgno, errval)
*/
__db_err(dbp->dbenv,
"unable to create/retrieve page %lu", (u_long)pgno);
(void)__db_panic(dbp->dbenv, errval);
return (__db_panic(dbp->dbenv, errval));
}
/*
@@ -113,24 +130,6 @@ __db_pgfmt(dbenv, pgno)
return (__db_panic(dbenv, EINVAL));
}
/*
* __db_eopnotsup --
* Common operation not supported message.
*
* PUBLIC: int __db_eopnotsup __P((const DB_ENV *));
*/
int
__db_eopnotsup(dbenv)
const DB_ENV *dbenv;
{
__db_err(dbenv, "operation not supported");
#ifdef EOPNOTSUPP
return (EOPNOTSUPP);
#else
return (EINVAL);
#endif
}
#ifdef DIAGNOSTIC
/*
* __db_assert --
@@ -167,7 +166,11 @@ int
__db_panic_msg(dbenv)
DB_ENV *dbenv;
{
__db_err(dbenv, "fatal region error detected; run recovery");
__db_err(dbenv, "PANIC: fatal region error detected; run recovery");
if (dbenv->db_paniccall != NULL)
dbenv->db_paniccall(dbenv, DB_RUNRECOVERY);
return (DB_RUNRECOVERY);
}
@@ -185,8 +188,6 @@ __db_panic(dbenv, errval)
if (dbenv != NULL) {
PANIC_SET(dbenv, 1);
dbenv->panic_errval = errval;
__db_err(dbenv, "PANIC: %s", db_strerror(errval));
if (dbenv->db_paniccall != NULL)
@@ -222,10 +223,15 @@ char *
db_strerror(error)
int error;
{
char *p;
if (error == 0)
return ("Successful return: 0");
if (error > 0)
return (strerror(error));
if (error > 0) {
if ((p = strerror(error)) != NULL)
return (p);
goto unknown_err;
}
/*
* !!!
@@ -235,6 +241,9 @@ db_strerror(error)
* altered.
*/
switch (error) {
case DB_BUFFER_SMALL:
return
("DB_BUFFER_SMALL: User memory too small for return value");
case DB_DONOTINDEX:
return ("DB_DONOTINDEX: Secondary index callback returns null");
case DB_KEYEMPTY:
@@ -246,8 +255,10 @@ db_strerror(error)
("DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock");
case DB_LOCK_NOTGRANTED:
return ("DB_LOCK_NOTGRANTED: Lock not granted");
case DB_LOG_BUFFER_FULL:
return ("DB_LOG_BUFFER_FULL: In-memory log buffer is full");
case DB_NOSERVER:
return ("DB_NOSERVER: Fatal error, no server");
return ("DB_NOSERVER: Fatal error, no RPC server");
case DB_NOSERVER_HOME:
return ("DB_NOSERVER_HOME: Home unrecognized at server");
case DB_NOSERVER_ID:
@@ -260,25 +271,38 @@ db_strerror(error)
return ("DB_PAGE_NOTFOUND: Requested page not found");
case DB_REP_DUPMASTER:
return ("DB_REP_DUPMASTER: A second master site appeared");
case DB_REP_HANDLE_DEAD:
return ("DB_REP_HANDLE_DEAD: Handle is no longer valid");
case DB_REP_HOLDELECTION:
return ("DB_REP_HOLDELECTION: Need to hold an election");
case DB_REP_ISPERM:
return ("DB_REP_ISPERM: Permanent record written");
case DB_REP_NEWMASTER:
return ("DB_REP_NEWMASTER: A new master has declared itself");
case DB_REP_NEWSITE:
return ("DB_REP_NEWSITE: A new site has entered the system");
case DB_REP_OUTDATED:
case DB_REP_NOTPERM:
return ("DB_REP_NOTPERM: Permanent log record not written");
case DB_REP_STARTUPDONE:
return
("DB_REP_OUTDATED: Insufficient logs on master to recover");
("DB_REP_STARTUPDONE: Client completed startup synchronization.");
case DB_REP_UNAVAIL:
return ("DB_REP_UNAVAIL: Unable to elect a master");
case DB_RUNRECOVERY:
return ("DB_RUNRECOVERY: Fatal error, run database recovery");
case DB_SECONDARY_BAD:
return
("DB_SECONDARY_BAD: Secondary index item missing from primary");
("DB_SECONDARY_BAD: Secondary index inconsistent with primary");
case DB_VERIFY_BAD:
return ("DB_VERIFY_BAD: Database verification failed");
default: {
case DB_VERSION_MISMATCH:
return
("DB_VERSION_MISMATCH: Database environment version mismatch");
default:
break;
}
unknown_err: {
/*
* !!!
* Room for a 64-bit number + slop. This buffer is only used
@@ -290,7 +314,6 @@ db_strerror(error)
(void)snprintf(ebuf, sizeof(ebuf), "Unknown error: %d", error);
return (ebuf);
}
}
}
/*
@@ -298,10 +321,11 @@ db_strerror(error)
* Standard DB error routine. The same as errx, except we don't write
* to stderr if no output mechanism was specified.
*
* PUBLIC: void __db_err __P((const DB_ENV *, const char *, ...));
* PUBLIC: void __db_err __P((const DB_ENV *, const char *, ...))
* PUBLIC: __attribute__ ((__format__ (__printf__, 2, 3)));
*/
void
#ifdef __STDC__
#ifdef STDC_HEADERS
__db_err(const DB_ENV *dbenv, const char *fmt, ...)
#else
__db_err(dbenv, fmt, va_alist)
@@ -328,34 +352,17 @@ __db_errcall(dbenv, error, error_set, fmt, ap)
va_list ap;
{
char *p;
char errbuf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */
char buf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */
p = errbuf;
p = buf;
if (fmt != NULL)
p += vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
p += vsnprintf(buf, sizeof(buf), fmt, ap);
if (error_set)
p += snprintf(p,
sizeof(errbuf) - (p - errbuf), ": %s", db_strerror(error));
/*
* !!!
* We're potentially manipulating strings handed us by the application,
* and on systems without a real snprintf() the sprintf() calls could
* have overflowed the buffer. We can't do anything about it now, but
* we don't want to return control to the application, we might have
* overwritten the stack with a Trojan horse. We're not trying to do
* anything recoverable here because systems without snprintf support
* are pretty rare anymore.
*/
if ((size_t)(p - errbuf) > sizeof(errbuf)) {
(void)fprintf(stderr,
"Berkeley DB: error callback interface buffer overflow\n");
(void)fflush(stderr);
sizeof(buf) - (size_t)(p - buf), ": %s",
db_strerror(error));
abort();
/* NOTREACHED */
}
dbenv->db_errcall(dbenv->db_errpfx, errbuf);
dbenv->db_errcall(dbenv, dbenv->db_errpfx, buf);
}
/*
@@ -390,15 +397,121 @@ __db_errfile(dbenv, error, error_set, fmt, ap)
(void)fflush(fp);
}
/*
* __db_msgadd --
* Aggregate a set of strings into a buffer for the callback API.
*
* PUBLIC: void __db_msgadd __P((DB_ENV *, DB_MSGBUF *, const char *, ...))
* PUBLIC: __attribute__ ((__format__ (__printf__, 3, 4)));
*/
void
#ifdef STDC_HEADERS
__db_msgadd(DB_ENV *dbenv, DB_MSGBUF *mbp, const char *fmt, ...)
#else
__db_msgadd(dbenv, mbp, fmt, va_alist)
DB_ENV *dbenv;
DB_MSGBUF *mbp;
const char *fmt;
va_dcl
#endif
{
va_list ap;
size_t len, olen;
char buf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */
#ifdef STDC_HEADERS
va_start(ap, fmt);
#else
va_start(ap);
#endif
len = (size_t)vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
/*
* There's a heap buffer in the DB_ENV handle we use to aggregate the
* message chunks. We maintain a pointer to the buffer, the next slot
* to be filled in in the buffer, and a total buffer length.
*/
olen = (size_t)(mbp->cur - mbp->buf);
if (olen + len >= mbp->len) {
if (__os_realloc(dbenv, mbp->len + len + 256, &mbp->buf))
return;
mbp->len += (len + 256);
mbp->cur = mbp->buf + olen;
}
memcpy(mbp->cur, buf, len + 1);
mbp->cur += len;
}
/*
* __db_msg --
* Standard DB stat message routine.
*
* PUBLIC: void __db_msg __P((const DB_ENV *, const char *, ...))
* PUBLIC: __attribute__ ((__format__ (__printf__, 2, 3)));
*/
void
#ifdef STDC_HEADERS
__db_msg(const DB_ENV *dbenv, const char *fmt, ...)
#else
__db_msg(dbenv, fmt, va_alist)
const DB_ENV *dbenv;
const char *fmt;
va_dcl
#endif
{
DB_REAL_MSG(dbenv, fmt);
}
/*
* __db_msgcall --
* Do the message work for callback functions.
*/
static void
__db_msgcall(dbenv, fmt, ap)
const DB_ENV *dbenv;
const char *fmt;
va_list ap;
{
char buf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */
(void)vsnprintf(buf, sizeof(buf), fmt, ap);
dbenv->db_msgcall(dbenv, buf);
}
/*
* __db_msgfile --
* Do the message work for FILE *s.
*/
static void
__db_msgfile(dbenv, fmt, ap)
const DB_ENV *dbenv;
const char *fmt;
va_list ap;
{
FILE *fp;
fp = dbenv == NULL ||
dbenv->db_msgfile == NULL ? stdout : dbenv->db_msgfile;
(void)vfprintf(fp, fmt, ap);
(void)fprintf(fp, "\n");
(void)fflush(fp);
}
/*
* __db_logmsg --
* Write information into the DB log.
*
* PUBLIC: void __db_logmsg __P((const DB_ENV *,
* PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, ...));
* PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, ...))
* PUBLIC: __attribute__ ((__format__ (__printf__, 5, 6)));
*/
void
#ifdef __STDC__
#ifdef STDC_HEADERS
__db_logmsg(const DB_ENV *dbenv,
DB_TXN *txnid, const char *opname, u_int32_t flags, const char *fmt, ...)
#else
@@ -418,7 +531,7 @@ __db_logmsg(dbenv, txnid, opname, flags, fmt, va_alist)
if (!LOGGING_ON(dbenv))
return;
#ifdef __STDC__
#ifdef STDC_HEADERS
va_start(ap, fmt);
#else
va_start(ap);
@@ -429,17 +542,17 @@ __db_logmsg(dbenv, txnid, opname, flags, fmt, va_alist)
memset(&msgdbt, 0, sizeof(msgdbt));
msgdbt.data = __logbuf;
msgdbt.size = vsnprintf(__logbuf, sizeof(__logbuf), fmt, ap);
msgdbt.size = (u_int32_t)vsnprintf(__logbuf, sizeof(__logbuf), fmt, ap);
va_end(ap);
/*
* XXX
* Explicitly discard the const. Otherwise, we have to const DB_ENV
* references throughout the logging subsystem.
*/
__db_debug_log(
(void)__db_debug_log(
(DB_ENV *)dbenv, txnid, &lsn, flags, &opdbt, -1, &msgdbt, NULL, 0);
va_end(ap);
}
/*
@@ -453,7 +566,7 @@ __db_unknown_flag(dbenv, routine, flag)
char *routine;
u_int32_t flag;
{
__db_err(dbenv, "%s: Unknown flag: 0x%x", routine, flag);
__db_err(dbenv, "%s: Unknown flag: %#x", routine, (u_int)flag);
DB_ASSERT(0);
return (EINVAL);
}
@@ -469,7 +582,9 @@ __db_unknown_type(dbenv, routine, type)
char *routine;
DBTYPE type;
{
__db_err(dbenv, "%s: Unknown db type: 0x%x", routine, type);
__db_err(dbenv,
"%s: Unexpected DB type: %s", routine, __db_dbtype_to_string(type));
DB_ASSERT(0);
return (EINVAL);
}
@@ -488,6 +603,7 @@ __db_check_txn(dbp, txn, assoc_lid, read_op)
int read_op;
{
DB_ENV *dbenv;
int isp, ret;
dbenv = dbp->dbenv;
@@ -522,8 +638,19 @@ __db_check_txn(dbp, txn, assoc_lid, read_op)
if (dbp->cur_lid >= TXN_MINIMUM)
goto open_err;
} else {
if (dbp->cur_lid >= TXN_MINIMUM && dbp->cur_lid != txn->txnid)
goto open_err;
if (F_ISSET(txn, TXN_DEADLOCK)) {
__db_err(dbenv,
"Previous deadlock return not resolved");
return (EINVAL);
}
if (dbp->cur_lid >= TXN_MINIMUM &&
dbp->cur_lid != txn->txnid) {
if ((ret = __lock_locker_is_parent(dbenv,
dbp->cur_lid, txn->txnid, &isp)) != 0)
return (ret);
if (!isp)
goto open_err;
}
if (!TXN_ON(dbenv))
return (__db_not_txn_env(dbenv));
@@ -577,3 +704,54 @@ __db_not_txn_env(dbenv)
__db_err(dbenv, "DB environment not configured for transactions");
return (EINVAL);
}
/*
* __db_rec_toobig --
* Fixed record length exceeded error message.
*
* PUBLIC: int __db_rec_toobig __P((DB_ENV *, u_int32_t, u_int32_t));
*/
int
__db_rec_toobig(dbenv, data_len, fixed_rec_len)
DB_ENV *dbenv;
u_int32_t data_len, fixed_rec_len;
{
__db_err(dbenv, "%s: length of %lu larger than database's value of %lu",
"Record length error", (u_long)data_len, (u_long)fixed_rec_len);
return (EINVAL);
}
/*
* __db_rec_repl --
* Fixed record replacement length error message.
*
* PUBLIC: int __db_rec_repl __P((DB_ENV *, u_int32_t, u_int32_t));
*/
int
__db_rec_repl(dbenv, data_size, data_dlen)
DB_ENV *dbenv;
u_int32_t data_size, data_dlen;
{
__db_err(dbenv,
"%s: replacement length %lu differs from replaced length %lu",
"Record length error", (u_long)data_size, (u_long)data_dlen);
return (EINVAL);
}
/*
* __db_check_lsn --
* Display the log sequence error message.
*
* PUBLIC: int __db_check_lsn __P((DB_ENV *, DB_LSN *, DB_LSN *));
*/
int
__db_check_lsn(dbenv, lsn, prev)
DB_ENV *dbenv;
DB_LSN *lsn, *prev;
{
__db_err(dbenv,
"Log sequence error: page LSN %lu %lu; previous LSN %lu %lu",
(u_long)(lsn)->file, (u_long)(lsn)->offset,
(u_long)(prev)->file, (u_long)(prev)->offset);
return (EINVAL);
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_getlong.c,v 11.22 2004/10/28 14:43:26 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_getlong.c,v 11.18 2002/03/28 20:13:33 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -26,11 +24,11 @@ static const char revid[] = "$Id: db_getlong.c,v 11.18 2002/03/28 20:13:33 bosti
* Return a long value inside of basic parameters.
*
* PUBLIC: int __db_getlong
* PUBLIC: __P((DB *, const char *, char *, long, long, long *));
* PUBLIC: __P((DB_ENV *, const char *, char *, long, long, long *));
*/
int
__db_getlong(dbp, progname, p, min, max, storep)
DB *dbp;
__db_getlong(dbenv, progname, p, min, max, storep)
DB_ENV *dbenv;
const char *progname;
char *p;
long min, max, *storep;
@@ -42,38 +40,38 @@ __db_getlong(dbp, progname, p, min, max, storep)
val = strtol(p, &end, 10);
if ((val == LONG_MIN || val == LONG_MAX) &&
__os_get_errno() == ERANGE) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: %s\n", progname, p, strerror(ERANGE));
else
dbp->err(dbp, ERANGE, "%s", p);
dbenv->err(dbenv, ERANGE, "%s", p);
return (1);
}
if (p[0] == '\0' || (end[0] != '\0' && end[0] != '\n')) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: Invalid numeric argument\n", progname, p);
else
dbp->errx(dbp, "%s: Invalid numeric argument", p);
dbenv->errx(dbenv, "%s: Invalid numeric argument", p);
return (1);
}
if (val < min) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: Less than minimum value (%ld)\n",
progname, p, min);
else
dbp->errx(dbp,
dbenv->errx(dbenv,
"%s: Less than minimum value (%ld)", p, min);
return (1);
}
if (val > max) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: Greater than maximum value (%ld)\n",
progname, p, max);
else
dbp->errx(dbp,
dbenv->errx(dbenv,
"%s: Greater than maximum value (%ld)", p, max);
return (1);
}
@@ -86,48 +84,43 @@ __db_getlong(dbp, progname, p, min, max, storep)
* Return an unsigned long value inside of basic parameters.
*
* PUBLIC: int __db_getulong
* PUBLIC: __P((DB *, const char *, char *, u_long, u_long, u_long *));
* PUBLIC: __P((DB_ENV *, const char *, char *, u_long, u_long, u_long *));
*/
int
__db_getulong(dbp, progname, p, min, max, storep)
DB *dbp;
__db_getulong(dbenv, progname, p, min, max, storep)
DB_ENV *dbenv;
const char *progname;
char *p;
u_long min, max, *storep;
{
#if !defined(HAVE_STRTOUL)
COMPQUIET(min, 0);
return (__db_getlong(dbp, progname, p, 0, max, (long *)storep));
#else
u_long val;
char *end;
__os_set_errno(0);
val = strtoul(p, &end, 10);
if (val == ULONG_MAX && __os_get_errno() == ERANGE) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: %s\n", progname, p, strerror(ERANGE));
else
dbp->err(dbp, ERANGE, "%s", p);
dbenv->err(dbenv, ERANGE, "%s", p);
return (1);
}
if (p[0] == '\0' || (end[0] != '\0' && end[0] != '\n')) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: Invalid numeric argument\n", progname, p);
else
dbp->errx(dbp, "%s: Invalid numeric argument", p);
dbenv->errx(dbenv, "%s: Invalid numeric argument", p);
return (1);
}
if (val < min) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: Less than minimum value (%lu)\n",
progname, p, min);
else
dbp->errx(dbp,
dbenv->errx(dbenv,
"%s: Less than minimum value (%lu)", p, min);
return (1);
}
@@ -139,16 +132,15 @@ __db_getulong(dbp, progname, p, min, max, storep)
* may not exist on all platforms.
*/
if (max != 0 && val > max) {
if (dbp == NULL)
if (dbenv == NULL)
fprintf(stderr,
"%s: %s: Greater than maximum value (%lu)\n",
progname, p, max);
else
dbp->errx(dbp,
dbenv->errx(dbenv,
"%s: Greater than maximum value (%lu)", p, max);
return (1);
}
*storep = val;
return (0);
#endif /* !defined(HAVE_STRTOUL) */
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Copyright (c) 2001-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_idspace.c,v 1.9 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_idspace.c,v 1.5 2002/02/01 18:15:29 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -44,7 +42,8 @@ __db_idcmp(a, b)
*
* On input, minp and maxp contain the minimum and maximum valid values for
* the name space and on return, they contain the minimum and maximum ids
* available (by finding the biggest gap).
* available (by finding the biggest gap). The minimum can be an inuse
* value, but the maximum cannot be.
*
* PUBLIC: void __db_idspace __P((u_int32_t *, int, u_int32_t *, u_int32_t *));
*/
@@ -73,7 +72,7 @@ __db_idspace(inuse, n, minp, maxp)
gap = 0;
low = 0;
qsort(inuse, n, sizeof(u_int32_t), __db_idcmp);
qsort(inuse, (size_t)n, sizeof(u_int32_t), __db_idcmp);
for (i = 0; i < n - 1; i++)
if ((t = (inuse[i + 1] - inuse[i])) > gap) {
gap = t;
@@ -85,9 +84,9 @@ __db_idspace(inuse, n, minp, maxp)
/* Do same check as we do in the n == 1 case. */
if (inuse[n - 1] != *maxp)
*minp = inuse[n - 1];
*maxp = inuse[0];
*maxp = inuse[0] - 1;
} else {
*minp = inuse[low];
*maxp = inuse[low + 1];
*maxp = inuse[low + 1] - 1;
}
}

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -34,14 +34,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: db_log2.c,v 11.9 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_log2.c,v 11.7 2002/02/01 18:15:30 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Copyright (c) 2001-2004
* Sleepycat Software. All rights reserved.
*
* $Id: util_arg.c,v 1.6 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: util_arg.c,v 1.4 2002/02/01 18:15:30 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

View File

@@ -1,23 +1,20 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Copyright (c) 2000-2004
* Sleepycat Software. All rights reserved.
*
* $Id: util_cache.c,v 1.8 2004/02/17 16:03:05 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: util_cache.c,v 1.3 2002/04/04 18:50:10 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif
#include "db_int.h"
@@ -26,59 +23,26 @@ static const char revid[] = "$Id: util_cache.c,v 1.3 2002/04/04 18:50:10 bostic
* __db_util_cache --
* Compute if we have enough cache.
*
* PUBLIC: int __db_util_cache __P((DB_ENV *, DB *, u_int32_t *, int *));
* PUBLIC: int __db_util_cache __P((DB *, u_int32_t *, int *));
*/
int
__db_util_cache(dbenv, dbp, cachep, resizep)
DB_ENV *dbenv;
__db_util_cache(dbp, cachep, resizep)
DB *dbp;
u_int32_t *cachep;
int *resizep;
{
DBTYPE type;
DB_BTREE_STAT *bsp;
DB_HASH_STAT *hsp;
DB_QUEUE_STAT *qsp;
u_int32_t pgsize;
int ret;
void *sp;
/* Get the current page size. */
if ((ret = dbp->get_pagesize(dbp, &pgsize)) != 0)
return (ret);
/*
* The current cache size is in cachep. If it's insufficient, set the
* the memory referenced by resizep to 1 and set cachep to the minimum
* size needed.
*/
if ((ret = dbp->get_type(dbp, &type)) != 0) {
dbenv->err(dbenv, ret, "DB->get_type");
return (ret);
}
if ((ret = dbp->stat(dbp, &sp, DB_FAST_STAT)) != 0) {
dbenv->err(dbenv, ret, "DB->stat");
return (ret);
}
switch (type) {
case DB_QUEUE:
qsp = (DB_QUEUE_STAT *)sp;
pgsize = qsp->qs_pagesize;
break;
case DB_HASH:
hsp = (DB_HASH_STAT *)sp;
pgsize = hsp->hash_pagesize;
break;
case DB_BTREE:
case DB_RECNO:
bsp = (DB_BTREE_STAT *)sp;
pgsize = bsp->bt_pagesize;
break;
default:
dbenv->err(dbenv, ret, "unknown database type: %d", type);
return (EINVAL);
}
free(sp);
/*
*
* Make sure our current cache is big enough. We want at least
* DB_MINPAGECACHE pages in the cache.
*/

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Copyright (c) 2000-2004
* Sleepycat Software. All rights reserved.
*
* $Id: util_log.c,v 1.14 2004/01/28 03:35:52 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: util_log.c,v 1.11 2002/02/01 18:15:30 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -27,7 +25,6 @@ static const char revid[] = "$Id: util_log.c,v 1.11 2002/02/01 18:15:30 bostic E
#endif
#include <string.h>
#include <unistd.h>
#endif
#include "db_int.h"

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2002
* Copyright (c) 2000-2004
* Sleepycat Software. All rights reserved.
*
* $Id: util_sig.c,v 1.9 2004/01/28 03:35:54 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: util_sig.c,v 1.7 2002/02/02 17:04:42 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>

View File

@@ -0,0 +1,273 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2004
* Sleepycat Software. All rights reserved.
*
* Some parts of this code originally written by Adam Stubblefield,
* -- astubble@rice.edu.
*
* $Id: aes_method.c,v 1.20 2004/09/17 22:00:25 mjc Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/crypto.h"
#include "dbinc/hmac.h"
static void __aes_err __P((DB_ENV *, int));
static int __aes_derivekeys __P((DB_ENV *, DB_CIPHER *, u_int8_t *, size_t));
/*
* __aes_setup --
* Setup AES functions.
*
* PUBLIC: int __aes_setup __P((DB_ENV *, DB_CIPHER *));
*/
int
__aes_setup(dbenv, db_cipher)
DB_ENV *dbenv;
DB_CIPHER *db_cipher;
{
AES_CIPHER *aes_cipher;
int ret;
db_cipher->adj_size = __aes_adj_size;
db_cipher->close = __aes_close;
db_cipher->decrypt = __aes_decrypt;
db_cipher->encrypt = __aes_encrypt;
db_cipher->init = __aes_init;
if ((ret = __os_calloc(dbenv, 1, sizeof(AES_CIPHER), &aes_cipher)) != 0)
return (ret);
db_cipher->data = aes_cipher;
return (0);
}
/*
* __aes_adj_size --
* Given a size, return an addition amount needed to meet the
* "chunk" needs of the algorithm.
*
* PUBLIC: u_int __aes_adj_size __P((size_t));
*/
u_int
__aes_adj_size(len)
size_t len;
{
if (len % DB_AES_CHUNK == 0)
return (0);
return (DB_AES_CHUNK - (u_int)(len % DB_AES_CHUNK));
}
/*
* __aes_close --
* Destroy the AES encryption instantiation.
*
* PUBLIC: int __aes_close __P((DB_ENV *, void *));
*/
int
__aes_close(dbenv, data)
DB_ENV *dbenv;
void *data;
{
__os_free(dbenv, data);
return (0);
}
/*
* __aes_decrypt --
* Decrypt data with AES.
*
* PUBLIC: int __aes_decrypt __P((DB_ENV *, void *, void *,
* PUBLIC: u_int8_t *, size_t));
*/
int
__aes_decrypt(dbenv, aes_data, iv, cipher, cipher_len)
DB_ENV *dbenv;
void *aes_data;
void *iv;
u_int8_t *cipher;
size_t cipher_len;
{
AES_CIPHER *aes;
cipherInstance c;
int ret;
aes = (AES_CIPHER *)aes_data;
if (iv == NULL || cipher == NULL)
return (EINVAL);
if ((cipher_len % DB_AES_CHUNK) != 0)
return (EINVAL);
/*
* Initialize the cipher
*/
if ((ret = __db_cipherInit(&c, MODE_CBC, iv)) < 0) {
__aes_err(dbenv, ret);
return (EAGAIN);
}
/* Do the decryption */
if ((ret = __db_blockDecrypt(&c, &aes->decrypt_ki, cipher,
cipher_len * 8, cipher)) < 0) {
__aes_err(dbenv, ret);
return (EAGAIN);
}
return (0);
}
/*
* __aes_encrypt --
* Encrypt data with AES.
*
* PUBLIC: int __aes_encrypt __P((DB_ENV *, void *, void *,
* PUBLIC: u_int8_t *, size_t));
*/
int
__aes_encrypt(dbenv, aes_data, iv, data, data_len)
DB_ENV *dbenv;
void *aes_data;
void *iv;
u_int8_t *data;
size_t data_len;
{
AES_CIPHER *aes;
cipherInstance c;
u_int32_t tmp_iv[DB_IV_BYTES/4];
int ret;
aes = (AES_CIPHER *)aes_data;
if (aes == NULL || data == NULL)
return (EINVAL);
if ((data_len % DB_AES_CHUNK) != 0)
return (EINVAL);
/*
* Generate the IV here. We store it in a tmp IV because
* the IV might be stored within the data we are encrypting
* and so we will copy it over to the given location after
* encryption is done.
* We don't do this outside of there because some encryption
* algorithms someone might add may not use IV's and we always
* want on here.
*/
if ((ret = __db_generate_iv(dbenv, tmp_iv)) != 0)
return (ret);
/*
* Initialize the cipher
*/
if ((ret = __db_cipherInit(&c, MODE_CBC, (char *)tmp_iv)) < 0) {
__aes_err(dbenv, ret);
return (EAGAIN);
}
/* Do the encryption */
if ((ret = __db_blockEncrypt(&c, &aes->encrypt_ki, data, data_len * 8,
data)) < 0) {
__aes_err(dbenv, ret);
return (EAGAIN);
}
memcpy(iv, tmp_iv, DB_IV_BYTES);
return (0);
}
/*
* __aes_init --
* Initialize the AES encryption instantiation.
*
* PUBLIC: int __aes_init __P((DB_ENV *, DB_CIPHER *));
*/
int
__aes_init(dbenv, db_cipher)
DB_ENV *dbenv;
DB_CIPHER *db_cipher;
{
return (__aes_derivekeys(dbenv, db_cipher, (u_int8_t *)dbenv->passwd,
dbenv->passwd_len));
}
static int
__aes_derivekeys(dbenv, db_cipher, passwd, plen)
DB_ENV *dbenv;
DB_CIPHER *db_cipher;
u_int8_t *passwd;
size_t plen;
{
SHA1_CTX ctx;
AES_CIPHER *aes;
int ret;
u_int32_t temp[DB_MAC_KEY/4];
if (passwd == NULL)
return (EINVAL);
aes = (AES_CIPHER *)db_cipher->data;
/* Derive the crypto keys */
__db_SHA1Init(&ctx);
__db_SHA1Update(&ctx, passwd, plen);
__db_SHA1Update(&ctx, (u_int8_t *)DB_ENC_MAGIC, strlen(DB_ENC_MAGIC));
__db_SHA1Update(&ctx, passwd, plen);
__db_SHA1Final((u_int8_t *)temp, &ctx);
if ((ret = __db_makeKey(&aes->encrypt_ki, DIR_ENCRYPT,
DB_AES_KEYLEN, (char *)temp)) != TRUE) {
__aes_err(dbenv, ret);
return (EAGAIN);
}
if ((ret = __db_makeKey(&aes->decrypt_ki, DIR_DECRYPT,
DB_AES_KEYLEN, (char *)temp)) != TRUE) {
__aes_err(dbenv, ret);
return (EAGAIN);
}
return (0);
}
/*
* __aes_err --
* Handle AES-specific errors. Codes and messages derived from
* rijndael/rijndael-api-fst.h.
*/
static void
__aes_err(dbenv, err)
DB_ENV *dbenv;
int err;
{
char *errstr;
switch (err) {
case BAD_KEY_DIR:
errstr = "AES key direction is invalid";
break;
case BAD_KEY_MAT:
errstr = "AES key material not of correct length";
break;
case BAD_KEY_INSTANCE:
errstr = "AES key passwd not valid";
break;
case BAD_CIPHER_MODE:
errstr = "AES cipher in wrong state (not initialized)";
break;
case BAD_BLOCK_LENGTH:
errstr = "AES bad block length";
break;
case BAD_CIPHER_INSTANCE:
errstr = "AES cipher instance is invalid";
break;
case BAD_DATA:
errstr = "AES data contents are invalid";
break;
case BAD_OTHER:
errstr = "AES unknown error";
break;
default:
errstr = "AES error unrecognized";
break;
}
__db_err(dbenv, errstr);
return;
}

385
storage/bdb/crypto/crypto.c Normal file
View File

@@ -0,0 +1,385 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* Some parts of this code originally written by Adam Stubblefield
* -- astubble@rice.edu
*
* $Id: crypto.c,v 1.31 2004/10/15 16:59:38 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/crypto.h"
/*
* __crypto_region_init --
* Initialize crypto.
*/
int
__crypto_region_init(dbenv)
DB_ENV *dbenv;
{
REGENV *renv;
REGINFO *infop;
CIPHER *cipher;
DB_CIPHER *db_cipher;
char *sh_passwd;
int ret;
db_cipher = dbenv->crypto_handle;
ret = 0;
infop = dbenv->reginfo;
renv = infop->primary;
MUTEX_LOCK(dbenv, &renv->mutex);
if (renv->cipher_off == INVALID_ROFF) {
if (!CRYPTO_ON(dbenv))
goto err;
if (!F_ISSET(infop, REGION_CREATE)) {
__db_err(dbenv,
"Joining non-encrypted environment with encryption key");
ret = EINVAL;
goto err;
}
if (F_ISSET(db_cipher, CIPHER_ANY)) {
__db_err(dbenv, "Encryption algorithm not supplied");
ret = EINVAL;
goto err;
}
/*
* Must create the shared information. We need:
* Shared cipher information that contains the passwd.
* After we copy the passwd, we smash and free the one in the
* dbenv.
*/
if ((ret = __db_shalloc(
infop, sizeof(CIPHER), MUTEX_ALIGN, &cipher)) != 0)
goto err;
memset(cipher, 0, sizeof(*cipher));
if ((ret = __db_shalloc(
infop, dbenv->passwd_len, 0, &sh_passwd)) != 0) {
__db_shalloc_free(infop, cipher);
goto err;
}
memset(sh_passwd, 0, dbenv->passwd_len);
cipher->passwd = R_OFFSET(infop, sh_passwd);
cipher->passwd_len = dbenv->passwd_len;
cipher->flags = db_cipher->alg;
memcpy(sh_passwd, dbenv->passwd, cipher->passwd_len);
renv->cipher_off = R_OFFSET(infop, cipher);
} else {
if (!CRYPTO_ON(dbenv)) {
__db_err(dbenv,
"Encrypted environment: no encryption key supplied");
ret = EINVAL;
goto err;
}
cipher = R_ADDR(infop, renv->cipher_off);
sh_passwd = R_ADDR(infop, cipher->passwd);
if ((cipher->passwd_len != dbenv->passwd_len) ||
memcmp(dbenv->passwd, sh_passwd, cipher->passwd_len) != 0) {
__db_err(dbenv, "Invalid password");
ret = EPERM;
goto err;
}
if (!F_ISSET(db_cipher, CIPHER_ANY) &&
db_cipher->alg != cipher->flags) {
__db_err(dbenv,
"Environment encrypted using a different algorithm");
ret = EINVAL;
goto err;
}
if (F_ISSET(db_cipher, CIPHER_ANY))
/*
* We have CIPHER_ANY and we are joining the
* existing env. Setup our cipher structure
* for whatever algorithm this env has.
*/
if ((ret = __crypto_algsetup(dbenv, db_cipher,
cipher->flags, 0)) != 0)
goto err;
}
MUTEX_UNLOCK(dbenv, &renv->mutex);
ret = db_cipher->init(dbenv, db_cipher);
/*
* On success, no matter if we allocated it or are using the
* already existing one, we are done with the passwd in the dbenv.
* We smash N-1 bytes so that we don't overwrite the nul.
*/
memset(dbenv->passwd, 0xff, dbenv->passwd_len-1);
__os_free(dbenv, dbenv->passwd);
dbenv->passwd = NULL;
dbenv->passwd_len = 0;
if (0) {
err: MUTEX_UNLOCK(dbenv, &renv->mutex);
}
return (ret);
}
/*
* __crypto_dbenv_close --
* Crypto-specific destruction of DB_ENV structure.
*
* PUBLIC: int __crypto_dbenv_close __P((DB_ENV *));
*/
int
__crypto_dbenv_close(dbenv)
DB_ENV *dbenv;
{
DB_CIPHER *db_cipher;
int ret;
ret = 0;
db_cipher = dbenv->crypto_handle;
if (dbenv->passwd != NULL) {
memset(dbenv->passwd, 0xff, dbenv->passwd_len-1);
__os_free(dbenv, dbenv->passwd);
dbenv->passwd = NULL;
}
if (!CRYPTO_ON(dbenv))
return (0);
if (!F_ISSET(db_cipher, CIPHER_ANY))
ret = db_cipher->close(dbenv, db_cipher->data);
__os_free(dbenv, db_cipher);
return (ret);
}
/*
* __crypto_region_destroy --
* Destroy any system resources allocated in the primary region.
*
* PUBLIC: int __crypto_region_destroy __P((DB_ENV *));
*/
int
__crypto_region_destroy(dbenv)
DB_ENV *dbenv;
{
CIPHER *cipher;
REGENV *renv;
REGINFO *infop;
infop = dbenv->reginfo;
renv = infop->primary;
if (renv->cipher_off != INVALID_ROFF) {
cipher = R_ADDR(infop, renv->cipher_off);
__db_shalloc_free(infop, R_ADDR(infop, cipher->passwd));
__db_shalloc_free(infop, cipher);
}
return (0);
}
/*
* __crypto_algsetup --
* Given a db_cipher structure and a valid algorithm flag, call
* the specific algorithm setup function.
*
* PUBLIC: int __crypto_algsetup __P((DB_ENV *, DB_CIPHER *, u_int32_t, int));
*/
int
__crypto_algsetup(dbenv, db_cipher, alg, do_init)
DB_ENV *dbenv;
DB_CIPHER *db_cipher;
u_int32_t alg;
int do_init;
{
int ret;
ret = 0;
if (!CRYPTO_ON(dbenv)) {
__db_err(dbenv, "No cipher structure given");
return (EINVAL);
}
F_CLR(db_cipher, CIPHER_ANY);
switch (alg) {
case CIPHER_AES:
db_cipher->alg = CIPHER_AES;
ret = __aes_setup(dbenv, db_cipher);
break;
default:
__db_panic(dbenv, EINVAL);
/* NOTREACHED */
}
if (do_init)
ret = db_cipher->init(dbenv, db_cipher);
return (ret);
}
/*
* __crypto_decrypt_meta --
* Perform decryption on a metapage if needed.
*
* PUBLIC: int __crypto_decrypt_meta __P((DB_ENV *, DB *, u_int8_t *, int));
*/
int
__crypto_decrypt_meta(dbenv, dbp, mbuf, do_metachk)
DB_ENV *dbenv;
DB *dbp;
u_int8_t *mbuf;
int do_metachk;
{
DB_CIPHER *db_cipher;
DB dummydb;
DBMETA *meta;
size_t pg_off;
int ret;
u_int8_t *iv;
/*
* If we weren't given a dbp, we just want to decrypt the page
* on behalf of some internal subsystem, not on behalf of a user
* with a dbp. Therefore, set up a dummy dbp so that the call
* to P_OVERHEAD below works.
*/
if (dbp == NULL) {
memset(&dummydb, 0, sizeof(DB));
dbp = &dummydb;
}
/*
* Meta-pages may be encrypted for DBMETASIZE bytes. If
* we have a non-zero IV (that is written after encryption)
* then we decrypt (or error if the user isn't set up for
* security). We guarantee that the IV space on non-encrypted
* pages will be zero and a zero-IV is illegal for encryption.
* Therefore any non-zero IV means an encrypted database.
* This basically checks the passwd on the file
* if we cannot find a good magic number.
* We walk through all the algorithms we know about attempting
* to decrypt (and possibly byteswap).
*
* !!!
* All method meta pages have the IV and checksum at the
* exact same location, but not in DBMETA, use BTMETA.
*/
ret = 0;
meta = (DBMETA *)mbuf;
if (meta->encrypt_alg != 0) {
db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
if (!F_ISSET(dbp, DB_AM_ENCRYPT)) {
if (!CRYPTO_ON(dbenv)) {
__db_err(dbenv,
"Encrypted database: no encryption flag specified");
return (EINVAL);
}
/*
* User has a correct, secure env, but has
* encountered a database in that env that is
* secure, but user didn't dbp->set_flags. Since
* it is existing, use encryption if it is that
* way already.
*/
F_SET(dbp, DB_AM_ENCRYPT|DB_AM_CHKSUM);
}
/*
* This was checked in set_flags when DB_AM_ENCRYPT was set.
* So it better still be true here.
*/
DB_ASSERT(CRYPTO_ON(dbenv));
if (!F_ISSET(db_cipher, CIPHER_ANY) &&
meta->encrypt_alg != db_cipher->alg) {
__db_err(dbenv,
"Database encrypted using a different algorithm");
return (EINVAL);
}
DB_ASSERT(F_ISSET(dbp, DB_AM_CHKSUM));
iv = ((BTMETA *)mbuf)->iv;
/*
* For ALL pages, we do not encrypt the beginning
* of the page that contains overhead information.
* This is true of meta and all other pages.
*/
pg_off = P_OVERHEAD(dbp);
alg_retry:
/*
* If they asked for a specific algorithm, then
* use it. Otherwise walk through those we know.
*/
if (!F_ISSET(db_cipher, CIPHER_ANY)) {
if (do_metachk && (ret = db_cipher->decrypt(dbenv,
db_cipher->data, iv, mbuf + pg_off,
DBMETASIZE - pg_off)))
return (ret);
if (((BTMETA *)meta)->crypto_magic !=
meta->magic) {
__db_err(dbenv, "Invalid password");
return (EINVAL);
}
/*
* Success here. The algorithm asked for and the one
* on the file match. We've just decrypted the meta
* page and checked the magic numbers. They match,
* indicating the password is right. All is right
* with the world.
*/
return (0);
}
/*
* If we get here, CIPHER_ANY must be set.
*/
ret = __crypto_algsetup(dbenv, db_cipher, meta->encrypt_alg, 1);
goto alg_retry;
} else if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
/*
* They gave us a passwd, but the database is not
* encrypted. This is an error. We do NOT want to
* silently allow them to write data in the clear when
* the user set up and expects encrypted data.
*
* This covers at least the following scenario.
* 1. User creates and sets up an encrypted database.
* 2. Attacker cannot read the actual data in the database
* because it is encrypted, but can remove/replace the file
* with an empty, unencrypted database file.
* 3. User sets encryption and we get to this code now.
* If we allowed the file to be used in the clear since
* it is that way on disk, the user would unsuspectingly
* write sensitive data in the clear.
* 4. Attacker reads data that user thought was encrypted.
*
* Therefore, asking for encryption with a database that
* was not encrypted is an error.
*/
__db_err(dbenv,
"Unencrypted database with a supplied encryption key");
return (EINVAL);
}
return (ret);
}
/*
* __crypto_set_passwd --
* Get the password from the shared region; and set it in a new
* environment handle. Use this to duplicate environment handles.
*
* PUBLIC: int __crypto_set_passwd __P((DB_ENV *, DB_ENV *));
*/
int
__crypto_set_passwd(dbenv_src, dbenv_dest)
DB_ENV *dbenv_src, *dbenv_dest;
{
CIPHER *cipher;
REGENV *renv;
REGINFO *infop;
char *sh_passwd;
int ret;
ret = 0;
infop = dbenv_src->reginfo;
renv = infop->primary;
DB_ASSERT(CRYPTO_ON(dbenv_src));
cipher = R_ADDR(infop, renv->cipher_off);
sh_passwd = R_ADDR(infop, cipher->passwd);
return (__dbenv_set_encrypt(dbenv_dest, sh_passwd, DB_ENCRYPT_AES));
}

View File

@@ -0,0 +1,639 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.76 [en] (X11; U; FreeBSD 4.3-RELEASE i386) [Netscape]">
</head>
<body>
<center>
<h1>
&nbsp;Security Interface for Berkeley DB</h1></center>
<center><i>Susan LoVerso</i>
<br><i>sue@sleepycat.com</i>
<br><i>Rev 1.6</i>
<br><i>2002 Feb 26</i></center>
<p>We provide an interface allowing secure access to Berkeley DB.&nbsp;&nbsp;
Our goal is to allow users to have encrypted secure databases.&nbsp; In
this document, the term <i>ciphering</i> means the act of encryption or
decryption.&nbsp; They are equal but opposite actions and the same issues
apply to both just in the opposite direction.
<h3>
Requirements</h3>
The overriding requirement is to provide a simple mechanism to allow users
to have a secure database.&nbsp; A secure database means that all of the
pages of a database will be encrypted, and all of the log files will be
encrypted.
<p>Falling out from this work will be a simple mechanism to allow users
to request that we checksum their data for additional error detection (without
encryption/decryption).
<p>We expect that data in process memory or stored in shared memory, potentially
backed by disk, is not encrypted or secure.
<h2>
<a NAME="DB Modifications"></a>DB Method Interface Modifications</h2>
With a logging environment, all database changes are recorded in the log
files.&nbsp; Therefore, users requiring secure databases in such environments
also require secure log files.
<p>A prior thought had been to allow different passwords on the environment
and the databases within.&nbsp; However, such a scheme, then requires that
the password be logged in order for recovery to be able to restore the
database.&nbsp; Therefore, any application having the password for the
log could get the password for any databases by reading the log.&nbsp;
So having a different password on a database does not gain any additional
security and it makes certain things harder and more complex.&nbsp; Some
of those more complex things include the need to handle database and env
passwords differently since they'd need to be stored and accessed from
different places.&nbsp; Also resolving the issue of how <i>db_checkpoint</i>
or <i>db_sync</i>, which flush database pages to disk, would find the passwords
of various databases without any dbps was unsolved.&nbsp; The feature didn't
gain anything and caused significant pain.&nbsp; Therefore the decision
is that there will be a single password protecting an environment and all
the logs and some databases within that environment.&nbsp; We do allow
users to have a secure environment and clear databases.&nbsp; Users that
want secure databases within a secure environment must set a flag.
<p>Users wishing to enable encryption on a database in a secure environment
or enable just checksumming on their database pages will use new flags
to <a href="../docs/api_c/db_set_flags.html">DB->set_flags()</a>.&nbsp;
Providing ciphering over an entire environment is accomplished by adding
a single environment method: <a href="../docs/api_c/env_set_encrypt.html">DBENV->set_encrypt()</a>.&nbsp;
Providing encryption for a database (not part of an environment) is accomplished
by adding a new database method: <a href="../docs/api_c/db_set_encrypt.html">DB->set_encrypt()</a>.
<p>Both of the <i>set_encrypt</i> methods must be called before their respective
<i>open</i> calls.&nbsp; The environment method must be before the environment
open because we must know about security before there is any possibility
of writing any log records out.&nbsp; The database method must be before
the database open in order to read the root page.&nbsp; The planned interfaces
for these methods are:
<pre>DBENV->set_encrypt(DBENV *dbenv,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* DB_ENV structure */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *passwd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Password */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int32_t flags);&nbsp;&nbsp;&nbsp;&nbsp; /* Flags */</pre>
<pre>DB->set_encrypt(DB *dbp,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* DB structure */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *passwd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Password */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int32_t flags);&nbsp;&nbsp;&nbsp;&nbsp; /* Flags */</pre>
The flags accepted by these functions are:
<pre>#define DB_ENCRYPT_AES&nbsp; 0x00000001&nbsp; /* Use the AES encryption algorithm */</pre>
Passwords are NULL-terminated strings.&nbsp; NULL or zero length strings
are illegal.&nbsp; These flags enable the checksumming and encryption using
the particular algorithms we have chosen for this implementation.&nbsp;
The flags are named such that there is a logical naming pattern if additional
checksum or encryption algorithms are used. If a user gives a flag of zero,
it will behave in a manner similar to DB_UNKNOWN. It will be illegal if
they are creating the environment or database, as an algorithm must be
specified. If they are joining an existing environment or opening an existing
database, they will use whatever algorithm is in force at the time.&nbsp;
Using DB_ENCRYPT_AES automatically implies SHA1 checksumming.
<p>These functions will perform several initialization steps.&nbsp; We
will allocate crypto_handle for our env handle and set up our function
pointers.&nbsp; We will allocate space and copy the password into our env
handle password area.&nbsp; Similar to <i>DB->set_cachesize</i>, calling
<i>DB->set_encrypt</i>
will actually reflect back into the local environment created by DB.
<p>Lastly, we will add a new flag, DB_OVERWRITE, to the <a href="../docs/api_c/env_remove.html">DBENV->remove</a>
method.&nbsp; The purpose of this flag is to force all of the memory used
by the shared regions to be overwritten before removal.&nbsp; We will use
<i>rm_overwrite</i>,
a function that overwrites and syncs a file 3 times with varying bit patterns
to really remove a file.&nbsp; Additionally, this flag will force a sync
of the overwritten regions to disk, if the regions are backed by the file
system.&nbsp; That way there is no residual information left in the clear
in memory or freed disk blocks.&nbsp; Although we expect that this flag
will be used by customers using security, primarily, its action is not
dependent on passwords or a secure setup, and so can be used by anyone.
<h4>
Initialization of the Environment</h4>
The setup of the security subsystem will be similar to replication initialization
since it is a sort of subsystem, but it does not have its own region.&nbsp;
When the environment handle is created via <i>db_env_create</i>, we initialize
our <i>set_encrypt</i> method to be the RPC or local version.&nbsp; Therefore
the <i>__dbenv</i> structure needs a new pointer:
<pre>&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp; *crypto_handle;&nbsp;&nbsp; /* Security handle */</pre>
The crypto handle will really point to a new <i>__db_cipher</i> structure
that will contain a set of functions and a pointer to the in-memory information
needed by the specific encryption algorithm.&nbsp; It will look like:
<pre>typedef struct __db_cipher {
&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*init)__P((...));&nbsp;&nbsp;&nbsp; /* Alg-specific initialization function */
&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*encrypt)__P((...)); /* Alg-specific encryption algorithm */
&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*decrypt)__P((...)); /* Alg-specific decryption function */
&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *data;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Pointer to alg-specific information (AES_CIPHER) */
&nbsp;&nbsp;&nbsp; u_int32_t flags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Cipher flags */
} DB_CIPHER;</pre>
<pre>#define DB_MAC_KEY&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp; /* Size of the MAC key */
typedef struct __aes_cipher {
&nbsp;&nbsp;&nbsp; keyInstance&nbsp;&nbsp;&nbsp; encrypt_ki;&nbsp;&nbsp; /* Encrypt keyInstance temp. */
&nbsp;&nbsp;&nbsp; keyInstance&nbsp;&nbsp;&nbsp; decrypt_ki;&nbsp;&nbsp; /* Decrypt keyInstance temp. */
&nbsp;&nbsp;&nbsp; u_int8_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mac_key[DB_MAC_KEY]; /* MAC key */
&nbsp;&nbsp;&nbsp; u_int32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* AES-specific flags */
} AES_CIPHER;</pre>
It should be noted that none of these structures have their own mutex.&nbsp;
We hold the environment region locked while we are creating this, but once
this is set up, it is read-only forever.
<p>During <a href="../docs/api_c/env_set_encrypt.html">dbenv->set_encrypt</a>,
we set the encryption, decryption and checksumming methods to the appropriate
functions based on the flags.&nbsp; This function will allocate us a crypto
handle that we store in the <i>__dbenv</i> structure just like all the
other subsystems.&nbsp; For now, only AES ciphering functions and SHA1
checksumming functions are supported.&nbsp; Also we will copy the password
into the <i>__dbenv</i> structure.&nbsp; We ultimately need to keep the
password in the environment's shared memory region or compare this one
against the one that is there, if we are joining an existing environment,
but we do not have it yet because open has not yet been called.&nbsp; We
will allocate a structure that will be used in initialization and set up
the function pointers to point to the algorithm-specific functions.
<p>In the&nbsp; <i>__dbenv_open</i> path, in <i>__db_e_attach</i>, if we
are creating the region and the <i>dbenv->passwd</i> field is set, we need
to use the length of the password in the initial computation of the environment's
size.&nbsp; This guarantees sufficient space for storing the password in
shared memory.&nbsp; Then we will call a new function to initialize the
security region, <i>__crypto_region_init</i> in <i>__dbenv_open</i>.&nbsp;
If we are the creator, we will allocate space in the shared region to store
the password and copy the password into that space.&nbsp; Or, if we are
not the creator we will compare the password stored in the dbenv with the
one in shared memory.&nbsp;&nbsp; Additionally, we will compare the ciphering
algorithm to the one stored in the shared region.We'll smash the dbenv
password and free it.&nbsp; If they do not match, we return an error.&nbsp;
If we are the creator we store the offset into the REGENV structure.&nbsp;
Then <i>__crypto_region_init&nbsp;</i> will call the initialization function
set up earlier based on the ciphering algorithm specified.&nbsp; For now
we will call <i>__aes_init</i>.&nbsp; Additionally this function will allocate
and set up the per-process state vector for this encryption's IVs.&nbsp;
See <a href="#Generating the Initialization Vector">Generating the Initialization
Vector</a> for a detailed description of the IV and state vector.
<p>In the AES-specific initialization function, <i>__aes_init</i>,&nbsp;
we will initialize it by calling
<i>__aes_derivekeys</i> in order to fill
in the keyInstance and mac_key fields in that structure.&nbsp; The REGENV
structure will have one additional item
<pre>&nbsp;&nbsp; roff_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; passwd_off;&nbsp;&nbsp; /* Offset of passwd */</pre>
<h4>
Initializing a Database</h4>
During <a href="../docs/api_c/db_set_encrypt.html">db->set_encrypt</a>,
we set the encryption, decryption and checksumming methods to the appropriate
functions based on the flags.&nbsp; Basically, we test that we are not
in an existing environment and we haven't called open.&nbsp; Then we just
call through the environment handle to set the password.
<p>Also, we will need to add a flag in the database meta-data page that
indicates that the database is encrypted and what its algorithm is.&nbsp;
This will be used when the meta-page is read after reopening a file. We
need this information on the meta-page in order to detect a user opening
a secure database without a password.&nbsp; I propose using the first unused1
byte (renaming it too) in the meta page for this purpose.
<p>All pages will not be encrypted for the first 64 bytes of data.&nbsp;
Database meta-pages will be encrypted on the first 512 bytes only.&nbsp;
All meta-page types will have an IV and checksum added within the first
512 bytes as well as a crypto magic number.&nbsp; This will expand the
size of the meta-page from 256 bytes to 512 bytes. The page in/out routines,
<i>__db_pgin</i> and <i>__db_pgout</i> know the page type of the page and
will apply the 512 bytes ciphering to meta pages.&nbsp; In <i>__db_pgout</i>,
if we have a crypto handle in our (private) environment, we will apply
ciphering to either the entire page, or the first 512 bytes if it is a
meta-page.&nbsp; In <i>__db_pgin</i>, we will decrypt if the page we have
a crypto handle.
<p>When multiple processes share a database, all must use the same password
as the database creator. Using an existing database requires several conditions
to be true.&nbsp; First, if the creator of the database did not create
with security, then opening later with security is an error.&nbsp; Second,
if the creator did create it with security, then opening later without
security is an error.&nbsp; Third, we need to be able to test and check
that when another process opens a secure database that the password they
provided is the same as the one in use by the creator.
<p>When reading the meta-page, in <i>__db_file_setup</i>, we do not go
through the paging functions, but directly read via <i>__os_read</i>.&nbsp;
It is at this point that we will determine if the user is configured correctly.&nbsp;
If the meta-page we read has an IV and checksum, they better have a crypto
handle.&nbsp; If they have a crypto handle, then the meta-page must have
an IV and checksum.&nbsp; If both of those are true, we test the password.&nbsp;
We compare the unencrypted magic number to the newly-decrypted crypto magic
number and if they are not the same, then we report that the user gave
us a bad password.
<p>On a mostly unrelated topic, even when we go to very large pagesizes,
the meta information will still be within a disk sector.&nbsp; So, after
talking it over with Keith and Margo, we determined that unencrypted meta-pages
still will not need a checksum.
<h3>
Encryption and Checksum Routines</h3>
These routines are provided to us by Adam Stubblefield at Rice University
(astubble@rice.edu).&nbsp; The functional interfaces are:
<pre>__aes_derivekeys(DB_ENV *dbenv,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* dbenv */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *passwd,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Password */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t passwd_len,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Length of passwd */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *mac_key,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 20 byte array to store MAC key */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keyInstance *encrypt_key,&nbsp;&nbsp; /* Encryption key of passwd */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keyInstance *decrypt_key);&nbsp; /* Decryption key of passwd */</pre>
This is the only function requiring the textual user password.&nbsp; From
the password, this function generates a key used in the checksum function,
<i>__db_chksum</i>.&nbsp;
It also fills in <i>keyInstance</i> structures which are then used in the
encryption and decryption routines.&nbsp; The keyInstance structures must
already be allocated.&nbsp; These will be stored in the AES_CIPHER structure.
<pre>&nbsp;__db_chksum(u_int8_t *data,&nbsp;&nbsp;&nbsp; /* Data to checksum */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t data_len,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Length of data */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *mac_key,&nbsp;&nbsp;&nbsp; /* 20 byte array from __db_derive_keys */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *checksum);&nbsp; /* 20 byte array to store checksum */</pre>
This function generates a checksum on the data given.&nbsp; This function
will do double-duty for users that simply want error detection on their
pages.&nbsp; When users are using encryption, the <i>mac_key </i>will contain
the 20-byte key set up in <i>__aes_derivekeys</i>.&nbsp; If they just want
checksumming, then <i>mac_key</i> will be NULL.&nbsp; According to Adam,
we can safely use the first N-bytes of the checksum.&nbsp; So for seeding
the generator for initialization vectors, we'll hash the time and then
send in the first 4 bytes for the seed.&nbsp; I believe we can probably
do the same thing for checksumming log records.&nbsp; We can only use 4
bytes for the checksum in the non-secure case.&nbsp; So when we want to
verify the log checksum we can compute the mac but just compare the first
4 bytes to the one we read.&nbsp; All locations where we generate or check
log record checksums that currently call <i>__ham_func4</i> will now call
<i>__db_chksum</i>.&nbsp;
I believe there are 5 such locations,
<i>__log_put, __log_putr, __log_newfile,
__log_rep_put
</i>and<i> __txn_force_abort.</i>
<pre>__aes_encrypt(DB_ENV *dbenv,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* dbenv */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keyInstance *key,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Password key instance from __db_derive_keys */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *iv,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Initialization vector */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *data,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Data to encrypt */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t data_len);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Length of data to encrypt - 16 byte multiple */</pre>
This is the function to encrypt data.&nbsp; It will be called to encrypt
pages and log records.&nbsp; The <i>key</i> instance is initialized in
<i>__aes_derivekeys</i>.&nbsp;
The initialization vector, <i>iv</i>, is the 16 byte random value set up
by the Mersenne Twister pseudo-random generator.&nbsp; Lastly, we pass
in a pointer to the <i>data</i> to encrypt and its length in <i>data_len</i>.&nbsp;
The <i>data_len</i> must be a multiple of 16 bytes. The encryption is done
in-place so that when the encryption code returns our encrypted data is
in the same location as the original data.
<pre>__aes_decrypt(DB_ENV *dbenv,&nbsp;&nbsp;&nbsp; /* dbenv */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keyInstance *key,&nbsp; /* Password key instance from __db_derive_keys */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *iv,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Initialization vector */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u_int8_t *data,&nbsp;&nbsp;&nbsp; /* Data to decrypt */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t data_len);&nbsp; /* Length of data to decrypt - 16 byte multiple */</pre>
This is the function to decrypt the data.&nbsp; It is exactly the same
as the encryption function except for the action it performs.&nbsp; All
of the args and issues are the same.&nbsp; It also decrypts in place.
<h3>
<a NAME="Generating the Initialization Vector"></a>Generating the Initialization
Vector</h3>
Internally, we need to provide a unique initialization vector (IV) of 16
bytes every time we encrypt any data with the same password.&nbsp; For
the IV we are planning on using mt19937, the Mersenne Twister, a random
number generator that has a period of 2**19937-1. This package can be found
at <a href="http://www.math.keio.ac.jp/~matumoto/emt.html">http://www.math.keio.ac.jp/~matumoto/emt.html</a>.&nbsp;
Tests show that although it repeats a single integer every once in a while,
that after several million iterations, it doesn't repeat any 4 integers
that we'd be stuffing into our 16-byte IV.&nbsp; We plan on seeding this
generator with the time (tv_sec) hashed through SHA1 when we create the
environment.&nbsp; This package uses a global state vector that contains
624 unsigned long integers.&nbsp; We do not allow a 16-byte IV of zero.&nbsp;
It is simpler just to reject any 4-byte value of 0 and if we get one, just
call the generator again and get a different number.&nbsp; We need to detect
holes in files and if we read an IV of zero that is a simple indication
that we need to check for an entire page of zero.&nbsp; The IVs are stored
on the page after encryption and are not encrypted themselves so it is
not possible for an entire encrypted page to be read as all zeroes, unless
it was a hole in a file.&nbsp; See <a href="#Holes in Files">Holes in Files</a>
for more details.
<p>We will not be holding any locks when we need to generate our IV but
we need to protect access to the state vector and the index.&nbsp; Calls
to the MT code will come while encrypting some data in <i>__aes_encrypt.</i>&nbsp;&nbsp;
The MT code will assume that all necessary locks are held in the caller.&nbsp;
We will have per-process state vectors that are set up when a process begins.&nbsp;
That way we minimize the contention and only multi-threaded processes need
acquire locks for the IV.&nbsp; We will have the state vector in the environment
handle in heap memory, as well as the index and there will be a mutex protecting
it for threaded access.&nbsp; This will be added to the <i>__dbenv</i>
structure:
<pre>&nbsp;&nbsp;&nbsp; DB_MUTEX&nbsp;&nbsp;&nbsp; *mt_mutexp;&nbsp;&nbsp; /* Mersenne Twister mutex */
&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *mti;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* MT index */
&nbsp;&nbsp;&nbsp; u_long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *mt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* MT state vector */</pre>
This portion of the environment will be initialized at the end of _<i>_dbenv_open</i>,
right after we initialize the other mutex for the <i>dblist</i>. When we
allocate the space, we will generate our initial state vector. If we are
multi-threaded we'll allocate and initialize our mutex also.
<p>We need to make changes to the MT code to make it work in our namespace
and&nbsp; to take&nbsp; a pointer to the location of the state vector and
the index.&nbsp;&nbsp; There will be a wrapper function <i>__db_generate_iv</i>
that DB will call and it will call the appropriate MT function.&nbsp; I
am also going to change the default seed to use a hashed time instead of
a hard coded value.&nbsp; I have looked at other implementations of the
MT code available on the web site.&nbsp; The C++ version does a hash on
the current time.&nbsp; I will modify our MT code to seed with the hashed
time as well.&nbsp; That way the code to seed is contained within the MT
code and we can just write the wrapper to get an IV.&nbsp; We will not
be changing the core computational code of MT.
<h2>
DB Internal Issues</h2>
<h4>
When do we Cipher?</h4>
All of the page ciphering is done in the <i>__db_pgin/__db_pgout</i> functions.&nbsp;
We will encrypt after the method-specific function on page-out and decrypt
before the method-specfic function on page-in.&nbsp; We do not hold any
locks when entering these functions.&nbsp; We determine that we need to
cipher based on the existence of the encryption flag in the dbp.
<p>For ciphering log records, the encryption will be done as the first
thing (or a new wrapper) in <i>__log_put.&nbsp; </i>See <a href="#Log Record Encryption">Log
Record Encryption</a> for those details.
<br>&nbsp;
<h4>
Page Changes</h4>
The checksum and IV values will be stored prior to the first index of the
page.&nbsp; We have a new P_INP macro that replaces use of inp[X] in the
code. &nbsp;This macro takes a dbp as an argument and determines where
our first index is based on whether we have DB_AM_CHKSUM and DB_AM_ENCRYPT
set.&nbsp; If neither is set, then our first index is where it always was.
&nbsp;If just checksumming is set, then we reserve a 4-byte checksum.&nbsp;
If encryption is set, then we reserve 36 bytes for our checksum/IV as well
as some space to get proper alignment to encrypt on a 16-byte boundary.
<p>Since several paging macros use inp[X] in them, those macros must now
take a dbp.&nbsp; There are a lot of changes to make all the necessary
paging macros take a dbp, although these changes are trivial in nature.
<p>Also, there is a new function <i>__db_chk_meta</i> to perform checksumming
and decryption checking on meta pages specifically.&nbsp; This function
is where we check that the database algorithm matches what the user gave
(or if they set DB_CIPHER_ANY then we set it), and other encryption related
testing for bad combinations of what is in the file versus what is in the
user structures.
<h4>
Verification</h4>
The verification code will also need to be updated to deal with secure
pages.&nbsp; Basically when the verification code reads in the meta page
it will call <i>__db_chk_meta</i> to perform any checksumming and decryption.
<h4>
<a NAME="Holes in Files"></a>Holes in Files</h4>
Holes in files will be dealt with rather simply.&nbsp; We need to be able
to distinguish reading a hole in a file from an encrypted page that happened
to encrypt to all zero's.&nbsp; If we read a hole in a file, we do not
want to send that empty page through the decryption routine.&nbsp; This
can be determined simply without incurring the performance penalty of comparing
every byte on a page on every read until we get a non-zero byte.
<br>The __db_pgin function is only given an invalid page P_INVALID in this
case.&nbsp;&nbsp;So, if the page type, which is always unencrypted, is
P_INVALID, then we do not perform any checksum verification or decryption.
<h4>
Errors and Recovery</h4>
Dealing with a checksum error is tricky.&nbsp; Ultimately, if a checksum
error occurs it is extremely likely that the user must do catastrophic
recovery.&nbsp; There is no other failure return other than&nbsp; DB_RUNRECOVERY
for indicating that the user should run catastrophic recovery.&nbsp; We
do not want to add a new error return for applications to check because
a lot of applications already look for and deal with DB_RUNRECOVERY as
an error condition and we want to fit ourselves into that application model.&nbsp;
We already indicate to the user that when they get that error, then they
need to run recovery.&nbsp; If recovery fails, then they need to run catastrophic
recovery.&nbsp; We need to get ourselves to the point where users will
run catastrophic recovery.
<p>If we get a checksum error, then we need to log a message stating a
checksum error occurred on page N.&nbsp; In <i>__db_pgin</i>, we can check
if logging is on in the environment.&nbsp; If so, we want to log the message.
<p>When the application gets the DB_RUNRECOVERY error, they'll have to
shut down their application and run recovery.&nbsp; When the recovery encounters
the record indicating checksum failure, then normal recovery will fail
and the user will have to perform catastrophic recovery.&nbsp; When catastrophic
recovery encounters that record, it will simply ignore it.
<h4>
<a NAME="Log Record Encryption"></a>Log Record Encryption</h4>
Log records will be ciphered.&nbsp; It might make sense to wrap <i>__log_put</i>
to encrypt the DBT we send down.&nbsp; The <i>__log_put </i>function is
where the checksum is computed before acquiring the region lock.&nbsp;
But also this function is where we call <i>__rep_send_message</i> to send
the DBT to the replication clients.&nbsp; Therefore, we need the DBT to
be encrypted prior to there.&nbsp; We also need it encrypted before checksumming.
I think <i>__log_put </i>will become <i>__log_put_internal</i>, and the
new <i>__log_put</i> will encrypt if needed and then call <i>__log_put_internal
</i>(the
function formerly known as <i>__log_put</i>).&nbsp; Log records are kept
in a shared memory region buffer prior to going out to disk.&nbsp; Records
in the buffer will be encrypted.&nbsp; No locks are held at the time we
will need to encrypt.
<p>On reading the log, via log cursors, the log code stores log records
in the log buffer.&nbsp; Records in that buffer will be encrypted, so decryption
will occur no matter whether we are returning records from the buffer or
if we are returning log records directly from the disk. Current checksum
checking is done in
<i>__log_get_c_int.</i>&nbsp; Decryption will be done
after the checksum is checked.
<p>There are currently two nasty issues with encrypted log records.&nbsp;
The first is that <i>__txn_force_abort</i> overwrites a commit record in
the log buffer with an abort record.&nbsp; Well, our log buffer will be
encrypted.&nbsp; Therefore, <i>__txn_force_abort</i> is going to need to
do encryption of its new record.&nbsp; This can be accomplished by sending
in the dbenv handle to the function.&nbsp; It is available to us in <i>__log_flush_commit</i>
and we can just pass it in.&nbsp; I don't like putting log encryption in
the txn code, but the layering violation is already there.
<p>The second issue is that the encryption code requires data that is a
multiple of 16 bytes and log record lengths are variable.&nbsp; We will
need to pad log records to meet the requirement.&nbsp; Since the callers
of <i>__log_put</i> set up the given DBT it is a logical place to pad if
necessary. We will modify the gen_rec.awk script to have all of the generated
logging functions pad for us if we have a crypto handle. This padding will
also expand the size of log files. Anyone calling <i>log_put</i> and using
security from the application will have to pad on their own or it will
return an error.
<p>When ciphering the log file, we will need a different header than the
current one.&nbsp; The current header only has space for a 4 byte checksum.&nbsp;
Our secure header will need space for the 16 byte IV and 20 byte checksum.&nbsp;
This will blow up our log files when running securely since every single
log record header will now consume 32 additional bytes.&nbsp; I believe
that the log header does not need to be encrypted.&nbsp; It contains an
offset, a length and our IV and checksum.&nbsp; Our IV and checksum are
never encrypted.&nbsp; I don't believe there to be any risk in having the
offset and length in the clear.
<p>I would prefer not to have two types of log headers that are incompatible
with each other.&nbsp; It is not acceptable to increase the log headers
of all users from 12 bytes to 44 bytes.&nbsp; Such a change would also
make log files incompatible with earlier releases.&nbsp; Worse even, is
that the <i>cksum</i> field of the header is in between the offset and
len.&nbsp; It would be really convenient if we could have just made a bigger
cksum portion without affecting the location of the other fields.&nbsp;
Oh well.&nbsp; Most customers will not be using encryption and we won't
make them pay the price of the expanded header.&nbsp; Keith indicates that
the log file format is changing with the next release so I will move the
cksum field so it can at least be overlaid.
<p>One method around this would be to have a single internal header that
contains all the information both mechanisms need, but when we write out
the header we choose which pieces to write.&nbsp; By appending the security
information to the end of the existing structure, and adding a size field,
we can modify a few places to use the size field to write out only the
current first 12 bytes, or the entire security header needed.
<h4>
Replication</h4>
Replication clients are going to need to start all of their individual
environment handles with the same password.&nbsp; The log records are going
to be sent to the clients decrypted and the clients will have to encrypt
them on their way to the client log files.&nbsp; We cannot send encrypted
log records to clients. &nbsp;The reason is that the checksum and IV&nbsp;are
stored in the log header and the master only sends the log record itself
to the client. &nbsp;Therefore, the client has no way to decrypt a log
record from the master. &nbsp;Therefore, anyone wanting to use truly secure
replication is going to have to have a secure transport mechanism.&nbsp;
By not encrypting records, clients can theoretically have different passwords
and DB won't care.
<p>On the master side we must copy the DBT sent in.&nbsp; We encrypt the
original and send to clients the clear record.&nbsp; On the client side,
support for encryption is added into <i>__log_rep_put</i>.
<h4>
Sharing the Environment</h4>
When multiple processes join the environment, all must use the same password
as the creator.
<p>Joining an existing environment requires several conditions to be true.&nbsp;
First, if the creator of the environment did not create with security,
then joining later with security is an error.&nbsp; Second, if the creator
did create it with security, then joining later without security is an
error.&nbsp; Third, we need to be able to test and check that when another
process joins a secure environment that the password they provided is the
same as the one in use by the creator.
<p>The first two scenarios should be fairly trivial to determine, if we
aren't creating the environment, we can compare what is there with what
we have.&nbsp; In the third case, the <i>__crypto_region_init</i> function
will see that the environment region has a valid passwd_off and we'll then
compare that password to the one we have in our dbenv handle.&nbsp; In
any case we'll smash the dbenv handle's passwd and free that memory before
returning whether we have a password match or not.
<p>We need to store the passwords themselves in the region because multiple
calls to the <i>__aes_derivekeys </i>function with the same password yields
different keyInstance contents.&nbsp; Therefore we don't have any way to
check passwords other than retaining and comparing the actual passwords.
<h4>
Other APIs</h4>
All of the other APIs will need interface enhancements to support the new
security methods.&nbsp; The Java and C++ interfaces will likely be done
by Michael Cahill and Sue will implement the Tcl and RPC changes.&nbsp;
Tcl will need the changes for testing purposes but the interface should
be public, not test-only.&nbsp; RPC should fully support security.&nbsp;
The biggest risk that I can see is that the client will send the password
to the server in the clear.&nbsp; Anyone sniffing the wires or running
tcpdump or other packet grabbing code could grab that.&nbsp; Someone really
interested in using security over RPC probably ought to add authentication
and other measures to the RPC server as well.
<h4>
<a NAME="Utilities"></a>Utilities</h4>
All should take a -P flag to specify a password for the environment or
password.&nbsp; Those that take an env and a database might need something
more to distinguish between env passwds and db passwds. Here is what we
do for each utility:
<ul>
<li>
berkeley_db_svc - Needs -P after each -h specified.</li>
<li>
db_archive - Needs -P if the env is encrypted.</li>
<li>
db_checkpoint - Needs -P if the env is encrypted.</li>
<li>
db_deadlock - No changes</li>
<li>
db_dump - Needs -P if the env or database is encrypted.</li>
<li>
db_load - Needs -P if the env or database is encrypted.</li>
<li>
db_printlog - Needs -P if the env is encrypted.</li>
<li>
db_recover - Needs -P if the env is encrypted.</li>
<li>
db_stat - Needs -P if the env or database is encrypted.</li>
<li>
db_upgrade - Needs -P if the env or database is encrypted.</li>
<li>
db_verify - Needs -P if the env or database is encrypted.</li>
</ul>
<h2>
Testing</h2>
All testing should be able to be accomplished via Tcl.&nbsp; The following
tests (and probably others I haven't thought of yet) should be performed:
<ul>
<li>
Basic functionality - basically a test001 but encrypted without an env</li>
<li>
Basic functionality, w/ env - like the previous test but with an env.</li>
<li>
Basic functionality, multiple processes - like first test, but make sure
others can correctly join.</li>
<li>
Basic functionality, mult. processes - like above test, but initialize/close
environment/database first so that the next test processes are all joiners
of an existing env, but creator no longer exists and the shared region
must be opened.</li>
<li>
Recovery test - Run recovery over an encrypted environment.</li>
<li>
Subdb test - Run with subdbs that are encrypted.</li>
<li>
Utility test - Verify the new options to all the utilities.</li>
<li>
Error handling - Test the basic setup errors for both env's and databases
with multiple processes.&nbsp; They are:</li>
<ol>
<li>
Attempt to set a NULL or zero-length passwd.</li>
<li>
Create Env w/ security and attempt to create database w/ its own password.</li>
<li>
Env/DB creates with security.&nbsp; Proc2 joins without - should get an
error.</li>
<li>
Env/DB creates without security.&nbsp; Proc2 joins with - should get an
error.</li>
<li>
Env/DB creates with security.&nbsp; Proc2 joins with different password
- should get an error.</li>
<li>
Env/DB creates with security.&nbsp; Closes.&nbsp; Proc2 reopens with different
password - should get an error.</li>
<li>
Env/DB creates with security.&nbsp; Closes.&nbsp; Tcl overwrites a page
of the database with garbage.&nbsp; Proc2 reopens with the correct password.&nbsp;
Code should detect checksum error.</li>
<li>
Env/DB creates with security.&nbsp; Open a 2nd identical DB with a different
password.&nbsp; Put the exact same data into both databases.&nbsp; Close.&nbsp;
Overwrite the identical page of DB1 with the one from DB2.&nbsp; Reopen
the database with correct DB1 password.&nbsp; Code should detect an encryption
error on that page.</li>
</ol>
</ul>
<h2>
Risks</h2>
There are several holes in this design.&nbsp; It is important to document
them clearly.
<p>The first is that all of the pages are stored in memory and possibly
the file system in the clear.&nbsp; The password is stored in the shared
data regions in the clear.&nbsp; Therefore if an attacker can read the
process memory, they can do whatever they want.&nbsp; If the attacker can
read system memory or swap they can access the data as well.&nbsp; Since
everything in the shared data regions (with the exception of the buffered
log) will be in the clear, it is important to realize that file backed
regions will be written in the clear, including the portion of the regions
containing passwords.&nbsp; We recommend to users that they use system
memory instead of file backed shared memory.
</body>
</html>

View File

@@ -0,0 +1,187 @@
/*
* $Id: mt19937db.c,v 1.12 2004/06/14 16:54:27 mjc Exp $
*/
#include "db_config.h"
#include "db_int.h"
#include "dbinc/crypto.h"
#include "dbinc/hmac.h"
/* A C-program for MT19937: Integer version (1999/10/28) */
/* genrand() generates one pseudorandom unsigned integer (32bit) */
/* which is uniformly distributed among 0 to 2^32-1 for each */
/* call. sgenrand(seed) sets initial values to the working area */
/* of 624 words. Before genrand(), sgenrand(seed) must be */
/* called once. (seed is any 32-bit integer.) */
/* Coded by Takuji Nishimura, considering the suggestions by */
/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */
/* This library is free software under the Artistic license: */
/* see the file COPYING distributed together with this code. */
/* For the verification of the code, its output sequence file */
/* mt19937int.out is attached (2001/4/2) */
/* Copyright (C) 1997, 1999 Makoto Matsumoto and Takuji Nishimura. */
/* Any feedback is very welcome. For any question, comments, */
/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */
/* matumoto@math.keio.ac.jp */
/* REFERENCE */
/* M. Matsumoto and T. Nishimura, */
/* "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform */
/* Pseudo-Random Number Generator", */
/* ACM Transactions on Modeling and Computer Simulation, */
/* Vol. 8, No. 1, January 1998, pp 3--30. */
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0df /* constant vector a */
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
#define LOWER_MASK 0x7fffffff /* least significant r bits */
/* Tempering parameters */
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
#define TEMPERING_SHIFT_U(y) (y >> 11)
#define TEMPERING_SHIFT_S(y) (y << 7)
#define TEMPERING_SHIFT_T(y) (y << 15)
#define TEMPERING_SHIFT_L(y) (y >> 18)
static void __db_sgenrand __P((unsigned long, unsigned long *, int *));
#ifdef NOT_USED
static void __db_lsgenrand __P((unsigned long *, unsigned long *, int *));
#endif
static unsigned long __db_genrand __P((DB_ENV *));
/*
* __db_generate_iv --
* Generate an initialization vector (IV)
*
* PUBLIC: int __db_generate_iv __P((DB_ENV *, u_int32_t *));
*/
int
__db_generate_iv(dbenv, iv)
DB_ENV *dbenv;
u_int32_t *iv;
{
int i, n, ret;
ret = 0;
n = DB_IV_BYTES / sizeof(u_int32_t);
MUTEX_THREAD_LOCK(dbenv, dbenv->mt_mutexp);
if (dbenv->mt == NULL) {
if ((ret = __os_calloc(dbenv, 1, N*sizeof(unsigned long),
&dbenv->mt)) != 0)
return (ret);
/* mti==N+1 means mt[N] is not initialized */
dbenv->mti = N + 1;
}
for (i = 0; i < n; i++)
{
/*
* We do not allow 0. If we get one just try again.
*/
do {
iv[i] = (u_int32_t)__db_genrand(dbenv);
} while (iv[i] == 0);
}
MUTEX_THREAD_UNLOCK(dbenv, dbenv->mt_mutexp);
return (0);
}
/* Initializing the array with a seed */
static void
__db_sgenrand(seed, mt, mtip)
unsigned long seed;
unsigned long mt[];
int *mtip;
{
int i;
DB_ASSERT(seed != 0);
for (i=0;i<N;i++) {
mt[i] = seed & 0xffff0000;
seed = 69069 * seed + 1;
mt[i] |= (seed & 0xffff0000) >> 16;
seed = 69069 * seed + 1;
}
*mtip = N;
}
#ifdef NOT_USED
/* Initialization by "sgenrand()" is an example. Theoretically, */
/* there are 2^19937-1 possible states as an intial state. */
/* This function allows to choose any of 2^19937-1 ones. */
/* Essential bits in "seed_array[]" is following 19937 bits: */
/* (seed_array[0]&UPPER_MASK), seed_array[1], ..., seed_array[N-1]. */
/* (seed_array[0]&LOWER_MASK) is discarded. */
/* Theoretically, */
/* (seed_array[0]&UPPER_MASK), seed_array[1], ..., seed_array[N-1] */
/* can take any values except all zeros. */
static void
__db_lsgenrand(seed_array, mt, mtip)
unsigned long seed_array[];
unsigned long mt[];
int *mtip;
/* the length of seed_array[] must be at least N */
{
int i;
for (i=0;i<N;i++)
mt[i] = seed_array[i];
*mtip=N;
}
#endif
static unsigned long
__db_genrand(dbenv)
DB_ENV *dbenv;
{
unsigned long y;
static unsigned long mag01[2]={0x0, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
u_int32_t secs, seed, usecs;
/*
* We are called with the mt_mutexp locked
*/
if (dbenv->mti >= N) { /* generate N words at one time */
int kk;
if (dbenv->mti == N+1) { /* if sgenrand() has not been called, */
/*
* Seed the generator with the hashed time. The __db_mac
* function will return 4 bytes if we don't send in a key.
*/
do {
__os_clock(dbenv, &secs, &usecs);
__db_chksum((u_int8_t *)&secs, sizeof(secs), NULL,
(u_int8_t *)&seed);
} while (seed == 0);
__db_sgenrand((long)seed, dbenv->mt, &dbenv->mti);
}
for (kk=0;kk<N-M;kk++) {
y = (dbenv->mt[kk]&UPPER_MASK)|(dbenv->mt[kk+1]&LOWER_MASK);
dbenv->mt[kk] = dbenv->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (;kk<N-1;kk++) {
y = (dbenv->mt[kk]&UPPER_MASK)|(dbenv->mt[kk+1]&LOWER_MASK);
dbenv->mt[kk] = dbenv->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (dbenv->mt[N-1]&UPPER_MASK)|(dbenv->mt[0]&LOWER_MASK);
dbenv->mt[N-1] = dbenv->mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
dbenv->mti = 0;
}
y = dbenv->mt[dbenv->mti++];
y ^= TEMPERING_SHIFT_U(y);
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
y ^= TEMPERING_SHIFT_L(y);
return y;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
/*
* $Id: rijndael-alg-fst.h,v 1.2 2002/01/08 18:53:37 sue Exp $
*/
/**
* rijndael-alg-fst.h
*
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __RIJNDAEL_ALG_FST_H
#define __RIJNDAEL_ALG_FST_H
#define MAXKC (256/32)
#define MAXKB (256/8)
#define MAXNR 14
typedef u_int8_t u8;
typedef u_int16_t u16;
typedef u_int32_t u32;
#endif /* __RIJNDAEL_ALG_FST_H */

View File

@@ -0,0 +1,496 @@
/**
* rijndael-api-fst.c
*
* @version 2.9 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Acknowledgements:
*
* We are deeply indebted to the following people for their bug reports,
* fixes, and improvement suggestions to this implementation. Though we
* tried to list all contributions, we apologise in advance for any
* missing reference.
*
* Andrew Bales <Andrew.Bales@Honeywell.com>
* Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
* John Skodon <skodonj@webquill.com>
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/crypto.h"
#include "crypto/rijndael/rijndael-alg-fst.h"
#include "crypto/rijndael/rijndael-api-fst.h"
/*
* __db_makeKey --
*
* PUBLIC: int __db_makeKey __P((keyInstance *, int, int, char *));
*/
int
__db_makeKey(key, direction, keyLen, keyMaterial)
keyInstance *key;
int direction;
int keyLen;
char *keyMaterial;
{
u8 cipherKey[MAXKB];
if (key == NULL) {
return BAD_KEY_INSTANCE;
}
if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
key->direction = direction;
} else {
return BAD_KEY_DIR;
}
if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) {
key->keyLen = keyLen;
} else {
return BAD_KEY_MAT;
}
if (keyMaterial != NULL) {
memcpy(cipherKey, keyMaterial, key->keyLen/8);
}
if (direction == DIR_ENCRYPT) {
key->Nr = __db_rijndaelKeySetupEnc(key->rk, cipherKey, keyLen);
} else {
key->Nr = __db_rijndaelKeySetupDec(key->rk, cipherKey, keyLen);
}
__db_rijndaelKeySetupEnc(key->ek, cipherKey, keyLen);
return TRUE;
}
/*
* __db_cipherInit --
*
* PUBLIC: int __db_cipherInit __P((cipherInstance *, int, char *));
*/
int
__db_cipherInit(cipher, mode, IV)
cipherInstance *cipher;
int mode;
char *IV;
{
if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
cipher->mode = mode;
} else {
return BAD_CIPHER_MODE;
}
if (IV != NULL) {
memcpy(cipher->IV, IV, MAX_IV_SIZE);
}
return TRUE;
}
/*
* __db_blockEncrypt --
*
* PUBLIC: int __db_blockEncrypt __P((cipherInstance *, keyInstance *, u_int8_t *,
* PUBLIC: size_t, u_int8_t *));
*/
int
__db_blockEncrypt(cipher, key, input, inputLen, outBuffer)
cipherInstance *cipher;
keyInstance *key;
u_int8_t *input;
size_t inputLen;
u_int8_t *outBuffer;
{
int i, k, t, numBlocks;
u8 block[16], *iv;
u32 tmpiv[4];
if (cipher == NULL ||
key == NULL ||
key->direction == DIR_DECRYPT) {
return BAD_CIPHER_STATE;
}
if (input == NULL || inputLen <= 0) {
return 0; /* nothing to do */
}
numBlocks = (int)(inputLen/128);
switch (cipher->mode) {
case MODE_ECB:
for (i = numBlocks; i > 0; i--) {
__db_rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
break;
case MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
memcpy(tmpiv, iv, MAX_IV_SIZE);
((u32*)block)[0] = ((u32*)input)[0] ^ tmpiv[0];
((u32*)block)[1] = ((u32*)input)[1] ^ tmpiv[1];
((u32*)block)[2] = ((u32*)input)[2] ^ tmpiv[2];
((u32*)block)[3] = ((u32*)input)[3] ^ tmpiv[3];
__db_rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
iv = outBuffer;
input += 16;
outBuffer += 16;
}
break;
case MODE_CFB1:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
memcpy(outBuffer, input, 16);
for (k = 0; k < 128; k++) {
__db_rijndaelEncrypt(key->ek, key->Nr, iv, block);
outBuffer[k >> 3] ^= (block[0] & (u_int)0x80) >> (k & 7);
for (t = 0; t < 15; t++) {
iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
}
iv[15] = (iv[15] << 1) | ((outBuffer[k >> 3] >> (7 - (k & 7))) & 1);
}
outBuffer += 16;
input += 16;
}
break;
default:
return BAD_CIPHER_STATE;
}
return 128*numBlocks;
}
/**
* Encrypt data partitioned in octets, using RFC 2040-like padding.
*
* @param input data to be encrypted (octet sequence)
* @param inputOctets input length in octets (not bits)
* @param outBuffer encrypted output data
*
* @return length in octets (not bits) of the encrypted output buffer.
*/
/*
* __db_padEncrypt --
*
* PUBLIC: int __db_padEncrypt __P((cipherInstance *, keyInstance *, u_int8_t *,
* PUBLIC: int, u_int8_t *));
*/
int
__db_padEncrypt(cipher, key, input, inputOctets, outBuffer)
cipherInstance *cipher;
keyInstance *key;
u_int8_t *input;
int inputOctets;
u_int8_t *outBuffer;
{
int i, numBlocks, padLen;
u8 block[16], *iv;
u32 tmpiv[4];
if (cipher == NULL ||
key == NULL ||
key->direction == DIR_DECRYPT) {
return BAD_CIPHER_STATE;
}
if (input == NULL || inputOctets <= 0) {
return 0; /* nothing to do */
}
numBlocks = inputOctets/16;
switch (cipher->mode) {
case MODE_ECB:
for (i = numBlocks; i > 0; i--) {
__db_rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
padLen = 16 - (inputOctets - 16*numBlocks);
DB_ASSERT(padLen > 0 && padLen <= 16);
memcpy(block, input, 16 - padLen);
memset(block + 16 - padLen, padLen, padLen);
__db_rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
break;
case MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
memcpy(tmpiv, iv, MAX_IV_SIZE);
((u32*)block)[0] = ((u32*)input)[0] ^ tmpiv[0];
((u32*)block)[1] = ((u32*)input)[1] ^ tmpiv[1];
((u32*)block)[2] = ((u32*)input)[2] ^ tmpiv[2];
((u32*)block)[3] = ((u32*)input)[3] ^ tmpiv[3];
__db_rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
iv = outBuffer;
input += 16;
outBuffer += 16;
}
padLen = 16 - (inputOctets - 16*numBlocks);
DB_ASSERT(padLen > 0 && padLen <= 16);
for (i = 0; i < 16 - padLen; i++) {
block[i] = input[i] ^ iv[i];
}
for (i = 16 - padLen; i < 16; i++) {
block[i] = (u_int8_t)padLen ^ iv[i];
}
__db_rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
break;
default:
return BAD_CIPHER_STATE;
}
return 16*(numBlocks + 1);
}
/*
* __db_blockDecrypt --
*
* PUBLIC: int __db_blockDecrypt __P((cipherInstance *, keyInstance *, u_int8_t *,
* PUBLIC: size_t, u_int8_t *));
*/
int
__db_blockDecrypt(cipher, key, input, inputLen, outBuffer)
cipherInstance *cipher;
keyInstance *key;
u_int8_t *input;
size_t inputLen;
u_int8_t *outBuffer;
{
int i, k, t, numBlocks;
u8 block[16], *iv;
u32 tmpiv[4];
if (cipher == NULL ||
key == NULL ||
(cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
return BAD_CIPHER_STATE;
}
if (input == NULL || inputLen <= 0) {
return 0; /* nothing to do */
}
numBlocks = (int)(inputLen/128);
switch (cipher->mode) {
case MODE_ECB:
for (i = numBlocks; i > 0; i--) {
__db_rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
break;
case MODE_CBC:
memcpy(tmpiv, cipher->IV, MAX_IV_SIZE);
for (i = numBlocks; i > 0; i--) {
__db_rijndaelDecrypt(key->rk, key->Nr, input, block);
((u32*)block)[0] ^= tmpiv[0];
((u32*)block)[1] ^= tmpiv[1];
((u32*)block)[2] ^= tmpiv[2];
((u32*)block)[3] ^= tmpiv[3];
memcpy(tmpiv, input, 16);
memcpy(outBuffer, block, 16);
input += 16;
outBuffer += 16;
}
break;
case MODE_CFB1:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
memcpy(outBuffer, input, 16);
for (k = 0; k < 128; k++) {
__db_rijndaelEncrypt(key->ek, key->Nr, iv, block);
for (t = 0; t < 15; t++) {
iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
}
iv[15] = (iv[15] << 1) | ((input[k >> 3] >> (7 - (k & 7))) & 1);
outBuffer[k >> 3] ^= (block[0] & (u_int)0x80) >> (k & 7);
}
outBuffer += 16;
input += 16;
}
break;
default:
return BAD_CIPHER_STATE;
}
return 128*numBlocks;
}
/*
* __db_padDecrypt --
*
* PUBLIC: int __db_padDecrypt __P((cipherInstance *, keyInstance *, u_int8_t *,
* PUBLIC: int, u_int8_t *));
*/
int
__db_padDecrypt(cipher, key, input, inputOctets, outBuffer)
cipherInstance *cipher;
keyInstance *key;
u_int8_t *input;
int inputOctets;
u_int8_t *outBuffer;
{
int i, numBlocks, padLen;
u8 block[16];
u32 tmpiv[4];
if (cipher == NULL ||
key == NULL ||
key->direction == DIR_ENCRYPT) {
return BAD_CIPHER_STATE;
}
if (input == NULL || inputOctets <= 0) {
return 0; /* nothing to do */
}
if (inputOctets % 16 != 0) {
return BAD_DATA;
}
numBlocks = inputOctets/16;
switch (cipher->mode) {
case MODE_ECB:
/* all blocks but last */
for (i = numBlocks - 1; i > 0; i--) {
__db_rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
input += 16;
outBuffer += 16;
}
/* last block */
__db_rijndaelDecrypt(key->rk, key->Nr, input, block);
padLen = block[15];
if (padLen >= 16) {
return BAD_DATA;
}
for (i = 16 - padLen; i < 16; i++) {
if (block[i] != padLen) {
return BAD_DATA;
}
}
memcpy(outBuffer, block, 16 - padLen);
break;
case MODE_CBC:
/* all blocks but last */
memcpy(tmpiv, cipher->IV, MAX_IV_SIZE);
for (i = numBlocks - 1; i > 0; i--) {
__db_rijndaelDecrypt(key->rk, key->Nr, input, block);
((u32*)block)[0] ^= tmpiv[0];
((u32*)block)[1] ^= tmpiv[1];
((u32*)block)[2] ^= tmpiv[2];
((u32*)block)[3] ^= tmpiv[3];
memcpy(tmpiv, input, 16);
memcpy(outBuffer, block, 16);
input += 16;
outBuffer += 16;
}
/* last block */
__db_rijndaelDecrypt(key->rk, key->Nr, input, block);
((u32*)block)[0] ^= tmpiv[0];
((u32*)block)[1] ^= tmpiv[1];
((u32*)block)[2] ^= tmpiv[2];
((u32*)block)[3] ^= tmpiv[3];
padLen = block[15];
if (padLen <= 0 || padLen > 16) {
return BAD_DATA;
}
for (i = 16 - padLen; i < 16; i++) {
if (block[i] != padLen) {
return BAD_DATA;
}
}
memcpy(outBuffer, block, 16 - padLen);
break;
default:
return BAD_CIPHER_STATE;
}
return 16*numBlocks - padLen;
}
#ifdef INTERMEDIATE_VALUE_KAT
/**
* cipherUpdateRounds:
*
* Encrypts/Decrypts exactly one full block a specified number of rounds.
* Only used in the Intermediate Value Known Answer Test.
*
* Returns:
* TRUE - on success
* BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized)
*/
/*
* __db_cipherUpdateRounds --
*
* PUBLIC: int __db_cipherUpdateRounds __P((cipherInstance *, keyInstance *,
* PUBLIC: u_int8_t *, int, u_int8_t *, int));
*/
int
__db_cipherUpdateRounds(cipher, key, input, inputLen, outBuffer, rounds)
cipherInstance *cipher;
keyInstance *key;
u_int8_t *input;
size_t inputLen;
u_int8_t *outBuffer;
int rounds;
{
u8 block[16];
if (cipher == NULL || key == NULL) {
return BAD_CIPHER_STATE;
}
memcpy(block, input, 16);
switch (key->direction) {
case DIR_ENCRYPT:
__db_rijndaelEncryptRound(key->rk, key->Nr, block, rounds);
break;
case DIR_DECRYPT:
__db_rijndaelDecryptRound(key->rk, key->Nr, block, rounds);
break;
default:
return BAD_KEY_DIR;
}
memcpy(outBuffer, block, 16);
return TRUE;
}
#endif /* INTERMEDIATE_VALUE_KAT */

View File

@@ -0,0 +1,91 @@
/*
* $Id: rijndael-api-fst.h,v 1.5 2003/03/17 19:42:18 bostic Exp $
*/
/**
* rijndael-api-fst.h
*
* @version 2.9 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Acknowledgements:
*
* We are deeply indebted to the following people for their bug reports,
* fixes, and improvement suggestions to this implementation. Though we
* tried to list all contributions, we apologise in advance for any
* missing reference.
*
* Andrew Bales <Andrew.Bales@Honeywell.com>
* Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
* John Skodon <skodonj@webquill.com>
*/
#ifndef __RIJNDAEL_API_FST_H
#define __RIJNDAEL_API_FST_H
#include "crypto/rijndael/rijndael-alg-fst.h"
/* Generic Defines */
#define DIR_ENCRYPT 0 /* Are we encrpyting? */
#define DIR_DECRYPT 1 /* Are we decrpyting? */
#define MODE_ECB 1 /* Are we ciphering in ECB mode? */
#define MODE_CBC 2 /* Are we ciphering in CBC mode? */
#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */
#undef TRUE
#define TRUE 1
#undef FALSE
#define FALSE 0
#define BITSPERBLOCK 128 /* Default number of bits in a cipher block */
/* Error Codes */
#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */
#define BAD_KEY_MAT -2 /* Key material not of correct length */
#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */
#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */
#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */
#define BAD_BLOCK_LENGTH -6
#define BAD_CIPHER_INSTANCE -7
#define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */
#define BAD_OTHER -9 /* Unknown error */
/* Algorithm-specific Defines */
#define MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */
#define MAX_IV_SIZE 16 /* # bytes needed to represent an IV */
/* Typedefs */
/* The structure for key information */
typedef struct {
u_int8_t direction; /* Key used for encrypting or decrypting? */
int keyLen; /* Length of the key */
char keyMaterial[MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */
int Nr; /* key-length-dependent number of rounds */
u32 rk[4*(MAXNR + 1)]; /* key schedule */
u32 ek[4*(MAXNR + 1)]; /* CFB1 key schedule (encryption only) */
} keyInstance;
/* The structure for cipher information */
typedef struct { /* changed order of the components */
u_int8_t mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
u_int8_t IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */
} cipherInstance;
#endif /* __RIJNDAEL_API_FST_H */

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_db.cpp,v 11.87 2004/07/15 18:26:48 ubell Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_db.cpp,v 11.71 2002/08/26 22:13:36 mjc Exp $";
#endif /* not lint */
#include <errno.h>
#include <string.h>
@@ -39,25 +37,24 @@ int Db::_name _argspec \
\
ret = db->_name _arglist; \
if (!_retok(ret)) \
DB_ERROR("Db::" # _name, ret, error_policy()); \
DB_ERROR(env_, "Db::" # _name, ret, error_policy()); \
return (ret); \
}
#define DB_METHOD_CHECKED(_name, _cleanup, _argspec, _arglist, _retok) \
#define DB_DESTRUCTOR(_name, _argspec, _arglist, _retok) \
int Db::_name _argspec \
{ \
int ret; \
DB *db = unwrap(this); \
\
if (!db) { \
DB_ERROR("Db::" # _name, EINVAL, error_policy()); \
DB_ERROR(env_, "Db::" # _name, EINVAL, error_policy()); \
return (EINVAL); \
} \
if (_cleanup) \
cleanup(); \
cleanup(); \
ret = db->_name _arglist; \
if (!_retok(ret)) \
DB_ERROR("Db::" # _name, ret, error_policy()); \
DB_ERROR(env_, "Db::" # _name, ret, error_policy()); \
return (ret); \
}
@@ -92,6 +89,7 @@ void Db::_name _argspec \
Db::Db(DbEnv *env, u_int32_t flags)
: imp_(0)
, env_(env)
, mpf_(0)
, construct_error_(0)
, flags_(0)
, construct_flags_(flags)
@@ -107,7 +105,7 @@ Db::Db(DbEnv *env, u_int32_t flags)
flags_ |= DB_CXX_PRIVATE_ENV;
if ((construct_error_ = initialize()) != 0)
DB_ERROR("Db::Db", construct_error_, error_policy());
DB_ERROR(env_, "Db::Db", construct_error_, error_policy());
}
// If the DB handle is still open, we close it. This is to make stack
@@ -150,7 +148,7 @@ int Db::initialize()
return (ret);
// Associate the DB with this object
imp_ = wrap(db);
imp_ = db;
db->api_internal = this;
// Create a new DbEnv from a DB_ENV* if it was created locally.
@@ -159,6 +157,10 @@ int Db::initialize()
if ((flags_ & DB_CXX_PRIVATE_ENV) != 0)
env_ = new DbEnv(db->dbenv, cxx_flags);
// Create a DbMpoolFile from the DB_MPOOLFILE* in the DB handle.
mpf_ = new DbMpoolFile();
mpf_->imp_ = db->mpf;
return (0);
}
@@ -173,7 +175,6 @@ void Db::cleanup()
if (db != NULL) {
// extra safety
db->api_internal = 0;
imp_ = 0;
// we must dispose of the DbEnv object if
@@ -187,6 +188,8 @@ void Db::cleanup()
delete env_;
env_ = 0;
}
delete mpf_;
}
}
@@ -215,26 +218,7 @@ int Db::error_policy()
}
}
int Db::close(u_int32_t flags)
{
DB *db = unwrap(this);
int ret;
// after a DB->close (no matter if success or failure),
// the underlying DB object must not be accessed,
// so we clean up in advance.
//
cleanup();
// It's safe to throw an error after the close,
// since our error mechanism does not peer into
// the DB* structures.
//
if ((ret = db->close(db, flags)) != 0)
DB_ERROR("Db::close", ret, error_policy());
return (ret);
}
DB_DESTRUCTOR(close, (u_int32_t flags), (db, flags), DB_RETOK_STD)
// The following cast implies that Dbc can be no larger than DBC
DB_METHOD(cursor, (DbTxn *txnid, Dbc **cursorp, u_int32_t flags),
@@ -259,9 +243,7 @@ void Db::errx(const char *format, ...)
DB_REAL_ERR(db->dbenv, 0, 0, 1, format);
}
DB_METHOD(fd, (int *fdp),
(db, fdp),
DB_RETOK_STD)
DB_METHOD(fd, (int *fdp), (db, fdp), DB_RETOK_STD)
int Db::get(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags)
{
@@ -271,10 +253,10 @@ int Db::get(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags)
ret = db->get(db, unwrap(txnid), key, value, flags);
if (!DB_RETOK_DBGET(ret)) {
if (ret == ENOMEM && DB_OVERFLOWED_DBT(value))
DB_ERROR_DBT("Db::get", value, error_policy());
if (ret == DB_BUFFER_SMALL)
DB_ERROR_DBT(env_, "Db::get", value, error_policy());
else
DB_ERROR("Db::get", ret, error_policy());
DB_ERROR(env_, "Db::get", ret, error_policy());
}
return (ret);
@@ -286,6 +268,23 @@ int Db::get_byteswapped(int *isswapped)
return (db->get_byteswapped(db, isswapped));
}
DbEnv *Db::get_env()
{
DB *db = (DB *)unwrapConst(this);
DB_ENV *dbenv = db->get_env(db);
return (dbenv != NULL ? DbEnv::get_DbEnv(dbenv) : NULL);
}
DbMpoolFile *Db::get_mpf()
{
return (mpf_);
}
DB_METHOD(get_dbname, (const char **filenamep, const char **dbnamep),
(db, filenamep, dbnamep), DB_RETOK_STD)
DB_METHOD(get_open_flags, (u_int32_t *flagsp), (db, flagsp), DB_RETOK_STD)
int Db::get_type(DBTYPE *dbtype)
{
DB *db = (DB *)unwrapConst(this);
@@ -296,13 +295,11 @@ int Db::get_type(DBTYPE *dbtype)
// or even extra data members, so these casts, although technically
// non-portable, "should" always be okay.
DB_METHOD(join, (Dbc **curslist, Dbc **cursorp, u_int32_t flags),
(db, (DBC **)curslist, (DBC **)cursorp, flags),
DB_RETOK_STD)
(db, (DBC **)curslist, (DBC **)cursorp, flags), DB_RETOK_STD)
DB_METHOD(key_range,
(DbTxn *txnid, Dbt *key, DB_KEY_RANGE *results, u_int32_t flags),
(db, unwrap(txnid), key, results, flags),
DB_RETOK_STD)
(db, unwrap(txnid), key, results, flags), DB_RETOK_STD)
// If an error occurred during the constructor, report it now.
// Otherwise, call the underlying DB->open method.
@@ -320,7 +317,7 @@ int Db::open(DbTxn *txnid, const char *file, const char *database,
mode);
if (!DB_RETOK_STD(ret))
DB_ERROR("Db::open", ret, error_policy());
DB_ERROR(env_, "Db::open", ret, error_policy());
return (ret);
}
@@ -335,39 +332,36 @@ int Db::pget(DbTxn *txnid, Dbt *key, Dbt *pkey, Dbt *value, u_int32_t flags)
/* The logic here is identical to Db::get - reuse the macro. */
if (!DB_RETOK_DBGET(ret)) {
if (ret == ENOMEM && DB_OVERFLOWED_DBT(value))
DB_ERROR_DBT("Db::pget", value, error_policy());
DB_ERROR_DBT(env_, "Db::pget", value, error_policy());
else
DB_ERROR("Db::pget", ret, error_policy());
DB_ERROR(env_, "Db::pget", ret, error_policy());
}
return (ret);
}
DB_METHOD(put,
(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags),
(db, unwrap(txnid), key, value, flags),
DB_RETOK_DBPUT)
DB_METHOD(put, (DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags),
(db, unwrap(txnid), key, value, flags), DB_RETOK_DBPUT)
DB_METHOD_CHECKED(rename, 1,
DB_DESTRUCTOR(rename,
(const char *file, const char *database, const char *newname,
u_int32_t flags),
(db, file, database, newname, flags), DB_RETOK_STD)
DB_METHOD_CHECKED(remove, 1,
(const char *file, const char *database, u_int32_t flags),
DB_DESTRUCTOR(remove, (const char *file, const char *database, u_int32_t flags),
(db, file, database, flags), DB_RETOK_STD)
DB_METHOD_CHECKED(truncate, 0,
(DbTxn *txnid, u_int32_t *countp, u_int32_t flags),
DB_METHOD(truncate, (DbTxn *txnid, u_int32_t *countp, u_int32_t flags),
(db, unwrap(txnid), countp, flags), DB_RETOK_STD)
DB_METHOD_CHECKED(stat, 0,
(void *sp, u_int32_t flags), (db, sp, flags), DB_RETOK_STD)
DB_METHOD(stat, (DbTxn *txnid, void *sp, u_int32_t flags),
(db, unwrap(txnid), sp, flags), DB_RETOK_STD)
DB_METHOD_CHECKED(sync, 0,
(u_int32_t flags), (db, flags), DB_RETOK_STD)
DB_METHOD(stat_print, (u_int32_t flags), (db, flags), DB_RETOK_STD)
DB_METHOD_CHECKED(upgrade, 0,
DB_METHOD(sync, (u_int32_t flags), (db, flags), DB_RETOK_STD)
DB_METHOD(upgrade,
(const char *name, u_int32_t flags), (db, name, flags), DB_RETOK_STD)
////////////////////////////////////////////////////////////////////////
@@ -412,7 +406,7 @@ extern "C" _rettype _db_##_name##_intercept_c _cargspec \
Db *cxxthis; \
\
DB_ASSERT(cthis != NULL); \
cxxthis = (Db *)cthis->api_internal; \
cxxthis = Db::get_Db(cthis); \
DB_ASSERT(cxxthis != NULL); \
DB_ASSERT(cxxthis->_name##_callback_ != 0); \
\
@@ -503,10 +497,10 @@ extern "C"
int _verify_callback_c(void *handle, const void *str_arg)
{
char *str;
__DB_OSTREAMCLASS *out;
__DB_STD(ostream) *out;
str = (char *)str_arg;
out = (__DB_OSTREAMCLASS *)handle;
out = (__DB_STD(ostream) *)handle;
(*out) << str;
if (out->fail())
@@ -516,19 +510,26 @@ int _verify_callback_c(void *handle, const void *str_arg)
}
int Db::verify(const char *name, const char *subdb,
__DB_OSTREAMCLASS *ostr, u_int32_t flags)
__DB_STD(ostream) *ostr, u_int32_t flags)
{
DB *db = unwrap(this);
int ret;
if (!db)
ret = EINVAL;
else
else {
// after a DB->verify (no matter if success or failure),
// the underlying DB object must not be accessed,
// so we clean up in advance.
//
cleanup();
ret = __db_verify_internal(db, name, subdb, ostr,
_verify_callback_c, flags);
}
if (!DB_RETOK_STD(ret))
DB_ERROR("Db::verify", ret, error_policy());
DB_ERROR(env_, "Db::verify", ret, error_policy());
return (ret);
}
@@ -537,36 +538,64 @@ DB_METHOD(set_bt_compare, (bt_compare_fcn_type func),
(db, func), DB_RETOK_STD)
DB_METHOD(set_bt_maxkey, (u_int32_t bt_maxkey),
(db, bt_maxkey), DB_RETOK_STD)
DB_METHOD(get_bt_minkey, (u_int32_t *bt_minkeyp),
(db, bt_minkeyp), DB_RETOK_STD)
DB_METHOD(set_bt_minkey, (u_int32_t bt_minkey),
(db, bt_minkey), DB_RETOK_STD)
DB_METHOD(set_bt_prefix, (bt_prefix_fcn_type func),
(db, func), DB_RETOK_STD)
DB_METHOD(set_dup_compare, (dup_compare_fcn_type func),
(db, func), DB_RETOK_STD)
DB_METHOD(set_encrypt, (const char *passwd, int flags),
DB_METHOD(get_encrypt_flags, (u_int32_t *flagsp),
(db, flagsp), DB_RETOK_STD)
DB_METHOD(set_encrypt, (const char *passwd, u_int32_t flags),
(db, passwd, flags), DB_RETOK_STD)
DB_METHOD_VOID(get_errfile, (FILE **errfilep), (db, errfilep))
DB_METHOD_VOID(set_errfile, (FILE *errfile), (db, errfile))
DB_METHOD_VOID(get_errpfx, (const char **errpfx), (db, errpfx))
DB_METHOD_VOID(set_errpfx, (const char *errpfx), (db, errpfx))
DB_METHOD(get_flags, (u_int32_t *flagsp), (db, flagsp),
DB_RETOK_STD)
DB_METHOD(set_flags, (u_int32_t flags), (db, flags),
DB_RETOK_STD)
DB_METHOD(get_h_ffactor, (u_int32_t *h_ffactorp),
(db, h_ffactorp), DB_RETOK_STD)
DB_METHOD(set_h_ffactor, (u_int32_t h_ffactor),
(db, h_ffactor), DB_RETOK_STD)
DB_METHOD(set_h_hash, (h_hash_fcn_type func),
(db, func), DB_RETOK_STD)
DB_METHOD(get_h_nelem, (u_int32_t *h_nelemp),
(db, h_nelemp), DB_RETOK_STD)
DB_METHOD(set_h_nelem, (u_int32_t h_nelem),
(db, h_nelem), DB_RETOK_STD)
DB_METHOD(get_lorder, (int *db_lorderp), (db, db_lorderp),
DB_RETOK_STD)
DB_METHOD(set_lorder, (int db_lorder), (db, db_lorder),
DB_RETOK_STD)
DB_METHOD_VOID(get_msgfile, (FILE **msgfilep), (db, msgfilep))
DB_METHOD_VOID(set_msgfile, (FILE *msgfile), (db, msgfile))
DB_METHOD(get_pagesize, (u_int32_t *db_pagesizep),
(db, db_pagesizep), DB_RETOK_STD)
DB_METHOD(set_pagesize, (u_int32_t db_pagesize),
(db, db_pagesize), DB_RETOK_STD)
DB_METHOD(get_re_delim, (int *re_delimp),
(db, re_delimp), DB_RETOK_STD)
DB_METHOD(set_re_delim, (int re_delim),
(db, re_delim), DB_RETOK_STD)
DB_METHOD(get_re_len, (u_int32_t *re_lenp),
(db, re_lenp), DB_RETOK_STD)
DB_METHOD(set_re_len, (u_int32_t re_len),
(db, re_len), DB_RETOK_STD)
DB_METHOD(get_re_pad, (int *re_padp),
(db, re_padp), DB_RETOK_STD)
DB_METHOD(set_re_pad, (int re_pad),
(db, re_pad), DB_RETOK_STD)
DB_METHOD(set_re_source, (char *re_source),
DB_METHOD(get_re_source, (const char **re_source),
(db, re_source), DB_RETOK_STD)
DB_METHOD(set_re_source, (const char *re_source),
(db, re_source), DB_RETOK_STD)
DB_METHOD(get_q_extentsize, (u_int32_t *extentsizep),
(db, extentsizep), DB_RETOK_STD)
DB_METHOD(set_q_extentsize, (u_int32_t extentsize),
(db, extentsize), DB_RETOK_STD)
@@ -574,11 +603,16 @@ DB_METHOD_QUIET(set_alloc, (db_malloc_fcn_type malloc_fcn,
db_realloc_fcn_type realloc_fcn, db_free_fcn_type free_fcn),
(db, malloc_fcn, realloc_fcn, free_fcn))
void Db::set_errcall(void (*arg)(const char *, char *))
void Db::set_errcall(void (*arg)(const DbEnv *, const char *, const char *))
{
env_->set_errcall(arg);
}
void Db::set_msgcall(void (*arg)(const DbEnv *, const char *))
{
env_->set_msgcall(arg);
}
void *Db::get_app_private() const
{
return unwrapConst(this)->app_private;
@@ -589,17 +623,34 @@ void Db::set_app_private(void *value)
unwrap(this)->app_private = value;
}
DB_METHOD(get_cachesize, (u_int32_t *gbytesp, u_int32_t *bytesp, int *ncachep),
(db, gbytesp, bytesp, ncachep), DB_RETOK_STD)
DB_METHOD(set_cachesize, (u_int32_t gbytes, u_int32_t bytes, int ncache),
(db, gbytes, bytes, ncache), DB_RETOK_STD)
DB_METHOD(set_cache_priority, (DB_CACHE_PRIORITY priority),
(db, priority), DB_RETOK_STD)
int Db::set_paniccall(void (*callback)(DbEnv *, int))
{
return (env_->set_paniccall(callback));
}
void Db::set_error_stream(__DB_OSTREAMCLASS *error_stream)
__DB_STD(ostream) *Db::get_error_stream()
{
return env_->get_error_stream();
}
void Db::set_error_stream(__DB_STD(ostream) *error_stream)
{
env_->set_error_stream(error_stream);
}
__DB_STD(ostream) *Db::get_message_stream()
{
return env_->get_message_stream();
}
void Db::set_message_stream(__DB_STD(ostream) *message_stream)
{
env_->set_message_stream(message_stream);
}
DB_METHOD_QUIET(get_transactional, (), (db))

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_dbc.cpp,v 11.59 2004/01/28 03:35:56 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_dbc.cpp,v 11.55 2002/07/03 21:03:52 bostic Exp $";
#endif /* not lint */
#include <errno.h>
#include <string.h>
@@ -39,7 +37,8 @@ int Dbc::_name _argspec \
\
ret = dbc->c_##_name _arglist; \
if (!_retok(ret)) \
DB_ERROR("Dbc::" # _name, ret, ON_ERROR_UNKNOWN); \
DB_ERROR(DbEnv::get_DbEnv(dbc->dbp->dbenv), \
"Dbc::" # _name, ret, ON_ERROR_UNKNOWN); \
return (ret); \
}
@@ -67,7 +66,8 @@ int Dbc::dup(Dbc** cursorp, u_int32_t _flags)
// The following cast implies that Dbc can be no larger than DBC
*cursorp = (Dbc*)new_cursor;
else
DB_ERROR("Dbc::dup", ret, ON_ERROR_UNKNOWN);
DB_ERROR(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::dup", ret, ON_ERROR_UNKNOWN);
return (ret);
}
@@ -81,11 +81,14 @@ int Dbc::get(Dbt* key, Dbt *data, u_int32_t _flags)
if (!DB_RETOK_DBCGET(ret)) {
if (ret == ENOMEM && DB_OVERFLOWED_DBT(key))
DB_ERROR_DBT("Dbc::get", key, ON_ERROR_UNKNOWN);
DB_ERROR_DBT(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::get", key, ON_ERROR_UNKNOWN);
else if (ret == ENOMEM && DB_OVERFLOWED_DBT(data))
DB_ERROR_DBT("Dbc::get", data, ON_ERROR_UNKNOWN);
DB_ERROR_DBT(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::get", data, ON_ERROR_UNKNOWN);
else
DB_ERROR("Dbc::get", ret, ON_ERROR_UNKNOWN);
DB_ERROR(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::get", ret, ON_ERROR_UNKNOWN);
}
return (ret);
@@ -101,11 +104,14 @@ int Dbc::pget(Dbt* key, Dbt *pkey, Dbt *data, u_int32_t _flags)
/* Logic is the same as for Dbc::get - reusing macro. */
if (!DB_RETOK_DBCGET(ret)) {
if (ret == ENOMEM && DB_OVERFLOWED_DBT(key))
DB_ERROR_DBT("Dbc::pget", key, ON_ERROR_UNKNOWN);
DB_ERROR_DBT(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::pget", key, ON_ERROR_UNKNOWN);
else if (ret == ENOMEM && DB_OVERFLOWED_DBT(data))
DB_ERROR_DBT("Dbc::pget", data, ON_ERROR_UNKNOWN);
DB_ERROR_DBT(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::pget", data, ON_ERROR_UNKNOWN);
else
DB_ERROR("Dbc::pget", ret, ON_ERROR_UNKNOWN);
DB_ERROR(DbEnv::get_DbEnv(dbc->dbp->dbenv),
"Dbc::pget", ret, ON_ERROR_UNKNOWN);
}
return (ret);

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_dbt.cpp,v 11.55 2004/01/28 03:35:56 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_dbt.cpp,v 11.53 2002/03/27 04:31:14 bostic Exp $";
#endif /* not lint */
#include <errno.h>
#include <string.h>

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_env.cpp,v 11.105 2004/09/22 22:20:31 mjc Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_env.cpp,v 11.88 2002/08/26 22:13:36 mjc Exp $";
#endif /* not lint */
#include <errno.h>
#include <stdio.h> // needed for set_error_stream
#include <string.h>
@@ -45,7 +43,7 @@ int DbEnv::_name _argspec \
#define DBENV_METHOD(_name, _argspec, _arglist) \
DBENV_METHOD_ERR(_name, _argspec, _arglist, \
DB_ERROR("DbEnv::" # _name, ret, error_policy()))
DB_ERROR(this, "DbEnv::" # _name, ret, error_policy()))
#define DBENV_METHOD_QUIET(_name, _argspec, _arglist) \
int DbEnv::_name _argspec \
@@ -63,13 +61,6 @@ void DbEnv::_name _argspec \
dbenv->_name _arglist; \
}
// This datatype is needed for picky compilers.
//
extern "C" {
typedef void (*db_errcall_fcn_type)
(const char *, char *);
};
// The reason for a static variable is that some structures
// (like Dbts) have no connection to any Db or DbEnv, so when
// errors occur in their methods, we must have some reasonable
@@ -81,8 +72,6 @@ extern "C" {
//
static int last_known_error_policy = ON_ERROR_UNKNOWN;
__DB_OSTREAMCLASS *DbEnv::error_stream_ = 0;
// These 'glue' function are declared as extern "C" so they will
// be compatible with picky compilers that do not allow mixing
// of function pointers to 'C' functions with function pointers
@@ -101,40 +90,45 @@ void _paniccall_intercept_c(DB_ENV *env, int errval)
}
extern "C"
void _stream_error_function_c(const char *prefix, char *message)
void _stream_error_function_c(const DB_ENV *env,
const char *prefix, const char *message)
{
DbEnv::_stream_error_function(prefix, message);
DbEnv::_stream_error_function(env, prefix, message);
}
extern "C"
void _stream_message_function_c(const DB_ENV *env, const char *message)
{
DbEnv::_stream_message_function(env, message);
}
extern "C"
int _app_dispatch_intercept_c(DB_ENV *env, DBT *dbt,
DB_LSN *lsn, db_recops op)
DB_LSN *lsn, db_recops op)
{
return (DbEnv::_app_dispatch_intercept(env, dbt, lsn, op));
}
extern "C"
int _rep_send_intercept_c(DB_ENV *env, const DBT *cntrl,
const DBT *data, int id, u_int32_t flags)
const DBT *data, const DB_LSN *lsn, int id,
u_int32_t flags)
{
return (DbEnv::_rep_send_intercept(env,
cntrl, data, id, flags));
cntrl, data, lsn, id, flags));
}
void DbEnv::_feedback_intercept(DB_ENV *env, int opcode, int pct)
{
if (env == 0) {
DB_ERROR("DbEnv::feedback_callback", EINVAL, ON_ERROR_UNKNOWN);
return;
}
DbEnv *cxxenv = (DbEnv *)env->api1_internal;
DbEnv *cxxenv = DbEnv::get_DbEnv(env);
if (cxxenv == 0) {
DB_ERROR("DbEnv::feedback_callback", EINVAL, ON_ERROR_UNKNOWN);
DB_ERROR(0,
"DbEnv::feedback_callback", EINVAL, ON_ERROR_UNKNOWN);
return;
}
if (cxxenv->feedback_callback_ == 0) {
DB_ERROR("DbEnv::feedback_callback", EINVAL,
cxxenv->error_policy());
DB_ERROR(DbEnv::get_DbEnv(env),
"DbEnv::feedback_callback", EINVAL, cxxenv->error_policy());
return;
}
(*cxxenv->feedback_callback_)(cxxenv, opcode, pct);
@@ -142,39 +136,33 @@ void DbEnv::_feedback_intercept(DB_ENV *env, int opcode, int pct)
void DbEnv::_paniccall_intercept(DB_ENV *env, int errval)
{
if (env == 0) {
DB_ERROR("DbEnv::paniccall_callback", EINVAL,
ON_ERROR_UNKNOWN);
}
DbEnv *cxxenv = (DbEnv *)env->api1_internal;
DbEnv *cxxenv = DbEnv::get_DbEnv(env);
if (cxxenv == 0) {
DB_ERROR("DbEnv::paniccall_callback", EINVAL,
ON_ERROR_UNKNOWN);
DB_ERROR(0,
"DbEnv::paniccall_callback", EINVAL, ON_ERROR_UNKNOWN);
return;
}
if (cxxenv->paniccall_callback_ == 0) {
DB_ERROR("DbEnv::paniccall_callback", EINVAL,
DB_ERROR(cxxenv, "DbEnv::paniccall_callback", EINVAL,
cxxenv->error_policy());
return;
}
(*cxxenv->paniccall_callback_)(cxxenv, errval);
}
int DbEnv::_app_dispatch_intercept(DB_ENV *env, DBT *dbt,
DB_LSN *lsn, db_recops op)
DB_LSN *lsn, db_recops op)
{
if (env == 0) {
DB_ERROR("DbEnv::app_dispatch_callback",
EINVAL, ON_ERROR_UNKNOWN);
return (EINVAL);
}
DbEnv *cxxenv = (DbEnv *)env->api1_internal;
DbEnv *cxxenv = DbEnv::get_DbEnv(env);
if (cxxenv == 0) {
DB_ERROR("DbEnv::app_dispatch_callback",
EINVAL, ON_ERROR_UNKNOWN);
DB_ERROR(DbEnv::get_DbEnv(env),
"DbEnv::app_dispatch_callback", EINVAL, ON_ERROR_UNKNOWN);
return (EINVAL);
}
if (cxxenv->app_dispatch_callback_ == 0) {
DB_ERROR("DbEnv::app_dispatch_callback",
EINVAL, cxxenv->error_policy());
DB_ERROR(DbEnv::get_DbEnv(env),
"DbEnv::app_dispatch_callback", EINVAL,
cxxenv->error_policy());
return (EINVAL);
}
Dbt *cxxdbt = (Dbt *)dbt;
@@ -183,22 +171,20 @@ int DbEnv::_app_dispatch_intercept(DB_ENV *env, DBT *dbt,
}
int DbEnv::_rep_send_intercept(DB_ENV *env, const DBT *cntrl,
const DBT *data, int id, u_int32_t flags)
const DBT *data, const DB_LSN *lsn,
int id, u_int32_t flags)
{
if (env == 0) {
DB_ERROR("DbEnv::rep_send_callback", EINVAL, ON_ERROR_UNKNOWN);
return (EINVAL);
}
DbEnv *cxxenv = (DbEnv *)env->api1_internal;
DbEnv *cxxenv = DbEnv::get_DbEnv(env);
if (cxxenv == 0) {
DB_ERROR("DbEnv::rep_send_callback", EINVAL, ON_ERROR_UNKNOWN);
DB_ERROR(DbEnv::get_DbEnv(env),
"DbEnv::rep_send_callback", EINVAL, ON_ERROR_UNKNOWN);
return (EINVAL);
}
const Dbt *cxxcntrl = (const Dbt *)cntrl;
const DbLsn *cxxlsn = (const DbLsn *)lsn;
Dbt *cxxdata = (Dbt *)data;
return ((*cxxenv->rep_send_callback_)(cxxenv,
cxxcntrl, cxxdata, id, flags));
cxxcntrl, cxxdata, cxxlsn, id, flags));
}
// A truism for the DbEnv object is that there is a valid
@@ -217,6 +203,8 @@ DbEnv::DbEnv(u_int32_t flags)
: imp_(0)
, construct_error_(0)
, construct_flags_(flags)
, error_stream_(0)
, message_stream_(0)
, app_dispatch_callback_(0)
, feedback_callback_(0)
, paniccall_callback_(0)
@@ -225,13 +213,16 @@ DbEnv::DbEnv(u_int32_t flags)
, rep_send_callback_(0)
{
if ((construct_error_ = initialize(0)) != 0)
DB_ERROR("DbEnv::DbEnv", construct_error_, error_policy());
DB_ERROR(this, "DbEnv::DbEnv", construct_error_,
error_policy());
}
DbEnv::DbEnv(DB_ENV *env, u_int32_t flags)
: imp_(0)
, construct_error_(0)
, construct_flags_(flags)
, error_stream_(0)
, message_stream_(0)
, app_dispatch_callback_(0)
, feedback_callback_(0)
, paniccall_callback_(0)
@@ -240,7 +231,8 @@ DbEnv::DbEnv(DB_ENV *env, u_int32_t flags)
, rep_send_callback_(0)
{
if ((construct_error_ = initialize(env)) != 0)
DB_ERROR("DbEnv::DbEnv", construct_error_, error_policy());
DB_ERROR(this, "DbEnv::DbEnv", construct_error_,
error_policy());
}
// If the DB_ENV handle is still open, we close it. This is to make stack
@@ -287,7 +279,7 @@ int DbEnv::close(u_int32_t flags)
// the DB* structures.
//
if ((ret = env->close(env, flags)) != 0)
DB_ERROR("DbEnv::close", ret, error_policy());
DB_ERROR(this, "DbEnv::close", ret, error_policy());
return (ret);
}
@@ -334,6 +326,10 @@ void *DbEnv::get_app_private() const
return unwrapConst(this)->app_private;
}
DBENV_METHOD(get_home, (const char **homep), (dbenv, homep))
DBENV_METHOD(get_open_flags, (u_int32_t *flagsp), (dbenv, flagsp))
DBENV_METHOD(get_data_dirs, (const char ***dirspp), (dbenv, dirspp))
// used internally during constructor
// to associate an existing DB_ENV with this DbEnv,
// or create a new one.
@@ -350,7 +346,7 @@ int DbEnv::initialize(DB_ENV *env)
construct_flags_ & ~DB_CXX_NO_EXCEPTIONS)) != 0)
return (ret);
}
imp_ = wrap(env);
imp_ = env;
env->api1_internal = this; // for DB_ENV* to DbEnv* conversion
return (0);
}
@@ -362,7 +358,7 @@ DBENV_METHOD_ERR(lock_get,
(u_int32_t locker, u_int32_t flags, const Dbt *obj,
db_lockmode_t lock_mode, DbLock *lock),
(dbenv, locker, flags, obj, lock_mode, &lock->lock_),
DbEnv::runtime_error_lock_get("DbEnv::lock_get", ret,
DbEnv::runtime_error_lock_get(this, "DbEnv::lock_get", ret,
DB_LOCK_GET, lock_mode, obj, *lock,
-1, error_policy()))
DBENV_METHOD(lock_id, (u_int32_t *idp), (dbenv, idp))
@@ -370,11 +366,12 @@ DBENV_METHOD(lock_id_free, (u_int32_t id), (dbenv, id))
DBENV_METHOD(lock_put, (DbLock *lock), (dbenv, &lock->lock_))
DBENV_METHOD(lock_stat, (DB_LOCK_STAT **statp, u_int32_t flags),
(dbenv, statp, flags))
DBENV_METHOD(lock_stat_print, (u_int32_t flags), (dbenv, flags))
DBENV_METHOD_ERR(lock_vec,
(u_int32_t locker, u_int32_t flags, DB_LOCKREQ list[],
int nlist, DB_LOCKREQ **elist_returned),
(dbenv, locker, flags, list, nlist, elist_returned),
DbEnv::runtime_error_lock_get("DbEnv::lock_vec", ret,
DbEnv::runtime_error_lock_get(this, "DbEnv::lock_vec", ret,
(*elist_returned)->op, (*elist_returned)->mode,
Dbt::get_Dbt((*elist_returned)->obj), DbLock((*elist_returned)->lock),
(*elist_returned) - list, error_policy()))
@@ -397,6 +394,7 @@ DBENV_METHOD(log_put, (DbLsn *lsn, const Dbt *data, u_int32_t flags),
(dbenv, lsn, data, flags))
DBENV_METHOD(log_stat, (DB_LOG_STAT **spp, u_int32_t flags),
(dbenv, spp, flags))
DBENV_METHOD(log_stat_print, (u_int32_t flags), (dbenv, flags))
int DbEnv::memp_fcreate(DbMpoolFile **dbmfp, u_int32_t flags)
{
@@ -411,9 +409,9 @@ int DbEnv::memp_fcreate(DbMpoolFile **dbmfp, u_int32_t flags)
if (DB_RETOK_STD(ret)) {
*dbmfp = new DbMpoolFile();
(*dbmfp)->imp_ = wrap(mpf);
(*dbmfp)->imp_ = mpf;
} else
DB_ERROR("DbMpoolFile::f_create", ret, ON_ERROR_UNKNOWN);
DB_ERROR(this, "DbMpoolFile::f_create", ret, ON_ERROR_UNKNOWN);
return (ret);
}
@@ -426,9 +424,8 @@ DBENV_METHOD(memp_register,
DBENV_METHOD(memp_stat,
(DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp, u_int32_t flags),
(dbenv, gsp, fsp, flags))
DBENV_METHOD(memp_stat_print, (u_int32_t flags), (dbenv, flags))
DBENV_METHOD(memp_sync, (DbLsn *sn), (dbenv, sn))
DBENV_METHOD(memp_trickle, (int pct, int *nwrotep), (dbenv, pct, nwrotep))
// If an error occurred during the constructor, report it now.
@@ -445,7 +442,7 @@ int DbEnv::open(const char *db_home, u_int32_t flags, int mode)
ret = env->open(env, db_home, flags, mode);
if (!DB_RETOK_STD(ret))
DB_ERROR("DbEnv::open", ret, error_policy());
DB_ERROR(this, "DbEnv::open", ret, error_policy());
return (ret);
}
@@ -462,7 +459,7 @@ int DbEnv::remove(const char *db_home, u_int32_t flags)
cleanup();
if ((ret = env->remove(env, db_home, flags)) != 0)
DB_ERROR("DbEnv::remove", ret, error_policy());
DB_ERROR(this, "DbEnv::remove", ret, error_policy());
return (ret);
}
@@ -473,7 +470,8 @@ int DbEnv::remove(const char *db_home, u_int32_t flags)
// ON_ERROR_RETURN do nothing here, the caller will return an error
// ON_ERROR_UNKNOWN defer the policy to policy saved in DbEnv::DbEnv
//
void DbEnv::runtime_error(const char *caller, int error, int error_policy)
void DbEnv::runtime_error(DbEnv *env,
const char *caller, int error, int error_policy)
{
if (error_policy == ON_ERROR_UNKNOWN)
error_policy = last_known_error_policy;
@@ -484,18 +482,28 @@ void DbEnv::runtime_error(const char *caller, int error, int error_policy)
case DB_LOCK_DEADLOCK:
{
DbDeadlockException dl_except(caller);
dl_except.set_env(env);
throw dl_except;
}
break;
case DB_RUNRECOVERY:
{
DbRunRecoveryException rr_except(caller);
rr_except.set_env(env);
throw rr_except;
}
break;
case DB_LOCK_NOTGRANTED:
{
DbLockNotGrantedException lng_except(caller);
lng_except.set_env(env);
throw lng_except;
}
break;
default:
{
DbException except(caller, error);
except.set_env(env);
throw except;
}
break;
@@ -505,7 +513,8 @@ void DbEnv::runtime_error(const char *caller, int error, int error_policy)
// Like DbEnv::runtime_error, but issue a DbMemoryException
// based on the fact that this Dbt is not large enough.
void DbEnv::runtime_error_dbt(const char *caller, Dbt *dbt, int error_policy)
void DbEnv::runtime_error_dbt(DbEnv *env,
const char *caller, Dbt *dbt, int error_policy)
{
if (error_policy == ON_ERROR_UNKNOWN)
error_policy = last_known_error_policy;
@@ -513,6 +522,7 @@ void DbEnv::runtime_error_dbt(const char *caller, Dbt *dbt, int error_policy)
// Creating and throwing the object in two separate
// statements seems to be necessary for HP compilers.
DbMemoryException except(caller, dbt);
except.set_env(env);
throw except;
}
}
@@ -520,12 +530,13 @@ void DbEnv::runtime_error_dbt(const char *caller, Dbt *dbt, int error_policy)
// Like DbEnv::runtime_error, but issue a DbLockNotGrantedException,
// or a regular runtime error.
// call regular runtime_error if it
void DbEnv::runtime_error_lock_get(const char *caller, int error,
void DbEnv::runtime_error_lock_get(DbEnv *env,
const char *caller, int error,
db_lockop_t op, db_lockmode_t mode, const Dbt *obj,
DbLock lock, int index, int error_policy)
{
if (error != DB_LOCK_NOTGRANTED) {
runtime_error(caller, error, error_policy);
runtime_error(env, caller, error, error_policy);
return;
}
@@ -536,52 +547,101 @@ void DbEnv::runtime_error_lock_get(const char *caller, int error,
// statements seems to be necessary for HP compilers.
DbLockNotGrantedException except(caller, op, mode,
obj, lock, index);
except.set_env(env);
throw except;
}
}
void DbEnv::_stream_error_function(
const DB_ENV *env, const char *prefix, const char *message)
{
const DbEnv *cxxenv = DbEnv::get_const_DbEnv(env);
if (cxxenv == 0) {
DB_ERROR(0,
"DbEnv::stream_error", EINVAL, ON_ERROR_UNKNOWN);
return;
}
if (cxxenv->error_callback_)
cxxenv->error_callback_(cxxenv, prefix, message);
else if (cxxenv->error_stream_) {
// HP compilers need the extra casts, we don't know why.
if (prefix) {
(*cxxenv->error_stream_) << prefix;
(*cxxenv->error_stream_) << (const char *)": ";
}
if (message)
(*cxxenv->error_stream_) << (const char *)message;
(*cxxenv->error_stream_) << (const char *)"\n";
}
}
void DbEnv::_stream_message_function(const DB_ENV *env, const char *message)
{
const DbEnv *cxxenv = DbEnv::get_const_DbEnv(env);
if (cxxenv == 0) {
DB_ERROR(0,
"DbEnv::stream_message", EINVAL, ON_ERROR_UNKNOWN);
return;
}
if (cxxenv->message_callback_)
cxxenv->message_callback_(cxxenv, message);
else if (cxxenv->message_stream_) {
// HP compilers need the extra casts, we don't know why.
(*cxxenv->message_stream_) << (const char *)message;
(*cxxenv->message_stream_) << (const char *)"\n";
}
}
// static method
char *DbEnv::strerror(int error)
{
return (db_strerror(error));
}
void DbEnv::_stream_error_function(const char *prefix, char *message)
{
// HP compilers need the extra casts, we don't know why.
if (error_stream_) {
if (prefix) {
(*error_stream_) << prefix << (const char *)": ";
}
if (message) {
(*error_stream_) << (const char *)message;
}
(*error_stream_) << (const char *)"\n";
}
}
// set methods
DBENV_METHOD_VOID(set_errfile, (FILE *errfile), (dbenv, errfile))
DBENV_METHOD_VOID(set_errpfx, (const char *errpfx), (dbenv, errpfx))
// We keep these alphabetical by field name,
// for comparison with Java's list.
//
DBENV_METHOD(set_data_dir, (const char *dir), (dbenv, dir))
DBENV_METHOD(set_encrypt, (const char *passwd, int flags),
DBENV_METHOD(get_encrypt_flags, (u_int32_t *flagsp),
(dbenv, flagsp))
DBENV_METHOD(set_encrypt, (const char *passwd, u_int32_t flags),
(dbenv, passwd, flags))
DBENV_METHOD_VOID(get_errfile, (FILE **errfilep), (dbenv, errfilep))
DBENV_METHOD_VOID(set_errfile, (FILE *errfile), (dbenv, errfile))
DBENV_METHOD_VOID(get_errpfx, (const char **errpfxp), (dbenv, errpfxp))
DBENV_METHOD_VOID(set_errpfx, (const char *errpfx), (dbenv, errpfx))
DBENV_METHOD(get_lg_bsize, (u_int32_t *bsizep), (dbenv, bsizep))
DBENV_METHOD(set_lg_bsize, (u_int32_t bsize), (dbenv, bsize))
DBENV_METHOD(get_lg_dir, (const char **dirp), (dbenv, dirp))
DBENV_METHOD(set_lg_dir, (const char *dir), (dbenv, dir))
DBENV_METHOD(get_lg_max, (u_int32_t *maxp), (dbenv, maxp))
DBENV_METHOD(set_lg_max, (u_int32_t max), (dbenv, max))
DBENV_METHOD(get_lg_regionmax, (u_int32_t *regionmaxp), (dbenv, regionmaxp))
DBENV_METHOD(set_lg_regionmax, (u_int32_t regionmax), (dbenv, regionmax))
DBENV_METHOD(get_lk_conflicts, (const u_int8_t **lk_conflictsp, int *lk_maxp),
(dbenv, lk_conflictsp, lk_maxp))
DBENV_METHOD(set_lk_conflicts, (u_int8_t *lk_conflicts, int lk_max),
(dbenv, lk_conflicts, lk_max))
DBENV_METHOD(get_lk_detect, (u_int32_t *detectp), (dbenv, detectp))
DBENV_METHOD(set_lk_detect, (u_int32_t detect), (dbenv, detect))
DBENV_METHOD(set_lk_max, (u_int32_t max), (dbenv, max))
DBENV_METHOD(get_lk_max_lockers, (u_int32_t *max_lockersp),
(dbenv, max_lockersp))
DBENV_METHOD(set_lk_max_lockers, (u_int32_t max_lockers), (dbenv, max_lockers))
DBENV_METHOD(get_lk_max_locks, (u_int32_t *max_locksp), (dbenv, max_locksp))
DBENV_METHOD(set_lk_max_locks, (u_int32_t max_locks), (dbenv, max_locks))
DBENV_METHOD(get_lk_max_objects, (u_int32_t *max_objectsp),
(dbenv, max_objectsp))
DBENV_METHOD(set_lk_max_objects, (u_int32_t max_objects), (dbenv, max_objects))
DBENV_METHOD(get_mp_mmapsize, (size_t *mmapsizep), (dbenv, mmapsizep))
DBENV_METHOD(set_mp_mmapsize, (size_t mmapsize), (dbenv, mmapsize))
DBENV_METHOD_VOID(get_msgfile, (FILE **msgfilep), (dbenv, msgfilep))
DBENV_METHOD_VOID(set_msgfile, (FILE *msgfile), (dbenv, msgfile))
DBENV_METHOD(get_tmp_dir, (const char **tmp_dirp), (dbenv, tmp_dirp))
DBENV_METHOD(set_tmp_dir, (const char *tmp_dir), (dbenv, tmp_dir))
DBENV_METHOD(get_tx_max, (u_int32_t *tx_maxp), (dbenv, tx_maxp))
DBENV_METHOD(set_tx_max, (u_int32_t tx_max), (dbenv, tx_max))
DBENV_METHOD_QUIET(set_alloc,
@@ -594,40 +654,36 @@ void DbEnv::set_app_private(void *value)
unwrap(this)->app_private = value;
}
DBENV_METHOD(get_cachesize,
(u_int32_t *gbytesp, u_int32_t *bytesp, int *ncachep),
(dbenv, gbytesp, bytesp, ncachep))
DBENV_METHOD(set_cachesize,
(u_int32_t gbytes, u_int32_t bytes, int ncache),
(dbenv, gbytes, bytes, ncache))
void DbEnv::set_errcall(void (*arg)(const char *, char *))
void DbEnv::set_errcall(void (*arg)(const DbEnv *, const char *, const char *))
{
DB_ENV *dbenv = unwrap(this);
// XXX
// We are casting from a function ptr declared with C++
// linkage to one (same arg types) declared with C
// linkage. It's hard to imagine a pair of C/C++
// compilers from the same vendor for which this
// won't work. Unfortunately, we can't use a
// intercept function like the others since the
// function does not have a (DbEnv*) as one of
// the args. If this causes trouble, we can pull
// the same trick we use in Java, namely stuffing
// a (DbEnv*) pointer into the prefix. We're
// avoiding this for the moment because it obfuscates.
//
(*(dbenv->set_errcall))(dbenv, (db_errcall_fcn_type)arg);
error_callback_ = arg;
error_stream_ = 0;
dbenv->set_errcall(dbenv, (arg == 0) ? 0 :
_stream_error_function_c);
}
// Note: This actually behaves a bit like a static function,
// since DB_ENV.db_errcall has no information about which
// db_env triggered the call. A user that has multiple DB_ENVs
// will simply not be able to have different streams for each one.
//
void DbEnv::set_error_stream(__DB_OSTREAMCLASS *stream)
__DB_STD(ostream) *DbEnv::get_error_stream()
{
return (error_stream_);
}
void DbEnv::set_error_stream(__DB_STD(ostream) *stream)
{
DB_ENV *dbenv = unwrap(this);
error_stream_ = stream;
error_callback_ = 0;
dbenv->set_errcall(dbenv, (stream == 0) ? 0 :
_stream_error_function_c);
}
@@ -638,12 +694,38 @@ int DbEnv::set_feedback(void (*arg)(DbEnv *, int, int))
feedback_callback_ = arg;
return ((*(dbenv->set_feedback))(dbenv, _feedback_intercept_c));
return (dbenv->set_feedback(dbenv, _feedback_intercept_c));
}
DBENV_METHOD(get_flags, (u_int32_t *flagsp), (dbenv, flagsp))
DBENV_METHOD(set_flags, (u_int32_t flags, int onoff), (dbenv, flags, onoff))
DBENV_METHOD(set_lk_conflicts, (u_int8_t *lk_conflicts, int lk_max),
(dbenv, lk_conflicts, lk_max))
void DbEnv::set_msgcall(void (*arg)(const DbEnv *, const char *))
{
DB_ENV *dbenv = unwrap(this);
message_callback_ = arg;
message_stream_ = 0;
dbenv->set_msgcall(dbenv, (arg == 0) ? 0 :
_stream_message_function_c);
}
__DB_STD(ostream) *DbEnv::get_message_stream()
{
return (message_stream_);
}
void DbEnv::set_message_stream(__DB_STD(ostream) *stream)
{
DB_ENV *dbenv = unwrap(this);
message_stream_ = stream;
message_callback_ = 0;
dbenv->set_msgcall(dbenv, (stream == 0) ? 0 :
_stream_message_function_c);
}
int DbEnv::set_paniccall(void (*arg)(DbEnv *, int))
{
@@ -651,14 +733,16 @@ int DbEnv::set_paniccall(void (*arg)(DbEnv *, int))
paniccall_callback_ = arg;
return ((*(dbenv->set_paniccall))(dbenv, _paniccall_intercept_c));
return (dbenv->set_paniccall(dbenv, _paniccall_intercept_c));
}
DBENV_METHOD(set_rpc_server,
(void *cl, char *host, long tsec, long ssec, u_int32_t flags),
(dbenv, cl, host, tsec, ssec, flags))
DBENV_METHOD(get_shm_key, (long *shm_keyp), (dbenv, shm_keyp))
DBENV_METHOD(set_shm_key, (long shm_key), (dbenv, shm_key))
// Note: this changes from last_known_error_policy to error_policy()
DBENV_METHOD(get_tas_spins, (u_int32_t *argp), (dbenv, argp))
DBENV_METHOD(set_tas_spins, (u_int32_t arg), (dbenv, arg))
int DbEnv::set_app_dispatch
@@ -668,14 +752,17 @@ int DbEnv::set_app_dispatch
int ret;
app_dispatch_callback_ = arg;
if ((ret = (*(dbenv->set_app_dispatch))(dbenv,
if ((ret = dbenv->set_app_dispatch(dbenv,
_app_dispatch_intercept_c)) != 0)
DB_ERROR("DbEnv::set_app_dispatch", ret, error_policy());
DB_ERROR(this, "DbEnv::set_app_dispatch", ret, error_policy());
return (ret);
}
DBENV_METHOD(get_tx_timestamp, (time_t *timestamp), (dbenv, timestamp))
DBENV_METHOD(set_tx_timestamp, (time_t *timestamp), (dbenv, timestamp))
DBENV_METHOD(get_verbose, (u_int32_t which, int *onoffp),
(dbenv, which, onoffp))
DBENV_METHOD(set_verbose, (u_int32_t which, int onoff), (dbenv, which, onoff))
int DbEnv::txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags)
@@ -688,7 +775,7 @@ int DbEnv::txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags)
if (DB_RETOK_STD(ret))
*tid = new DbTxn(txn);
else
DB_ERROR("DbEnv::txn_begin", ret, error_policy());
DB_ERROR(this, "DbEnv::txn_begin", ret, error_policy());
return (ret);
}
@@ -716,20 +803,20 @@ int DbEnv::txn_recover(DbPreplist *preplist, long count,
&c_preplist);
if (ret != 0) {
DB_ERROR("DbEnv::txn_recover", ret, error_policy());
DB_ERROR(this, "DbEnv::txn_recover", ret, error_policy());
return (ret);
}
if ((ret =
dbenv->txn_recover(dbenv, c_preplist, count, retp, flags)) != 0) {
__os_free(dbenv, c_preplist);
DB_ERROR("DbEnv::txn_recover", ret, error_policy());
DB_ERROR(this, "DbEnv::txn_recover", ret, error_policy());
return (ret);
}
for (i = 0; i < *retp; i++) {
preplist[i].txn = new DbTxn();
preplist[i].txn->imp_ = wrap(c_preplist[i].txn);
preplist[i].txn->imp_ = c_preplist[i].txn;
memcpy(preplist[i].gid, c_preplist[i].gid,
sizeof(preplist[i].gid));
}
@@ -741,9 +828,11 @@ int DbEnv::txn_recover(DbPreplist *preplist, long count,
DBENV_METHOD(txn_stat, (DB_TXN_STAT **statp, u_int32_t flags),
(dbenv, statp, flags))
DBENV_METHOD(txn_stat_print, (u_int32_t flags), (dbenv, flags))
int DbEnv::set_rep_transport(u_int32_t myid,
int (*f_send)(DbEnv *, const Dbt *, const Dbt *, int, u_int32_t))
int DbEnv::set_rep_transport(int myid,
int (*f_send)(DbEnv *, const Dbt *, const Dbt *, const DbLsn *, int,
u_int32_t))
{
DB_ENV *dbenv = unwrap(this);
int ret;
@@ -751,23 +840,26 @@ int DbEnv::set_rep_transport(u_int32_t myid,
rep_send_callback_ = f_send;
if ((ret = dbenv->set_rep_transport(dbenv,
myid, _rep_send_intercept_c)) != 0)
DB_ERROR("DbEnv::set_rep_transport", ret, error_policy());
DB_ERROR(this, "DbEnv::set_rep_transport", ret, error_policy());
return (ret);
}
DBENV_METHOD(rep_elect,
(int nsites, int pri, u_int32_t timeout, int *idp),
(dbenv, nsites, pri, timeout, idp))
(int nsites,
int nvotes, int priority, u_int32_t timeout, int *eidp, u_int32_t flags),
(dbenv, nsites, nvotes, priority, timeout, eidp, flags))
int DbEnv::rep_process_message(Dbt *control, Dbt *rec, int *idp)
int DbEnv::rep_process_message(Dbt *control,
Dbt *rec, int *idp, DbLsn *ret_lsnp)
{
DB_ENV *dbenv = unwrap(this);
int ret;
ret = dbenv->rep_process_message(dbenv, control, rec, idp);
ret = dbenv->rep_process_message(dbenv, control, rec, idp, ret_lsnp);
if (!DB_RETOK_REPPMSG(ret))
DB_ERROR("DbEnv::rep_process_message", ret, error_policy());
DB_ERROR(this, "DbEnv::rep_process_message", ret,
error_policy());
return (ret);
}
@@ -778,10 +870,16 @@ DBENV_METHOD(rep_start,
DBENV_METHOD(rep_stat, (DB_REP_STAT **statp, u_int32_t flags),
(dbenv, statp, flags))
DBENV_METHOD(rep_stat_print, (u_int32_t flags), (dbenv, flags))
DBENV_METHOD(get_rep_limit, (u_int32_t *gbytesp, u_int32_t *bytesp),
(dbenv, gbytesp, bytesp))
DBENV_METHOD(set_rep_limit, (u_int32_t gbytes, u_int32_t bytes),
(dbenv, gbytes, bytes))
DBENV_METHOD(get_timeout,
(db_timeout_t *timeoutp, u_int32_t flags),
(dbenv, timeoutp, flags))
DBENV_METHOD(set_timeout,
(db_timeout_t timeout, u_int32_t flags),
(dbenv, timeout, flags))
@@ -796,7 +894,5 @@ char *DbEnv::version(int *major, int *minor, int *patch)
DbEnv *DbEnv::wrap_DB_ENV(DB_ENV *dbenv)
{
DbEnv *wrapped_env = get_DbEnv(dbenv);
if (wrapped_env == NULL)
wrapped_env = new DbEnv(dbenv, 0);
return wrapped_env;
return (wrapped_env != NULL) ? wrapped_env : new DbEnv(dbenv, 0);
}

View File

@@ -1,68 +1,20 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_except.cpp,v 11.28 2004/09/22 03:34:48 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_except.cpp,v 11.17 2002/08/23 01:07:27 mjc Exp $";
#endif /* not lint */
#include <string.h>
#include <errno.h>
#include "db_cxx.h"
#include "dbinc/cxx_int.h"
// tmpString is used to create strings on the stack
//
class tmpString
{
public:
tmpString(const char *str1,
const char *str2 = 0,
const char *str3 = 0,
const char *str4 = 0,
const char *str5 = 0);
~tmpString() { delete [] s_; }
operator const char *() { return (s_); }
private:
char *s_;
};
tmpString::tmpString(const char *str1,
const char *str2,
const char *str3,
const char *str4,
const char *str5)
{
size_t len = strlen(str1);
if (str2)
len += strlen(str2);
if (str3)
len += strlen(str3);
if (str4)
len += strlen(str4);
if (str5)
len += strlen(str5);
s_ = new char[len+1];
strcpy(s_, str1);
if (str2)
strcat(s_, str2);
if (str3)
strcat(s_, str3);
if (str4)
strcat(s_, str4);
if (str5)
strcat(s_, str5);
}
// Note: would not be needed if we can inherit from exception
// It does not appear to be possible to inherit from exception
// with the current Microsoft library (VC5.0).
@@ -80,65 +32,113 @@ static char *dupString(const char *s)
// //
////////////////////////////////////////////////////////////////////////
DbException::~DbException()
DbException::~DbException() throw()
{
if (what_)
delete [] what_;
delete [] what_;
}
DbException::DbException(int err)
: err_(err)
, env_(0)
{
what_ = dupString(db_strerror(err));
describe(0, 0);
}
DbException::DbException(const char *description)
: err_(0)
, env_(0)
{
what_ = dupString(tmpString(description));
describe(0, description);
}
DbException::DbException(const char *prefix, int err)
DbException::DbException(const char *description, int err)
: err_(err)
, env_(0)
{
what_ = dupString(tmpString(prefix, ": ", db_strerror(err)));
describe(0, description);
}
DbException::DbException(const char *prefix1, const char *prefix2, int err)
DbException::DbException(const char *prefix, const char *description, int err)
: err_(err)
, env_(0)
{
what_ = dupString(tmpString(prefix1, ": ", prefix2, ": ",
db_strerror(err)));
describe(prefix, description);
}
DbException::DbException(const DbException &that)
: err_(that.err_)
: __DB_STD(exception)()
, what_(dupString(that.what_))
, err_(that.err_)
, env_(0)
{
what_ = dupString(that.what_);
}
DbException &DbException::operator = (const DbException &that)
{
if (this != &that) {
err_ = that.err_;
if (what_)
delete [] what_;
what_ = 0; // in case new throws exception
delete [] what_;
what_ = dupString(that.what_);
}
return (*this);
}
void DbException::describe(const char *prefix, const char *description)
{
char msgbuf[1024], *p, *end;
p = msgbuf;
end = msgbuf + sizeof(msgbuf) - 1;
if (prefix != NULL) {
strncpy(p, prefix, (p < end) ? end - p: 0);
p += strlen(prefix);
strncpy(p, ": ", (p < end) ? end - p: 0);
p += 2;
}
if (description != NULL) {
strncpy(p, description, (p < end) ? end - p: 0);
p += strlen(description);
if (err_ != 0) {
strncpy(p, ": ", (p < end) ? end - p: 0);
p += 2;
}
}
if (err_ != 0) {
strncpy(p, db_strerror(err_), (p < end) ? end - p: 0);
p += strlen(db_strerror(err_));
}
/*
* If the result was too long, the buffer will not be null-terminated,
* so we need to fix that here before duplicating it.
*/
if (p >= end)
*end = '\0';
what_ = dupString(msgbuf);
}
int DbException::get_errno() const
{
return (err_);
}
const char *DbException::what() const
const char *DbException::what() const throw()
{
return (what_);
}
DbEnv *DbException::get_env() const
{
return env_;
}
void DbException::set_env(DbEnv *env)
{
env_= env;
}
////////////////////////////////////////////////////////////////////////
// //
// DbMemoryException //
@@ -146,7 +146,7 @@ const char *DbException::what() const
////////////////////////////////////////////////////////////////////////
static const char *memory_err_desc = "Dbt not large enough for available data";
DbMemoryException::~DbMemoryException()
DbMemoryException::~DbMemoryException() throw()
{
}
@@ -156,25 +156,12 @@ DbMemoryException::DbMemoryException(Dbt *dbt)
{
}
DbMemoryException::DbMemoryException(const char *description)
: DbException(description, ENOMEM)
, dbt_(0)
{
}
DbMemoryException::DbMemoryException(const char *prefix, Dbt *dbt)
: DbException(prefix, memory_err_desc, ENOMEM)
, dbt_(dbt)
{
}
DbMemoryException::DbMemoryException(const char *prefix1, const char *prefix2,
Dbt *dbt)
: DbException(prefix1, prefix2, ENOMEM)
, dbt_(dbt)
{
}
DbMemoryException::DbMemoryException(const DbMemoryException &that)
: DbException(that)
, dbt_(that.dbt_)
@@ -202,7 +189,7 @@ Dbt *DbMemoryException::get_dbt() const
// //
////////////////////////////////////////////////////////////////////////
DbDeadlockException::~DbDeadlockException()
DbDeadlockException::~DbDeadlockException() throw()
{
}
@@ -230,7 +217,7 @@ DbDeadlockException
// //
////////////////////////////////////////////////////////////////////////
DbLockNotGrantedException::~DbLockNotGrantedException()
DbLockNotGrantedException::~DbLockNotGrantedException() throw()
{
delete lock_;
}
@@ -243,9 +230,19 @@ DbLockNotGrantedException::DbLockNotGrantedException(const char *prefix,
, op_(op)
, mode_(mode)
, obj_(obj)
, lock_(new DbLock(lock))
, index_(index)
{
lock_ = new DbLock(lock);
}
DbLockNotGrantedException::DbLockNotGrantedException(const char *description)
: DbException(description, DB_LOCK_NOTGRANTED)
, op_(DB_LOCK_GET)
, mode_(DB_LOCK_NG)
, obj_(NULL)
, lock_(NULL)
, index_(0)
{
}
DbLockNotGrantedException::DbLockNotGrantedException
@@ -255,7 +252,7 @@ DbLockNotGrantedException::DbLockNotGrantedException
op_ = that.op_;
mode_ = that.mode_;
obj_ = that.obj_;
lock_ = new DbLock(*that.lock_);
lock_ = (that.lock_ != NULL) ? new DbLock(*that.lock_) : NULL;
index_ = that.index_;
}
@@ -267,7 +264,7 @@ DbLockNotGrantedException
op_ = that.op_;
mode_ = that.mode_;
obj_ = that.obj_;
lock_ = new DbLock(*that.lock_);
lock_ = (that.lock_ != NULL) ? new DbLock(*that.lock_) : NULL;
index_ = that.index_;
}
return (*this);
@@ -298,15 +295,13 @@ int DbLockNotGrantedException::get_index() const
return index_;
}
////////////////////////////////////////////////////////////////////////
// //
// DbRunRecoveryException //
// //
////////////////////////////////////////////////////////////////////////
DbRunRecoveryException::~DbRunRecoveryException()
DbRunRecoveryException::~DbRunRecoveryException() throw()
{
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_lock.cpp,v 11.19 2004/01/28 03:35:56 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_lock.cpp,v 11.17 2002/03/27 04:31:16 bostic Exp $";
#endif /* not lint */
#include <errno.h>
#include <string.h>

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_logc.cpp,v 11.13 2004/02/05 02:25:12 mjc Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_logc.cpp,v 11.8 2002/07/03 21:03:53 bostic Exp $";
#endif /* not lint */
#include <errno.h>
#include <string.h>
@@ -37,11 +35,12 @@ int DbLogc::close(u_int32_t _flags)
{
DB_LOGC *logc = this;
int ret;
DbEnv *dbenv2 = DbEnv::get_DbEnv(logc->dbenv);
ret = logc->close(logc, _flags);
if (!DB_RETOK_STD(ret))
DB_ERROR("DbLogc::close", ret, ON_ERROR_UNKNOWN);
DB_ERROR(dbenv2, "DbLogc::close", ret, ON_ERROR_UNKNOWN);
return (ret);
}
@@ -55,10 +54,12 @@ int DbLogc::get(DbLsn *lsn, Dbt *data, u_int32_t _flags)
ret = logc->get(logc, lsn, data, _flags);
if (!DB_RETOK_LGGET(ret)) {
if (ret == ENOMEM && DB_OVERFLOWED_DBT(data))
DB_ERROR_DBT("DbLogc::get", data, ON_ERROR_UNKNOWN);
if (ret == DB_BUFFER_SMALL)
DB_ERROR_DBT(DbEnv::get_DbEnv(logc->dbenv),
"DbLogc::get", data, ON_ERROR_UNKNOWN);
else
DB_ERROR("DbLogc::get", ret, ON_ERROR_UNKNOWN);
DB_ERROR(DbEnv::get_DbEnv(logc->dbenv),
"DbLogc::get", ret, ON_ERROR_UNKNOWN);
}
return (ret);

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_mpool.cpp,v 11.28 2004/01/28 03:35:56 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_mpool.cpp,v 11.20 2002/07/03 21:03:53 bostic Exp $";
#endif /* not lint */
#include <errno.h>
#include "db_cxx.h"
@@ -35,7 +33,8 @@ int DbMpoolFile::_name _argspec \
else \
ret = mpf->_name _arglist; \
if (!_retok(ret)) \
DB_ERROR("DbMpoolFile::"#_name, ret, ON_ERROR_UNKNOWN); \
DB_ERROR(DbEnv::get_DbEnv(mpf->dbenv), \
"DbMpoolFile::"#_name, ret, ON_ERROR_UNKNOWN); \
return (ret); \
}
@@ -66,6 +65,7 @@ int DbMpoolFile::close(u_int32_t flags)
{
DB_MPOOLFILE *mpf = unwrap(this);
int ret;
DbEnv *dbenv = DbEnv::get_DbEnv(mpf->dbenv);
if (mpf == NULL)
ret = EINVAL;
@@ -79,32 +79,51 @@ int DbMpoolFile::close(u_int32_t flags)
delete this;
if (!DB_RETOK_STD(ret))
DB_ERROR("DbMpoolFile::close", ret, ON_ERROR_UNKNOWN);
DB_ERROR(dbenv, "DbMpoolFile::close", ret, ON_ERROR_UNKNOWN);
return (ret);
}
DB_MPOOLFILE_METHOD(get, (db_pgno_t *pgnoaddr, u_int32_t flags, void *pagep),
(mpf, pgnoaddr, flags, pagep), DB_RETOK_MPGET)
DB_MPOOLFILE_METHOD_VOID(last_pgno, (db_pgno_t *pgnoaddr), (mpf, pgnoaddr))
DB_MPOOLFILE_METHOD(open,
(const char *file, u_int32_t flags, int mode, size_t pagesize),
(mpf, file, flags, mode, pagesize), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(put, (void *pgaddr, u_int32_t flags),
(mpf, pgaddr, flags), DB_RETOK_STD)
DB_MPOOLFILE_METHOD_VOID(refcnt, (db_pgno_t *pgnoaddr), (mpf, pgnoaddr))
DB_MPOOLFILE_METHOD(set, (void *pgaddr, u_int32_t flags),
(mpf, pgaddr, flags), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_clear_len, (u_int32_t *lenp),
(mpf, lenp), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_clear_len, (u_int32_t len),
(mpf, len), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_fileid, (u_int8_t *fileid),
(mpf, fileid), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_fileid, (u_int8_t *fileid),
(mpf, fileid), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_flags, (u_int32_t *flagsp),
(mpf, flagsp), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_flags, (u_int32_t flags, int onoff),
(mpf, flags, onoff), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_ftype, (int *ftypep),
(mpf, ftypep), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_ftype, (int ftype),
(mpf, ftype), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_lsn_offset, (int32_t *offsetp),
(mpf, offsetp), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_lsn_offset, (int32_t offset),
(mpf, offset), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_maxsize, (u_int32_t *gbytesp, u_int32_t *bytesp),
(mpf, gbytesp, bytesp), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_maxsize, (u_int32_t gbytes, u_int32_t bytes),
(mpf, gbytes, bytes), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(get_pgcookie, (DBT *dbt),
(mpf, dbt), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_pgcookie, (DBT *dbt),
(mpf, dbt), DB_RETOK_STD)
DB_MPOOLFILE_METHOD_VOID(set_unlink, (int ul), (mpf, ul))
DB_MPOOLFILE_METHOD(get_priority, (DB_CACHE_PRIORITY *priorityp),
(mpf, priorityp), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(set_priority, (DB_CACHE_PRIORITY priority),
(mpf, priority), DB_RETOK_STD)
DB_MPOOLFILE_METHOD(sync, (),
(mpf), DB_RETOK_STD)

View File

@@ -0,0 +1,65 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_multi.cpp,v 1.4 2004/01/28 03:35:56 bostic Exp $
*/
#include "db_config.h"
#include "db_cxx.h"
DbMultipleIterator::DbMultipleIterator(const Dbt &dbt)
: data_((u_int8_t*)dbt.get_data()),
p_((u_int32_t*)(data_ + dbt.get_size() - sizeof(u_int32_t)))
{
}
bool DbMultipleDataIterator::next(Dbt &data)
{
if (*p_ == (u_int32_t)-1) {
data.set_data(0);
data.set_size(0);
p_ = 0;
} else {
data.set_data(data_ + *p_--);
data.set_size(*p_--);
if (data.get_size() == 0 && data.get_data() == data_)
data.set_data(0);
}
return (data.get_data() != 0);
}
bool DbMultipleKeyDataIterator::next(Dbt &key, Dbt &data)
{
if (*p_ == (u_int32_t)-1) {
key.set_data(0);
key.set_size(0);
data.set_data(0);
data.set_size(0);
p_ = 0;
} else {
key.set_data(data_ + *p_--);
key.set_size(*p_--);
data.set_data(data_ + *p_--);
data.set_size(*p_--);
}
return (data.get_data() != 0);
}
bool DbMultipleRecnoDataIterator::next(db_recno_t &recno, Dbt &data)
{
if (*p_ == (u_int32_t)0) {
recno = 0;
data.set_data(0);
data.set_size(0);
p_ = 0;
} else {
recno = *p_--;
data.set_data(data_ + *p_--);
data.set_size(*p_--);
}
return (recno != 0);
}

113
storage/bdb/cxx/cxx_seq.cpp Normal file
View File

@@ -0,0 +1,113 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_seq.cpp,v 11.3 2004/09/23 20:05:08 mjc Exp $
*/
#include "db_config.h"
#include <errno.h>
#include <string.h>
#include "db_cxx.h"
#include "dbinc/cxx_int.h"
#include "db_int.h"
// Helper macro for simple methods that pass through to the
// underlying C method. It may return an error or raise an exception.
// Note this macro expects that input _argspec is an argument
// list element (e.g., "char *arg") and that _arglist is the arguments
// that should be passed through to the C method (e.g., "(db, arg)")
//
#define DBSEQ_METHOD(_name, _argspec, _arglist, _destructor) \
int DbSequence::_name _argspec \
{ \
int ret; \
DB_SEQUENCE *seq = unwrap(this); \
DbEnv *dbenv = DbEnv::get_DbEnv(seq->seq_dbp->dbenv); \
\
ret = seq->_name _arglist; \
if (_destructor) \
imp_ = 0; \
if (!DB_RETOK_STD(ret)) \
DB_ERROR(dbenv, \
"DbSequence::" # _name, ret, ON_ERROR_UNKNOWN); \
return (ret); \
}
DbSequence::DbSequence(Db *db, u_int32_t flags)
: imp_(0)
{
DB_SEQUENCE *seq;
int ret;
if ((ret = db_sequence_create(&seq, unwrap(db), flags)) != 0)
DB_ERROR(db->get_env(), "DbSequence::DbSequence", ret,
ON_ERROR_UNKNOWN);
else {
imp_ = seq;
seq->api_internal = this;
}
}
DbSequence::DbSequence(DB_SEQUENCE *seq)
: imp_(seq)
{
seq->api_internal = this;
}
DbSequence::~DbSequence()
{
DB_SEQUENCE *seq;
seq = unwrap(this);
if (seq != NULL)
(void)seq->close(seq, 0);
}
DBSEQ_METHOD(open, (DbTxn *txnid, Dbt *key, u_int32_t flags),
(seq, unwrap(txnid), key, flags), 0)
DBSEQ_METHOD(initial_value, (db_seq_t value), (seq, value), 0)
DBSEQ_METHOD(close, (u_int32_t flags), (seq, flags), 1)
DBSEQ_METHOD(remove, (DbTxn *txnid, u_int32_t flags),
(seq, unwrap(txnid), flags), 1)
DBSEQ_METHOD(stat, (DB_SEQUENCE_STAT **sp, u_int32_t flags),
(seq, sp, flags), 0)
DBSEQ_METHOD(stat_print, (u_int32_t flags), (seq, flags), 0)
DBSEQ_METHOD(get,
(DbTxn *txnid, int32_t delta, db_seq_t *retp, u_int32_t flags),
(seq, unwrap(txnid), delta, retp, flags), 0)
DBSEQ_METHOD(get_cachesize, (int32_t *sizep), (seq, sizep), 0)
DBSEQ_METHOD(set_cachesize, (int32_t size), (seq, size), 0)
DBSEQ_METHOD(get_flags, (u_int32_t *flagsp), (seq, flagsp), 0)
DBSEQ_METHOD(set_flags, (u_int32_t flags), (seq, flags), 0)
DBSEQ_METHOD(get_range, (db_seq_t *minp, db_seq_t *maxp), (seq, minp, maxp), 0)
DBSEQ_METHOD(set_range, (db_seq_t min, db_seq_t max), (seq, min, max), 0)
Db *DbSequence::get_db()
{
DB_SEQUENCE *seq = unwrap(this);
DB *db;
(void)seq->get_db(seq, &db);
return Db::get_Db(db);
}
Dbt *DbSequence::get_key()
{
DB_SEQUENCE *seq = unwrap(this);
memset(&key_, 0, sizeof (DBT));
(void)seq->get_key(seq, &key_);
return Dbt::get_Dbt(&key_);
}
// static method
DbSequence *DbSequence::wrap_DB_SEQUENCE(DB_SEQUENCE *seq)
{
DbSequence *wrapped_seq = get_DbSequence(seq);
return (wrapped_seq != NULL) ? wrapped_seq : new DbSequence(seq);
}

View File

@@ -1,22 +1,21 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997-2002
* Copyright (c) 1997-2004
* Sleepycat Software. All rights reserved.
*
* $Id: cxx_txn.cpp,v 11.33 2004/09/22 22:20:31 mjc Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: cxx_txn.cpp,v 11.27 2002/07/20 13:50:11 dda Exp $";
#endif /* not lint */
#include <errno.h>
#include "db_cxx.h"
#include "dbinc/cxx_int.h"
#include "db_int.h"
#include "dbinc/txn.h"
// Helper macro for simple methods that pass through to the
// underlying C method. It may return an error or raise an exception.
@@ -24,19 +23,20 @@ static const char revid[] = "$Id: cxx_txn.cpp,v 11.27 2002/07/20 13:50:11 dda Ex
// list element (e.g., "char *arg") and that _arglist is the arguments
// that should be passed through to the C method (e.g., "(db, arg)")
//
#define DBTXN_METHOD(_name, _delete, _argspec, _arglist) \
int DbTxn::_name _argspec \
{ \
int ret; \
DB_TXN *txn = unwrap(this); \
\
ret = txn->_name _arglist; \
/* Weird, but safe if we don't access this again. */ \
if (_delete) \
delete this; \
if (!DB_RETOK_STD(ret)) \
DB_ERROR("DbTxn::" # _name, ret, ON_ERROR_UNKNOWN); \
return (ret); \
#define DBTXN_METHOD(_name, _delete, _argspec, _arglist) \
int DbTxn::_name _argspec \
{ \
int ret; \
DB_TXN *txn = unwrap(this); \
DbEnv *dbenv = DbEnv::get_DbEnv(txn->mgrp->dbenv); \
\
ret = txn->_name _arglist; \
/* Weird, but safe if we don't access this again. */ \
if (_delete) \
delete this; \
if (!DB_RETOK_STD(ret)) \
DB_ERROR(dbenv, "DbTxn::" # _name, ret, ON_ERROR_UNKNOWN); \
return (ret); \
}
// private constructor, never called but needed by some C++ linkers
@@ -46,7 +46,7 @@ DbTxn::DbTxn()
}
DbTxn::DbTxn(DB_TXN *txn)
: imp_(wrap(txn))
: imp_(txn)
{
txn->api_internal = this;
}
@@ -75,7 +75,5 @@ DBTXN_METHOD(set_timeout, 0, (db_timeout_t timeout, u_int32_t flags),
DbTxn *DbTxn::wrap_DB_TXN(DB_TXN *txn)
{
DbTxn *wrapped_txn = get_DbTxn(txn);
if (wrapped_txn == NULL)
wrapped_txn = new DbTxn(txn);
return wrapped_txn;
return (wrapped_txn != NULL) ? wrapped_txn : new DbTxn(txn);
}

View File

@@ -1,17 +1,15 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: crdel.src,v 11.24 2002/04/17 19:02:57 krinsky Exp $
* $Id: crdel.src,v 11.29 2004/06/17 17:35:15 bostic Exp $
*/
PREFIX __crdel
DBPRIVATE
INCLUDE #include "db_config.h"
INCLUDE
INCLUDE #ifndef NO_SYSTEM_INCLUDES
INCLUDE #include <sys/types.h>
INCLUDE
@@ -25,7 +23,6 @@ INCLUDE #include "dbinc/db_page.h"
INCLUDE #include "dbinc/db_dispatch.h"
INCLUDE #include "dbinc/db_am.h"
INCLUDE #include "dbinc/log.h"
INCLUDE #include "dbinc/rep.h"
INCLUDE #include "dbinc/txn.h"
INCLUDE
@@ -39,7 +36,7 @@ INCLUDE
*/
BEGIN metasub 142
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
PGDBT page DBT s
POINTER lsn DB_LSN * lu
END

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: crdel_rec.c,v 11.68 2004/04/29 00:07:55 ubell Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: crdel_rec.c,v 11.64 2002/08/14 20:27:34 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -19,8 +17,10 @@ static const char revid[] = "$Id: crdel_rec.c,v 11.64 2002/08/14 20:27:34 bostic
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/hash.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
/*
* __crdel_metasub_recover --
@@ -49,16 +49,10 @@ __crdel_metasub_recover(dbenv, dbtp, lsnp, op, info)
REC_PRINT(__crdel_metasub_print);
REC_INTRO(__crdel_metasub_read, 0);
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
if (DB_REDO(op)) {
if ((ret = mpf->get(mpf,
&argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
} else {
*lsnp = argp->prev_lsn;
ret = 0;
goto out;
}
if ((ret = __memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
*lsnp = argp->prev_lsn;
ret = 0;
goto out;
}
modified = 0;
@@ -84,7 +78,7 @@ __crdel_metasub_recover(dbenv, dbtp, lsnp, op, info)
LSN(pagep) = argp->lsn;
modified = 1;
}
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
pagep = NULL;
@@ -92,6 +86,6 @@ done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (pagep != NULL)
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
REC_CLOSE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,15 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db.src,v 11.18 2002/04/17 19:02:58 krinsky Exp $
* $Id: db.src,v 11.28 2004/06/17 17:35:15 bostic Exp $
*/
PREFIX __db
DBPRIVATE
INCLUDE #include "db_config.h"
INCLUDE
INCLUDE #ifndef NO_SYSTEM_INCLUDES
INCLUDE #include <sys/types.h>
INCLUDE
@@ -25,7 +23,6 @@ INCLUDE #include "dbinc/db_page.h"
INCLUDE #include "dbinc/db_dispatch.h"
INCLUDE #include "dbinc/db_am.h"
INCLUDE #include "dbinc/log.h"
INCLUDE #include "dbinc/rep.h"
INCLUDE #include "dbinc/txn.h"
INCLUDE
@@ -48,7 +45,7 @@ INCLUDE
BEGIN addrem 41
ARG opcode u_int32_t lu
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
ARG indx u_int32_t lu
ARG nbytes u_int32_t lu
PGDBT hdr DBT s
@@ -74,9 +71,9 @@ END
BEGIN big 43
ARG opcode u_int32_t lu
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
WRLOCKNZ prev_pgno db_pgno_t lu
WRLOCKNZ next_pgno db_pgno_t lu
ARG pgno db_pgno_t lu
ARG prev_pgno db_pgno_t lu
ARG next_pgno db_pgno_t lu
DBT dbt DBT s
POINTER pagelsn DB_LSN * lu
POINTER prevlsn DB_LSN * lu
@@ -93,33 +90,11 @@ END
*/
BEGIN ovref 44
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
ARG adjust int32_t ld
POINTER lsn DB_LSN * lu
END
/*
* relink -- Handles relinking around a page.
*
* opcode: indicates if this is an addpage or delete page
* pgno: the page being changed.
* lsn the page's original lsn.
* prev: the previous page.
* lsn_prev: the previous page's original lsn.
* next: the next page.
* lsn_next: the previous page's original lsn.
*/
BEGIN relink 45
ARG opcode u_int32_t lu
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
POINTER lsn DB_LSN * lu
WRLOCKNZ prev db_pgno_t lu
POINTER lsn_prev DB_LSN * lu
WRLOCKNZ next db_pgno_t lu
POINTER lsn_next DB_LSN * lu
END
/*
* Debug -- log an operation upon entering an access method.
* op: Operation (cursor, c_close, c_get, c_put, c_del,
@@ -142,7 +117,7 @@ END
*/
BEGIN noop 48
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
POINTER prevlsn DB_LSN * lu
END
@@ -155,15 +130,17 @@ END
* pgno: the page allocated.
* ptype: the type of the page allocated.
* next: the next page on the free list.
* last_pgno: the last page in the file after this op.
*/
BEGIN pg_alloc 49
DB fileid int32_t ld
POINTER meta_lsn DB_LSN * lu
WRLOCK meta_pgno db_pgno_t lu
ARG meta_pgno db_pgno_t lu
POINTER page_lsn DB_LSN * lu
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
ARG ptype u_int32_t lu
ARG next db_pgno_t lu
ARG last_pgno db_pgno_t lu
END
/*
@@ -174,14 +151,16 @@ END
* meta_pgno: the meta-data page number.
* header: the header from the free'd page.
* next: the previous next pointer on the metadata page.
* last_pgno: the last page in the file before this op.
*/
BEGIN pg_free 50
DB fileid int32_t ld
WRLOCK pgno db_pgno_t lu
ARG pgno db_pgno_t lu
POINTER meta_lsn DB_LSN * lu
WRLOCK meta_pgno db_pgno_t lu
ARG meta_pgno db_pgno_t lu
PGDBT header DBT s
ARG next db_pgno_t lu
ARG last_pgno db_pgno_t lu
END
/*
@@ -193,3 +172,67 @@ END
*/
BEGIN cksum 51
END
/*
* pg_freedata: used to record freeing a page with data on it.
*
* pgno: the page being freed.
* meta_lsn: the meta-data page's original lsn.
* meta_pgno: the meta-data page number.
* header: the header and index entries from the free'd page.
* data: the data from the free'd page.
* next: the previous next pointer on the metadata page.
* last_pgno: the last page in the file before this op.
*/
BEGIN pg_freedata 52
DB fileid int32_t ld
ARG pgno db_pgno_t lu
POINTER meta_lsn DB_LSN * lu
ARG meta_pgno db_pgno_t lu
PGDBT header DBT s
ARG next db_pgno_t lu
ARG last_pgno db_pgno_t lu
PGDBT data DBT s
END
/*
* pg_prepare: used to record an aborted page in a prepared transaction.
*
* pgno: the page being freed.
*/
BEGIN pg_prepare 53
DB fileid int32_t ld
ARG pgno db_pgno_t lu
END
/*
* pg_new: used to record a new page put on the free list.
*
* pgno: the page being freed.
* meta_lsn: the meta-data page's original lsn.
* meta_pgno: the meta-data page number.
* header: the header from the free'd page.
* next: the previous next pointer on the metadata page.
*/
BEGIN pg_new 54
DB fileid int32_t ld
ARG pgno db_pgno_t lu
POINTER meta_lsn DB_LSN * lu
ARG meta_pgno db_pgno_t lu
PGDBT header DBT s
ARG next db_pgno_t lu
END
/*
* pg_init: used to reinitialize a page during truncate.
*
* pgno: the page being initialized.
* header: the header from the page.
* data: data that used to be on the page.
*/
BEGIN pg_init 60
DB fileid int32_t ld
ARG pgno db_pgno_t lu
PGDBT header DBT s
PGDBT data DBT s
END

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998-2002
* Copyright (c) 1998-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_am.c,v 11.120 2004/10/07 17:33:32 sue Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_am.c,v 11.96 2002/08/27 15:17:32 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -29,91 +27,16 @@ static const char revid[] = "$Id: db_am.c,v 11.96 2002/08/27 15:17:32 bostic Exp
static int __db_append_primary __P((DBC *, DBT *, DBT *));
static int __db_secondary_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
static int __db_secondary_close __P((DB *, u_int32_t));
#ifdef DEBUG
static int __db_cprint_item __P((DBC *));
#endif
/*
* __db_cursor --
* Allocate and return a cursor.
* __db_cursor_int --
* Internal routine to create a cursor.
*
* PUBLIC: int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t));
*/
int
__db_cursor(dbp, txn, dbcp, flags)
DB *dbp;
DB_TXN *txn;
DBC **dbcp;
u_int32_t flags;
{
DB_ENV *dbenv;
DBC *dbc;
db_lockmode_t mode;
u_int32_t op;
int ret;
dbenv = dbp->dbenv;
PANIC_CHECK(dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor");
/* Validate arguments. */
if ((ret = __db_cursorchk(dbp, flags)) != 0)
return (ret);
/*
* Check for consistent transaction usage. For now, assume that
* this cursor might be used for read operations only (in which
* case it may not require a txn). We'll check more stringently
* in c_del and c_put. (Note that this all means that the
* read-op txn tests have to be a subset of the write-op ones.)
*/
if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
return (ret);
if ((ret = __db_icursor(dbp,
txn, dbp->type, PGNO_INVALID, 0, DB_LOCK_INVALIDID, dbcp)) != 0)
return (ret);
dbc = *dbcp;
/*
* If this is CDB, do all the locking in the interface, which is
* right here.
*/
if (CDB_LOCKING(dbenv)) {
op = LF_ISSET(DB_OPFLAGS_MASK);
mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE :
((op == DB_WRITECURSOR) ? DB_LOCK_IWRITE : DB_LOCK_READ);
if ((ret = dbenv->lock_get(dbenv, dbc->locker, 0,
&dbc->lock_dbt, mode, &dbc->mylock)) != 0) {
(void)__db_c_close(dbc);
return (ret);
}
if (op == DB_WRITECURSOR)
F_SET(dbc, DBC_WRITECURSOR);
if (op == DB_WRITELOCK)
F_SET(dbc, DBC_WRITER);
}
if (LF_ISSET(DB_DIRTY_READ) ||
(txn != NULL && F_ISSET(txn, TXN_DIRTY_READ)))
F_SET(dbc, DBC_DIRTY_READ);
return (0);
}
/*
* __db_icursor --
* Internal version of __db_cursor. If dbcp is
* non-NULL it is assumed to point to an area to
* initialize as a cursor.
*
* PUBLIC: int __db_icursor
* PUBLIC: int __db_cursor_int
* PUBLIC: __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, u_int32_t, DBC **));
*/
int
__db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
__db_cursor_int(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
DB *dbp;
DB_TXN *txn;
DBTYPE dbtype;
@@ -122,7 +45,7 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
u_int32_t lockerid;
DBC **dbcp;
{
DBC *dbc, *adbc;
DBC *dbc;
DBC_INTERNAL *cp;
DB_ENV *dbenv;
int allocated, ret;
@@ -131,6 +54,9 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
allocated = 0;
/*
* If dbcp is non-NULL it is assumed to point to an area to initialize
* as a cursor.
*
* Take one from the free list if it's available. Take only the
* right type. With off page dups we may have different kinds
* of cursors on the queue for a single database.
@@ -146,7 +72,7 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
if (dbc == NULL) {
if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(DBC), &dbc)) != 0)
if ((ret = __os_calloc(dbenv, 1, sizeof(DBC), &dbc)) != 0)
return (ret);
allocated = 1;
dbc->flags = 0;
@@ -156,28 +82,33 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
/* Set up locking information. */
if (LOCKING_ON(dbenv)) {
/*
* If we are not threaded, then there is no need to
* create new locker ids. We know that no one else
* is running concurrently using this DB, so we can
* take a peek at any cursors on the active queue.
* If we are not threaded, we share a locker ID among
* all cursors opened in the environment handle,
* allocating one if this is the first cursor.
*
* This relies on the fact that non-threaded DB handles
* always have non-threaded environment handles, since
* we set DB_THREAD on DB handles created with threaded
* environment handles.
*/
if (!DB_IS_THREADED(dbp) &&
(adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
dbc->lid = adbc->lid;
else {
if ((ret =
dbenv->lock_id(dbenv, &dbc->lid)) != 0)
if (!DB_IS_THREADED(dbp)) {
if (dbp->dbenv->env_lid == DB_LOCK_INVALIDID &&
(ret =
__lock_id(dbenv,&dbp->dbenv->env_lid)) != 0)
goto err;
dbc->lid = dbp->dbenv->env_lid;
} else {
if ((ret = __lock_id(dbenv, &dbc->lid)) != 0)
goto err;
F_SET(dbc, DBC_OWN_LID);
}
/*
* In CDB, secondary indices should share a lock file
* ID with the primary; otherwise we're susceptible to
* deadlocks. We also use __db_icursor rather
* than sdbp->cursor to create secondary update
* cursors in c_put and c_del; these won't
* acquire a new lock.
* ID with the primary; otherwise we're susceptible
* to deadlocks. We also use __db_cursor_int rather
* than __db_cursor to create secondary update cursors
* in c_put and c_del; these won't acquire a new lock.
*
* !!!
* Since this is in the one-time cursor allocation
@@ -185,7 +116,7 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
* close, all cursors in the secondary when we
* associate.
*/
if (CDB_LOCKING(dbp->dbenv) &&
if (CDB_LOCKING(dbenv) &&
F_ISSET(dbp, DB_AM_SECONDARY))
memcpy(dbc->lock.fileid,
dbp->s_primary->fileid, DB_FILE_ID_LEN);
@@ -231,9 +162,9 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
if ((ret = __qam_c_init(dbc)) != 0)
goto err;
break;
case DB_UNKNOWN:
default:
ret = __db_unknown_type(dbp->dbenv,
"__db_icursor", dbtype);
ret = __db_unknown_type(dbenv, "DB->cursor", dbtype);
goto err;
}
@@ -270,10 +201,8 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
dbc->locker = lockerid;
else
dbc->locker = dbc->lid;
} else {
} else
dbc->locker = txn->txnid;
txn->cursors++;
}
/*
* These fields change when we are used as a secondary index, so
@@ -283,7 +212,7 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
* __db_c_get is used by all access methods, so this should be safe.
*/
if (F_ISSET(dbp, DB_AM_SECONDARY))
dbc->c_get = __db_c_secondary_get;
dbc->c_get = __db_c_secondary_get_pp;
if (is_opd)
F_SET(dbc, DBC_OPD);
@@ -310,11 +239,20 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
case DB_HASH:
case DB_QUEUE:
break;
case DB_UNKNOWN:
default:
ret = __db_unknown_type(dbp->dbenv, "__db_icursor", dbp->type);
ret = __db_unknown_type(dbenv, "DB->cursor", dbp->type);
goto err;
}
/*
* The transaction keeps track of how many cursors were opened within
* it to catch application errors where the cursor isn't closed when
* the transaction is resolved.
*/
if (txn != NULL)
++txn->cursors;
MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);
F_SET(dbc, DBC_ACTIVE);
@@ -324,189 +262,7 @@ __db_icursor(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)
return (0);
err: if (allocated)
__os_free(dbp->dbenv, dbc);
return (ret);
}
#ifdef DEBUG
/*
* __db_cprint --
* Display the cursor active and free queues.
*
* PUBLIC: int __db_cprint __P((DB *));
*/
int
__db_cprint(dbp)
DB *dbp;
{
DBC *dbc;
int ret, t_ret;
ret = 0;
MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp);
fprintf(stderr, "Active queue:\n");
for (dbc = TAILQ_FIRST(&dbp->active_queue);
dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
if ((t_ret = __db_cprint_item(dbc)) != 0 && ret == 0)
ret = t_ret;
fprintf(stderr, "Free queue:\n");
for (dbc = TAILQ_FIRST(&dbp->free_queue);
dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
if ((t_ret = __db_cprint_item(dbc)) != 0 && ret == 0)
ret = t_ret;
MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);
return (ret);
}
static
int __db_cprint_item(dbc)
DBC *dbc;
{
static const FN fn[] = {
{ DBC_ACTIVE, "active" },
{ DBC_COMPENSATE, "compensate" },
{ DBC_OPD, "off-page-dup" },
{ DBC_RECOVER, "recover" },
{ DBC_RMW, "read-modify-write" },
{ DBC_TRANSIENT, "transient" },
{ DBC_WRITECURSOR, "write cursor" },
{ DBC_WRITEDUP, "internally dup'ed write cursor" },
{ DBC_WRITER, "short-term write cursor" },
{ 0, NULL }
};
DB *dbp;
DBC_INTERNAL *cp;
const char *s;
dbp = dbc->dbp;
cp = dbc->internal;
s = __db_dbtype_to_string(dbc->dbtype);
if (strcmp(s, "UNKNOWN TYPE") == 0) {
DB_ASSERT(0);
return (1);
}
fprintf(stderr, "%s/%#0lx: opd: %#0lx\n",
s, P_TO_ULONG(dbc), P_TO_ULONG(cp->opd));
fprintf(stderr, "\ttxn: %#0lx lid: %lu locker: %lu\n",
P_TO_ULONG(dbc->txn), (u_long)dbc->lid, (u_long)dbc->locker);
fprintf(stderr, "\troot: %lu page/index: %lu/%lu",
(u_long)cp->root, (u_long)cp->pgno, (u_long)cp->indx);
__db_prflags(dbc->flags, fn, stderr);
fprintf(stderr, "\n");
switch (dbp->type) {
case DB_BTREE:
__bam_cprint(dbc);
break;
case DB_HASH:
__ham_cprint(dbc);
break;
default:
break;
}
return (0);
}
#endif /* DEBUG */
/*
* db_fd --
* Return a file descriptor for flock'ing.
*
* PUBLIC: int __db_fd __P((DB *, int *));
*/
int
__db_fd(dbp, fdp)
DB *dbp;
int *fdp;
{
DB_FH *fhp;
int ret;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->fd");
/*
* XXX
* Truly spectacular layering violation.
*/
if ((ret = __mp_xxx_fh(dbp->mpf, &fhp)) != 0)
return (ret);
if (F_ISSET(fhp, DB_FH_VALID)) {
*fdp = fhp->fd;
return (0);
} else {
*fdp = -1;
__db_err(dbp->dbenv, "DB does not have a valid file handle");
return (ENOENT);
}
}
/*
* __db_get --
* Return a key/data pair.
*
* PUBLIC: int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
*/
int
__db_get(dbp, txn, key, data, flags)
DB *dbp;
DB_TXN *txn;
DBT *key, *data;
u_int32_t flags;
{
DBC *dbc;
int mode, ret, t_ret;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get");
if ((ret = __db_getchk(dbp, key, data, flags)) != 0)
return (ret);
/* Check for consistent transaction usage. */
if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
return (ret);
mode = 0;
if (LF_ISSET(DB_DIRTY_READ)) {
mode = DB_DIRTY_READ;
LF_CLR(DB_DIRTY_READ);
}
else if (flags == DB_CONSUME || flags == DB_CONSUME_WAIT)
mode = DB_WRITELOCK;
if ((ret = dbp->cursor(dbp, txn, &dbc, mode)) != 0)
return (ret);
DEBUG_LREAD(dbc, txn, "__db_get", key, NULL, flags);
/*
* The DBC_TRANSIENT flag indicates that we're just doing a
* single operation with this cursor, and that in case of
* error we don't need to restore it to its old position--we're
* going to close it right away. Thus, we can perform the get
* without duplicating the cursor, saving some cycles in this
* common case.
*
* SET_RET_MEM indicates that if key and/or data have no DBT
* flags set and DB manages the returned-data memory, that memory
* will belong to this handle, not to the underlying cursor.
*/
F_SET(dbc, DBC_TRANSIENT);
SET_RET_MEM(dbc, dbp);
if (LF_ISSET(~(DB_RMW | DB_MULTIPLE)) == 0)
LF_SET(DB_SET);
ret = dbc->c_get(dbc, key, data, flags);
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
__os_free(dbenv, dbc);
return (ret);
}
@@ -526,36 +282,14 @@ __db_put(dbp, txn, key, data, flags)
DBC *dbc;
DBT tdata;
DB_ENV *dbenv;
int ret, t_ret, txn_local;
int ret, t_ret;
dbc = NULL;
dbenv = dbp->dbenv;
txn_local = 0;
PANIC_CHECK(dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->put");
/* Validate arguments. */
if ((ret = __db_putchk(dbp, key, data,
flags, F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK))) != 0)
if ((ret = __db_cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
return (ret);
/* Create local transaction as necessary. */
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
return (ret);
txn_local = 1;
LF_CLR(DB_AUTO_COMMIT);
}
/* Check for consistent transaction usage. */
if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
goto err;
if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
goto err;
DEBUG_LWRITE(dbc, txn, "db_put", key, data, flags);
DEBUG_LWRITE(dbc, txn, "DB->put", key, data, flags);
SET_RET_MEM(dbc, dbp);
@@ -594,10 +328,15 @@ __db_put(dbp, txn, key, data, flags)
if ((ret = __ram_append(dbc, key, &tdata)) != 0)
goto err;
break;
case DB_BTREE:
case DB_HASH:
case DB_UNKNOWN:
default:
/* The interface should prevent this. */
DB_ASSERT(0);
ret = __db_ferr(dbenv, "__db_put", flags);
DB_ASSERT(
dbp->type == DB_QUEUE || dbp->type == DB_RECNO);
ret = __db_ferr(dbenv, "DB->put", 0);
goto err;
}
@@ -621,7 +360,7 @@ __db_put(dbp, txn, key, data, flags)
FREE_IF_NEEDED(dbp, &tdata);
/* No need for a cursor put; we're done. */
goto err;
goto done;
case DB_NOOVERWRITE:
flags = 0;
/*
@@ -636,7 +375,7 @@ __db_put(dbp, txn, key, data, flags)
* If we're doing page-level locking, set the read-modify-write
* flag, we're going to overwrite immediately.
*/
if ((ret = dbc->c_get(dbc, key, &tdata,
if ((ret = __db_c_get(dbc, key, &tdata,
DB_SET | (STD_LOCKING(dbc) ? DB_RMW : 0))) == 0)
ret = DB_KEYEXIST;
else if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
@@ -646,34 +385,27 @@ __db_put(dbp, txn, key, data, flags)
/* Fall through to normal cursor put. */
break;
}
if (ret == 0)
ret = dbc->c_put(dbc,
ret = __db_c_put(dbc,
key, data, flags == 0 ? DB_KEYLAST : flags);
err: /* Close the cursor. */
if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
err:
done: /* Close the cursor. */
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
/* Commit for DB_AUTO_COMMIT. */
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
}
return (ret);
}
/*
* __db_delete --
* __db_del --
* Delete the items referenced by a key.
*
* PUBLIC: int __db_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
* PUBLIC: int __db_del __P((DB *, DB_TXN *, DBT *, u_int32_t));
*/
int
__db_delete(dbp, txn, key, flags)
__db_del(dbp, txn, key, flags)
DB *dbp;
DB_TXN *txn;
DBT *key;
@@ -681,38 +413,15 @@ __db_delete(dbp, txn, key, flags)
{
DBC *dbc;
DBT data, lkey;
DB_ENV *dbenv;
u_int32_t f_init, f_next;
int ret, t_ret, txn_local;
dbc = NULL;
dbenv = dbp->dbenv;
txn_local = 0;
PANIC_CHECK(dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del");
/* Check for invalid flags. */
if ((ret = __db_delchk(dbp, key, flags)) != 0)
return (ret);
/* Create local transaction as necessary. */
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
return (ret);
txn_local = 1;
LF_CLR(DB_AUTO_COMMIT);
}
/* Check for consistent transaction usage. */
if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
goto err;
int ret, t_ret;
/* Allocate a cursor. */
if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
if ((ret = __db_cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
goto err;
DEBUG_LWRITE(dbc, txn, "db_delete", key, NULL, flags);
DEBUG_LWRITE(dbc, txn, "DB->del", key, NULL, flags);
COMPQUIET(flags, 0);
/*
* Walk a cursor through the key/data pairs, deleting as we go. Set
@@ -737,7 +446,7 @@ __db_delete(dbp, txn, key, flags)
}
/* Walk through the set of key/data pairs, deleting as we go. */
if ((ret = dbc->c_get(dbc, key, &data, f_init)) != 0)
if ((ret = __db_c_get(dbc, key, &data, f_init)) != 0)
goto err;
/*
@@ -760,40 +469,29 @@ __db_delete(dbp, txn, key, flags)
* The ordinary AM-independent alternative will work just fine with
* a hash; it'll just be slower.
*/
if (dbp->type == DB_HASH) {
if (dbp->type == DB_HASH)
if (LIST_FIRST(&dbp->s_secondaries) == NULL &&
!F_ISSET(dbp, DB_AM_SECONDARY) &&
dbc->internal->opd == NULL) {
ret = __ham_quick_delete(dbc);
goto err;
goto done;
}
}
for (;;) {
if ((ret = dbc->c_del(dbc, 0)) != 0)
goto err;
if ((ret = dbc->c_get(dbc, &lkey, &data, f_next)) != 0) {
if (ret == DB_NOTFOUND) {
if ((ret = __db_c_del(dbc, 0)) != 0)
break;
if ((ret = __db_c_get(dbc, &lkey, &data, f_next)) != 0) {
if (ret == DB_NOTFOUND)
ret = 0;
break;
}
goto err;
break;
}
}
done:
err: /* Discard the cursor. */
if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
/* Commit for DB_AUTO_COMMIT. */
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
}
return (ret);
}
@@ -801,22 +499,17 @@ err: /* Discard the cursor. */
* __db_sync --
* Flush the database cache.
*
* PUBLIC: int __db_sync __P((DB *, u_int32_t));
* PUBLIC: int __db_sync __P((DB *));
*/
int
__db_sync(dbp, flags)
__db_sync(dbp)
DB *dbp;
u_int32_t flags;
{
int ret, t_ret;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
ret = 0;
if ((ret = __db_syncchk(dbp, flags)) != 0)
return (ret);
/* Read-only trees never need to be sync'd. */
/* If the database was read-only, we're done. */
if (F_ISSET(dbp, DB_AM_RDONLY))
return (0);
@@ -824,13 +517,17 @@ __db_sync(dbp, flags)
if (dbp->type == DB_RECNO)
ret = __ram_writeback(dbp);
/* If the tree was never backed by a database file, we're done. */
/* If the database was never backed by a database file, we're done. */
if (F_ISSET(dbp, DB_AM_INMEM))
return (0);
return (ret);
if (dbp->type == DB_QUEUE)
ret = __qam_sync(dbp);
else
/* Flush any dirty pages from the cache to the backing file. */
if ((t_ret = __memp_fsync(dbp->mpf)) != 0 && ret == 0)
ret = t_ret;
/* Flush any dirty pages from the cache to the backing file. */
if ((t_ret = dbp->mpf->sync(dbp->mpf)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
@@ -851,40 +548,11 @@ __db_associate(dbp, txn, sdbp, callback, flags)
DB_ENV *dbenv;
DBC *pdbc, *sdbc;
DBT skey, key, data;
int build, ret, t_ret, txn_local;
int build, ret, t_ret;
dbenv = dbp->dbenv;
PANIC_CHECK(dbenv);
txn_local = 0;
pdbc = NULL;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
memset(&skey, 0, sizeof(DBT));
if ((ret = __db_associatechk(dbp, sdbp, callback, flags)) != 0)
return (ret);
/*
* Create a local transaction as necessary, check for consistent
* transaction usage, and, if we have no transaction but do have
* locking on, acquire a locker id for the handle lock acquisition.
*/
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
return (ret);
txn_local = 1;
} else if (txn != NULL && !TXN_ON(dbenv))
return (__db_not_txn_env(dbenv));
/*
* Check that if an open transaction is in progress, we're in it,
* for other common transaction errors, and for concurrent associates.
*/
if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
return (ret);
pdbc = sdbc = NULL;
ret = 0;
sdbp->s_callback = callback;
sdbp->s_primary = dbp;
@@ -893,23 +561,7 @@ __db_associate(dbp, txn, sdbp, callback, flags)
sdbp->get = __db_secondary_get;
sdbp->stored_close = sdbp->close;
sdbp->close = __db_secondary_close;
/*
* Secondary cursors may have the primary's lock file ID, so we
* need to make sure that no older cursors are lying around
* when we make the transition.
*/
if (TAILQ_FIRST(&sdbp->active_queue) != NULL ||
TAILQ_FIRST(&sdbp->join_queue) != NULL) {
__db_err(dbenv,
"Databases may not become secondary indices while cursors are open");
ret = EINVAL;
goto err;
}
while ((sdbc = TAILQ_FIRST(&sdbp->free_queue)) != NULL)
if ((ret = __db_c_destroy(sdbc)) != 0)
goto err;
sdbp->close = __db_secondary_close_pp;
F_SET(sdbp, DB_AM_SECONDARY);
@@ -920,19 +572,18 @@ __db_associate(dbp, txn, sdbp, callback, flags)
*/
build = 0;
if (LF_ISSET(DB_CREATE)) {
if ((ret = sdbp->cursor(sdbp, txn, &sdbc, 0)) != 0)
if ((ret = __db_cursor(sdbp, txn, &sdbc, 0)) != 0)
goto err;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
/*
* We don't care about key or data; we're just doing
* an existence check.
*/
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
F_SET(&key, DB_DBT_PARTIAL | DB_DBT_USERMEM);
F_SET(&data, DB_DBT_PARTIAL | DB_DBT_USERMEM);
if ((ret = sdbc->c_real_get(sdbc, &key, &data,
if ((ret = __db_c_get(sdbc, &key, &data,
(STD_LOCKING(sdbc) ? DB_RMW : 0) |
DB_FIRST)) == DB_NOTFOUND) {
build = 1;
@@ -943,8 +594,12 @@ __db_associate(dbp, txn, sdbp, callback, flags)
* Secondary cursors have special refcounting close
* methods. Be careful.
*/
if ((t_ret = __db_c_close(sdbc)) != 0)
if ((t_ret = __db_c_close(sdbc)) != 0 && ret == 0)
ret = t_ret;
/* Reset for later error check. */
sdbc = NULL;
if (ret != 0)
goto err;
}
@@ -976,10 +631,10 @@ __db_associate(dbp, txn, sdbp, callback, flags)
* as the secondary, so they won't conflict. This should
* be harmless even if we're not using CDB.
*/
if ((ret = sdbp->cursor(sdbp, txn, &sdbc,
if ((ret = __db_cursor(sdbp, txn, &sdbc,
CDB_LOCKING(sdbp->dbenv) ? DB_WRITECURSOR : 0)) != 0)
goto err;
if ((ret = __db_icursor(dbp,
if ((ret = __db_cursor_int(dbp,
txn, dbp->type, PGNO_INVALID, 0, sdbc->locker, &pdbc)) != 0)
goto err;
@@ -988,15 +643,14 @@ __db_associate(dbp, txn, sdbp, callback, flags)
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
while ((ret = pdbc->c_get(pdbc, &key, &data, DB_NEXT)) == 0) {
while ((ret = __db_c_get(pdbc, &key, &data, DB_NEXT)) == 0) {
memset(&skey, 0, sizeof(DBT));
if ((ret = callback(sdbp, &key, &data, &skey)) != 0) {
if (ret == DB_DONOTINDEX)
continue;
else
goto err;
goto err;
}
if ((ret = sdbc->c_put(sdbc,
if ((ret = __db_c_put(sdbc,
&skey, &key, DB_UPDATE_SECONDARY)) != 0) {
FREE_IF_NEEDED(sdbp, &skey);
goto err;
@@ -1006,79 +660,16 @@ __db_associate(dbp, txn, sdbp, callback, flags)
}
if (ret == DB_NOTFOUND)
ret = 0;
if ((ret = sdbc->c_close(sdbc)) != 0)
goto err;
}
err: if (pdbc != NULL && (t_ret = pdbc->c_close(pdbc)) != 0 && ret == 0)
err: if (sdbc != NULL && (t_ret = __db_c_close(sdbc)) != 0 && ret == 0)
ret = t_ret;
if (pdbc != NULL && (t_ret = __db_c_close(pdbc)) != 0 && ret == 0)
ret = t_ret;
dbp->associate_lid = DB_LOCK_INVALIDID;
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
}
return (ret);
}
/*
* __db_pget --
* Return a primary key/data pair given a secondary key.
*
* PUBLIC: int __db_pget __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t));
*/
int
__db_pget(dbp, txn, skey, pkey, data, flags)
DB *dbp;
DB_TXN *txn;
DBT *skey, *pkey, *data;
u_int32_t flags;
{
DBC *dbc;
int ret, t_ret;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->pget");
if ((ret = __db_pgetchk(dbp, skey, pkey, data, flags)) != 0)
return (ret);
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
return (ret);
SET_RET_MEM(dbc, dbp);
/*
* The underlying cursor pget will fill in a default DBT for null
* pkeys, and use the cursor's returned-key memory internally to
* store any intermediate primary keys. However, we've just set
* the returned-key memory to the DB handle's key memory, which
* is unsafe to use if the DB handle is threaded. If the pkey
* argument is NULL, use the DBC-owned returned-key memory
* instead; it'll go away when we close the cursor before we
* return, but in this case that's just fine, as we're not
* returning the primary key.
*/
if (pkey == NULL)
dbc->rkey = &dbc->my_rkey;
DEBUG_LREAD(dbc, txn, "__db_pget", skey, NULL, flags);
/*
* The cursor is just a perfectly ordinary secondary database
* cursor. Call its c_pget() method to do the dirty work.
*/
if (flags == 0 || flags == DB_RMW)
flags |= DB_SET;
ret = dbc->c_pget(dbc, skey, pkey, data, flags);
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
@@ -1096,7 +687,7 @@ __db_secondary_get(sdbp, txn, skey, data, flags)
{
DB_ASSERT(F_ISSET(sdbp, DB_AM_SECONDARY));
return (sdbp->pget(sdbp, txn, skey, NULL, data, flags));
return (__db_pget_pp(sdbp, txn, skey, NULL, data, flags));
}
/*
@@ -1104,8 +695,10 @@ __db_secondary_get(sdbp, txn, skey, data, flags)
* Wrapper function for DB->close() which we use on secondaries to
* manage refcounting and make sure we don't close them underneath
* a primary that is updating.
*
* PUBLIC: int __db_secondary_close __P((DB *, u_int32_t));
*/
static int
int
__db_secondary_close(sdbp, flags)
DB *sdbp;
u_int32_t flags;
@@ -1138,7 +731,7 @@ __db_secondary_close(sdbp, flags)
* sdbp->close is this function; call the real one explicitly if
* need be.
*/
return (doclose ? __db_close(sdbp, flags) : 0);
return (doclose ? __db_close(sdbp, NULL, flags) : 0);
}
/*
@@ -1179,12 +772,12 @@ __db_append_primary(dbc, key, data)
* correctly-constructed full data item from this partial
* put is on the page waiting for us.
*/
if ((ret = __db_c_idup(dbc, &pdbc, DB_POSITIONI)) != 0)
if ((ret = __db_c_idup(dbc, &pdbc, DB_POSITION)) != 0)
return (ret);
memset(&pkey, 0, sizeof(DBT));
memset(&pdata, 0, sizeof(DBT));
if ((ret = pdbc->c_get(pdbc, &pkey, &pdata, DB_CURRENT)) != 0)
if ((ret = __db_c_get(pdbc, &pkey, &pdata, DB_CURRENT)) != 0)
goto err;
key = &pkey;
@@ -1210,7 +803,7 @@ __db_append_primary(dbc, key, data)
goto err;
}
if ((ret = __db_icursor(sdbp, dbc->txn, sdbp->type,
if ((ret = __db_cursor_int(sdbp, dbc->txn, sdbp->type,
PGNO_INVALID, 0, dbc->locker, &sdbc)) != 0) {
FREE_IF_NEEDED(sdbp, &skey);
goto err;
@@ -1230,7 +823,7 @@ __db_append_primary(dbc, key, data)
if (!F_ISSET(sdbp, DB_AM_DUP)) {
memset(&oldpkey, 0, sizeof(DBT));
F_SET(&oldpkey, DB_DBT_MALLOC);
ret = sdbc->c_real_get(sdbc, &skey, &oldpkey,
ret = __db_c_get(sdbc, &skey, &oldpkey,
DB_SET | (STD_LOCKING(dbc) ? DB_RMW : 0));
if (ret == 0) {
cmp = __bam_defcmp(sdbp, &oldpkey, key);
@@ -1252,18 +845,18 @@ __db_append_primary(dbc, key, data)
goto err1;
}
ret = sdbc->c_put(sdbc, &skey, key, DB_UPDATE_SECONDARY);
ret = __db_c_put(sdbc, &skey, key, DB_UPDATE_SECONDARY);
err1: FREE_IF_NEEDED(sdbp, &skey);
if ((t_ret = sdbc->c_close(sdbc)) != 0 && ret == 0)
if ((t_ret = __db_c_close(sdbc)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
}
err: if (pdbc != NULL && (t_ret = pdbc->c_close(pdbc)) != 0 && ret == 0)
err: if (pdbc != NULL && (t_ret = __db_c_close(pdbc)) != 0 && ret == 0)
ret = t_ret;
if (sdbp != NULL && (t_ret = __db_s_done(sdbp)) != 0 && ret == 0)
ret = t_ret;

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -35,14 +35,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: db_conv.c,v 11.45 2004/01/28 03:35:57 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_conv.c,v 11.38 2002/08/15 03:00:13 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -100,6 +98,8 @@ __db_pgin(dbenv, pg, pp, cookie)
*/
if (FLD_ISSET(((DBMETA *)pp)->metaflags, DBMETA_CHKSUM))
F_SET(dbp, DB_AM_CHKSUM);
else
F_CLR(dbp, DB_AM_CHKSUM);
if (((DBMETA *)pp)->encrypt_alg != 0 ||
F_ISSET(dbp, DB_AM_ENCRYPT))
is_hmac = 1;
@@ -139,22 +139,25 @@ __db_pgin(dbenv, pg, pp, cookie)
* If there is no configuration problem and we don't get a match,
* it's fatal: panic the system.
*/
if (F_ISSET(dbp, DB_AM_CHKSUM) && sum_len != 0)
if (F_ISSET(dbp, DB_AM_CHKSUM) && sum_len != 0) {
if (F_ISSET(dbp, DB_AM_SWAP) && is_hmac == 0)
P_32_SWAP(chksum);
switch (ret = __db_check_chksum(
dbenv, db_cipher, chksum, pp, sum_len, is_hmac)) {
case 0:
break;
case -1:
if (DBENV_LOGGING(dbenv))
__db_cksum_log(
(void)__db_cksum_log(
dbenv, NULL, &not_used, DB_FLUSH);
__db_err(dbenv,
"checksum error: catastrophic recovery required");
"checksum error: page %lu: catastrophic recovery required",
(u_long)pg);
return (__db_panic(dbenv, DB_RUNRECOVERY));
default:
return (ret);
}
}
if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
DB_ASSERT(db_cipher != NULL);
DB_ASSERT(F_ISSET(dbp, DB_AM_CHKSUM));
@@ -330,6 +333,8 @@ __db_pgout(dbenv, pg, pp, cookie)
break;
}
__db_chksum(pp, sum_len, key, chksum);
if (F_ISSET(dbp, DB_AM_SWAP) && !F_ISSET(dbp, DB_AM_ENCRYPT))
P_32_SWAP(chksum);
}
return (0);
}
@@ -436,6 +441,8 @@ __db_byteswap(dbenv, dbp, pg, h, pagesize, pgin)
SWAP32(p); /* pgno */
SWAP32(p); /* tlen */
break;
default:
return (__db_pgfmt(dbenv, pg));
}
}
@@ -484,6 +491,8 @@ __db_byteswap(dbenv, dbp, pg, h, pagesize, pgin)
M_32_SWAP(bo->pgno);
M_32_SWAP(bo->tlen);
break;
default:
return (__db_pgfmt(dbenv, pg));
}
if (!pgin)
@@ -509,6 +518,8 @@ __db_byteswap(dbenv, dbp, pg, h, pagesize, pgin)
M_32_SWAP(bo->pgno);
M_32_SWAP(bo->tlen);
break;
default:
return (__db_pgfmt(dbenv, pg));
}
if (!pgin)

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_dup.c,v 11.39 2004/02/18 21:34:37 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_dup.c,v 11.32 2002/08/08 03:57:47 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -20,7 +18,7 @@ static const char revid[] = "$Id: db_dup.c,v 11.32 2002/08/08 03:57:47 bostic Ex
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
#include "dbinc/db_am.h"
/*
@@ -164,118 +162,3 @@ __db_pitem(dbc, pagep, indx, nbytes, hdr, data)
return (0);
}
/*
* __db_relink --
* Relink around a deleted page.
*
* PUBLIC: int __db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int));
*/
int
__db_relink(dbc, add_rem, pagep, new_next, needlock)
DBC *dbc;
u_int32_t add_rem;
PAGE *pagep, **new_next;
int needlock;
{
DB *dbp;
PAGE *np, *pp;
DB_LOCK npl, ppl;
DB_LSN *nlsnp, *plsnp, ret_lsn;
DB_MPOOLFILE *mpf;
int ret;
dbp = dbc->dbp;
np = pp = NULL;
LOCK_INIT(npl);
LOCK_INIT(ppl);
nlsnp = plsnp = NULL;
mpf = dbp->mpf;
ret = 0;
/*
* Retrieve and lock the one/two pages. For a remove, we may need
* two pages (the before and after). For an add, we only need one
* because, the split took care of the prev.
*/
if (pagep->next_pgno != PGNO_INVALID) {
if (needlock && (ret = __db_lget(dbc,
0, pagep->next_pgno, DB_LOCK_WRITE, 0, &npl)) != 0)
goto err;
if ((ret = mpf->get(mpf, &pagep->next_pgno, 0, &np)) != 0) {
__db_pgerr(dbp, pagep->next_pgno, ret);
goto err;
}
nlsnp = &np->lsn;
}
if (add_rem == DB_REM_PAGE && pagep->prev_pgno != PGNO_INVALID) {
if (needlock && (ret = __db_lget(dbc,
0, pagep->prev_pgno, DB_LOCK_WRITE, 0, &ppl)) != 0)
goto err;
if ((ret = mpf->get(mpf, &pagep->prev_pgno, 0, &pp)) != 0) {
__db_pgerr(dbp, pagep->next_pgno, ret);
goto err;
}
plsnp = &pp->lsn;
}
/* Log the change. */
if (DBC_LOGGING(dbc)) {
if ((ret = __db_relink_log(dbp, dbc->txn, &ret_lsn, 0, add_rem,
pagep->pgno, &pagep->lsn, pagep->prev_pgno, plsnp,
pagep->next_pgno, nlsnp)) != 0)
goto err;
} else
LSN_NOT_LOGGED(ret_lsn);
if (np != NULL)
np->lsn = ret_lsn;
if (pp != NULL)
pp->lsn = ret_lsn;
if (add_rem == DB_REM_PAGE)
pagep->lsn = ret_lsn;
/*
* Modify and release the two pages.
*
* !!!
* The parameter new_next gets set to the page following the page we
* are removing. If there is no following page, then new_next gets
* set to NULL.
*/
if (np != NULL) {
if (add_rem == DB_ADD_PAGE)
np->prev_pgno = pagep->pgno;
else
np->prev_pgno = pagep->prev_pgno;
if (new_next == NULL)
ret = mpf->put(mpf, np, DB_MPOOL_DIRTY);
else {
*new_next = np;
ret = mpf->set(mpf, np, DB_MPOOL_DIRTY);
}
if (ret != 0)
goto err;
if (needlock)
(void)__TLPUT(dbc, npl);
} else if (new_next != NULL)
*new_next = NULL;
if (pp != NULL) {
pp->next_pgno = pagep->next_pgno;
if ((ret = mpf->put(mpf, pp, DB_MPOOL_DIRTY)) != 0)
goto err;
if (needlock)
(void)__TLPUT(dbc, ppl);
}
return (0);
err: if (np != NULL)
(void)mpf->put(mpf, np, 0);
if (needlock)
(void)__TLPUT(dbc, npl);
if (pp != NULL)
(void)mpf->put(mpf, pp, 0);
if (needlock)
(void)__TLPUT(dbc, ppl);
return (ret);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,14 @@
/*
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998-2002
* Copyright (c) 1998-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_join.c,v 11.75 2004/09/22 03:30:23 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_join.c,v 11.55 2002/08/08 03:57:47 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -23,10 +21,11 @@ static const char revid[] = "$Id: db_join.c,v 11.55 2002/08/08 03:57:47 bostic E
#include "dbinc/db_join.h"
#include "dbinc/btree.h"
static int __db_join_close __P((DBC *));
static int __db_join_close_pp __P((DBC *));
static int __db_join_cmp __P((const void *, const void *));
static int __db_join_del __P((DBC *, u_int32_t));
static int __db_join_get __P((DBC *, DBT *, DBT *, u_int32_t));
static int __db_join_get_pp __P((DBC *, DBT *, DBT *, u_int32_t));
static int __db_join_getnext __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t));
static int __db_join_primget __P((DB *,
DB_TXN *, u_int32_t, DBT *, DBT *, u_int32_t));
@@ -67,7 +66,7 @@ static int __db_join_put __P((DBC *, DBT *, DBT *, u_int32_t));
* cursor method of a DB, join cursors are created through an explicit
* call to DB->join.
*
* The curslist is an array of existing, intialized cursors and primary
* The curslist is an array of existing, initialized cursors and primary
* is the DB of the primary file. The data item that joins all the
* cursors in the curslist is used as the key into the primary and that
* key and data are returned. When no more items are left in the join
@@ -84,26 +83,18 @@ __db_join(primary, curslist, dbcp, flags)
DB_ENV *dbenv;
DBC *dbc;
JOIN_CURSOR *jc;
int ret;
u_int32_t i;
size_t ncurs, nslots;
u_int32_t i;
int ret;
COMPQUIET(nslots, 0);
PANIC_CHECK(primary->dbenv);
if ((ret = __db_joinchk(primary, curslist, flags)) != 0)
return (ret);
dbenv = primary->dbenv;
dbc = NULL;
jc = NULL;
dbenv = primary->dbenv;
if ((ret = __os_calloc(dbenv, 1, sizeof(DBC), &dbc)) != 0)
goto err;
if ((ret = __os_calloc(dbenv,
1, sizeof(JOIN_CURSOR), &jc)) != 0)
if ((ret = __os_calloc(dbenv, 1, sizeof(JOIN_CURSOR), &jc)) != 0)
goto err;
if ((ret = __os_malloc(dbenv, 256, &jc->j_key.data)) != 0)
@@ -122,7 +113,7 @@ __db_join(primary, curslist, dbcp, flags)
* the number of cursors involved in the join, because the
* list is NULL-terminated.
*/
ncurs = jc->j_curslist - curslist;
ncurs = (size_t)(jc->j_curslist - curslist);
nslots = ncurs + 1;
/*
@@ -208,18 +199,21 @@ __db_join(primary, curslist, dbcp, flags)
* because this is the last thing that can fail. Modifier of this
* function beware!
*/
if ((ret = jc->j_curslist[0]->c_dup(jc->j_curslist[0], jc->j_workcurs,
DB_POSITIONI)) != 0)
if ((ret =
__db_c_dup(jc->j_curslist[0], jc->j_workcurs, DB_POSITION)) != 0)
goto err;
dbc->c_close = __db_join_close;
dbc->c_close = __db_join_close_pp;
dbc->c_del = __db_join_del;
dbc->c_get = __db_join_get;
dbc->c_get = __db_join_get_pp;
dbc->c_put = __db_join_put;
dbc->internal = (DBC_INTERNAL *) jc;
dbc->internal = (DBC_INTERNAL *)jc;
dbc->dbp = primary;
jc->j_primary = primary;
/* Stash the first cursor's transaction here for easy access. */
dbc->txn = curslist[0]->txn;
*dbcp = dbc;
MUTEX_THREAD_LOCK(dbenv, primary->mutexp);
@@ -233,7 +227,7 @@ err: if (jc != NULL) {
__os_free(dbenv, jc->j_curslist);
if (jc->j_workcurs != NULL) {
if (jc->j_workcurs[0] != NULL)
__os_free(dbenv, jc->j_workcurs[0]);
(void)__db_c_close(jc->j_workcurs[0]);
__os_free(dbenv, jc->j_workcurs);
}
if (jc->j_fdupcurs != NULL)
@@ -247,6 +241,36 @@ err: if (jc != NULL) {
return (ret);
}
/*
* __db_join_close_pp --
* DBC->c_close pre/post processing for join cursors.
*/
static int
__db_join_close_pp(dbc)
DBC *dbc;
{
DB_ENV *dbenv;
DB *dbp;
int handle_check, ret;
dbp = dbc->dbp;
dbenv = dbp->dbenv;
PANIC_CHECK(dbenv);
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check &&
(ret = __db_rep_enter(dbp, 0, 0, dbc->txn != NULL)) != 0)
return (ret);
ret = __db_join_close(dbc);
if (handle_check)
__env_db_rep_exit(dbenv);
return (ret);
}
static int
__db_join_put(dbc, key, data, flags)
DBC *dbc;
@@ -273,6 +297,77 @@ __db_join_del(dbc, flags)
return (EINVAL);
}
/*
* __db_join_get_pp --
* DBjoin->get pre/post processing.
*/
static int
__db_join_get_pp(dbc, key, data, flags)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
{
DB *dbp;
DB_ENV *dbenv;
u_int32_t handle_check, save_flags;
int ret;
dbp = dbc->dbp;
dbenv = dbp->dbenv;
/* Save the original flags value. */
save_flags = flags;
PANIC_CHECK(dbenv);
if (LF_ISSET(DB_DIRTY_READ | DB_DEGREE_2 | DB_RMW)) {
if (!LOCKING_ON(dbp->dbenv))
return (__db_fnl(dbp->dbenv, "DBcursor->c_get"));
LF_CLR(DB_DIRTY_READ | DB_DEGREE_2 | DB_RMW);
}
switch (flags) {
case 0:
case DB_JOIN_ITEM:
break;
default:
return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0));
}
/*
* A partial get of the key of a join cursor don't make much sense;
* the entire key is necessary to query the primary database
* and find the datum, and so regardless of the size of the key
* it would not be a performance improvement. Since it would require
* special handling, we simply disallow it.
*
* A partial get of the data, however, potentially makes sense (if
* all possible data are a predictable large structure, for instance)
* and causes us no headaches, so we permit it.
*/
if (F_ISSET(key, DB_DBT_PARTIAL)) {
__db_err(dbp->dbenv,
"DB_DBT_PARTIAL may not be set on key during join_get");
return (EINVAL);
}
handle_check = IS_REPLICATED(dbp->dbenv, dbp);
if (handle_check &&
(ret = __db_rep_enter(dbp, 1, 0, dbc->txn != NULL)) != 0)
return (ret);
/* Restore the original flags value. */
flags = save_flags;
ret = __db_join_get(dbc, key, data, flags);
if (handle_check)
__env_db_rep_exit(dbenv);
return (ret);
}
static int
__db_join_get(dbc, key_arg, data_arg, flags)
DBC *dbc;
@@ -289,18 +384,13 @@ __db_join_get(dbc, key_arg, data_arg, flags)
dbp = dbc->dbp;
jc = (JOIN_CURSOR *)dbc->internal;
PANIC_CHECK(dbp->dbenv);
operation = LF_ISSET(DB_OPFLAGS_MASK);
/* !!!
* If the set of flags here changes, check that __db_join_primget
* is updated to handle them properly.
*/
opmods = LF_ISSET(DB_RMW | DB_DIRTY_READ);
if ((ret = __db_joingetchk(dbp, key_arg, flags)) != 0)
return (ret);
opmods = LF_ISSET(DB_RMW | DB_DEGREE_2 | DB_DIRTY_READ);
/*
* Since we are fetching the key as a datum in the secondary indices,
@@ -329,11 +419,10 @@ __db_join_get(dbc, key_arg, data_arg, flags)
goto samekey;
F_CLR(jc, JOIN_RETRY);
retry: ret = jc->j_workcurs[0]->c_real_get(jc->j_workcurs[0],
&jc->j_key, key_n,
retry: ret = __db_c_get(jc->j_workcurs[0], &jc->j_key, key_n,
opmods | (jc->j_exhausted[0] ? DB_NEXT_DUP : DB_CURRENT));
if (ret == ENOMEM) {
if (ret == DB_BUFFER_SMALL) {
jc->j_key.ulen <<= 1;
if ((ret = __os_realloc(dbp->dbenv,
jc->j_key.ulen, &jc->j_key.data)) != 0)
@@ -358,7 +447,7 @@ retry: ret = jc->j_workcurs[0]->c_real_get(jc->j_workcurs[0],
*/
for (i = 1; i < jc->j_ncurs; i++) {
if (jc->j_fdupcurs[i] != NULL &&
(ret = jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0)
(ret = __db_c_close(jc->j_fdupcurs[i])) != 0)
goto err;
jc->j_fdupcurs[i] = NULL;
}
@@ -382,9 +471,8 @@ retry: ret = jc->j_workcurs[0]->c_real_get(jc->j_workcurs[0],
DB_ASSERT(jc->j_curslist[i] != NULL);
if (jc->j_workcurs[i] == NULL)
/* If this is NULL, we need to dup curslist into it. */
if ((ret = jc->j_curslist[i]->c_dup(
jc->j_curslist[i], jc->j_workcurs + i,
DB_POSITIONI)) != 0)
if ((ret = __db_c_dup(jc->j_curslist[i],
&jc->j_workcurs[i], DB_POSITION)) != 0)
goto err;
retry2: cp = jc->j_workcurs[i];
@@ -435,7 +523,7 @@ retry2: cp = jc->j_workcurs[i];
* and let strange things happen--we
* can't make rope childproof.
*/
if ((ret = jc->j_workcurs[j]->c_close(
if ((ret = __db_c_close(
jc->j_workcurs[j])) != 0)
goto err;
if (!SORTED_SET(jc, 0) ||
@@ -448,10 +536,10 @@ retry2: cp = jc->j_workcurs[i];
jc->j_workcurs[j] = NULL;
else
/* Partial reset suffices. */
if ((jc->j_fdupcurs[j]->c_dup(
if ((__db_c_dup(
jc->j_fdupcurs[j],
&jc->j_workcurs[j],
DB_POSITIONI)) != 0)
DB_POSITION)) != 0)
goto err;
jc->j_exhausted[j] = 0;
}
@@ -467,23 +555,21 @@ retry2: cp = jc->j_workcurs[i];
for (j = i + 1;
jc->j_workcurs[j] != NULL;
j++) {
if ((ret = jc->j_workcurs[j]->c_close(
jc->j_workcurs[j])) != 0)
if ((ret =
__db_c_close(jc->j_workcurs[j])) != 0)
goto err;
jc->j_exhausted[j] = 0;
if (jc->j_fdupcurs[j] != NULL &&
(ret = jc->j_fdupcurs[j]->c_dup(
jc->j_fdupcurs[j], &jc->j_workcurs[j],
DB_POSITIONI)) != 0)
goto err;
else
if (jc->j_fdupcurs[j] == NULL)
jc->j_workcurs[j] = NULL;
else if ((ret = __db_c_dup(jc->j_fdupcurs[j],
&jc->j_workcurs[j], DB_POSITION)) != 0)
goto err;
}
goto retry2;
/* NOTREACHED */
}
if (ret == ENOMEM) {
if (ret == DB_BUFFER_SMALL) {
jc->j_key.ulen <<= 1;
if ((ret = __os_realloc(dbp->dbenv, jc->j_key.ulen,
&jc->j_key.data)) != 0) {
@@ -521,9 +607,8 @@ mem_err: __db_err(dbp->dbenv,
* duplicate duplicates; store this into jc->j_fdupcurs[i].
*/
if (SORTED_SET(jc, i) && jc->j_fdupcurs[i] == NULL && (ret =
cp->c_dup(cp, &jc->j_fdupcurs[i], DB_POSITIONI)) != 0)
__db_c_dup(cp, &jc->j_fdupcurs[i], DB_POSITION)) != 0)
goto err;
}
err: if (ret != 0)
@@ -534,7 +619,7 @@ samekey: /*
* Get the key we tried and failed to return last time;
* it should be the current datum of all the secondary cursors.
*/
if ((ret = jc->j_workcurs[0]->c_real_get(jc->j_workcurs[0],
if ((ret = __db_c_get(jc->j_workcurs[0],
&jc->j_key, key_n, DB_CURRENT | opmods)) != 0)
return (ret);
F_CLR(jc, JOIN_RETRY);
@@ -615,7 +700,13 @@ samekey: /*
return (ret);
}
static int
/*
* __db_join_close --
* DBC->c_close for join cursors.
*
* PUBLIC: int __db_join_close __P((DBC *));
*/
int
__db_join_close(dbc)
DBC *dbc;
{
@@ -653,11 +744,11 @@ __db_join_close(dbc)
* mucking with.
*/
for (i = 0; i < jc->j_ncurs; i++) {
if (jc->j_workcurs[i] != NULL && (t_ret =
jc->j_workcurs[i]->c_close(jc->j_workcurs[i])) != 0)
if (jc->j_workcurs[i] != NULL &&
(t_ret = __db_c_close(jc->j_workcurs[i])) != 0)
ret = t_ret;
if (jc->j_fdupcurs[i] != NULL && (t_ret =
jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0)
if (jc->j_fdupcurs[i] != NULL &&
(t_ret = __db_c_close(jc->j_fdupcurs[i])) != 0)
ret = t_ret;
}
@@ -711,7 +802,7 @@ __db_join_getnext(dbc, key, data, exhausted, opmods)
*/
memset(&ldata, 0, sizeof(DBT));
F_SET(&ldata, DB_DBT_MALLOC);
if ((ret = dbc->c_real_get(dbc,
if ((ret = __db_c_get(dbc,
key, &ldata, opmods | DB_CURRENT)) != 0)
break;
cmp = func(dbp, data, &ldata);
@@ -736,7 +827,7 @@ __db_join_getnext(dbc, key, data, exhausted, opmods)
__os_ufree(dbp->dbenv, ldata.data);
/* FALLTHROUGH */
case 1:
ret = dbc->c_real_get(dbc, key, data, opmods | DB_GET_BOTHC);
ret = __db_c_get(dbc, key, data, opmods | DB_GET_BOTHC);
break;
default:
ret = EINVAL;
@@ -757,17 +848,14 @@ __db_join_cmp(a, b)
DBC *dbca, *dbcb;
db_recno_t counta, countb;
/* In case c_count fails, pretend cursors are equal. */
counta = countb = 0;
dbca = *((DBC * const *)a);
dbcb = *((DBC * const *)b);
if (dbca->c_count(dbca, &counta, 0) != 0 ||
dbcb->c_count(dbcb, &countb, 0) != 0)
if (__db_c_count(dbca, &counta) != 0 ||
__db_c_count(dbcb, &countb) != 0)
return (0);
return (counta - countb);
return ((long)counta - (long)countb);
}
/*
@@ -784,7 +872,11 @@ __db_join_primget(dbp, txn, lockerid, key, data, flags)
u_int32_t flags;
{
DBC *dbc;
int dirty, ret, rmw, t_ret;
int ret, rmw, t_ret;
if ((ret = __db_cursor_int(dbp,
txn, dbp->type, PGNO_INVALID, 0, lockerid, &dbc)) != 0)
return (ret);
/*
* The only allowable flags here are the two flags copied into
@@ -793,17 +885,17 @@ __db_join_primget(dbp, txn, lockerid, key, data, flags)
* It's a DB bug if we allow any other flags down in here.
*/
rmw = LF_ISSET(DB_RMW);
dirty = LF_ISSET(DB_DIRTY_READ);
LF_CLR(DB_RMW | DB_DIRTY_READ);
DB_ASSERT(flags == 0);
if ((ret = __db_icursor(dbp,
txn, dbp->type, PGNO_INVALID, 0, lockerid, &dbc)) != 0)
return (ret);
if (dirty ||
if (LF_ISSET(DB_DIRTY_READ) ||
(txn != NULL && F_ISSET(txn, TXN_DIRTY_READ)))
F_SET(dbc, DBC_DIRTY_READ);
if (LF_ISSET(DB_DEGREE_2) ||
(txn != NULL && F_ISSET(txn, TXN_DEGREE_2)))
F_SET(dbc, DBC_DEGREE_2);
LF_CLR(DB_RMW | DB_DIRTY_READ | DB_DEGREE_2);
DB_ASSERT(flags == 0);
F_SET(dbc, DBC_TRANSIENT);
/*
@@ -813,10 +905,26 @@ __db_join_primget(dbp, txn, lockerid, key, data, flags)
*/
SET_RET_MEM(dbc, dbp);
ret = dbc->c_get(dbc, key, data, DB_SET | rmw);
ret = __db_c_get(dbc, key, data, DB_SET | rmw);
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_secondary_corrupt --
* Report that a secondary index appears corrupt, as it has a record
* that does not correspond to a record in the primary or vice versa.
*
* PUBLIC: int __db_secondary_corrupt __P((DB *));
*/
int
__db_secondary_corrupt(dbp)
DB *dbp;
{
__db_err(dbp->dbenv,
"Secondary index corrupt: not consistent with primary");
return (DB_SECONDARY_BAD);
}

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,14 +38,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: db_meta.c,v 11.89 2004/10/05 14:28:33 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_meta.c,v 11.61 2002/08/08 03:57:48 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -56,9 +54,10 @@ static const char revid[] = "$Id: db_meta.c,v 11.61 2002/08/08 03:57:48 bostic E
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
#include "dbinc/db_am.h"
static void __db_init_meta __P((void *, u_int32_t, db_pgno_t, u_int32_t));
static void __db_init_meta __P((DB *, void *, db_pgno_t, u_int32_t));
/*
* __db_init_meta --
@@ -67,9 +66,9 @@ static void __db_init_meta __P((void *, u_int32_t, db_pgno_t, u_int32_t));
* retain the page number and LSN of the existing page.
*/
static void
__db_init_meta(p, pgsize, pgno, pgtype)
__db_init_meta(dbp, p, pgno, pgtype)
DB *dbp;
void *p;
u_int32_t pgsize;
db_pgno_t pgno;
u_int32_t pgtype;
{
@@ -80,7 +79,9 @@ __db_init_meta(p, pgsize, pgno, pgtype)
save_lsn = meta->lsn;
memset(meta, 0, sizeof(DBMETA));
meta->lsn = save_lsn;
meta->pagesize = pgsize;
meta->pagesize = dbp->pgsize;
if (F_ISSET(dbp, DB_AM_CHKSUM))
FLD_SET(meta->metaflags, DBMETA_CHKSUM);
meta->pgno = pgno;
meta->type = (u_int8_t)pgtype;
}
@@ -103,8 +104,9 @@ __db_new(dbc, type, pagepp)
DB_LSN lsn;
DB_MPOOLFILE *mpf;
PAGE *h;
db_pgno_t pgno, newnext;
int meta_flags, extend, ret;
db_pgno_t last, pgno, newnext;
u_int32_t meta_flags;
int extend, ret, t_ret;
meta = NULL;
meta_flags = 0;
@@ -117,15 +119,16 @@ __db_new(dbc, type, pagepp)
if ((ret = __db_lget(dbc,
LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &meta)) != 0)
goto err;
last = meta->last_pgno;
if (meta->free == PGNO_INVALID) {
pgno = meta->last_pgno + 1;
last = pgno = meta->last_pgno + 1;
ZERO_LSN(lsn);
extend = 1;
} else {
pgno = meta->free;
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
goto err;
/*
@@ -145,8 +148,8 @@ __db_new(dbc, type, pagepp)
*/
if (DBC_LOGGING(dbc)) {
if ((ret = __db_pg_alloc_log(dbp, dbc->txn, &LSN(meta), 0,
&LSN(meta), PGNO_BASE_MD, &lsn, pgno,
(u_int32_t)type, newnext)) != 0)
&LSN(meta), PGNO_BASE_MD, &lsn,
pgno, (u_int32_t)type, newnext, meta->last_pgno)) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(meta));
@@ -155,12 +158,12 @@ __db_new(dbc, type, pagepp)
meta->free = newnext;
if (extend == 1) {
meta->last_pgno++;
if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_NEW, &h)) != 0)
if ((ret = __memp_fget(mpf, &pgno, DB_MPOOL_NEW, &h)) != 0)
goto err;
DB_ASSERT(last == pgno);
meta->last_pgno = pgno;
ZERO_LSN(h->lsn);
h->pgno = pgno;
DB_ASSERT(pgno == meta->last_pgno);
}
LSN(h) = LSN(meta);
@@ -169,14 +172,18 @@ __db_new(dbc, type, pagepp)
if (TYPE(h) != P_INVALID)
return (__db_panic(dbp->dbenv, EINVAL));
(void)mpf->put(mpf, (PAGE *)meta, DB_MPOOL_DIRTY);
(void)__TLPUT(dbc, metalock);
ret = __memp_fput(mpf, (PAGE *)meta, DB_MPOOL_DIRTY);
meta = NULL;
if ((t_ret = __TLPUT(dbc, metalock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
switch (type) {
case P_BTREEMETA:
case P_HASHMETA:
case P_QAMMETA:
__db_init_meta(h, dbp->pgsize, h->pgno, type);
__db_init_meta(dbp, h, h->pgno, type);
break;
default:
P_INIT(h, dbp->pgsize,
@@ -201,9 +208,9 @@ __db_new(dbc, type, pagepp)
return (0);
err: if (h != NULL)
(void)mpf->put(mpf, h, 0);
(void)__memp_fput(mpf, h, 0);
if (meta != NULL)
(void)mpf->put(mpf, meta, meta_flags);
(void)__memp_fput(mpf, meta, meta_flags);
(void)__TLPUT(dbc, metalock);
return (ret);
}
@@ -221,7 +228,7 @@ __db_free(dbc, h)
{
DBMETA *meta;
DB *dbp;
DBT ldbt;
DBT ddbt, ldbt;
DB_LOCK metalock;
DB_MPOOLFILE *mpf;
db_pgno_t pgno;
@@ -242,7 +249,7 @@ __db_free(dbc, h)
if ((ret = __db_lget(dbc,
LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
goto err;
if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0) {
if ((ret = __memp_fget(mpf, &pgno, 0, &meta)) != 0) {
(void)__TLPUT(dbc, metalock);
goto err;
}
@@ -253,10 +260,42 @@ __db_free(dbc, h)
memset(&ldbt, 0, sizeof(ldbt));
ldbt.data = h;
ldbt.size = P_OVERHEAD(dbp);
if ((ret = __db_pg_free_log(dbp,
dbc->txn, &LSN(meta), 0, h->pgno,
&LSN(meta), PGNO_BASE_MD, &ldbt, meta->free)) != 0) {
(void)mpf->put(mpf, (PAGE *)meta, 0);
switch (h->type) {
case P_HASH:
case P_IBTREE:
case P_IRECNO:
case P_LBTREE:
case P_LRECNO:
case P_LDUP:
if (h->entries > 0) {
ldbt.size += h->entries * sizeof(db_indx_t);
ddbt.data = (u_int8_t *)h + h->hf_offset;
ddbt.size = dbp->pgsize - h->hf_offset;
ret = __db_pg_freedata_log(dbp, dbc->txn,
&LSN(meta), 0, h->pgno, &LSN(meta),
PGNO_BASE_MD, &ldbt,
meta->free, meta->last_pgno, &ddbt);
break;
}
goto log;
case P_HASHMETA:
ldbt.size = sizeof(HMETA);
goto log;
case P_BTREEMETA:
ldbt.size = sizeof(BTMETA);
goto log;
case P_OVERFLOW:
ldbt.size += OV_LEN(h);
goto log;
default:
DB_ASSERT(h->type != P_QAMDATA);
log: ret = __db_pg_free_log(dbp,
dbc->txn, &LSN(meta), 0, h->pgno, &LSN(meta),
PGNO_BASE_MD, &ldbt, meta->free, meta->last_pgno);
}
if (ret != 0) {
(void)__memp_fput(mpf, (PAGE *)meta, 0);
(void)__TLPUT(dbc, metalock);
goto err;
}
@@ -264,20 +303,44 @@ __db_free(dbc, h)
LSN_NOT_LOGGED(LSN(meta));
LSN(h) = LSN(meta);
P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, meta->free, 0, P_INVALID);
#ifdef HAVE_FTRUNCATE
if (h->pgno == meta->last_pgno) {
if ((ret = __memp_fput(mpf, h, DB_MPOOL_DISCARD)) != 0)
goto err;
/* Give the page back to the OS. */
if ((ret = __memp_ftruncate(mpf, meta->last_pgno, 0)) != 0)
goto err;
meta->last_pgno--;
h = NULL;
} else
#endif
meta->free = h->pgno;
{
/*
* If we are not truncating the page then we
* reinitialize it and put it hat the head of
* the free list.
*/
P_INIT(h, dbp->pgsize,
h->pgno, PGNO_INVALID, meta->free, 0, P_INVALID);
#ifdef DIAGNOSTIC
memset((u_int8_t *) h + P_OVERHEAD(dbp),
CLEAR_BYTE, dbp->pgsize - P_OVERHEAD(dbp));
#endif
meta->free = h->pgno;
}
/* Discard the metadata page. */
if ((t_ret =
mpf->put(mpf, (PAGE *)meta, DB_MPOOL_DIRTY)) != 0 && ret == 0)
__memp_fput(mpf, (PAGE *)meta, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, metalock)) != 0 && ret == 0)
ret = t_ret;
/* Discard the caller's page reference. */
dirty_flag = DB_MPOOL_DIRTY;
err: if ((t_ret = mpf->put(mpf, h, dirty_flag)) != 0 && ret == 0)
err: if (h != NULL &&
(t_ret = __memp_fput(mpf, h, dirty_flag)) != 0 && ret == 0)
ret = t_ret;
/*
@@ -298,34 +361,21 @@ int
__db_lprint(dbc)
DBC *dbc;
{
DB_ENV *dbenv;
DB *dbp;
DB_LOCKREQ req;
dbp = dbc->dbp;
dbenv = dbp->dbenv;
if (LOCKING_ON(dbp->dbenv)) {
if (LOCKING_ON(dbenv)) {
req.op = DB_LOCK_DUMP;
dbp->dbenv->lock_vec(dbp->dbenv, dbc->locker, 0, &req, 1, NULL);
(void)__lock_vec(dbenv, dbc->locker, 0, &req, 1, NULL);
}
return (0);
}
#endif
/*
* Implement the rules for transactional locking. We can release the previous
* lock if we are not in a transaction or COUPLE_ALWAYS is specifed (used in
* record locking). If we are doing dirty reads then we can release read locks
* and down grade write locks.
*/
#define DB_PUT_ACTION(dbc, action, lockp) \
(((action == LCK_COUPLE || action == LCK_COUPLE_ALWAYS) && \
LOCK_ISSET(*lockp)) ? \
(dbc->txn == NULL || action == LCK_COUPLE_ALWAYS || \
(F_ISSET(dbc, DBC_DIRTY_READ) && \
(lockp)->mode == DB_LOCK_DIRTY)) ? LCK_COUPLE : \
(F_ISSET((dbc)->dbp, DB_AM_DIRTY) && \
(lockp)->mode == DB_LOCK_WRITE) ? LCK_DOWNGRADE : 0 : 0)
/*
* __db_lget --
* The standard lock get call.
@@ -359,7 +409,7 @@ __db_lget(dbc, action, pgno, mode, lkflags, lockp)
if (CDB_LOCKING(dbenv) ||
!LOCKING_ON(dbenv) || F_ISSET(dbc, DBC_COMPENSATE) ||
(F_ISSET(dbc, DBC_RECOVER) &&
(action != LCK_ROLLBACK || F_ISSET(dbenv, DB_ENV_REP_CLIENT))) ||
(action != LCK_ROLLBACK || IS_REP_CLIENT(dbenv))) ||
(action != LCK_ALWAYS && F_ISSET(dbc, DBC_OPD))) {
LOCK_INIT(*lockp);
return (0);
@@ -371,6 +421,8 @@ __db_lget(dbc, action, pgno, mode, lkflags, lockp)
else
dbc->lock.type = DB_PAGE_LOCK;
lkflags &= ~DB_LOCK_RECORD;
if (action == LCK_ROLLBACK)
lkflags |= DB_LOCK_ABORT;
/*
* If the transaction enclosing this cursor has DB_LOCK_NOWAIT set,
@@ -382,42 +434,69 @@ __db_lget(dbc, action, pgno, mode, lkflags, lockp)
if (F_ISSET(dbc, DBC_DIRTY_READ) && mode == DB_LOCK_READ)
mode = DB_LOCK_DIRTY;
has_timeout = txn != NULL && F_ISSET(txn, TXN_LOCKTIMEOUT);
has_timeout = F_ISSET(dbc, DBC_RECOVER) ||
(txn != NULL && F_ISSET(txn, TXN_LOCKTIMEOUT));
switch (DB_PUT_ACTION(dbc, action, lockp)) {
/*
* Transactional locking.
* Hold on to the previous read lock only if we are in full isolation.
* COUPLE_ALWAYS indicates we are holding an interior node
* which need not be isolated.
* Downgrade write locks if we are supporting dirty readers.
*/
if ((action != LCK_COUPLE && action != LCK_COUPLE_ALWAYS) ||
!LOCK_ISSET(*lockp))
action = 0;
else if (dbc->txn == NULL || action == LCK_COUPLE_ALWAYS)
action = LCK_COUPLE;
else if (F_ISSET(dbc, DBC_DEGREE_2) && lockp->mode == DB_LOCK_READ)
action = LCK_COUPLE;
else if (F_ISSET(dbc, DBC_DIRTY_READ) && lockp->mode == DB_LOCK_DIRTY)
action = LCK_COUPLE;
else if (F_ISSET(dbc->dbp, DB_AM_DIRTY) && lockp->mode == DB_LOCK_WRITE)
action = LCK_DOWNGRADE;
else
action = 0;
switch (action) {
case LCK_DOWNGRADE:
if ((ret = __lock_downgrade(
dbenv, lockp, DB_LOCK_WWRITE, 0)) != 0)
return (ret);
/* FALLTHROUGH */
default:
if (!has_timeout) {
ret = __lock_get(dbenv,
dbc->locker, lkflags, &dbc->lock_dbt, mode, lockp);
break;
}
/* FALLTHROUGH */
case LCK_COUPLE:
lck_couple: couple[0].op = has_timeout? DB_LOCK_GET_TIMEOUT : DB_LOCK_GET;
couple[0].op = has_timeout? DB_LOCK_GET_TIMEOUT : DB_LOCK_GET;
couple[0].obj = &dbc->lock_dbt;
couple[0].mode = mode;
if (action == LCK_COUPLE_ALWAYS)
action = LCK_COUPLE;
UMRW_SET(couple[0].timeout);
if (has_timeout)
couple[0].timeout = txn->lock_timeout;
couple[0].timeout =
F_ISSET(dbc, DBC_RECOVER) ? 0 : txn->lock_timeout;
if (action == LCK_COUPLE) {
couple[1].op = DB_LOCK_PUT;
couple[1].lock = *lockp;
}
ret = dbenv->lock_vec(dbenv, dbc->locker,
ret = __lock_vec(dbenv, dbc->locker,
lkflags, couple, action == LCK_COUPLE ? 2 : 1, &reqp);
if (ret == 0 || reqp == &couple[1])
*lockp = couple[0].lock;
break;
case LCK_DOWNGRADE:
if ((ret = dbenv->lock_downgrade(
dbenv, lockp, DB_LOCK_WWRITE, 0)) != 0)
return (ret);
/* FALL THROUGH */
default:
if (has_timeout)
goto lck_couple;
ret = dbenv->lock_get(dbenv,
dbc->locker, lkflags, &dbc->lock_dbt, mode, lockp);
break;
}
return (ret);
if (txn != NULL && ret == DB_LOCK_DEADLOCK)
F_SET(txn, TXN_DEADLOCK);
return ((ret == DB_LOCK_NOTGRANTED &&
!F_ISSET(dbenv, DB_ENV_TIME_NOTGRANTED)) ? DB_LOCK_DEADLOCK : ret);
}
/*
@@ -432,13 +511,28 @@ __db_lput(dbc, lockp)
DB_LOCK *lockp;
{
DB_ENV *dbenv;
int ret;
int action, ret;
/*
* Transactional locking.
* Hold on to the read locks only if we are in full isolation.
* Downgrade write locks if we are supporting dirty readers.
*/
if (F_ISSET(dbc->dbp, DB_AM_DIRTY) && lockp->mode == DB_LOCK_WRITE)
action = LCK_DOWNGRADE;
else if (dbc->txn == NULL)
action = LCK_COUPLE;
else if (F_ISSET(dbc, DBC_DEGREE_2) && lockp->mode == DB_LOCK_READ)
action = LCK_COUPLE;
else if (F_ISSET(dbc, DBC_DIRTY_READ) && lockp->mode == DB_LOCK_DIRTY)
action = LCK_COUPLE;
else
action = 0;
dbenv = dbc->dbp->dbenv;
switch (DB_PUT_ACTION(dbc, LCK_COUPLE, lockp)) {
switch (action) {
case LCK_COUPLE:
ret = dbenv->lock_put(dbenv, lockp);
ret = __lock_put(dbenv, lockp, 0);
break;
case LCK_DOWNGRADE:
ret = __lock_downgrade(dbenv, lockp, DB_LOCK_WWRITE, 0);

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2002
* Copyright (c) 1999-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_method.c,v 11.116 2004/10/11 18:22:05 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_method.c,v 11.78 2002/07/02 19:26:55 sue Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -21,44 +19,55 @@ static const char revid[] = "$Id: db_method.c,v 11.78 2002/07/02 19:26:55 sue Ex
#include <string.h>
#endif
#ifdef HAVE_RPC
#include "db_server.h"
#endif
#include "db_int.h"
#include "dbinc/crypto.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/hash.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
#include "dbinc/qam.h"
#include "dbinc/xa.h"
#include "dbinc_auto/xa_ext.h"
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
#ifdef HAVE_RPC
#include "dbinc_auto/db_server.h"
#include "dbinc_auto/rpc_client_ext.h"
#endif
static int __db_get_byteswapped __P((DB *, int *));
static int __db_get_dbname __P((DB *, const char **, const char **));
static DB_ENV *__db_get_env __P((DB *));
static int __db_get_transactional __P((DB *));
static int __db_get_type __P((DB *, DBTYPE *dbtype));
static int __db_init __P((DB *, u_int32_t));
static int __db_key_range
__P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
static int __db_set_alloc __P((DB *, void *(*)(size_t),
void *(*)(void *, size_t), void (*)(void *)));
static int __db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t)));
static int __db_get_cachesize __P((DB *, u_int32_t *, u_int32_t *, int *));
static int __db_set_cachesize __P((DB *, u_int32_t, u_int32_t, int));
static int __db_set_cache_priority __P((DB *, DB_CACHE_PRIORITY));
static int __db_set_dup_compare
__P((DB *, int (*)(DB *, const DBT *, const DBT *)));
static int __db_get_encrypt_flags __P((DB *, u_int32_t *));
static int __db_set_encrypt __P((DB *, const char *, u_int32_t));
static int __db_set_feedback __P((DB *, void (*)(DB *, int, int)));
static int __db_set_flags __P((DB *, u_int32_t));
static int __db_set_pagesize __P((DB *, u_int32_t));
static void __db_map_flags __P((DB *, u_int32_t *, u_int32_t *));
static int __db_get_pagesize __P((DB *, u_int32_t *));
static int __db_set_paniccall __P((DB *, void (*)(DB_ENV *, int)));
static void __db_set_errcall __P((DB *, void (*)(const char *, char *)));
static void __db_set_errcall
__P((DB *, void (*)(const DB_ENV *, const char *, const char *)));
static void __db_get_errfile __P((DB *, FILE **));
static void __db_set_errfile __P((DB *, FILE *));
static void __db_get_errpfx __P((DB *, const char **));
static void __db_set_errpfx __P((DB *, const char *));
static int __db_stat_fail __P((DB *, void *, u_int32_t));
static void __db_set_msgcall
__P((DB *, void (*)(const DB_ENV *, const char *)));
static void __db_get_msgfile __P((DB *, FILE **));
static void __db_set_msgfile __P((DB *, FILE *));
static void __dbh_err __P((DB *, int, const char *, ...));
static void __dbh_errx __P((DB *, const char *, ...));
@@ -85,6 +94,8 @@ db_create(dbpp, dbenv, flags)
switch (flags) {
case 0:
break;
case DB_REP_CREATE:
break;
case DB_XA_CREATE:
if (dbenv != NULL) {
__db_err(dbenv,
@@ -113,25 +124,47 @@ db_create(dbpp, dbenv, flags)
else
#endif
ret = __db_init(dbp, flags);
if (ret != 0) {
__os_free(dbenv, dbp);
return (ret);
}
if (ret != 0)
goto err;
/* If we don't have an environment yet, allocate a local one. */
if (dbenv == NULL) {
if ((ret = db_env_create(&dbenv, 0)) != 0) {
__os_free(dbenv, dbp);
return (ret);
}
if ((ret = db_env_create(&dbenv, 0)) != 0)
goto err;
F_SET(dbenv, DB_ENV_DBLOCAL);
}
++dbenv->db_ref;
dbp->dbenv = dbenv;
MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
++dbenv->db_ref;
MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
/*
* Set the replication timestamp; it's 0 if we're not in a replicated
* environment.
*/
dbp->timestamp =
(F_ISSET(dbenv, DB_ENV_DBLOCAL) || !REP_ON(dbenv)) ? 0 :
((REGENV *)((REGINFO *)dbenv->reginfo)->primary)->rep_timestamp;
/* If not RPC, open a backing DB_MPOOLFILE handle in the memory pool. */
#ifdef HAVE_RPC
if (!RPC_ON(dbenv))
#endif
if ((ret = __memp_fcreate(dbenv, &dbp->mpf)) != 0)
goto err;
dbp->type = DB_UNKNOWN;
*dbpp = dbp;
return (0);
err: if (dbp->mpf != NULL)
(void)__memp_fclose(dbp->mpf, 0);
if (dbenv != NULL && F_ISSET(dbenv, DB_ENV_DBLOCAL))
(void)__dbenv_close(dbenv, 0);
__os_free(dbenv, dbp);
*dbpp = NULL;
return (ret);
}
/*
@@ -156,42 +189,57 @@ __db_init(dbp, flags)
FLD_SET(dbp->am_ok,
DB_OK_BTREE | DB_OK_HASH | DB_OK_QUEUE | DB_OK_RECNO);
dbp->associate = __db_associate;
dbp->close = __db_close;
dbp->cursor = __db_cursor;
dbp->del = __db_delete;
dbp->associate = __db_associate_pp;
dbp->close = __db_close_pp;
dbp->cursor = __db_cursor_pp;
dbp->del = __db_del_pp;
dbp->dump = __db_dump_pp;
dbp->err = __dbh_err;
dbp->errx = __dbh_errx;
dbp->fd = __db_fd;
dbp->get = __db_get;
dbp->fd = __db_fd_pp;
dbp->get = __db_get_pp;
dbp->get_byteswapped = __db_get_byteswapped;
dbp->get_dbname = __db_get_dbname;
dbp->get_env = __db_get_env;
dbp->get_open_flags = __db_get_open_flags;
dbp->get_transactional = __db_get_transactional;
dbp->get_type = __db_get_type;
dbp->join = __db_join;
dbp->key_range = __db_key_range;
dbp->open = __db_open;
dbp->pget = __db_pget;
dbp->put = __db_put;
dbp->remove = __db_remove;
dbp->rename = __db_rename;
dbp->truncate = __db_truncate;
dbp->join = __db_join_pp;
dbp->key_range = __db_key_range_pp;
dbp->open = __db_open_pp;
dbp->pget = __db_pget_pp;
dbp->put = __db_put_pp;
dbp->remove = __db_remove_pp;
dbp->rename = __db_rename_pp;
dbp->truncate = __db_truncate_pp;
dbp->set_alloc = __db_set_alloc;
dbp->set_append_recno = __db_set_append_recno;
dbp->get_cachesize = __db_get_cachesize;
dbp->set_cachesize = __db_set_cachesize;
dbp->set_cache_priority = __db_set_cache_priority;
dbp->set_dup_compare = __db_set_dup_compare;
dbp->get_encrypt_flags = __db_get_encrypt_flags;
dbp->set_encrypt = __db_set_encrypt;
dbp->set_errcall = __db_set_errcall;
dbp->get_errfile = __db_get_errfile;
dbp->set_errfile = __db_set_errfile;
dbp->get_errpfx = __db_get_errpfx;
dbp->set_errpfx = __db_set_errpfx;
dbp->set_feedback = __db_set_feedback;
dbp->get_flags = __db_get_flags;
dbp->set_flags = __db_set_flags;
dbp->get_lorder = __db_get_lorder;
dbp->set_lorder = __db_set_lorder;
dbp->set_msgcall = __db_set_msgcall;
dbp->get_msgfile = __db_get_msgfile;
dbp->set_msgfile = __db_set_msgfile;
dbp->get_pagesize = __db_get_pagesize;
dbp->set_pagesize = __db_set_pagesize;
dbp->set_paniccall = __db_set_paniccall;
dbp->stat = __db_stat_fail;
dbp->sync = __db_sync;
dbp->upgrade = __db_upgrade;
dbp->verify = __db_verify;
dbp->stat = __db_stat_pp;
dbp->stat_print = __db_stat_print_pp;
dbp->sync = __db_sync_pp;
dbp->upgrade = __db_upgrade_pp;
dbp->verify = __db_verify_pp;
/* Access method specific. */
if ((ret = __bam_db_create(dbp)) != 0)
@@ -208,6 +256,9 @@ __db_init(dbp, flags)
if (LF_ISSET(DB_XA_CREATE) && (ret = __db_xa_create(dbp)) != 0)
return (ret);
if (LF_ISSET(DB_REP_CREATE))
F_SET(dbp, DB_AM_REPLICATION);
return (0);
}
@@ -245,7 +296,7 @@ __dbh_am_chk(dbp, flags)
* Error message, including the standard error string.
*/
static void
#ifdef __STDC__
#ifdef STDC_HEADERS
__dbh_err(DB *dbp, int error, const char *fmt, ...)
#else
__dbh_err(dbp, error, fmt, va_alist)
@@ -263,7 +314,7 @@ __dbh_err(dbp, error, fmt, va_alist)
* Error message.
*/
static void
#ifdef __STDC__
#ifdef STDC_HEADERS
__dbh_errx(DB *dbp, const char *fmt, ...)
#else
__dbh_errx(dbp, fmt, va_alist)
@@ -284,12 +335,52 @@ __db_get_byteswapped(dbp, isswapped)
DB *dbp;
int *isswapped;
{
DB_ILLEGAL_BEFORE_OPEN(dbp, "get_byteswapped");
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_byteswapped");
*isswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0;
return (0);
}
/*
* __db_get_dbname --
* Get the name of the database as passed to DB->open.
*/
static int
__db_get_dbname(dbp, fnamep, dnamep)
DB *dbp;
const char **fnamep, **dnamep;
{
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_dbname");
if (fnamep != NULL)
*fnamep = dbp->fname;
if (dnamep != NULL)
*dnamep = dbp->dname;
return (0);
}
/*
* __db_get_env --
* Get the DB_ENV handle that was passed to db_create.
*/
static DB_ENV *
__db_get_env(dbp)
DB *dbp;
{
return (dbp->dbenv);
}
/*
* get_transactional --
* Get whether this database was created in a transaction.
*/
static int
__db_get_transactional(dbp)
DB *dbp;
{
return (F_ISSET(dbp, DB_AM_TXN) ? 1 : 0);
}
/*
* __db_get_type --
* Return type of underlying database.
@@ -299,35 +390,12 @@ __db_get_type(dbp, dbtype)
DB *dbp;
DBTYPE *dbtype;
{
DB_ILLEGAL_BEFORE_OPEN(dbp, "get_type");
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_type");
*dbtype = dbp->type;
return (0);
}
/*
* __db_key_range --
* Return proportion of keys above and below given key.
*/
static int
__db_key_range(dbp, txn, key, kr, flags)
DB *dbp;
DB_TXN *txn;
DBT *key;
DB_KEY_RANGE *kr;
u_int32_t flags;
{
COMPQUIET(txn, NULL);
COMPQUIET(key, NULL);
COMPQUIET(kr, NULL);
COMPQUIET(flags, 0);
DB_ILLEGAL_BEFORE_OPEN(dbp, "key_range");
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
return (EINVAL);
}
/*
* __db_set_append_recno --
* Set record number append routine.
@@ -337,7 +405,7 @@ __db_set_append_recno(dbp, func)
DB *dbp;
int (*func) __P((DB *, DBT *, db_recno_t));
{
DB_ILLEGAL_AFTER_OPEN(dbp, "set_append_recno");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_append_recno");
DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
dbp->db_append_recno = func;
@@ -345,6 +413,22 @@ __db_set_append_recno(dbp, func)
return (0);
}
/*
* __db_get_cachesize --
* Get underlying cache size.
*/
static int
__db_get_cachesize(dbp, cache_gbytesp, cache_bytesp, ncachep)
DB *dbp;
u_int32_t *cache_gbytesp, *cache_bytesp;
int *ncachep;
{
DB_ILLEGAL_IN_ENV(dbp, "DB->get_cachesize");
return (__memp_get_cachesize(dbp->dbenv,
cache_gbytesp, cache_bytesp, ncachep));
}
/*
* __db_set_cachesize --
* Set underlying cache size.
@@ -355,33 +439,13 @@ __db_set_cachesize(dbp, cache_gbytes, cache_bytes, ncache)
u_int32_t cache_gbytes, cache_bytes;
int ncache;
{
DB_ILLEGAL_IN_ENV(dbp, "set_cachesize");
DB_ILLEGAL_AFTER_OPEN(dbp, "set_cachesize");
DB_ILLEGAL_IN_ENV(dbp, "DB->set_cachesize");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_cachesize");
return (dbp->dbenv->set_cachesize(
return (__memp_set_cachesize(
dbp->dbenv, cache_gbytes, cache_bytes, ncache));
}
/*
* __db_set_cache_priority --
* Set cache priority for pages from this file.
*/
static int
__db_set_cache_priority(dbp, priority)
DB *dbp;
DB_CACHE_PRIORITY priority;
{
/*
* If an underlying DB_MPOOLFILE exists, call it. Otherwise, save
* the information away until DB->open is called.
*/
if (dbp->mpf == NULL) {
dbp->priority = priority;
return (0);
}
return (dbp->mpf->set_priority(dbp->mpf, priority));
}
/*
* __db_set_dup_compare --
* Set duplicate comparison routine.
@@ -393,10 +457,10 @@ __db_set_dup_compare(dbp, func)
{
int ret;
DB_ILLEGAL_AFTER_OPEN(dbp, "dup_compare");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->dup_compare");
DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
if ((ret = dbp->set_flags(dbp, DB_DUPSORT)) != 0)
if ((ret = __db_set_flags(dbp, DB_DUPSORT)) != 0)
return (ret);
dbp->dup_compare = func;
@@ -404,6 +468,19 @@ __db_set_dup_compare(dbp, func)
return (0);
}
/*
* __db_get_encrypt_flags --
*/
static int
__db_get_encrypt_flags(dbp, flagsp)
DB *dbp;
u_int32_t *flagsp;
{
DB_ILLEGAL_IN_ENV(dbp, "DB->get_encrypt_flags");
return (__dbenv_get_encrypt_flags(dbp->dbenv, flagsp));
}
/*
* __db_set_encrypt --
* Set database passwd.
@@ -417,10 +494,10 @@ __db_set_encrypt(dbp, passwd, flags)
DB_CIPHER *db_cipher;
int ret;
DB_ILLEGAL_IN_ENV(dbp, "set_encrypt");
DB_ILLEGAL_AFTER_OPEN(dbp, "set_encrypt");
DB_ILLEGAL_IN_ENV(dbp, "DB->set_encrypt");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_encrypt");
if ((ret = dbp->dbenv->set_encrypt(dbp->dbenv, passwd, flags)) != 0)
if ((ret = __dbenv_set_encrypt(dbp->dbenv, passwd, flags)) != 0)
return (ret);
/*
@@ -432,15 +509,23 @@ __db_set_encrypt(dbp, passwd, flags)
(ret = db_cipher->init(dbp->dbenv, db_cipher)) != 0)
return (ret);
return (dbp->set_flags(dbp, DB_ENCRYPT));
return (__db_set_flags(dbp, DB_ENCRYPT));
}
static void
__db_set_errcall(dbp, errcall)
DB *dbp;
void (*errcall) __P((const char *, char *));
void (*errcall) __P((const DB_ENV *, const char *, const char *));
{
dbp->dbenv->set_errcall(dbp->dbenv, errcall);
__dbenv_set_errcall(dbp->dbenv, errcall);
}
static void
__db_get_errfile(dbp, errfilep)
DB *dbp;
FILE **errfilep;
{
__dbenv_get_errfile(dbp->dbenv, errfilep);
}
static void
@@ -448,7 +533,15 @@ __db_set_errfile(dbp, errfile)
DB *dbp;
FILE *errfile;
{
dbp->dbenv->set_errfile(dbp->dbenv, errfile);
__dbenv_set_errfile(dbp->dbenv, errfile);
}
static void
__db_get_errpfx(dbp, errpfxp)
DB *dbp;
const char **errpfxp;
{
__dbenv_get_errpfx(dbp->dbenv, errpfxp);
}
static void
@@ -456,7 +549,7 @@ __db_set_errpfx(dbp, errpfx)
DB *dbp;
const char *errpfx;
{
dbp->dbenv->set_errpfx(dbp->dbenv, errpfx);
__dbenv_set_errpfx(dbp->dbenv, errpfx);
}
static int
@@ -468,42 +561,143 @@ __db_set_feedback(dbp, feedback)
return (0);
}
static int
/*
* __db_map_flags --
* Maps between public and internal flag values.
* This function doesn't check for validity, so it can't fail.
*/
static void
__db_map_flags(dbp, inflagsp, outflagsp)
DB *dbp;
u_int32_t *inflagsp, *outflagsp;
{
COMPQUIET(dbp, NULL);
if (FLD_ISSET(*inflagsp, DB_CHKSUM)) {
FLD_SET(*outflagsp, DB_AM_CHKSUM);
FLD_CLR(*inflagsp, DB_CHKSUM);
}
if (FLD_ISSET(*inflagsp, DB_ENCRYPT)) {
FLD_SET(*outflagsp, DB_AM_ENCRYPT | DB_AM_CHKSUM);
FLD_CLR(*inflagsp, DB_ENCRYPT);
}
if (FLD_ISSET(*inflagsp, DB_TXN_NOT_DURABLE)) {
FLD_SET(*outflagsp, DB_AM_NOT_DURABLE);
FLD_CLR(*inflagsp, DB_TXN_NOT_DURABLE);
}
}
/*
* __db_get_flags --
* The DB->get_flags method.
*
* PUBLIC: int __db_get_flags __P((DB *, u_int32_t *));
*/
int
__db_get_flags(dbp, flagsp)
DB *dbp;
u_int32_t *flagsp;
{
static const u_int32_t db_flags[] = {
DB_CHKSUM,
DB_DUP,
DB_DUPSORT,
DB_ENCRYPT,
DB_INORDER,
DB_RECNUM,
DB_RENUMBER,
DB_REVSPLITOFF,
DB_SNAPSHOT,
DB_TXN_NOT_DURABLE,
0
};
u_int32_t f, flags, mapped_flag;
int i;
flags = 0;
for (i = 0; (f = db_flags[i]) != 0; i++) {
mapped_flag = 0;
__db_map_flags(dbp, &f, &mapped_flag);
__bam_map_flags(dbp, &f, &mapped_flag);
__ram_map_flags(dbp, &f, &mapped_flag);
#ifdef HAVE_QUEUE
__qam_map_flags(dbp, &f, &mapped_flag);
#endif
DB_ASSERT(f == 0);
if (F_ISSET(dbp, mapped_flag) == mapped_flag)
LF_SET(db_flags[i]);
}
*flagsp = flags;
return (0);
}
/*
* __db_set_flags --
* DB->set_flags.
*
* PUBLIC: int __db_set_flags __P((DB *, u_int32_t));
*/
int
__db_set_flags(dbp, flags)
DB *dbp;
u_int32_t flags;
{
DB_ENV *dbenv;
int ret;
/*
* !!!
* The hash access method only takes two flags: DB_DUP and DB_DUPSORT.
* The Btree access method uses them for the same purposes, and so we
* resolve them there.
*
* The queue access method takes no flags.
*/
if (LF_ISSET(DB_ENCRYPT)) {
if (!CRYPTO_ON(dbp->dbenv)) {
__db_err(dbp->dbenv,
dbenv = dbp->dbenv;
if (LF_ISSET(DB_ENCRYPT) && !CRYPTO_ON(dbenv)) {
__db_err(dbenv,
"Database environment not configured for encryption");
return (EINVAL);
}
F_SET(dbp, DB_AM_ENCRYPT);
F_SET(dbp, DB_AM_CHKSUM);
LF_CLR(DB_ENCRYPT);
}
if (LF_ISSET(DB_CHKSUM_SHA1)) {
F_SET(dbp, DB_AM_CHKSUM);
LF_CLR(DB_CHKSUM_SHA1);
return (EINVAL);
}
if (LF_ISSET(DB_TXN_NOT_DURABLE))
ENV_REQUIRES_CONFIG(dbenv,
dbenv->tx_handle, "DB_NOT_DURABLE", DB_INIT_TXN);
__db_map_flags(dbp, &flags, &dbp->flags);
if ((ret = __bam_set_flags(dbp, &flags)) != 0)
return (ret);
if ((ret = __ram_set_flags(dbp, &flags)) != 0)
return (ret);
#ifdef HAVE_QUEUE
if ((ret = __qam_set_flags(dbp, &flags)) != 0)
return (ret);
#endif
return (flags == 0 ? 0 : __db_ferr(dbp->dbenv, "DB->set_flags", 0));
return (flags == 0 ? 0 : __db_ferr(dbenv, "DB->set_flags", 0));
}
/*
* __db_get_lorder --
* Get whether lorder is swapped or not.
*
* PUBLIC: int __db_get_lorder __P((DB *, int *));
*/
int
__db_get_lorder(dbp, db_lorderp)
DB *dbp;
int *db_lorderp;
{
int ret;
/* Flag if the specified byte order requires swapping. */
switch (ret = __db_byteorder(dbp->dbenv, 1234)) {
case 0:
*db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 4321 : 1234;
break;
case DB_SWAPBYTES:
*db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 1234 : 4321;
break;
default:
return (ret);
/* NOTREACHED */
}
return (0);
}
/*
@@ -519,7 +713,7 @@ __db_set_lorder(dbp, db_lorder)
{
int ret;
DB_ILLEGAL_AFTER_OPEN(dbp, "set_lorder");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_lorder");
/* Flag if the specified byte order requires swapping. */
switch (ret = __db_byteorder(dbp->dbenv, db_lorder)) {
@@ -543,19 +737,57 @@ __db_set_alloc(dbp, mal_func, real_func, free_func)
void *(*real_func) __P((void *, size_t));
void (*free_func) __P((void *));
{
DB_ILLEGAL_IN_ENV(dbp, "set_alloc");
DB_ILLEGAL_AFTER_OPEN(dbp, "set_alloc");
DB_ILLEGAL_IN_ENV(dbp, "DB->set_alloc");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_alloc");
return (dbp->dbenv->set_alloc(dbp->dbenv,
mal_func, real_func, free_func));
return (__dbenv_set_alloc(dbp->dbenv, mal_func, real_func, free_func));
}
static void
__db_set_msgcall(dbp, msgcall)
DB *dbp;
void (*msgcall) __P((const DB_ENV *, const char *));
{
__dbenv_set_msgcall(dbp->dbenv, msgcall);
}
static void
__db_get_msgfile(dbp, msgfilep)
DB *dbp;
FILE **msgfilep;
{
__dbenv_get_msgfile(dbp->dbenv, msgfilep);
}
static void
__db_set_msgfile(dbp, msgfile)
DB *dbp;
FILE *msgfile;
{
__dbenv_set_msgfile(dbp->dbenv, msgfile);
}
static int
__db_get_pagesize(dbp, db_pagesizep)
DB *dbp;
u_int32_t *db_pagesizep;
{
*db_pagesizep = dbp->pgsize;
return (0);
}
/*
* __db_set_pagesize --
* DB->set_pagesize
*
* PUBLIC: int __db_set_pagesize __P((DB *, u_int32_t));
*/
int
__db_set_pagesize(dbp, db_pagesize)
DB *dbp;
u_int32_t db_pagesize;
{
DB_ILLEGAL_AFTER_OPEN(dbp, "set_pagesize");
DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_pagesize");
if (db_pagesize < DB_MIN_PGSIZE) {
__db_err(dbp->dbenv, "page sizes may not be smaller than %lu",
@@ -592,27 +824,7 @@ __db_set_paniccall(dbp, paniccall)
DB *dbp;
void (*paniccall) __P((DB_ENV *, int));
{
return (dbp->dbenv->set_paniccall(dbp->dbenv, paniccall));
}
static int
__db_stat_fail(dbp, sp, flags)
DB *dbp;
void *sp;
u_int32_t flags;
{
COMPQUIET(sp, NULL);
COMPQUIET(flags, 0);
/*
* DB->stat isn't initialized until the actual DB->open call,
* but we don't want to core dump.
*/
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
/* NOTREACHED */
return (EINVAL);
return (__dbenv_set_paniccall(dbp->dbenv, paniccall));
}
#ifdef HAVE_RPC
@@ -642,9 +854,12 @@ __dbcl_init(dbp, dbenv, flags)
dbp->fd = __dbcl_db_fd;
dbp->get = __dbcl_db_get;
dbp->get_byteswapped = __db_get_byteswapped;
dbp->get_transactional = __db_get_transactional;
dbp->get_type = __db_get_type;
dbp->join = __dbcl_db_join;
dbp->key_range = __dbcl_db_key_range;
dbp->get_dbname = __dbcl_db_get_name;
dbp->get_open_flags = __dbcl_db_get_open_flags;
dbp->open = __dbcl_db_open_wrap;
dbp->pget = __dbcl_db_pget;
dbp->put = __dbcl_db_put;
@@ -652,16 +867,22 @@ __dbcl_init(dbp, dbenv, flags)
dbp->rename = __dbcl_db_rename;
dbp->set_alloc = __dbcl_db_alloc;
dbp->set_append_recno = __dbcl_db_set_append_recno;
dbp->get_cachesize = __dbcl_db_get_cachesize;
dbp->set_cachesize = __dbcl_db_cachesize;
dbp->set_cache_priority = __dbcl_db_cache_priority;
dbp->set_dup_compare = __dbcl_db_dup_compare;
dbp->get_encrypt_flags = __dbcl_db_get_encrypt_flags;
dbp->set_encrypt = __dbcl_db_encrypt;
dbp->set_errcall = __db_set_errcall;
dbp->get_errfile = __db_get_errfile;
dbp->set_errfile = __db_set_errfile;
dbp->get_errpfx = __db_get_errpfx;
dbp->set_errpfx = __db_set_errpfx;
dbp->set_feedback = __dbcl_db_feedback;
dbp->get_flags = __dbcl_db_get_flags;
dbp->set_flags = __dbcl_db_flags;
dbp->get_lorder = __dbcl_db_get_lorder;
dbp->set_lorder = __dbcl_db_lorder;
dbp->get_pagesize = __dbcl_db_get_pagesize;
dbp->set_pagesize = __dbcl_db_pagesize;
dbp->set_paniccall = __dbcl_db_panic;
dbp->stat = __dbcl_db_stat;
@@ -675,15 +896,23 @@ __dbcl_init(dbp, dbenv, flags)
*/
dbp->set_bt_compare = __dbcl_db_bt_compare;
dbp->set_bt_maxkey = __dbcl_db_bt_maxkey;
dbp->get_bt_minkey = __dbcl_db_get_bt_minkey;
dbp->set_bt_minkey = __dbcl_db_bt_minkey;
dbp->set_bt_prefix = __dbcl_db_bt_prefix;
dbp->get_h_ffactor = __dbcl_db_get_h_ffactor;
dbp->set_h_ffactor = __dbcl_db_h_ffactor;
dbp->set_h_hash = __dbcl_db_h_hash;
dbp->get_h_nelem = __dbcl_db_get_h_nelem;
dbp->set_h_nelem = __dbcl_db_h_nelem;
dbp->get_q_extentsize = __dbcl_db_get_extentsize;
dbp->set_q_extentsize = __dbcl_db_extentsize;
dbp->get_re_delim = __dbcl_db_get_re_delim;
dbp->set_re_delim = __dbcl_db_re_delim;
dbp->get_re_len = __dbcl_db_get_re_len;
dbp->set_re_len = __dbcl_db_re_len;
dbp->get_re_pad = __dbcl_db_get_re_pad;
dbp->set_re_pad = __dbcl_db_re_pad;
dbp->get_re_source = __dbcl_db_get_re_source;
dbp->set_re_source = __dbcl_db_re_source;
return (__dbcl_db_create(dbp, dbenv, flags));

View File

@@ -1,20 +1,17 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_open.c,v 11.240 2004/09/22 20:53:19 margo Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_open.c,v 11.215 2002/08/15 15:27:52 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#endif
@@ -30,50 +27,49 @@ static const char revid[] = "$Id: db_open.c,v 11.215 2002/08/15 15:27:52 bostic
#include "dbinc/hash.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#include "dbinc/qam.h"
#include "dbinc/txn.h"
static int __db_openchk __P((DB *,
DB_TXN *, const char *, const char *, DBTYPE, u_int32_t));
/*
* __db_open --
* Main library interface to the DB access methods.
* DB->open method.
*
* This routine gets called in three different ways:
*
* 1. It can be called to open a file/database. In this case, subdb will
* be NULL and meta_pgno will be PGNO_BASE_MD.
* 2. It can be called to open a subdatabase during normal operation. In
* this case, name and subname will both be non-NULL and meta_pgno will
* be PGNO_BASE_MD (also PGNO_INVALID).
* 3. It can be called during recovery to open a file/database, in which case
* name will be non-NULL, subname will be NULL, and meta-pgno will be
* PGNO_BASE_MD.
* 4. It can be called during recovery to open a subdatabase, in which case
* name will be non-NULL, subname may be NULL and meta-pgno will be
* a valid pgno (i.e., not PGNO_BASE_MD).
*
* PUBLIC: int __db_open __P((DB *, DB_TXN *,
* PUBLIC: const char *, const char *, DBTYPE, u_int32_t, int));
* PUBLIC: const char *, const char *, DBTYPE, u_int32_t, int, db_pgno_t));
*/
int
__db_open(dbp, txn, name, subdb, type, flags, mode)
__db_open(dbp, txn, fname, dname, type, flags, mode, meta_pgno)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb;
const char *fname, *dname;
DBTYPE type;
u_int32_t flags;
int mode;
db_pgno_t meta_pgno;
{
DB_ENV *dbenv;
int remove_master, remove_me, ret, t_ret, txn_local;
int ret;
u_int32_t id;
dbenv = dbp->dbenv;
remove_me = remove_master = txn_local = 0;
id = TXN_INVALID;
PANIC_CHECK(dbenv);
if ((ret = __db_openchk(dbp, txn, name, subdb, type, flags)) != 0)
return (ret);
/*
* Create local transaction as necessary, check for consistent
* transaction usage.
*/
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
return (ret);
txn_local = 1;
} else
if (txn != NULL && !TXN_ON(dbenv))
return (__db_not_txn_env(dbenv));
DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, fname);
/*
* If the environment was configured with threads, the DB handle
@@ -92,123 +88,21 @@ __db_open(dbp, txn, name, subdb, type, flags, mode)
if (LF_ISSET(DB_DIRTY_READ))
F_SET(dbp, DB_AM_DIRTY);
if (txn != NULL)
F_SET(dbp, DB_AM_TXN);
/* Fill in the type. */
dbp->type = type;
/*
* If we're opening a subdatabase, we have to open (and potentially
* create) the main database, and then get (and potentially store)
* our base page number in that database. Then, we can finally open
* the subdatabase.
*/
if ((ret = __db_dbopen(
dbp, txn, name, subdb, flags, mode, PGNO_BASE_MD)) != 0)
goto err;
/*
* You can open the database that describes the subdatabases in the
* rest of the file read-only. The content of each key's data is
* unspecified and applications should never be adding new records
* or updating existing records. However, during recovery, we need
* to open these databases R/W so we can redo/undo changes in them.
* Likewise, we need to open master databases read/write during
* rename and remove so we can be sure they're fully sync'ed, so
* we provide an override flag for the purpose.
*/
if (subdb == NULL && !IS_RECOVERING(dbenv) && !LF_ISSET(DB_RDONLY) &&
!LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) {
__db_err(dbenv,
"files containing multiple databases may only be opened read-only");
ret = EINVAL;
goto err;
}
err: /* If we were successful, don't discard the file on close. */
if (ret == 0)
/* If we were successful, don't discard the file on close. */
F_CLR(dbp, DB_AM_DISCARD | DB_AM_CREATED | DB_AM_CREATED_MSTR);
else {
/*
* If we are not transactional, we need to remove the
* databases/subdatabases. If we are transactional, then
* the abort of the child transaction should take care of
* cleaning them up.
*/
remove_me = txn == NULL && F_ISSET(dbp, DB_AM_CREATED);
remove_master = txn == NULL && F_ISSET(dbp, DB_AM_CREATED_MSTR);
/*
* If we had an error, it may have happened before or after
* we actually logged the open. If it happened before, then
* abort won't know anything about it and won't close or
* refresh the dbp, so we need to do it explicitly.
*/
(void)__db_refresh(dbp, txn, DB_NOSYNC);
}
/* Remove anyone we created. */
if (remove_master || (subdb == NULL && remove_me))
/* Remove file. */
(void)dbenv->dbremove(dbenv, txn, name, NULL, 0);
else if (remove_me)
/* Remove subdatabase. */
(void)dbenv->dbremove(dbenv, txn, name, subdb, 0);
/* Commit for DB_AUTO_COMMIT. */
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
}
return (ret);
}
/*
* __db_dbopen --
* Open a database. This routine gets called in three different ways.
* 1. It can be called to open a file/database. In this case, subdb will
* be NULL and meta_pgno will be PGNO_BASE_MD.
* 2. It can be called to open a subdatabase during normal operation. In
* this case, name and subname will both be non-NULL and meta_pgno will
* be PGNO_BAS_MD (also PGNO_INVALID).
* 3. It can be called during recovery to open a subdatabase in which case
* name will be non-NULL, subname mqy be NULL and meta-pgno will be
* a valid pgno (i.e., not PGNO_BASE_MD).
*
* PUBLIC: int __db_dbopen __P((DB *, DB_TXN *,
* PUBLIC: const char *, const char *, u_int32_t, int, db_pgno_t));
*/
int
__db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb;
u_int32_t flags;
int mode;
db_pgno_t meta_pgno;
{
DB_ENV *dbenv;
int ret;
u_int32_t id;
dbenv = dbp->dbenv;
id = TXN_INVALID;
if (txn != NULL)
F_SET(dbp, DB_AM_TXN);
DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, name);
/*
* If name is NULL, it's always a create, so make sure that we
* If fname is NULL, it's always a create, so make sure that we
* have a type specified. It would be nice if this checking
* were done in __db_open where most of the interface checking
* is done, but this interface (__db_dbopen) is used by the
* recovery and limbo system, so we need to safeguard this
* interface as well.
*/
if (name == NULL) {
if (fname == NULL) {
F_SET(dbp, DB_AM_INMEM);
if (dbp->type == DB_UNKNOWN) {
@@ -235,17 +129,17 @@ __db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
* Store the locker in the file id structure -- we can get it
* from there as necessary, and it saves having two copies.
*/
if (LOCKING_ON(dbenv) && (ret = dbenv->lock_id(dbenv,
(u_int32_t *)dbp->fileid)) != 0)
if (LOCKING_ON(dbenv) &&
(ret = __lock_id(dbenv, (u_int32_t *)dbp->fileid)) != 0)
return (ret);
} else if (subdb == NULL && meta_pgno == PGNO_BASE_MD) {
} else if (dname == NULL && meta_pgno == PGNO_BASE_MD) {
/* Open/create the underlying file. Acquire locks. */
if ((ret =
__fop_file_setup(dbp, txn, name, mode, flags, &id)) != 0)
__fop_file_setup(dbp, txn, fname, mode, flags, &id)) != 0)
return (ret);
} else {
if ((ret = __fop_subdb_setup(dbp,
txn, name, subdb, mode, flags)) != 0)
txn, fname, dname, mode, flags)) != 0)
return (ret);
meta_pgno = dbp->meta_pgno;
}
@@ -261,13 +155,13 @@ __db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
* opened and updated the master using access method interfaces,
* so we don't want to get rid of any pages that are in the mpool.
* If we created the file when we opened the master, we already hit
* this check in a non-subdb context then.
* this check in a non-subdatabase context then.
*/
if (subdb == NULL && F_ISSET(dbp, DB_AM_CREATED))
if (dname == NULL && F_ISSET(dbp, DB_AM_CREATED))
LF_SET(DB_TRUNCATE);
/* Set up the underlying environment. */
if ((ret = __db_dbenv_setup(dbp, txn, name, id, flags)) != 0)
if ((ret = __db_dbenv_setup(dbp, txn, fname, id, flags)) != 0)
return (ret);
/*
@@ -283,21 +177,21 @@ __db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
* For unnamed files, we need to actually create the file now
* that the mpool is open.
*/
if (name == NULL && (ret = __db_new_file(dbp, txn, NULL, NULL)) != 0)
if (fname == NULL && (ret = __db_new_file(dbp, txn, NULL, NULL)) != 0)
return (ret);
switch (dbp->type) {
case DB_BTREE:
ret = __bam_open(dbp, txn, name, meta_pgno, flags);
ret = __bam_open(dbp, txn, fname, meta_pgno, flags);
break;
case DB_HASH:
ret = __ham_open(dbp, txn, name, meta_pgno, flags);
ret = __ham_open(dbp, txn, fname, meta_pgno, flags);
break;
case DB_RECNO:
ret = __ram_open(dbp, txn, name, meta_pgno, flags);
ret = __ram_open(dbp, txn, fname, meta_pgno, flags);
break;
case DB_QUEUE:
ret = __qam_open(dbp, txn, name, meta_pgno, mode, flags);
ret = __qam_open(dbp, txn, fname, meta_pgno, mode, flags);
break;
case DB_UNKNOWN:
return (__db_unknown_type(dbenv, "__db_dbopen", dbp->type));
@@ -305,7 +199,7 @@ __db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
if (ret != 0)
goto err;
DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, name);
DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, fname);
/*
* Unnamed files don't need handle locks, so we only have to check
@@ -313,7 +207,7 @@ __db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
* files.
*/
if (!F_ISSET(dbp, DB_AM_RECOVER) &&
name != NULL && LOCK_ISSET(dbp->handle_lock)) {
fname != NULL && LOCK_ISSET(dbp->handle_lock)) {
if (txn != NULL) {
ret = __txn_lockevent(dbenv,
txn, dbp, &dbp->handle_lock, dbp->lid);
@@ -327,6 +221,23 @@ err:
return (ret);
}
/*
* __db_get_open_flags --
* Accessor for flags passed into DB->open call
*
* PUBLIC: int __db_get_open_flags __P((DB *, u_int32_t *));
*/
int
__db_get_open_flags(dbp, flagsp)
DB *dbp;
u_int32_t *flagsp;
{
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_open_flags");
*flagsp = dbp->open_flags;
return (0);
}
/*
* __db_new_file --
* Create a new database file.
@@ -353,6 +264,7 @@ __db_new_file(dbp, txn, fhp, name)
case DB_QUEUE:
ret = __qam_new_file(dbp, txn, fhp, name);
break;
case DB_UNKNOWN:
default:
__db_err(dbp->dbenv,
"%s: Invalid type %d specified", name, dbp->type);
@@ -391,10 +303,10 @@ __db_init_subdb(mdbp, dbp, name, txn)
if (!F_ISSET(dbp, DB_AM_CREATED)) {
/* Subdb exists; read meta-data page and initialize. */
mpf = mdbp->mpf;
if ((ret = mpf->get(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
if ((ret = __memp_fget(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
goto err;
ret = __db_meta_setup(mdbp->dbenv, dbp, name, meta, 0, 0);
if ((t_ret = mpf->put(mpf, meta, 0)) != 0 && ret == 0)
if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
ret = t_ret;
/*
* If __db_meta_setup found that the meta-page hadn't
@@ -417,6 +329,7 @@ __db_init_subdb(mdbp, dbp, name, txn)
case DB_QUEUE:
ret = EINVAL;
break;
case DB_UNKNOWN:
default:
__db_err(dbp->dbenv,
"Invalid subdatabase type %d specified", dbp->type);
@@ -442,7 +355,8 @@ __db_chk_meta(dbenv, dbp, meta, do_metachk)
DBMETA *meta;
int do_metachk;
{
int is_hmac, ret;
int is_hmac, ret, swapped;
u_int32_t orig_chk;
u_int8_t *chksum;
ret = 0;
@@ -453,11 +367,34 @@ __db_chk_meta(dbenv, dbp, meta, do_metachk)
is_hmac = meta->encrypt_alg == 0 ? 0 : 1;
chksum = ((BTMETA *)meta)->chksum;
if (do_metachk && ((ret = __db_check_chksum(dbenv,
(DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
DBMETASIZE, is_hmac)) != 0))
return (ret);
}
/*
* If we need to swap, the checksum function overwrites the
* original checksum with 0, so we need to save a copy of the
* original for swapping later.
*/
orig_chk = *(u_int32_t *)chksum;
/*
* We cannot add this to __db_metaswap because that gets done
* later after we've verified the checksum or decrypted.
*/
if (do_metachk) {
swapped = 0;
chk_retry: if ((ret = __db_check_chksum(dbenv,
(DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
DBMETASIZE, is_hmac)) != 0) {
if (is_hmac || swapped)
return (ret);
M_32_SWAP(orig_chk);
swapped = 1;
*(u_int32_t *)chksum = orig_chk;
goto chk_retry;
}
}
} else if (dbp != NULL)
F_CLR(dbp, DB_AM_CHKSUM);
#ifdef HAVE_CRYPTO
ret = __crypto_decrypt_meta(dbenv, dbp, (u_int8_t *)meta, do_metachk);
@@ -544,6 +481,10 @@ swap_retry:
switch (magic) {
case DB_BTREEMAGIC:
if (dbp->type != DB_UNKNOWN &&
dbp->type != DB_RECNO && dbp->type != DB_BTREE)
goto bad_format;
flags = meta->flags;
if (F_ISSET(dbp, DB_AM_SWAP))
M_32_SWAP(flags);
@@ -556,12 +497,17 @@ swap_retry:
return (ret);
break;
case DB_HASHMAGIC:
if (dbp->type != DB_UNKNOWN && dbp->type != DB_HASH)
goto bad_format;
dbp->type = DB_HASH;
if ((oflags & DB_TRUNCATE) == 0 && (ret =
__ham_metachk(dbp, name, (HMETA *)meta)) != 0)
return (ret);
break;
case DB_QAMMAGIC:
if (dbp->type != DB_UNKNOWN && dbp->type != DB_QUEUE)
goto bad_format;
dbp->type = DB_QUEUE;
if ((oflags & DB_TRUNCATE) == 0 && (ret =
__qam_metachk(dbp, name, (QMETA *)meta)) != 0)
@@ -569,135 +515,20 @@ swap_retry:
break;
case DB_RENAMEMAGIC:
F_SET(dbp, DB_AM_IN_RENAME);
/* Copy the file's ID. */
memcpy(dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
break;
default:
goto bad_format;
}
return (0);
bad_format:
__db_err(dbenv, "%s: unexpected file type or format", name);
if (F_ISSET(dbp, DB_AM_RECOVER))
ret = ENOENT;
else
__db_err(dbenv, "%s: unexpected file type or format", name);
return (ret == 0 ? EINVAL : ret);
}
/*
* __db_openchk --
* Interface error checking for open calls.
*/
static int
__db_openchk(dbp, txn, name, subdb, type, flags)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb;
DBTYPE type;
u_int32_t flags;
{
DB_ENV *dbenv;
int ret;
u_int32_t ok_flags;
dbenv = dbp->dbenv;
/* Validate arguments. */
#define OKFLAGS \
(DB_AUTO_COMMIT | DB_CREATE | DB_DIRTY_READ | DB_EXCL | \
DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_RDWRMASTER | \
DB_THREAD | DB_TRUNCATE | DB_WRITEOPEN)
if ((ret = __db_fchk(dbenv, "DB->open", flags, OKFLAGS)) != 0)
return (ret);
if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE))
return (__db_ferr(dbenv, "DB->open", 1));
if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE))
return (__db_ferr(dbenv, "DB->open", 1));
#ifdef HAVE_VXWORKS
if (LF_ISSET(DB_TRUNCATE)) {
__db_err(dbenv, "DB_TRUNCATE unsupported in VxWorks");
return (__db_eopnotsup(dbenv));
}
#endif
switch (type) {
case DB_UNKNOWN:
if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) {
__db_err(dbenv,
"%s: DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE",
name);
return (EINVAL);
}
ok_flags = 0;
break;
case DB_BTREE:
ok_flags = DB_OK_BTREE;
break;
case DB_HASH:
ok_flags = DB_OK_HASH;
break;
case DB_QUEUE:
ok_flags = DB_OK_QUEUE;
break;
case DB_RECNO:
ok_flags = DB_OK_RECNO;
break;
default:
__db_err(dbenv, "unknown type: %lu", (u_long)type);
return (EINVAL);
}
if (ok_flags)
DB_ILLEGAL_METHOD(dbp, ok_flags);
/* The environment may have been created, but never opened. */
if (!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_OPEN_CALLED)) {
__db_err(dbenv, "environment not yet opened");
return (EINVAL);
}
/*
* Historically, you could pass in an environment that didn't have a
* mpool, and DB would create a private one behind the scenes. This
* no longer works.
*/
if (!F_ISSET(dbenv, DB_ENV_DBLOCAL) && !MPOOL_ON(dbenv)) {
__db_err(dbenv, "environment did not include a memory pool");
return (EINVAL);
}
/*
* You can't specify threads during DB->open if subsystems in the
* environment weren't configured with them.
*/
if (LF_ISSET(DB_THREAD) &&
!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_THREAD)) {
__db_err(dbenv, "environment not created using DB_THREAD");
return (EINVAL);
}
/* DB_TRUNCATE is not transaction recoverable. */
if (LF_ISSET(DB_TRUNCATE) && txn != NULL) {
__db_err(dbenv,
"DB_TRUNCATE illegal with transaction specified");
return (EINVAL);
}
/* Subdatabase checks. */
if (subdb != NULL) {
/* Subdatabases must be created in named files. */
if (name == NULL) {
__db_err(dbenv,
"multiple databases cannot be created in temporary files");
return (EINVAL);
}
/* Truncate is a physical file operation */
if (LF_ISSET(DB_TRUNCATE)) {
__db_err(dbenv,
"DB_TRUNCATE illegal with multiple databases");
return (EINVAL);
}
/* QAM can't be done as a subdatabase. */
if (type == DB_QUEUE) {
__db_err(dbenv, "Queue databases must be one-per-file");
return (EINVAL);
}
}
return (0);
}

View File

@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
@@ -38,14 +38,12 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: db_overflow.c,v 11.54 2004/03/28 17:17:50 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_overflow.c,v 11.46 2002/08/08 03:57:48 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -54,8 +52,9 @@ static const char revid[] = "$Id: db_overflow.c,v 11.46 2002/08/08 03:57:48 bost
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/db_am.h"
#include "dbinc/db_verify.h"
#include "dbinc/mp.h"
/*
* Big key/data code.
@@ -116,7 +115,7 @@ __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
if (F_ISSET(dbt, DB_DBT_USERMEM)) {
if (needed > dbt->ulen) {
dbt->size = needed;
return (ENOMEM);
return (DB_BUFFER_SMALL);
}
} else if (F_ISSET(dbt, DB_DBT_MALLOC)) {
if ((ret = __os_umalloc(dbenv, needed, &dbt->data)) != 0)
@@ -124,13 +123,20 @@ __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
} else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
if ((ret = __os_urealloc(dbenv, needed, &dbt->data)) != 0)
return (ret);
} else if (*bpsz == 0 || *bpsz < needed) {
} else if (bpsz != NULL && (*bpsz == 0 || *bpsz < needed)) {
if ((ret = __os_realloc(dbenv, needed, bpp)) != 0)
return (ret);
*bpsz = needed;
dbt->data = *bpp;
} else
} else if (bpp != NULL)
dbt->data = *bpp;
else {
DB_ASSERT(
F_ISSET(dbt,
DB_DBT_USERMEM | DB_DBT_MALLOC | DB_DBT_REALLOC) ||
bpsz != NULL || bpp != NULL);
return (DB_BUFFER_SMALL);
}
/*
* Step through the linked list of pages, copying the data on each
@@ -138,7 +144,7 @@ __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
*/
dbt->size = needed;
for (curoff = 0, p = dbt->data; pgno != PGNO_INVALID && needed > 0;) {
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
return (ret);
/* Check if we need any bytes from this page. */
@@ -157,7 +163,7 @@ __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
}
curoff += OV_LEN(h);
pgno = h->next_pgno;
(void)mpf->put(mpf, h, 0);
(void)__memp_fput(mpf, h, 0);
}
return (0);
}
@@ -222,7 +228,7 @@ __db_poff(dbc, dbt, pgnop)
lastp == NULL ? &null_lsn : &LSN(lastp),
&null_lsn)) != 0) {
if (lastp != NULL)
(void)mpf->put(mpf,
(void)__memp_fput(mpf,
lastp, DB_MPOOL_DIRTY);
lastp = pagep;
break;
@@ -251,12 +257,12 @@ __db_poff(dbc, dbt, pgnop)
else {
lastp->next_pgno = PGNO(pagep);
pagep->prev_pgno = PGNO(lastp);
(void)mpf->put(mpf, lastp, DB_MPOOL_DIRTY);
(void)__memp_fput(mpf, lastp, DB_MPOOL_DIRTY);
}
lastp = pagep;
}
if (lastp != NULL &&
(t_ret = mpf->put(mpf, lastp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
(t_ret = __memp_fput(mpf, lastp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
@@ -281,22 +287,20 @@ __db_ovref(dbc, pgno, adjust)
dbp = dbc->dbp;
mpf = dbp->mpf;
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0) {
__db_pgerr(dbp, pgno, ret);
return (ret);
}
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
return (__db_pgerr(dbp, pgno, ret));
if (DBC_LOGGING(dbc)) {
if ((ret = __db_ovref_log(dbp,
dbc->txn, &LSN(h), 0, h->pgno, adjust, &LSN(h))) != 0) {
(void)mpf->put(mpf, h, 0);
(void)__memp_fput(mpf, h, 0);
return (ret);
}
} else
LSN_NOT_LOGGED(LSN(h));
OV_REF(h) += adjust;
(void)mpf->put(mpf, h, DB_MPOOL_DIRTY);
(void)__memp_fput(mpf, h, DB_MPOOL_DIRTY);
return (0);
}
@@ -322,10 +326,8 @@ __db_doff(dbc, pgno)
mpf = dbp->mpf;
do {
if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) {
__db_pgerr(dbp, pgno, ret);
return (ret);
}
if ((ret = __memp_fget(mpf, &pgno, 0, &pagep)) != 0)
return (__db_pgerr(dbp, pgno, ret));
DB_ASSERT(TYPE(pagep) == P_OVERFLOW);
/*
@@ -333,7 +335,7 @@ __db_doff(dbc, pgno)
* decrement the reference count and return.
*/
if (OV_REF(pagep) > 1) {
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
return (__db_ovref(dbc, pgno, -1));
}
@@ -346,12 +348,13 @@ __db_doff(dbc, pgno)
PGNO(pagep), PREV_PGNO(pagep),
NEXT_PGNO(pagep), &tmp_dbt,
&LSN(pagep), &null_lsn, &null_lsn)) != 0) {
(void)mpf->put(mpf, pagep, 0);
(void)__memp_fput(mpf, pagep, 0);
return (ret);
}
} else
LSN_NOT_LOGGED(LSN(pagep));
pgno = pagep->next_pgno;
OV_LEN(pagep) = 0;
if ((ret = __db_free(dbc, pagep)) != 0)
return (ret);
} while (pgno != PGNO_INVALID);
@@ -411,7 +414,7 @@ __db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp)
/* While there are both keys to compare. */
for (*cmpp = 0, p1 = dbt->data,
key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) {
if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &pagep)) != 0)
return (ret);
cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left;
@@ -424,7 +427,7 @@ __db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp)
break;
}
pgno = NEXT_PGNO(pagep);
if ((ret = mpf->put(mpf, pagep, 0)) != 0)
if ((ret = __memp_fput(mpf, pagep, 0)) != 0)
return (ret);
if (*cmpp != 0)
return (0);
@@ -438,289 +441,3 @@ __db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp)
return (0);
}
/*
* __db_vrfy_overflow --
* Verify overflow page.
*
* PUBLIC: int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
* PUBLIC: u_int32_t));
*/
int
__db_vrfy_overflow(dbp, vdp, h, pgno, flags)
DB *dbp;
VRFY_DBINFO *vdp;
PAGE *h;
db_pgno_t pgno;
u_int32_t flags;
{
VRFY_PAGEINFO *pip;
int isbad, ret, t_ret;
isbad = 0;
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
if (ret == DB_VERIFY_BAD)
isbad = 1;
else
goto err;
}
pip->refcount = OV_REF(h);
if (pip->refcount < 1) {
EPRINT((dbp->dbenv,
"Page %lu: overflow page has zero reference count",
(u_long)pgno));
isbad = 1;
}
/* Just store for now. */
pip->olen = HOFFSET(h);
err: if ((t_ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
/*
* __db_vrfy_ovfl_structure --
* Walk a list of overflow pages, avoiding cycles and marking
* pages seen.
*
* PUBLIC: int __db_vrfy_ovfl_structure
* PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t));
*/
int
__db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
u_int32_t tlen;
u_int32_t flags;
{
DB *pgset;
VRFY_PAGEINFO *pip;
db_pgno_t next, prev;
int isbad, p, ret, t_ret;
u_int32_t refcount;
pgset = vdp->pgset;
DB_ASSERT(pgset != NULL);
isbad = 0;
/* This shouldn't happen, but just to be sure. */
if (!IS_VALID_PGNO(pgno))
return (DB_VERIFY_BAD);
/*
* Check the first prev_pgno; it ought to be PGNO_INVALID,
* since there's no prev page.
*/
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
/* The refcount is stored on the first overflow page. */
refcount = pip->refcount;
if (pip->type != P_OVERFLOW) {
EPRINT((dbp->dbenv,
"Page %lu: overflow page of invalid type %lu",
(u_long)pgno, (u_long)pip->type));
ret = DB_VERIFY_BAD;
goto err; /* Unsafe to continue. */
}
prev = pip->prev_pgno;
if (prev != PGNO_INVALID) {
EPRINT((dbp->dbenv,
"Page %lu: first page in overflow chain has a prev_pgno %lu",
(u_long)pgno, (u_long)prev));
isbad = 1;
}
for (;;) {
/*
* This is slightly gross. Btree leaf pages reference
* individual overflow trees multiple times if the overflow page
* is the key to a duplicate set. The reference count does not
* reflect this multiple referencing. Thus, if this is called
* during the structure verification of a btree leaf page, we
* check to see whether we've seen it from a leaf page before
* and, if we have, adjust our count of how often we've seen it
* accordingly.
*
* (This will screw up if it's actually referenced--and
* correctly refcounted--from two different leaf pages, but
* that's a very unlikely brokenness that we're not checking for
* anyway.)
*/
if (LF_ISSET(ST_OVFL_LEAF)) {
if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) {
if ((ret =
__db_vrfy_pgset_dec(pgset, pgno)) != 0)
goto err;
} else
F_SET(pip, VRFY_OVFL_LEAFSEEN);
}
if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
goto err;
/*
* We may have seen this elsewhere, if the overflow entry
* has been promoted to an internal page.
*/
if ((u_int32_t)p > refcount) {
EPRINT((dbp->dbenv,
"Page %lu: encountered twice in overflow traversal",
(u_long)pgno));
ret = DB_VERIFY_BAD;
goto err;
}
if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0)
goto err;
/* Keep a running tab on how much of the item we've seen. */
tlen -= pip->olen;
/* Send feedback to the application about our progress. */
if (!LF_ISSET(DB_SALVAGE))
__db_vrfy_struct_feedback(dbp, vdp);
next = pip->next_pgno;
/* Are we there yet? */
if (next == PGNO_INVALID)
break;
/*
* We've already checked this when we saved it, but just
* to be sure...
*/
if (!IS_VALID_PGNO(next)) {
DB_ASSERT(0);
EPRINT((dbp->dbenv,
"Page %lu: bad next_pgno %lu on overflow page",
(u_long)pgno, (u_long)next));
ret = DB_VERIFY_BAD;
goto err;
}
if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 ||
(ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0)
return (ret);
if (pip->prev_pgno != pgno) {
EPRINT((dbp->dbenv,
"Page %lu: bad prev_pgno %lu on overflow page (should be %lu)",
(u_long)next, (u_long)pip->prev_pgno,
(u_long)pgno));
isbad = 1;
/*
* It's safe to continue because we have separate
* cycle detection.
*/
}
pgno = next;
}
if (tlen > 0) {
isbad = 1;
EPRINT((dbp->dbenv,
"Page %lu: overflow item incomplete", (u_long)pgno));
}
err: if ((t_ret =
__db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
/*
* __db_safe_goff --
* Get an overflow item, very carefully, from an untrusted database,
* in the context of the salvager.
*
* PUBLIC: int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t,
* PUBLIC: DBT *, void **, u_int32_t));
*/
int
__db_safe_goff(dbp, vdp, pgno, dbt, buf, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
DBT *dbt;
void **buf;
u_int32_t flags;
{
DB_MPOOLFILE *mpf;
PAGE *h;
int ret, t_ret;
u_int32_t bytesgot, bytes;
u_int8_t *src, *dest;
mpf = dbp->mpf;
h = NULL;
ret = t_ret = 0;
bytesgot = bytes = 0;
while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) {
/*
* Mark that we're looking at this page; if we've seen it
* already, quit.
*/
if ((ret = __db_salvage_markdone(vdp, pgno)) != 0)
break;
if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
break;
/*
* Make sure it's really an overflow page, unless we're
* being aggressive, in which case we pretend it is.
*/
if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) {
ret = DB_VERIFY_BAD;
break;
}
src = (u_int8_t *)h + P_OVERHEAD(dbp);
bytes = OV_LEN(h);
if (bytes + P_OVERHEAD(dbp) > dbp->pgsize)
bytes = dbp->pgsize - P_OVERHEAD(dbp);
if ((ret = __os_realloc(dbp->dbenv,
bytesgot + bytes, buf)) != 0)
break;
dest = (u_int8_t *)*buf + bytesgot;
bytesgot += bytes;
memcpy(dest, src, bytes);
pgno = NEXT_PGNO(h);
if ((ret = mpf->put(mpf, h, 0)) != 0)
break;
h = NULL;
}
/*
* If we're being aggressive, salvage a partial datum if there
* was an error somewhere along the way.
*/
if (ret == 0 || LF_ISSET(DB_AGGRESSIVE)) {
dbt->size = bytesgot;
dbt->data = *buf;
}
/* If we broke out on error, don't leave pages pinned. */
if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}

View File

@@ -0,0 +1,374 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*/
/*
* Copyright (c) 1990, 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*/
/*
* Copyright (c) 1990, 1993, 1994, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: db_ovfl_vrfy.c,v 11.56 2004/01/28 03:35:57 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/db_am.h"
#include "dbinc/db_verify.h"
#include "dbinc/mp.h"
/*
* __db_vrfy_overflow --
* Verify overflow page.
*
* PUBLIC: int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
* PUBLIC: u_int32_t));
*/
int
__db_vrfy_overflow(dbp, vdp, h, pgno, flags)
DB *dbp;
VRFY_DBINFO *vdp;
PAGE *h;
db_pgno_t pgno;
u_int32_t flags;
{
VRFY_PAGEINFO *pip;
int isbad, ret, t_ret;
isbad = 0;
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
if (ret == DB_VERIFY_BAD)
isbad = 1;
else
goto err;
}
pip->refcount = OV_REF(h);
if (pip->refcount < 1) {
EPRINT((dbp->dbenv,
"Page %lu: overflow page has zero reference count",
(u_long)pgno));
isbad = 1;
}
/* Just store for now. */
pip->olen = HOFFSET(h);
err: if ((t_ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
/*
* __db_vrfy_ovfl_structure --
* Walk a list of overflow pages, avoiding cycles and marking
* pages seen.
*
* PUBLIC: int __db_vrfy_ovfl_structure
* PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t));
*/
int
__db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
u_int32_t tlen;
u_int32_t flags;
{
DB *pgset;
VRFY_PAGEINFO *pip;
db_pgno_t next, prev;
int isbad, ret, seen_cnt, t_ret;
u_int32_t refcount;
pgset = vdp->pgset;
DB_ASSERT(pgset != NULL);
isbad = 0;
/* This shouldn't happen, but just to be sure. */
if (!IS_VALID_PGNO(pgno))
return (DB_VERIFY_BAD);
/*
* Check the first prev_pgno; it ought to be PGNO_INVALID,
* since there's no prev page.
*/
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
/* The refcount is stored on the first overflow page. */
refcount = pip->refcount;
if (pip->type != P_OVERFLOW) {
EPRINT((dbp->dbenv,
"Page %lu: overflow page of invalid type %lu",
(u_long)pgno, (u_long)pip->type));
ret = DB_VERIFY_BAD;
goto err; /* Unsafe to continue. */
}
prev = pip->prev_pgno;
if (prev != PGNO_INVALID) {
EPRINT((dbp->dbenv,
"Page %lu: first page in overflow chain has a prev_pgno %lu",
(u_long)pgno, (u_long)prev));
isbad = 1;
}
for (;;) {
/*
* We may have seen this page elsewhere, if the overflow entry
* has been promoted to an internal page; we just want to
* make sure that each overflow page is seen exactly as many
* times as its refcount dictates.
*
* Note that this code also serves to keep us from looping
* infinitely if there's a cycle in an overflow chain.
*/
if ((ret = __db_vrfy_pgset_get(pgset, pgno, &seen_cnt)) != 0)
goto err;
if ((u_int32_t)seen_cnt > refcount) {
EPRINT((dbp->dbenv,
"Page %lu: encountered too many times in overflow traversal",
(u_long)pgno));
ret = DB_VERIFY_BAD;
goto err;
}
if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0)
goto err;
/*
* Each overflow page can be referenced multiple times,
* because it's possible for overflow Btree keys to get
* promoted to internal pages. We want to make sure that
* each page is referenced from a Btree leaf (or Hash data
* page, which we consider a "leaf" here) exactly once; if
* the parent was a leaf, set a flag to indicate that we've
* seen this page in a leaf context.
*
* If the parent is not a leaf--in which case it's a Btree
* internal page--we don't need to bother doing any further
* verification, as we'll do it when we hit the leaf (or
* complain that we never saw the leaf). Only the first
* page in an overflow chain should ever have a refcount
* greater than 1, and the combination of the LEAFSEEN check
* and the fact that we bail after the first page for
* non-leaves should ensure this.
*
* Note that each "child" of a page, such as an overflow page,
* is stored and verified in a structure check exactly once,
* so this code does not need to contend with the fact that
* overflow chains used as Btree duplicate keys may be
* referenced multiply from a single Btree leaf page.
*/
if (LF_ISSET(ST_OVFL_LEAF)) {
if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) {
EPRINT((dbp->dbenv,
"Page %lu: overflow page linked twice from leaf or data page",
(u_long)pgno));
ret = DB_VERIFY_BAD;
goto err;
}
F_SET(pip, VRFY_OVFL_LEAFSEEN);
}
/*
* We want to verify each overflow chain only once, and
* although no chain should be linked more than once from a
* leaf page, we can't guarantee that it'll be linked that
* once if it's linked from an internal page and the key
* is gone.
*
* seen_cnt is the number of times we'd encountered this page
* before calling this function.
*/
if (seen_cnt == 0) {
/*
* Keep a running tab on how much of the item we've
* seen.
*/
tlen -= pip->olen;
/* Send the application feedback about our progress. */
if (!LF_ISSET(DB_SALVAGE))
__db_vrfy_struct_feedback(dbp, vdp);
} else
goto done;
next = pip->next_pgno;
/* Are we there yet? */
if (next == PGNO_INVALID)
break;
/*
* We've already checked this when we saved it, but just
* to be sure...
*/
if (!IS_VALID_PGNO(next)) {
DB_ASSERT(0);
EPRINT((dbp->dbenv,
"Page %lu: bad next_pgno %lu on overflow page",
(u_long)pgno, (u_long)next));
ret = DB_VERIFY_BAD;
goto err;
}
if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 ||
(ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0)
return (ret);
if (pip->prev_pgno != pgno) {
EPRINT((dbp->dbenv,
"Page %lu: bad prev_pgno %lu on overflow page (should be %lu)",
(u_long)next, (u_long)pip->prev_pgno,
(u_long)pgno));
isbad = 1;
/*
* It's safe to continue because we have separate
* cycle detection.
*/
}
pgno = next;
}
if (tlen > 0) {
isbad = 1;
EPRINT((dbp->dbenv,
"Page %lu: overflow item incomplete", (u_long)pgno));
}
done:
err: if ((t_ret =
__db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
/*
* __db_safe_goff --
* Get an overflow item, very carefully, from an untrusted database,
* in the context of the salvager.
*
* PUBLIC: int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t,
* PUBLIC: DBT *, void *, u_int32_t));
*/
int
__db_safe_goff(dbp, vdp, pgno, dbt, buf, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
DBT *dbt;
void *buf;
u_int32_t flags;
{
DB_MPOOLFILE *mpf;
PAGE *h;
int ret, t_ret;
u_int32_t bytesgot, bytes;
u_int8_t *src, *dest;
mpf = dbp->mpf;
h = NULL;
ret = t_ret = 0;
bytesgot = bytes = 0;
while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) {
/*
* Mark that we're looking at this page; if we've seen it
* already, quit.
*/
if ((ret = __db_salvage_markdone(vdp, pgno)) != 0)
break;
if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
break;
/*
* Make sure it's really an overflow page, unless we're
* being aggressive, in which case we pretend it is.
*/
if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) {
ret = DB_VERIFY_BAD;
break;
}
src = (u_int8_t *)h + P_OVERHEAD(dbp);
bytes = OV_LEN(h);
if (bytes + P_OVERHEAD(dbp) > dbp->pgsize)
bytes = dbp->pgsize - P_OVERHEAD(dbp);
if ((ret = __os_realloc(dbp->dbenv,
bytesgot + bytes, buf)) != 0)
break;
dest = *(u_int8_t **)buf + bytesgot;
bytesgot += bytes;
memcpy(dest, src, bytes);
pgno = NEXT_PGNO(h);
if ((ret = __memp_fput(mpf, h, 0)) != 0)
break;
h = NULL;
}
/*
* If we're being aggressive, salvage a partial datum if there
* was an error somewhere along the way.
*/
if (ret == 0 || LF_ISSET(DB_AGGRESSIVE)) {
dbt->size = bytesgot;
dbt->data = *(void **)buf;
}
/* If we broke out on error, don't leave pages pinned. */
if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_reclaim.c,v 11.42 2004/06/10 04:46:44 ubell Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_reclaim.c,v 11.28 2002/08/06 06:11:17 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
@@ -20,7 +18,7 @@ static const char revid[] = "$Id: db_reclaim.c,v 11.28 2002/08/06 06:11:17 bosti
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
/*
* __db_traverse_big
@@ -48,12 +46,18 @@ __db_traverse_big(dbp, pgno, callback, cookie)
do {
did_put = 0;
if ((ret = mpf->get(mpf, &pgno, 0, &p)) != 0)
if ((ret = __memp_fget(mpf, &pgno, 0, &p)) != 0)
return (ret);
/*
* If we are freeing pages only process the overflow
* chain if the head of the chain has a refcount of 1.
*/
pgno = NEXT_PGNO(p);
if (callback == __db_truncate_callback && OV_REF(p) != 1)
pgno = PGNO_INVALID;
if ((ret = callback(dbp, p, cookie, &did_put)) == 0 &&
!did_put)
ret = mpf->put(mpf, p, 0);
ret = __memp_fput(mpf, p, 0);
} while (ret == 0 && pgno != PGNO_INVALID);
return (ret);
@@ -79,8 +83,15 @@ __db_reclaim_callback(dbp, p, cookie, putp)
{
int ret;
COMPQUIET(dbp, NULL);
/*
* We don't want to log the free of the root with the subdb.
* If we abort then the subdb may not be openable to undo
* the free.
*/
if ((dbp->type == DB_BTREE || dbp->type == DB_RECNO) &&
PGNO(p) == ((BTREE *)dbp->bt_internal)->bt_root)
return (0);
if ((ret = __db_free(cookie, p)) != 0)
return (ret);
*putp = 1;
@@ -103,12 +114,9 @@ __db_truncate_callback(dbp, p, cookie, putp)
void *cookie;
int *putp;
{
DBMETA *meta;
DBT ldbt;
DB_LOCK metalock;
DB_MPOOLFILE *mpf;
DBT ddbt, ldbt;
db_indx_t indx, len, off, tlen, top;
db_pgno_t pgno;
db_trunc_param *param;
u_int8_t *hk, type;
int ret;
@@ -147,7 +155,12 @@ __db_truncate_callback(dbp, p, cookie, putp)
*putp = 0;
break;
case P_LRECNO:
param->count += top;
for (indx = 0; indx < top; indx += O_INDX) {
type = GET_BKEYDATA(dbp, p, indx)->type;
if (!B_DISSET(type))
++param->count;
}
if (((BTREE *)dbp->bt_internal)->bt_root == PGNO(p)) {
type = P_LRECNO;
goto reinit;
@@ -165,8 +178,8 @@ __db_truncate_callback(dbp, p, cookie, putp)
for (indx = 0; indx < top; indx += P_INDX) {
switch (*H_PAIRDATA(dbp, p, indx)) {
case H_OFFDUP:
case H_OFFPAGE:
break;
case H_OFFPAGE:
case H_KEYDATA:
++param->count;
break;
@@ -174,12 +187,15 @@ __db_truncate_callback(dbp, p, cookie, putp)
tlen = LEN_HDATA(dbp, p, 0, indx);
hk = H_PAIRDATA(dbp, p, indx);
for (off = 0; off < tlen;
off += len + 2 * sizeof (db_indx_t)) {
off += len + 2 * sizeof(db_indx_t)) {
++param->count;
memcpy(&len,
HKEYDATA_DATA(hk)
+ off, sizeof(db_indx_t));
}
break;
default:
return (__db_pgfmt(dbp->dbenv, p->pgno));
}
}
/* Don't free the head of the bucket. */
@@ -188,41 +204,16 @@ __db_truncate_callback(dbp, p, cookie, putp)
reinit: *putp = 0;
if (DBC_LOGGING(param->dbc)) {
pgno = PGNO_BASE_MD;
if ((ret = __db_lget(param->dbc, LCK_ALWAYS,
pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
return (ret);
if ((ret = mpf->get(mpf,
&pgno, 0, (PAGE **)&meta)) != 0) {
goto err;
}
memset(&ldbt, 0, sizeof(ldbt));
memset(&ddbt, 0, sizeof(ddbt));
ldbt.data = p;
ldbt.size = P_OVERHEAD(dbp);
if ((ret = __db_pg_free_log(dbp,
param->dbc->txn, &LSN(meta), 0,
p->pgno, &LSN(meta),
PGNO_BASE_MD, &ldbt, meta->free)) != 0)
goto err;
LSN(p) = LSN(meta);
if ((ret =
__db_pg_alloc_log(dbp,
param->dbc->txn, &LSN(meta), 0,
&LSN(meta), PGNO_BASE_MD,
&p->lsn, p->pgno, type, meta->free)) != 0) {
err: (void)mpf->put(mpf, (PAGE *)meta, 0);
(void)__TLPUT(param->dbc, metalock);
return (ret);
}
LSN(p) = LSN(meta);
if ((ret = mpf->put(mpf,
(PAGE *)meta, DB_MPOOL_DIRTY)) != 0) {
(void)__TLPUT(param->dbc, metalock);
return (ret);
}
if ((ret = __TLPUT(param->dbc, metalock)) != 0)
ldbt.size += p->entries * sizeof(db_indx_t);
ddbt.data = (u_int8_t *)p + p->hf_offset;
ddbt.size = dbp->pgsize - p->hf_offset;
if ((ret = __db_pg_init_log(dbp,
param->dbc->txn, &LSN(p), 0,
p->pgno, &ldbt, &ddbt)) != 0)
return (ret);
} else
LSN_NOT_LOGGED(LSN(p));
@@ -239,7 +230,7 @@ err: (void)mpf->put(mpf, (PAGE *)meta, 0);
if ((ret = __db_free(param->dbc, p)) != 0)
return (ret);
} else {
if ((ret = mpf->put(mpf, p, DB_MPOOL_DIRTY)) != 0)
if ((ret = __memp_fput(mpf, p, DB_MPOOL_DIRTY)) != 0)
return (ret);
*putp = 1;
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Copyright (c) 2001-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_remove.c,v 11.219 2004/09/16 17:55:17 margo Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_remove.c,v 11.203 2002/08/19 18:34:18 margo Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif
@@ -23,27 +21,25 @@ static const char revid[] = "$Id: db_remove.c,v 11.203 2002/08/19 18:34:18 margo
#include "dbinc/db_shash.h"
#include "dbinc/lock.h"
static int __db_subdb_remove __P((DB *, DB_TXN *, const char *, const char *));
static int __db_dbtxn_remove __P((DB *, DB_TXN *, const char *));
static int __db_subdb_remove __P((DB *, DB_TXN *, const char *, const char *));
/*
* __dbenv_dbremove
* Remove method for DB_ENV.
* __dbenv_dbremove_pp
* DB_ENV->dbremove pre/post processing.
*
* PUBLIC: int __dbenv_dbremove __P((DB_ENV *,
* PUBLIC: int __dbenv_dbremove_pp __P((DB_ENV *,
* PUBLIC: DB_TXN *, const char *, const char *, u_int32_t));
*/
int
__dbenv_dbremove(dbenv, txn, name, subdb, flags)
__dbenv_dbremove_pp(dbenv, txn, name, subdb, flags)
DB_ENV *dbenv;
DB_TXN *txn;
const char *name, *subdb;
u_int32_t flags;
{
DB *dbp;
int ret, t_ret, txn_local;
txn_local = 0;
int handle_check, ret, t_ret, txn_local;
PANIC_CHECK(dbenv);
ENV_ILLEGAL_BEFORE_OPEN(dbenv, "DB_ENV->dbremove");
@@ -52,63 +48,79 @@ __dbenv_dbremove(dbenv, txn, name, subdb, flags)
if ((ret = __db_fchk(dbenv, "DB->remove", flags, DB_AUTO_COMMIT)) != 0)
return (ret);
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
return (ret);
/*
* Create local transaction as necessary, check for consistent
* transaction usage.
*/
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
if ((ret = __db_txn_auto_init(dbenv, &txn)) != 0)
return (ret);
txn_local = 1;
} else
} else {
if (txn != NULL && !TXN_ON(dbenv))
return (__db_not_txn_env(dbenv));
txn_local = 0;
}
ret = __db_remove_i(dbp, txn, name, subdb);
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
goto err;
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 1, txn != NULL)) != 0)
goto err;
ret = __db_remove_int(dbp, txn, name, subdb, flags);
/* Commit for DB_AUTO_COMMIT. */
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
/*
* We created the DBP here and when we committed/aborted,
* we release all the tranasctional locks, which includes
* the handle lock; mark the handle cleared explicitly.
* We created the DBP here and when we commit/abort, we'll
* release all the transactional locks, including the handle
* lock; mark the handle cleared explicitly.
*/
LOCK_INIT(dbp->handle_lock);
dbp->lid = DB_LOCK_INVALIDID;
} else if (txn != NULL) {
/*
* We created this handle locally so we need to close it
* and clean it up. Unfortunately, it's holding transactional
* locks that need to persist until the end of transaction.
* If we invalidate the locker id (dbp->lid), then the close
* won't free these locks prematurely.
*/
dbp->lid = DB_LOCK_INVALIDID;
}
if (handle_check)
__env_db_rep_exit(dbenv);
err: if (txn_local)
ret = __db_txn_auto_resolve(dbenv, txn, 0, ret);
/*
* We never opened this dbp for real, so don't call the transactional
* version of DB->close, and use NOSYNC to avoid calling into mpool.
* We never opened this dbp for real, so don't include a transaction
* handle, and use NOSYNC to avoid calling into mpool.
*/
if ((t_ret = dbp->close(dbp, DB_NOSYNC)) != 0 && ret == 0)
if ((t_ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_remove
* Remove method for DB.
* __db_remove_pp
* DB->remove pre/post processing.
*
* PUBLIC: int __db_remove __P((DB *, const char *, const char *, u_int32_t));
* PUBLIC: int __db_remove_pp
* PUBLIC: __P((DB *, const char *, const char *, u_int32_t));
*/
int
__db_remove(dbp, name, subdb, flags)
__db_remove_pp(dbp, name, subdb, flags)
DB *dbp;
const char *name, *subdb;
u_int32_t flags;
{
DB_ENV *dbenv;
int ret, t_ret;
int handle_check, ret;
dbenv = dbp->dbenv;
@@ -126,57 +138,85 @@ __db_remove(dbp, name, subdb, flags)
*/
if (F_ISSET(dbp, DB_AM_OPEN_CALLED)) {
ret = __db_mi_open(dbenv, "DB->remove", 1);
goto err;
return (ret);
}
/* Validate arguments. */
if ((ret = __db_fchk(dbenv, "DB->remove", flags, 0)) != 0)
goto err;
return (ret);
/* Check for consistent transaction usage. */
if ((ret = __db_check_txn(dbp, NULL, DB_LOCK_INVALIDID, 0)) != 0)
goto err;
return (ret);
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 1, 0)) != 0)
return (ret);
/* Remove the file. */
ret = __db_remove_i(dbp, NULL, name, subdb);
ret = __db_remove(dbp, NULL, name, subdb, flags);
/*
* We never opened this dbp for real, use NOSYNC to avoid calling into
* mpool.
*/
err: if ((t_ret = dbp->close(dbp, DB_NOSYNC)) != 0 && ret == 0)
if (handle_check)
__env_db_rep_exit(dbenv);
return (ret);
}
/*
* __db_remove
* DB->remove method.
*
* PUBLIC: int __db_remove
* PUBLIC: __P((DB *, DB_TXN *, const char *, const char *, u_int32_t));
*/
int
__db_remove(dbp, txn, name, subdb, flags)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb;
u_int32_t flags;
{
int ret, t_ret;
ret = __db_remove_int(dbp, txn, name, subdb, flags);
if ((t_ret = __db_close(dbp, txn, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_remove_i
* Internal remove method for DB.
* __db_remove_int
* Worker function for the DB->remove method.
*
* PUBLIC: int __db_remove_i __P((DB *, DB_TXN *, const char *, const char *));
* PUBLIC: int __db_remove_int __P((DB *,
* PUBLIC: DB_TXN *, const char *, const char *, u_int32_t));
*/
int
__db_remove_i(dbp, txn, name, subdb)
__db_remove_int(dbp, txn, name, subdb, flags)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb;
u_int32_t flags;
{
DB_ENV *dbenv;
DB_LSN newlsn;
int ret;
char *real_name;
char *real_name, *tmpname;
dbenv = dbp->dbenv;
real_name = NULL;
real_name = tmpname = NULL;
/* Handle subdatabase removes separately. */
if (subdb != NULL)
return (__db_subdb_remove(dbp, txn, name, subdb));
if (subdb != NULL) {
ret = __db_subdb_remove(dbp, txn, name, subdb);
goto err;
}
/* Handle transactional file removes separately. */
if (txn != NULL)
return (__db_dbtxn_remove(dbp, txn, name));
if (txn != NULL) {
ret = __db_dbtxn_remove(dbp, txn, name);
goto err;
}
/*
* The remaining case is a non-transactional file remove.
@@ -185,20 +225,30 @@ __db_remove_i(dbp, txn, name, subdb)
*/
if ((ret = __db_appname(dbenv,
DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
return (ret);
goto err;
/*
* If force is set, remove the temporary file. Ignore errors because
* the backup file might not exist.
*/
if (LF_ISSET(DB_FORCE) &&
(ret = __db_backup_name(dbenv, real_name, NULL, &tmpname)) == 0)
(void)__os_unlink(dbenv, tmpname);
if ((ret = __fop_remove_setup(dbp, NULL, real_name, 0)) != 0)
goto err;
if (dbp->db_am_remove != NULL &&
(ret = dbp->db_am_remove(dbp, NULL, name, subdb, &newlsn)) != 0)
(ret = dbp->db_am_remove(dbp, NULL, name, subdb)) != 0)
goto err;
ret = __fop_remove(dbenv, NULL, dbp->fileid, name, DB_APP_DATA);
ret = __fop_remove(dbenv, NULL, dbp->fileid, name, DB_APP_DATA,
F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0);
err:
if (real_name != NULL)
err: if (real_name != NULL)
__os_free(dbenv, real_name);
if (tmpname != NULL)
__os_free(dbenv, tmpname);
return (ret);
}
@@ -222,7 +272,7 @@ __db_subdb_remove(dbp, txn, name, subdb)
if ((ret = db_create(&sdbp, dbp->dbenv, 0)) != 0)
goto err;
if ((ret = __db_open(sdbp,
txn, name, subdb, DB_UNKNOWN, DB_WRITEOPEN, 0)) != 0)
txn, name, subdb, DB_UNKNOWN, DB_WRITEOPEN, 0, PGNO_BASE_MD)) != 0)
goto err;
DB_TEST_RECOVERY(sdbp, DB_TEST_PREDESTROY, ret, name);
@@ -238,6 +288,8 @@ __db_subdb_remove(dbp, txn, name, subdb)
if ((ret = __ham_reclaim(sdbp, txn)) != 0)
goto err;
break;
case DB_QUEUE:
case DB_UNKNOWN:
default:
ret = __db_unknown_type(
sdbp->dbenv, "__db_subdb_remove", sdbp->type);
@@ -260,11 +312,11 @@ __db_subdb_remove(dbp, txn, name, subdb)
DB_TEST_RECOVERY_LABEL
err:
/* Close the main and subdatabases. */
if ((t_ret = __db_close_i(sdbp, txn, 0)) != 0 && ret == 0)
if ((t_ret = __db_close(sdbp, txn, 0)) != 0 && ret == 0)
ret = t_ret;
if (mdbp != NULL &&
(t_ret = __db_close_i(mdbp, txn, 0)) != 0 && ret == 0)
(t_ret = __db_close(mdbp, txn, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
@@ -277,7 +329,6 @@ __db_dbtxn_remove(dbp, txn, name)
const char *name;
{
DB_ENV *dbenv;
DB_LSN newlsn;
int ret;
char *tmpname;
@@ -297,15 +348,16 @@ __db_dbtxn_remove(dbp, txn, name)
DB_TEST_RECOVERY(dbp, DB_TEST_PREDESTROY, ret, name);
if ((ret = __db_rename_i(dbp, txn, name, NULL, tmpname)) != 0)
if ((ret = __db_rename_int(dbp, txn, name, NULL, tmpname)) != 0)
goto err;
/* The internal removes will also translate into delayed removes. */
if (dbp->db_am_remove != NULL &&
(ret = dbp->db_am_remove(dbp, txn, tmpname, NULL, &newlsn)) != 0)
(ret = dbp->db_am_remove(dbp, txn, tmpname, NULL)) != 0)
goto err;
ret = __fop_remove(dbenv, txn, dbp->fileid, tmpname, DB_APP_DATA);
ret = __fop_remove(dbenv, txn, dbp->fileid, tmpname, DB_APP_DATA,
F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0);
DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, name);

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Copyright (c) 2001-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_rename.c,v 11.216 2004/09/16 17:55:17 margo Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_rename.c,v 11.203 2002/08/07 16:16:47 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
@@ -23,28 +21,28 @@ static const char revid[] = "$Id: db_rename.c,v 11.203 2002/08/07 16:16:47 bosti
#include "dbinc/fop.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
static int __db_subdb_rename __P(( DB *, DB_TXN *,
const char *, const char *, const char *));
static int __dbenv_dbrename __P((DB_ENV *,
DB_TXN *, const char *, const char *, const char *, int));
static int __db_subdb_rename __P((DB *,
DB_TXN *, const char *, const char *, const char *));
/*
* __dbenv_dbrename
* Rename method for DB_ENV.
* __dbenv_dbrename_pp
* DB_ENV->dbrename pre/post processing.
*
* PUBLIC: int __dbenv_dbrename __P((DB_ENV *, DB_TXN *,
* PUBLIC: int __dbenv_dbrename_pp __P((DB_ENV *, DB_TXN *,
* PUBLIC: const char *, const char *, const char *, u_int32_t));
*/
int
__dbenv_dbrename(dbenv, txn, name, subdb, newname, flags)
__dbenv_dbrename_pp(dbenv, txn, name, subdb, newname, flags)
DB_ENV *dbenv;
DB_TXN *txn;
const char *name, *subdb, *newname;
u_int32_t flags;
{
DB *dbp;
int ret, t_ret, txn_local;
txn_local = 0;
int ret, txn_local;
PANIC_CHECK(dbenv);
ENV_ILLEGAL_BEFORE_OPEN(dbenv, "DB_ENV->dbrename");
@@ -53,67 +51,97 @@ __dbenv_dbrename(dbenv, txn, name, subdb, newname, flags)
if ((ret = __db_fchk(dbenv, "DB->rename", flags, DB_AUTO_COMMIT)) != 0)
return (ret);
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
return (ret);
/*
* Create local transaction as necessary, check for consistent
* transaction usage.
*/
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
if ((ret = __db_txn_auto_init(dbenv, &txn)) != 0)
return (ret);
txn_local = 1;
} else
} else {
if (txn != NULL && !TXN_ON(dbenv))
return (__db_not_txn_env(dbenv));
txn_local = 0;
}
ret = __db_rename_i(dbp, txn, name, subdb, newname);
ret = __dbenv_dbrename(dbenv, txn, name, subdb, newname, txn_local);
return (txn_local ? __db_txn_auto_resolve(dbenv, txn, 0, ret) : ret);
}
/*
* __dbenv_dbrename
* DB_ENV->dbrename.
*/
static int
__dbenv_dbrename(dbenv, txn, name, subdb, newname, txn_local)
DB_ENV *dbenv;
DB_TXN *txn;
const char *name, *subdb, *newname;
int txn_local;
{
DB *dbp;
int handle_check, ret, t_ret;
if ((ret = db_create(&dbp, dbenv, 0)) != 0)
return (ret);
if (txn != NULL)
F_SET(dbp, DB_AM_TXN);
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 1, txn != NULL)) != 0)
goto err;
ret = __db_rename_int(dbp, txn, name, subdb, newname);
/* Commit for DB_AUTO_COMMIT. */
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
/*
* We created the DBP here and when we committed/aborted,
* we release all the tranasctional locks, which includes
* the handle lock; mark the handle cleared explicitly.
* We created the DBP here and when we commit/abort, we'll
* release all the transactional locks, including the handle
* lock; mark the handle cleared explicitly.
*/
LOCK_INIT(dbp->handle_lock);
dbp->lid = DB_LOCK_INVALIDID;
} else if (txn != NULL) {
/*
* We created this handle locally so we need to close it
* and clean it up. Unfortunately, it's holding transactional
* locks that need to persist until the end of transaction.
* If we invalidate the locker id (dbp->lid), then the close
* won't free these locks prematurely.
*/
dbp->lid = DB_LOCK_INVALIDID;
}
/*
* We never opened this dbp for real, so don't call the transactional
* version of DB->close, and use NOSYNC to avoid calling into mpool.
*/
if ((t_ret = dbp->close(dbp, DB_NOSYNC)) != 0 && ret == 0)
if (handle_check)
__env_db_rep_exit(dbenv);
err:
if ((t_ret = __db_close(dbp, txn, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_rename
* Rename method for DB.
* __db_rename_pp
* DB->rename pre/post processing.
*
* PUBLIC: int __db_rename __P((DB *,
* PUBLIC: int __db_rename_pp __P((DB *,
* PUBLIC: const char *, const char *, const char *, u_int32_t));
*/
int
__db_rename(dbp, name, subdb, newname, flags)
__db_rename_pp(dbp, name, subdb, newname, flags)
DB *dbp;
const char *name, *subdb, *newname;
u_int32_t flags;
{
DB_ENV *dbenv;
int ret, t_ret;
int handle_check, ret;
dbenv = dbp->dbenv;
handle_check = 0;
PANIC_CHECK(dbenv);
@@ -140,28 +168,54 @@ __db_rename(dbp, name, subdb, newname, flags)
if ((ret = __db_check_txn(dbp, NULL, DB_LOCK_INVALIDID, 0)) != 0)
goto err;
/* Rename the file. */
ret = __db_rename_i(dbp, NULL, name, subdb, newname);
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 1, 0)) != 0) {
handle_check = 0;
goto err;
}
/*
* We never opened this dbp for real, use NOSYNC to avoid calling into
* mpool.
*/
err: if ((t_ret = dbp->close(dbp, DB_NOSYNC)) != 0 && ret == 0)
/* Rename the file. */
ret = __db_rename(dbp, NULL, name, subdb, newname);
err: if (handle_check)
__env_db_rep_exit(dbenv);
return (ret);
}
/*
* __db_rename
* DB->rename method.
*
* PUBLIC: int __db_rename
* PUBLIC: __P((DB *, DB_TXN *, const char *, const char *, const char *));
*/
int
__db_rename(dbp, txn, name, subdb, newname)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb, *newname;
{
int ret, t_ret;
ret = __db_rename_int(dbp, txn, name, subdb, newname);
if ((t_ret = __db_close(dbp, txn, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_rename_i
* Internal rename method for DB.
* __db_rename_int
* Worker function for DB->rename method; the close of the dbp is
* left in the wrapper routine.
*
* PUBLIC: int __db_rename_i __P((DB *,
* PUBLIC: DB_TXN *, const char *, const char *, const char *));
* PUBLIC: int __db_rename_int
* PUBLIC: __P((DB *, DB_TXN *, const char *, const char *, const char *));
*/
int
__db_rename_i(dbp, txn, name, subdb, newname)
__db_rename_int(dbp, txn, name, subdb, newname)
DB *dbp;
DB_TXN *txn;
const char *name, *subdb, *newname;
@@ -180,9 +234,11 @@ __db_rename_i(dbp, txn, name, subdb, newname)
goto err;
}
/* From here on down, this pertains to files. */
/* Find the real name of the file. */
/*
* From here on down, this pertains to files.
*
* Find the real name of the file.
*/
if ((ret = __db_appname(dbenv,
DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
goto err;
@@ -220,8 +276,7 @@ __db_rename_i(dbp, txn, name, subdb, newname)
DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, newname);
DB_TEST_RECOVERY_LABEL
err:
if (real_name != NULL)
err: if (real_name != NULL)
__os_free(dbenv, real_name);
return (ret);
@@ -265,14 +320,14 @@ __db_subdb_rename(dbp, txn, name, subdb, newname)
MU_OPEN, NULL, 0)) != 0)
goto err;
if ((ret = mdbp->mpf->get(mdbp->mpf, &dbp->meta_pgno, 0, &meta)) != 0)
if ((ret = __memp_fget(mdbp->mpf, &dbp->meta_pgno, 0, &meta)) != 0)
goto err;
memcpy(&dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
memcpy(dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
if ((ret = __fop_lock_handle(dbenv,
dbp, mdbp->lid, DB_LOCK_WRITE, NULL, 0)) != 0)
dbp, mdbp->lid, DB_LOCK_WRITE, NULL, NOWAIT_FLAG(txn))) != 0)
goto err;
ret = mdbp->mpf->put(mdbp->mpf, meta, 0);
ret = __memp_fput(mdbp->mpf, meta, 0);
meta = NULL;
if (ret != 0)
goto err;
@@ -286,11 +341,11 @@ __db_subdb_rename(dbp, txn, name, subdb, newname)
DB_TEST_RECOVERY_LABEL
err:
if (meta != NULL &&
(t_ret = mdbp->mpf->put(mdbp->mpf, meta, 0)) != 0 && ret == 0)
(t_ret = __memp_fput(mdbp->mpf, meta, 0)) != 0 && ret == 0)
ret = t_ret;
if (mdbp != NULL &&
(t_ret = __db_close_i(mdbp, txn, 0)) != 0 && ret == 0)
(t_ret = __db_close(mdbp, txn, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
return (ret);

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_ret.c,v 11.26 2004/02/05 02:25:13 mjc Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_ret.c,v 11.21 2002/03/28 19:21:47 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -92,6 +90,8 @@ __db_retcopy(dbenv, dbt, data, len, memp, memsize)
{
int ret;
ret = 0;
/* If returning a partial record, reset the length. */
if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
data = (u_int8_t *)data + dbt->doff;
@@ -103,14 +103,6 @@ __db_retcopy(dbenv, dbt, data, len, memp, memsize)
len = 0;
}
/*
* Return the length of the returned record in the DBT size field.
* This satisfies the requirement that if we're using user memory
* and insufficient memory was provided, return the amount necessary
* in the size field.
*/
dbt->size = len;
/*
* Allocate memory to be owned by the application: DB_DBT_MALLOC,
* DB_DBT_REALLOC.
@@ -127,28 +119,36 @@ __db_retcopy(dbenv, dbt, data, len, memp, memsize)
* memory pointer is allowed to be NULL.
*/
if (F_ISSET(dbt, DB_DBT_MALLOC)) {
if ((ret = __os_umalloc(dbenv, len, &dbt->data)) != 0)
return (ret);
ret = __os_umalloc(dbenv, len, &dbt->data);
} else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
if ((ret = __os_urealloc(dbenv, len, &dbt->data)) != 0)
return (ret);
if (dbt->data == NULL || dbt->size == 0 || dbt->size < len)
ret = __os_urealloc(dbenv, len, &dbt->data);
} else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
if (len != 0 && (dbt->data == NULL || dbt->ulen < len))
return (ENOMEM);
ret = DB_BUFFER_SMALL;
} else if (memp == NULL || memsize == NULL) {
return (EINVAL);
ret = EINVAL;
} else {
if (len != 0 && (*memsize == 0 || *memsize < len)) {
if ((ret = __os_realloc(dbenv, len, memp)) != 0) {
if ((ret = __os_realloc(dbenv, len, memp)) == 0)
*memsize = len;
else
*memsize = 0;
return (ret);
}
*memsize = len;
}
dbt->data = *memp;
if (ret == 0)
dbt->data = *memp;
}
if (len != 0)
if (ret == 0 && len != 0)
memcpy(dbt->data, data, len);
return (0);
/*
* Return the length of the returned record in the DBT size field.
* This satisfies the requirement that if we're using user memory
* and insufficient memory was provided, return the amount necessary
* in the size field.
*/
dbt->size = len;
return (ret);
}

155
storage/bdb/db/db_setid.c Normal file
View File

@@ -0,0 +1,155 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_setid.c,v 1.6 2004/09/24 13:41:08 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_swap.h"
#include "dbinc/db_am.h"
/*
* __db_fileid_reset --
* Reset the file IDs for every database in the file.
*
* PUBLIC: int __db_fileid_reset __P((DB_ENV *, char *, int));
*/
int
__db_fileid_reset(dbenv, name, passwd)
DB_ENV *dbenv;
char *name;
int passwd;
{
DB *dbp;
DBC *dbcp;
DBT key, data;
DB_MPOOLFILE *mpf;
db_pgno_t pgno;
int t_ret, ret;
void *pagep;
char *real_name;
u_int8_t fileid[DB_FILE_ID_LEN];
dbp = NULL;
dbcp = NULL;
real_name = NULL;
/* Get the real backing file name. */
if ((ret = __db_appname(dbenv,
DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
return (ret);
/* Get a new file ID. */
if ((ret = __os_fileid(dbenv, real_name, 1, fileid)) != 0) {
dbenv->err(dbenv, ret, "unable to get new file ID");
goto err;
}
/* Create the DB object. */
if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
goto err;
}
/* If configured with a password, the databases are encrypted. */
if (passwd && (ret = dbp->set_flags(dbp, DB_ENCRYPT)) != 0) {
dbp->err(dbp, ret, "DB->set_flags: DB_ENCRYPT");
goto err;
}
/*
* Open the DB file.
*
* !!!
* Note DB_RDWRMASTER flag, we need to open the master database file
* for writing in this case.
*/
if ((ret = dbp->open(dbp,
NULL, name, NULL, DB_UNKNOWN, DB_RDWRMASTER, 0)) != 0) {
dbp->err(dbp, ret, "DB->open: %s", name);
goto err;
}
mpf = dbp->mpf;
pgno = PGNO_BASE_MD;
if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) {
dbp->err(dbp, ret,
"%s: DB_MPOOLFILE->get: %lu", name, (u_long)pgno);
goto err;
}
memcpy(((DBMETA *)pagep)->uid, fileid, DB_FILE_ID_LEN);
if ((ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0) {
dbp->err(dbp, ret,
"%s: DB_MPOOLFILE->put: %lu", name, (u_long)pgno);
goto err;
}
/*
* If the database file doesn't support subdatabases, we only have
* to update a single metadata page. Otherwise, we have to open a
* cursor and step through the master database, and update all of
* the subdatabases' metadata pages.
*/
if (!F_ISSET(dbp, DB_AM_SUBDB))
goto err;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
dbp->err(dbp, ret, "DB->cursor");
goto err;
}
while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
/*
* XXX
* We're handling actual data, not on-page meta-data, so it
* hasn't been converted to/from opposite endian architectures.
* Do it explicitly, now.
*/
memcpy(&pgno, data.data, sizeof(db_pgno_t));
DB_NTOHL(&pgno);
if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) {
dbp->err(dbp, ret,
"%s: DB_MPOOLFILE->get: %lu", name, (u_long)pgno);
goto err;
}
memcpy(((DBMETA *)pagep)->uid, fileid, DB_FILE_ID_LEN);
if ((ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0) {
dbp->err(dbp, ret,
"%s: DB_MPOOLFILE->put: %lu", name, (u_long)pgno);
goto err;
}
}
if (ret == DB_NOTFOUND)
ret = 0;
else
dbp->err(dbp, ret, "DBcursor->get");
err: if (dbcp != NULL && (t_ret = dbcp->c_close(dbcp)) != 0) {
dbp->err(dbp, ret, "DBcursor->close");
if (ret == 0)
ret = t_ret;
}
if (dbp != NULL && (t_ret = dbp->close(dbp, 0)) != 0) {
dbenv->err(dbenv, ret, "DB->close");
if (ret == 0)
ret = t_ret;
}
if (real_name != NULL)
__os_free(dbenv, real_name);
return (ret);
}

View File

@@ -0,0 +1,83 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_setlsn.c,v 1.2 2004/04/27 16:10:13 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_am.h"
/*
* __db_lsn_reset --
* Reset the LSNs for every page in the file.
*
* PUBLIC: int __db_lsn_reset __P((DB_ENV *, char *, int));
*/
int
__db_lsn_reset(dbenv, name, passwd)
DB_ENV *dbenv;
char *name;
int passwd;
{
DB *dbp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
db_pgno_t pgno;
int t_ret, ret;
/* Create the DB object. */
if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "db_create");
return (1);
}
/* If configured with a password, the databases are encrypted. */
if (passwd && (ret = dbp->set_flags(dbp, DB_ENCRYPT)) != 0) {
dbp->err(dbp, ret, "DB->set_flags: DB_ENCRYPT");
goto err;
}
/*
* Open the DB file.
*
* !!!
* Note DB_RDWRMASTER flag, we need to open the master database file
* for writing in this case.
*/
if ((ret = dbp->open(dbp,
NULL, name, NULL, DB_UNKNOWN, DB_RDWRMASTER, 0)) != 0) {
dbp->err(dbp, ret, "DB->open: %s", name);
goto err;
}
/* Reset the LSN on every page of the database file. */
mpf = dbp->mpf;
for (pgno = 0; (ret = mpf->get(mpf, &pgno, 0, &pagep)) == 0; ++pgno) {
LSN_NOT_LOGGED(pagep->lsn);
if ((ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0) {
dbp->err(dbp, ret, "DB_MPOOLFILE->put: %s", name);
goto err;
}
}
if (ret == DB_PAGE_NOTFOUND)
ret = 0;
else
dbp->err(dbp, ret, "DB_MPOOLFILE->get: %s", name);
err: if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
ret = t_ret;
return (ret == 0 ? 0 : 1);
}

500
storage/bdb/db/db_stati.c Normal file
View File

@@ -0,0 +1,500 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_stati.c,v 11.123 2004/07/19 16:40:51 bostic Exp $
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/btree.h"
#include "dbinc/hash.h"
#include "dbinc/qam.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#ifdef HAVE_STATISTICS
static int __db_print_all __P((DB *, u_int32_t));
static int __db_print_citem __P((DBC *));
static int __db_print_cursor __P((DB *));
static int __db_print_stats __P((DB *, u_int32_t));
static int __db_stat_arg __P((DB *, u_int32_t));
/*
* __db_stat_pp --
* DB->stat pre/post processing.
*
* PUBLIC: int __db_stat_pp __P((DB *, DB_TXN *, void *, u_int32_t));
*/
int
__db_stat_pp(dbp, txn, spp, flags)
DB *dbp;
DB_TXN *txn;
void *spp;
u_int32_t flags;
{
DB_ENV *dbenv;
int handle_check, ret;
dbenv = dbp->dbenv;
PANIC_CHECK(dbp->dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
if ((ret = __db_stat_arg(dbp, flags)) != 0)
return (ret);
/* Check for replication block. */
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0)
return (ret);
ret = __db_stat(dbp, txn, spp, flags);
/* Release replication block. */
if (handle_check)
__env_db_rep_exit(dbenv);
return (ret);
}
/*
* __db_stat --
* DB->stat.
*
* PUBLIC: int __db_stat __P((DB *, DB_TXN *, void *, u_int32_t));
*/
int
__db_stat(dbp, txn, spp, flags)
DB *dbp;
DB_TXN *txn;
void *spp;
u_int32_t flags;
{
DB_ENV *dbenv;
DBC *dbc;
int ret, t_ret;
dbenv = dbp->dbenv;
/* Acquire a cursor. */
if ((ret = __db_cursor(dbp, txn,
&dbc, LF_ISSET(DB_DEGREE_2 | DB_DIRTY_READ))) != 0)
return (ret);
DEBUG_LWRITE(dbc, NULL, "DB->stat", NULL, NULL, flags);
LF_CLR(DB_DEGREE_2 | DB_DIRTY_READ);
switch (dbp->type) {
case DB_BTREE:
case DB_RECNO:
ret = __bam_stat(dbc, spp, flags);
break;
case DB_HASH:
ret = __ham_stat(dbc, spp, flags);
break;
case DB_QUEUE:
ret = __qam_stat(dbc, spp, flags);
break;
case DB_UNKNOWN:
default:
ret = (__db_unknown_type(dbenv, "DB->stat", dbp->type));
break;
}
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_stat_arg --
* Check DB->stat arguments.
*/
static int
__db_stat_arg(dbp, flags)
DB *dbp;
u_int32_t flags;
{
DB_ENV *dbenv;
dbenv = dbp->dbenv;
/* Check for invalid function flags. */
LF_CLR(DB_DEGREE_2 | DB_DIRTY_READ);
switch (flags) {
case 0:
case DB_FAST_STAT:
case DB_CACHED_COUNTS: /* Deprecated and undocumented. */
break;
case DB_RECORDCOUNT: /* Deprecated and undocumented. */
if (dbp->type == DB_RECNO)
break;
if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_AM_RECNUM))
break;
/* FALLTHROUGH */
default:
return (__db_ferr(dbenv, "DB->stat", 0));
}
return (0);
}
/*
* __db_stat_print_pp --
* DB->stat_print pre/post processing.
*
* PUBLIC: int __db_stat_print_pp __P((DB *, u_int32_t));
*/
int
__db_stat_print_pp(dbp, flags)
DB *dbp;
u_int32_t flags;
{
DB_ENV *dbenv;
int handle_check, ret;
dbenv = dbp->dbenv;
PANIC_CHECK(dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
/*
* !!!
* The actual argument checking is simple, do it inline.
*/
if ((ret = __db_fchk(dbenv, "DB->stat_print",
flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0)
return (ret);
/* Check for replication block. */
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0)
return (ret);
ret = __db_stat_print(dbp, flags);
/* Release replication block. */
if (handle_check)
__env_db_rep_exit(dbenv);
return (ret);
}
/*
* __db_stat_print --
* DB->stat_print.
*
* PUBLIC: int __db_stat_print __P((DB *, u_int32_t));
*/
int
__db_stat_print(dbp, flags)
DB *dbp;
u_int32_t flags;
{
int ret;
if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
ret = __db_print_stats(dbp, flags);
if (flags == 0 || ret != 0)
return (ret);
}
if (LF_ISSET(DB_STAT_ALL) && (ret = __db_print_all(dbp, flags)) != 0)
return (ret);
return (0);
}
/*
* __db_print_stats --
* Display default DB handle statistics.
*/
static int
__db_print_stats(dbp, flags)
DB *dbp;
u_int32_t flags;
{
DBC *dbc;
DB_ENV *dbenv;
int ret, t_ret;
dbenv = dbp->dbenv;
/* Acquire a cursor. */
if ((ret = __db_cursor(dbp, NULL, &dbc, 0)) != 0)
return (ret);
DEBUG_LWRITE(dbc, NULL, "DB->stat_print", NULL, NULL, 0);
switch (dbp->type) {
case DB_BTREE:
case DB_RECNO:
ret = __bam_stat_print(dbc, flags);
break;
case DB_HASH:
ret = __ham_stat_print(dbc, flags);
break;
case DB_QUEUE:
ret = __qam_stat_print(dbc, flags);
break;
case DB_UNKNOWN:
default:
ret = (__db_unknown_type(dbenv, "DB->stat_print", dbp->type));
break;
}
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
/*
* __db_print_all --
* Display debugging DB handle statistics.
*/
static int
__db_print_all(dbp, flags)
DB *dbp;
u_int32_t flags;
{
static const FN fn[] = {
{ DB_AM_CHKSUM, "DB_AM_CHKSUM" },
{ DB_AM_CL_WRITER, "DB_AM_CL_WRITER" },
{ DB_AM_COMPENSATE, "DB_AM_COMPENSATE" },
{ DB_AM_CREATED, "DB_AM_CREATED" },
{ DB_AM_CREATED_MSTR, "DB_AM_CREATED_MSTR" },
{ DB_AM_DBM_ERROR, "DB_AM_DBM_ERROR" },
{ DB_AM_DELIMITER, "DB_AM_DELIMITER" },
{ DB_AM_DIRTY, "DB_AM_DIRTY" },
{ DB_AM_DISCARD, "DB_AM_DISCARD" },
{ DB_AM_DUP, "DB_AM_DUP" },
{ DB_AM_DUPSORT, "DB_AM_DUPSORT" },
{ DB_AM_ENCRYPT, "DB_AM_ENCRYPT" },
{ DB_AM_FIXEDLEN, "DB_AM_FIXEDLEN" },
{ DB_AM_INMEM, "DB_AM_INMEM" },
{ DB_AM_IN_RENAME, "DB_AM_IN_RENAME" },
{ DB_AM_NOT_DURABLE, "DB_AM_NOT_DURABLE" },
{ DB_AM_OPEN_CALLED, "DB_AM_OPEN_CALLED" },
{ DB_AM_PAD, "DB_AM_PAD" },
{ DB_AM_PGDEF, "DB_AM_PGDEF" },
{ DB_AM_RDONLY, "DB_AM_RDONLY" },
{ DB_AM_RECNUM, "DB_AM_RECNUM" },
{ DB_AM_RECOVER, "DB_AM_RECOVER" },
{ DB_AM_RENUMBER, "DB_AM_RENUMBER" },
{ DB_AM_REPLICATION, "DB_AM_REPLICATION" },
{ DB_AM_REVSPLITOFF, "DB_AM_REVSPLITOFF" },
{ DB_AM_SECONDARY, "DB_AM_SECONDARY" },
{ DB_AM_SNAPSHOT, "DB_AM_SNAPSHOT" },
{ DB_AM_SUBDB, "DB_AM_SUBDB" },
{ DB_AM_SWAP, "DB_AM_SWAP" },
{ DB_AM_TXN, "DB_AM_TXN" },
{ DB_AM_VERIFYING, "DB_AM_VERIFYING" },
{ 0, NULL }
};
DB_ENV *dbenv;
dbenv = dbp->dbenv;
__db_msg(dbenv, "%s", DB_GLOBAL(db_line));
__db_msg(dbenv, "DB handle information:");
STAT_ULONG("Page size", dbp->pgsize);
STAT_ISSET("Append recno", dbp->db_append_recno);
STAT_ISSET("Feedback", dbp->db_feedback);
STAT_ISSET("Dup compare", dbp->dup_compare);
STAT_ISSET("App private", dbp->app_private);
STAT_ISSET("DbEnv", dbp->dbenv);
STAT_STRING("Type", __db_dbtype_to_string(dbp->type));
__db_print_mutex(dbenv, NULL, dbp->mutexp, "Thread mutex", flags);
STAT_STRING("File", dbp->fname);
STAT_STRING("Database", dbp->dname);
STAT_HEX("Open flags", dbp->open_flags);
__db_print_fileid(dbenv, dbp->fileid, "\tFile ID");
STAT_ULONG("Cursor adjust ID", dbp->adj_fileid);
STAT_ULONG("Meta pgno", dbp->meta_pgno);
STAT_ULONG("Locker ID", dbp->lid);
STAT_ULONG("Handle lock", dbp->cur_lid);
STAT_ULONG("Associate lock", dbp->associate_lid);
STAT_ULONG("RPC remote ID", dbp->cl_id);
__db_msg(dbenv,
"%.24s\tReplication handle timestamp",
dbp->timestamp == 0 ? "0" : ctime(&dbp->timestamp));
STAT_ISSET("Secondary callback", dbp->s_callback);
STAT_ISSET("Primary handle", dbp->s_primary);
STAT_ISSET("api internal", dbp->api_internal);
STAT_ISSET("Btree/Recno internal", dbp->bt_internal);
STAT_ISSET("Hash internal", dbp->h_internal);
STAT_ISSET("Queue internal", dbp->q_internal);
STAT_ISSET("XA internal", dbp->xa_internal);
__db_prflags(dbenv, NULL, dbp->flags, fn, NULL, "\tFlags");
if (dbp->log_filename == NULL)
STAT_ISSET("File naming information", dbp->log_filename);
else
__dbreg_print_fname(dbenv, dbp->log_filename);
(void)__db_print_cursor(dbp);
return (0);
}
/*
* __db_print_cursor --
* Display the cursor active and free queues.
*/
static int
__db_print_cursor(dbp)
DB *dbp;
{
DB_ENV *dbenv;
DBC *dbc;
int ret, t_ret;
dbenv = dbp->dbenv;
__db_msg(dbenv, "%s", DB_GLOBAL(db_line));
__db_msg(dbenv, "DB handle cursors:");
ret = 0;
MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp);
__db_msg(dbenv, "Active queue:");
for (dbc = TAILQ_FIRST(&dbp->active_queue);
dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0)
ret = t_ret;
__db_msg(dbenv, "Join queue:");
for (dbc = TAILQ_FIRST(&dbp->join_queue);
dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0)
ret = t_ret;
__db_msg(dbenv, "Free queue:");
for (dbc = TAILQ_FIRST(&dbp->free_queue);
dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0)
ret = t_ret;
MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);
return (ret);
}
static
int __db_print_citem(dbc)
DBC *dbc;
{
static const FN fn[] = {
{ DBC_ACTIVE, "DBC_ACTIVE" },
{ DBC_COMPENSATE, "DBC_COMPENSATE" },
{ DBC_DEGREE_2, "DBC_DEGREE_2" },
{ DBC_DIRTY_READ, "DBC_DIRTY_READ" },
{ DBC_OPD, "DBC_OPD" },
{ DBC_RECOVER, "DBC_RECOVER" },
{ DBC_RMW, "DBC_RMW" },
{ DBC_TRANSIENT, "DBC_TRANSIENT" },
{ DBC_WRITECURSOR, "DBC_WRITECURSOR" },
{ DBC_WRITER, "DBC_WRITER" },
{ DBC_MULTIPLE, "DBC_MULTIPLE" },
{ DBC_MULTIPLE_KEY, "DBC_MULTIPLE_KEY" },
{ DBC_OWN_LID, "DBC_OWN_LID" },
{ 0, NULL }
};
DB *dbp;
DBC_INTERNAL *cp;
DB_ENV *dbenv;
dbp = dbc->dbp;
dbenv = dbp->dbenv;
cp = dbc->internal;
STAT_HEX("DBC", dbc);
STAT_HEX("Associated dbp", dbc->dbp);
STAT_HEX("Associated txn", dbc->txn);
STAT_HEX("Internal", cp);
STAT_HEX("Default locker ID", dbc->lid);
STAT_HEX("Locker", dbc->locker);
STAT_STRING("Type", __db_dbtype_to_string(dbc->dbtype));
STAT_HEX("Off-page duplicate cursor", cp->opd);
STAT_HEX("Referenced page", cp->page);
STAT_ULONG("Root", cp->root);
STAT_ULONG("Page number", cp->pgno);
STAT_ULONG("Page index", cp->indx);
STAT_STRING("Lock mode", __db_lockmode_to_string(cp->lock_mode));
__db_prflags(dbenv, NULL, dbc->flags, fn, NULL, "\tFlags");
switch (dbc->dbtype) {
case DB_BTREE:
case DB_RECNO:
__bam_print_cursor(dbc);
break;
case DB_HASH:
__ham_print_cursor(dbc);
break;
case DB_UNKNOWN:
DB_ASSERT(dbp->type != DB_UNKNOWN);
/* FALLTHROUGH */
case DB_QUEUE:
default:
break;
}
return (0);
}
#else /* !HAVE_STATISTICS */
int
__db_stat_pp(dbp, txn, spp, flags)
DB *dbp;
DB_TXN *txn;
void *spp;
u_int32_t flags;
{
COMPQUIET(spp, NULL);
COMPQUIET(txn, NULL);
COMPQUIET(flags, 0);
return (__db_stat_not_built(dbp->dbenv));
}
int
__db_stat_print_pp(dbp, flags)
DB *dbp;
u_int32_t flags;
{
COMPQUIET(flags, 0);
return (__db_stat_not_built(dbp->dbenv));
}
#endif

View File

@@ -1,95 +1,202 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2001-2002
* Copyright (c) 2001-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_truncate.c,v 11.201 2004/07/15 15:52:51 sue Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_truncate.c,v 11.185 2002/08/07 16:16:48 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/log.h"
#include "dbinc/btree.h"
#include "dbinc/hash.h"
#include "dbinc/qam.h"
#include "dbinc/txn.h"
static int __db_cursor_check __P((DB *));
/*
* __db_truncate
* truncate method for DB.
* __db_truncate_pp
* DB->truncate pre/post processing.
*
* PUBLIC: int __db_truncate __P((DB *, DB_TXN *, u_int32_t *, u_int32_t));
* PUBLIC: int __db_truncate_pp __P((DB *, DB_TXN *, u_int32_t *, u_int32_t));
*/
int
__db_truncate(dbp, txn, countp, flags)
__db_truncate_pp(dbp, txn, countp, flags)
DB *dbp;
DB_TXN *txn;
u_int32_t *countp, flags;
{
DB_ENV *dbenv;
int ret, t_ret, txn_local;
int handle_check, ret, txn_local;
dbenv = dbp->dbenv;
ret = txn_local = 0;
PANIC_CHECK(dbenv);
/* Check for invalid flags. */
if (F_ISSET(dbp, DB_AM_SECONDARY)) {
__db_err(dbenv,
"DBP->truncate forbidden on secondary indices");
return (EINVAL);
}
if ((ret =
__db_fchk(dbenv, "DB->truncate", flags, DB_AUTO_COMMIT)) != 0)
return (ret);
/*
* Make sure there are no active cursors on this db. Since we drop
* pages we cannot really adjust cursors.
*/
if (__db_cursor_check(dbp) != 0) {
__db_err(dbenv,
"DB->truncate not permitted with active cursors");
return (EINVAL);
}
/*
* Create local transaction as necessary, check for consistent
* transaction usage.
*/
txn_local = 0;
if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
if ((ret = __db_txn_auto(dbp, &txn)) != 0)
return (ret);
if ((ret = __db_txn_auto_init(dbenv, &txn)) != 0)
goto err;
txn_local = 1;
} else
if (txn != NULL && !TXN_ON(dbenv))
return (__db_not_txn_env(dbenv));
LF_CLR(DB_AUTO_COMMIT);
} else if (txn != NULL && !TXN_ON(dbenv)) {
ret = __db_not_txn_env(dbenv);
return (ret);
}
handle_check = IS_REPLICATED(dbenv, dbp);
if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0)
goto err;
ret = __db_truncate(dbp, txn, countp);
if (handle_check)
__env_db_rep_exit(dbenv);
err: return (txn_local ? __db_txn_auto_resolve(dbenv, txn, 0, ret) : ret);
}
/*
* __db_truncate
* DB->truncate.
*
* PUBLIC: int __db_truncate __P((DB *, DB_TXN *, u_int32_t *));
*/
int
__db_truncate(dbp, txn, countp)
DB *dbp;
DB_TXN *txn;
u_int32_t *countp;
{
DB *sdbp;
DBC *dbc;
DB_ENV *dbenv;
u_int32_t scount;
int ret, t_ret;
dbenv = dbp->dbenv;
dbc = NULL;
ret = 0;
/*
* Run through all secondaries and truncate them first. The count
* returned is the count of the primary only. QUEUE uses normal
* processing to truncate so it will update the secondaries normally.
*/
if (dbp->type != DB_QUEUE && LIST_FIRST(&dbp->s_secondaries) != NULL) {
for (sdbp = __db_s_first(dbp);
sdbp != NULL && ret == 0; ret = __db_s_next(&sdbp))
if ((ret = __db_truncate(sdbp, txn, &scount)) != 0)
break;
if (sdbp != NULL)
(void)__db_s_done(sdbp);
if (ret != 0)
return (ret);
}
DB_TEST_RECOVERY(dbp, DB_TEST_PREDESTROY, ret, NULL);
/* Acquire a cursor. */
if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
return (ret);
DEBUG_LWRITE(dbc, txn, "DB->truncate", NULL, NULL, 0);
switch (dbp->type) {
case DB_BTREE:
case DB_RECNO:
if ((ret = __bam_truncate(dbp, txn, countp)) != 0)
goto err;
break;
case DB_HASH:
if ((ret = __ham_truncate(dbp, txn, countp)) != 0)
goto err;
break;
case DB_QUEUE:
if ((ret = __qam_truncate(dbp, txn, countp)) != 0)
goto err;
break;
default:
ret = __db_unknown_type(
dbenv, "__db_truncate", dbp->type);
goto err;
case DB_BTREE:
case DB_RECNO:
ret = __bam_truncate(dbc, countp);
break;
case DB_HASH:
ret = __ham_truncate(dbc, countp);
break;
case DB_QUEUE:
ret = __qam_truncate(dbc, countp);
break;
case DB_UNKNOWN:
default:
ret = __db_unknown_type(dbenv, "DB->truncate", dbp->type);
break;
}
/* Discard the cursor. */
if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
ret = t_ret;
DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, NULL);
DB_TEST_RECOVERY_LABEL
err:
/* Commit for DB_AUTO_COMMIT. */
if (txn_local) {
if (ret == 0)
ret = txn->commit(txn, 0);
else
if ((t_ret = txn->abort(txn)) != 0)
ret = __db_panic(dbenv, t_ret);
}
return (ret);
}
/*
* __db_cursor_check --
* See if there are any active cursors on this db.
*/
static int
__db_cursor_check(dbp)
DB *dbp;
{
DB *ldbp;
DBC *dbc;
DB_ENV *dbenv;
int found;
dbenv = dbp->dbenv;
MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
for (found = 0, ldbp = __dblist_get(dbenv, dbp->adj_fileid);
ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
ldbp = LIST_NEXT(ldbp, dblistlinks)) {
MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
for (dbc = TAILQ_FIRST(&ldbp->active_queue);
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
if (IS_INITIALIZED(dbc)) {
found = 1;
break;
}
}
MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
if (found == 1)
break;
}
MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
return (found);
}

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_upg.c,v 11.35 2004/03/24 20:37:35 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_upg.c,v 11.29 2002/03/27 18:59:04 krinsky Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -36,11 +34,43 @@ static int (* const func_31_list[P_PAGETYPE_MAX])
NULL, /* P_OVERFLOW */
__ham_31_hashmeta, /* P_HASHMETA */
__bam_31_btreemeta, /* P_BTREEMETA */
NULL, /* P_QAMMETA */
NULL, /* P_QAMDATA */
NULL, /* P_LDUP */
};
static int __db_page_pass __P((DB *, char *, u_int32_t, int (* const [])
(DB *, char *, u_int32_t, DB_FH *, PAGE *, int *), DB_FH *));
/*
* __db_upgrade_pp --
* DB->upgrade pre/post processing.
*
* PUBLIC: int __db_upgrade_pp __P((DB *, const char *, u_int32_t));
*/
int
__db_upgrade_pp(dbp, fname, flags)
DB *dbp;
const char *fname;
u_int32_t flags;
{
DB_ENV *dbenv;
int ret;
dbenv = dbp->dbenv;
PANIC_CHECK(dbp->dbenv);
/*
* !!!
* The actual argument checking is simple, do it inline.
*/
if ((ret = __db_fchk(dbenv, "DB->upgrade", flags, DB_DUPSORT)) != 0)
return (ret);
return (__db_upgrade(dbp, fname, flags));
}
/*
* __db_upgrade --
* Upgrade an existing database.
@@ -54,17 +84,14 @@ __db_upgrade(dbp, fname, flags)
u_int32_t flags;
{
DB_ENV *dbenv;
DB_FH fh;
DB_FH *fhp;
size_t n;
int ret, t_ret;
u_int8_t mbuf[256];
char *real_name;
dbenv = dbp->dbenv;
/* Validate arguments. */
if ((ret = __db_fchk(dbenv, "DB->upgrade", flags, DB_DUPSORT)) != 0)
return (ret);
fhp = NULL;
/* Get the real backing file name. */
if ((ret = __db_appname(dbenv,
@@ -72,7 +99,7 @@ __db_upgrade(dbp, fname, flags)
return (ret);
/* Open the file. */
if ((ret = __os_open(dbenv, real_name, 0, 0, &fh)) != 0) {
if ((ret = __os_open(dbenv, real_name, 0, 0, &fhp)) != 0) {
__db_err(dbenv, "%s: %s", real_name, db_strerror(ret));
return (ret);
}
@@ -85,7 +112,7 @@ __db_upgrade(dbp, fname, flags)
* Read the metadata page. We read 256 bytes, which is larger than
* any access method's metadata page and smaller than any disk sector.
*/
if ((ret = __os_read(dbenv, &fh, mbuf, sizeof(mbuf), &n)) != 0)
if ((ret = __os_read(dbenv, fhp, mbuf, sizeof(mbuf), &n)) != 0)
goto err;
switch (((DBMETA *)mbuf)->magic) {
@@ -100,9 +127,9 @@ __db_upgrade(dbp, fname, flags)
__bam_30_btreemeta(dbp, real_name, mbuf)) != 0)
goto err;
if ((ret = __os_seek(dbenv,
&fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
goto err;
if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
if ((ret = __os_write(dbenv, fhp, mbuf, 256, &n)) != 0)
goto err;
/* FALLTHROUGH */
case 7:
@@ -113,7 +140,7 @@ __db_upgrade(dbp, fname, flags)
memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
if ((ret = __db_page_pass(
dbp, real_name, flags, func_31_list, &fh)) != 0)
dbp, real_name, flags, func_31_list, fhp)) != 0)
goto err;
/* FALLTHROUGH */
case 8:
@@ -138,9 +165,9 @@ __db_upgrade(dbp, fname, flags)
__ham_30_hashmeta(dbp, real_name, mbuf)) != 0)
goto err;
if ((ret = __os_seek(dbenv,
&fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
goto err;
if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
if ((ret = __os_write(dbenv, fhp, mbuf, 256, &n)) != 0)
goto err;
/*
@@ -152,14 +179,14 @@ __db_upgrade(dbp, fname, flags)
* the end of the database file.
*
* In DB 3.X, we now create all the hash pages
* belonging to a doubling atomicly; it's not
* belonging to a doubling atomically; it's not
* safe to just save them for later, because when
* we create an overflow page we'll just create
* a new last page (whatever that may be). Grow
* the database to the end of the current doubling.
*/
if ((ret =
__ham_30_sizefix(dbp, &fh, real_name, mbuf)) != 0)
__ham_30_sizefix(dbp, fhp, real_name, mbuf)) != 0)
goto err;
/* FALLTHROUGH */
case 6:
@@ -170,7 +197,7 @@ __db_upgrade(dbp, fname, flags)
memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
if ((ret = __db_page_pass(
dbp, real_name, flags, func_31_list, &fh)) != 0)
dbp, real_name, flags, func_31_list, fhp)) != 0)
goto err;
/* FALLTHROUGH */
case 7:
@@ -198,9 +225,9 @@ __db_upgrade(dbp, fname, flags)
if ((ret = __qam_32_qammeta(dbp, real_name, mbuf)) != 0)
return (ret);
if ((ret = __os_seek(dbenv,
&fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
goto err;
if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0)
if ((ret = __os_write(dbenv, fhp, mbuf, 256, &n)) != 0)
goto err;
/* FALLTHROUGH */
case 3:
@@ -232,9 +259,10 @@ __db_upgrade(dbp, fname, flags)
goto err;
}
ret = __os_fsync(dbenv, &fh);
ret = __os_fsync(dbenv, fhp);
err: if ((t_ret = __os_closehandle(dbenv, &fh)) != 0 && ret == 0)
err: if (fhp != NULL &&
(t_ret = __os_closehandle(dbenv, fhp)) != 0 && ret == 0)
ret = t_ret;
__os_free(dbenv, real_name);
@@ -277,7 +305,8 @@ __db_page_pass(dbp, real_name, flags, fl, fhp)
/* Walk the file, calling the underlying conversion functions. */
for (i = 0; i < pgno_last; ++i) {
if (dbp->db_feedback != NULL)
dbp->db_feedback(dbp, DB_UPGRADE, (i * 100)/pgno_last);
dbp->db_feedback(
dbp, DB_UPGRADE, (int)((i * 100)/pgno_last));
if ((ret = __os_seek(dbenv,
fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0)
break;

View File

@@ -1,16 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Copyright (c) 1996-2004
* Sleepycat Software. All rights reserved.
*
* $Id: db_upg_opd.c,v 11.21 2004/03/19 16:10:26 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_upg_opd.c,v 11.18 2002/08/06 06:11:18 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
@@ -102,26 +100,26 @@ __db_31_offdup(dbp, real_name, fhp, sorted, pgnop)
}
/* If we only have a single page, it's easy. */
if (cur_cnt > 1) {
/*
* pgno_cur is the list of pages we just converted. We're
* going to walk that list, but we'll need to create a new
* list while we do so.
*/
if ((ret = __os_malloc(dbp->dbenv,
cur_cnt * sizeof(db_pgno_t), &pgno_next)) != 0)
goto err;
if (cur_cnt <= 1)
goto done;
/* Figure out where we can start allocating new pages. */
if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
goto err;
/*
* pgno_cur is the list of pages we just converted. We're
* going to walk that list, but we'll need to create a new
* list while we do so.
*/
if ((ret = __os_malloc(dbp->dbenv,
cur_cnt * sizeof(db_pgno_t), &pgno_next)) != 0)
goto err;
/* Allocate room for an internal page. */
if ((ret = __os_malloc(dbp->dbenv,
dbp->pgsize, &ipage)) != 0)
goto err;
PGNO(ipage) = PGNO_INVALID;
}
/* Figure out where we can start allocating new pages. */
if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
goto err;
/* Allocate room for an internal page. */
if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &ipage)) != 0)
goto err;
PGNO(ipage) = PGNO_INVALID;
/*
* Repeatedly walk the list of pages, building internal pages, until
@@ -181,7 +179,7 @@ __db_31_offdup(dbp, real_name, fhp, sorted, pgnop)
pgno_next = tmp;
}
*pgnop = pgno_cur[0];
done: *pgnop = pgno_cur[0];
err: if (pgno_cur != NULL)
__os_free(dbp->dbenv, pgno_cur);

Some files were not shown because too many files have changed in this diff Show More