diff options
author | Panu Matilainen <pmatilai@redhat.com> | 2007-07-16 16:48:14 +0300 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2007-07-16 16:48:14 +0300 |
commit | 2cfd3012bfcb5c5c61bbaf662ef084e0ab789d79 (patch) | |
tree | e12ee52087506ac8c7a5eee83b17497d98df2d40 /db/tcl | |
parent | b754fe19fd387ca5fe8e7c00ddaa25c898fa192f (diff) | |
download | librpm-tizen-2cfd3012bfcb5c5c61bbaf662ef084e0ab789d79.tar.gz librpm-tizen-2cfd3012bfcb5c5c61bbaf662ef084e0ab789d79.tar.bz2 librpm-tizen-2cfd3012bfcb5c5c61bbaf662ef084e0ab789d79.zip |
Update internal BDB to version 4.5.20
Diffstat (limited to 'db/tcl')
-rw-r--r-- | db/tcl/docs/db.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/env.html | 9 | ||||
-rw-r--r-- | db/tcl/docs/historic.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/index.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/library.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/lock.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/log.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/mpool.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/rep.html | 2 | ||||
-rw-r--r-- | db/tcl/docs/test.html | 48 | ||||
-rw-r--r-- | db/tcl/docs/txn.html | 2 | ||||
-rw-r--r-- | db/tcl/tcl_compat.c | 18 | ||||
-rw-r--r-- | db/tcl/tcl_db.c | 506 | ||||
-rw-r--r-- | db/tcl/tcl_db_pkg.c | 389 | ||||
-rw-r--r-- | db/tcl/tcl_dbcursor.c | 158 | ||||
-rw-r--r-- | db/tcl/tcl_env.c | 332 | ||||
-rw-r--r-- | db/tcl/tcl_internal.c | 157 | ||||
-rw-r--r-- | db/tcl/tcl_lock.c | 21 | ||||
-rw-r--r-- | db/tcl/tcl_log.c | 41 | ||||
-rw-r--r-- | db/tcl/tcl_mp.c | 84 | ||||
-rw-r--r-- | db/tcl/tcl_rep.c | 571 | ||||
-rw-r--r-- | db/tcl/tcl_seq.c | 26 | ||||
-rw-r--r-- | db/tcl/tcl_txn.c | 175 | ||||
-rw-r--r-- | db/tcl/tcl_util.c | 266 |
24 files changed, 1950 insertions, 869 deletions
diff --git a/db/tcl/docs/db.html b/db/tcl/docs/db.html index db8382b75..91a5e6542 100644 --- a/db/tcl/docs/db.html +++ b/db/tcl/docs/db.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> diff --git a/db/tcl/docs/env.html b/db/tcl/docs/env.html index 3203a02b8..cb73bed10 100644 --- a/db/tcl/docs/env.html +++ b/db/tcl/docs/env.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <html> <head> @@ -181,11 +181,6 @@ a deadlock</li> </ul> <li> -<b>-lock_max </b>sets the maximum size of the lock table to <b><i>max </i></b>using -the <a href="../../docs/api_c/env_set_lk_max.html">DBENV->set_lk_max</a> -method call</li> - -<li> <b>-lock_max_locks </b>sets the maximum number of locks to <b><i>max </i></b>using the <a href="../../docs/api_c/env_set_lk_max_locks.html">DBENV->set_lk_max_locks</a> method call</li> @@ -241,7 +236,7 @@ DBENV->rep_master</a> call.</li> <li> <b>-rep_transport </b>specifies the replication transport function, using the -<a href="../../docs/api_c/rep_transport.html">DBENV->set_rep_transport</a> +<a href="../../docs/api_c/rep_transport.html">DBENV->rep_set_transport</a> call. This site's machine ID is set to <b><i>machineid</i></b> and the send function, a Tcl proc, is set to <b><i>sendproc</i></b>.</li> diff --git a/db/tcl/docs/historic.html b/db/tcl/docs/historic.html index f5a43e14d..72b40b489 100644 --- a/db/tcl/docs/historic.html +++ b/db/tcl/docs/historic.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> diff --git a/db/tcl/docs/index.html b/db/tcl/docs/index.html index 4f4e1e90c..7acf4d1ed 100644 --- a/db/tcl/docs/index.html +++ b/db/tcl/docs/index.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> diff --git a/db/tcl/docs/library.html b/db/tcl/docs/library.html index 217213ed8..35ce8cf15 100644 --- a/db/tcl/docs/library.html +++ b/db/tcl/docs/library.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> diff --git a/db/tcl/docs/lock.html b/db/tcl/docs/lock.html index 75e0bb2de..d418519ff 100644 --- a/db/tcl/docs/lock.html +++ b/db/tcl/docs/lock.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <html> <head> diff --git a/db/tcl/docs/log.html b/db/tcl/docs/log.html index 5fdd132d5..0cda2bc47 100644 --- a/db/tcl/docs/log.html +++ b/db/tcl/docs/log.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> diff --git a/db/tcl/docs/mpool.html b/db/tcl/docs/mpool.html index 83c1f452c..59372aa34 100644 --- a/db/tcl/docs/mpool.html +++ b/db/tcl/docs/mpool.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> diff --git a/db/tcl/docs/rep.html b/db/tcl/docs/rep.html index d50b62375..2f1ee7a58 100644 --- a/db/tcl/docs/rep.html +++ b/db/tcl/docs/rep.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <html> <head> diff --git a/db/tcl/docs/test.html b/db/tcl/docs/test.html index a01140183..f714beb37 100644 --- a/db/tcl/docs/test.html +++ b/db/tcl/docs/test.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <HTML> <HEAD> @@ -100,51 +100,5 @@ deletion process.</LI> call in deletion</LI> </UL> -<HR WIDTH="100%"> -<BR><B>> <env> mutex <I>mode nitems</I></B> -<P>This command creates a mutex region for testing. It sets the mode -of the region to <B><I>mode</I></B> and sets up for <B><I>nitems</I></B> -number of mutex entries. After we successfully get a handle to a -mutex we create a command of the form <B><I>$env.mutexX</I></B>, where -X is an integer starting at 0 (e.g. <B>$env.mutex0, $env.mutex1, -</B>etc). -We use the <I>Tcl_CreateObjCommand() </I> to create the top level -mutex function. It is through this handle that the user can access -all of the commands described below. Internally, the mutex handle -is sent as the <I>ClientData</I> portion of the new command set so that -all future mutex calls access the appropriate handle. -<P> -<HR WIDTH="100%"><B>> <mutex> close</B> -<P>This command closes the mutex and renders the handle invalid. -This command directly translates to the __db_r_detach function call. -It returns either a 0 (for success), or it throws a Tcl error with -a system message. -<P>Additionally, since the handle is no longer valid, we will call <I>Tcl_DeleteCommand() -</I>so -that further uses of the handle will be dealt with properly by Tcl itself. -<HR WIDTH="100%"><B>> <mutex> get <I>id</I></B> -<P>This command locks the mutex identified by <B><I>id</I></B>. It -returns either a 0 (for success), or it throws a Tcl error with a -system message. -<BR> -<HR WIDTH="100%"><B>> <mutex> release <I>id</I></B> -<P>This command releases the mutex identified by <B><I>id</I></B>. -It returns either a 0 (for success), or it throws a Tcl error with -a system message. -<BR> -<HR WIDTH="100%"><B>> <mutex> getval <I>id</I></B> -<P>This command gets the value stored for the mutex identified by <B><I>id</I></B>. -It returns either the value, or it throws a Tcl error with a system -message. -<BR> -<HR WIDTH="100%"><B>> <mutex> setval <I>id val</I></B> -<P>This command sets the value stored for the mutex identified by <B><I>id -</I></B>to -<B><I>val</I></B>. -It returns either a 0 (for success), or it throws a Tcl error with -a system message. -<BR> -<HR WIDTH="100%"> -<BR> </BODY> </HTML> diff --git a/db/tcl/docs/txn.html b/db/tcl/docs/txn.html index 8abef4b31..27892d3ea 100644 --- a/db/tcl/docs/txn.html +++ b/db/tcl/docs/txn.html @@ -1,4 +1,4 @@ -<!--Copyright 1999-2004 by Sleepycat Software, Inc.--> +<!--Copyright 1999-2006 by Oracle Corporation.--> <!--All rights reserved.--> <html> <head> diff --git a/db/tcl/tcl_compat.c b/db/tcl/tcl_compat.c index 8b518f761..79c63aa8c 100644 --- a/db/tcl/tcl_compat.c +++ b/db/tcl/tcl_compat.c @@ -1,28 +1,20 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_compat.c,v 11.46 2004/10/07 16:48:39 bostic Exp $ + * $Id: tcl_compat.c,v 12.4 2006/08/24 14:46:32 bostic Exp $ */ #include "db_config.h" - #ifdef CONFIG_TEST +#define DB_DBM_HSEARCH 1 +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#define DB_DBM_HSEARCH 1 - -#include "db_int.h" #include "dbinc/tcl_db.h" /* diff --git a/db/tcl/tcl_db.c b/db/tcl/tcl_db.c index f60be3f43..9de948ea6 100644 --- a/db/tcl/tcl_db.c +++ b/db/tcl/tcl_db.c @@ -1,23 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_db.c,v 11.145 2004/10/07 16:48:39 bostic Exp $ + * $Id: tcl_db.c,v 12.23 2006/08/24 14:46:32 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/db_page.h" #include "dbinc/db_am.h" #include "dbinc/tcl_db.h" @@ -37,6 +32,11 @@ static int tcl_DbKeyRange __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); static int tcl_DbPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); static int tcl_DbStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); static int tcl_DbTruncate __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +#ifdef CONFIG_TEST +static int tcl_DbCompact __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbCompactStat __P((Tcl_Interp *, + int, Tcl_Obj * CONST*, DB *)); +#endif static int tcl_DbCursor __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *, DBC **)); static int tcl_DbJoin __P((Tcl_Interp *, @@ -99,6 +99,8 @@ db_Cmd(clientData, interp, objc, objv) "pget", "rpcid", "test", + "compact", + "compact_stat", #endif "associate", "close", @@ -139,6 +141,8 @@ db_Cmd(clientData, interp, objc, objv) DBPGET, DBRPCID, DBTEST, + DBCOMPACT, + DBCOMPACT_STAT, #endif DBASSOCIATE, DBCLOSE, @@ -235,6 +239,15 @@ db_Cmd(clientData, interp, objc, objv) case DBTEST: result = tcl_EnvTest(interp, objc, objv, dbp->dbenv); break; + + case DBCOMPACT: + result = tcl_DbCompact(interp, objc, objv, dbp); + break; + + case DBCOMPACT_STAT: + result = tcl_DbCompactStat(interp, objc, objv, dbp); + break; + #endif case DBASSOCIATE: result = tcl_DbAssociate(interp, objc, objv, dbp); @@ -539,8 +552,8 @@ tcl_DbStat(interp, objc, objv, dbp) { static const char *dbstatopts[] = { #ifdef CONFIG_TEST - "-degree_2", - "-dirty", + "-read_committed", + "-read_uncommitted", #endif "-faststat", "-txn", @@ -548,8 +561,8 @@ tcl_DbStat(interp, objc, objv, dbp) }; enum dbstatopts { #ifdef CONFIG_TEST - DBCUR_DEGREE2, - DBCUR_DIRTY, + DBCUR_READ_COMMITTED, + DBCUR_READ_UNCOMMITTED, #endif DBCUR_FASTSTAT, DBCUR_TXN @@ -579,11 +592,11 @@ tcl_DbStat(interp, objc, objv, dbp) i++; switch ((enum dbstatopts)optindex) { #ifdef CONFIG_TEST - case DBCUR_DEGREE2: - flag |= DB_DEGREE_2; + case DBCUR_READ_COMMITTED: + flag |= DB_READ_COMMITTED; break; - case DBCUR_DIRTY: - flag |= DB_DIRTY_READ; + case DBCUR_READ_UNCOMMITTED: + flag |= DB_READ_UNCOMMITTED; break; #endif case DBCUR_FASTSTAT: @@ -775,6 +788,8 @@ tcl_DbClose(interp, objc, objv, dbp, dbip) if (endarg) break; } + if (dbip->i_cdata != NULL) + __os_free(dbp->dbenv, dbip->i_cdata); _DbInfoDelete(interp, dbip); _debug_check(); @@ -801,7 +816,6 @@ tcl_DbPut(interp, objc, objv, dbp) "-nodupdata", #endif "-append", - "-auto_commit", "-nooverwrite", "-partial", "-txn", @@ -812,7 +826,6 @@ tcl_DbPut(interp, objc, objv, dbp) DBGET_NODUPDATA, #endif DBPUT_APPEND, - DBPUT_AUTO_COMMIT, DBPUT_NOOVER, DBPUT_PART, DBPUT_TXN @@ -828,7 +841,7 @@ tcl_DbPut(interp, objc, objv, dbp) void *dtmp, *ktmp; db_recno_t recno; u_int32_t flag; - int auto_commit, elemc, end, freekey, freedata; + int elemc, end, freekey, freedata; int i, optindex, result, ret; char *arg, msg[MSG_SIZE]; @@ -881,7 +894,6 @@ tcl_DbPut(interp, objc, objv, dbp) * defined above. */ i = 2; - auto_commit = 0; while (i < end) { if (Tcl_GetIndexFromObj(interp, objv[i], dbputopts, "option", TCL_EXACT, &optindex) != TCL_OK) @@ -909,9 +921,6 @@ tcl_DbPut(interp, objc, objv, dbp) result = TCL_ERROR; } break; - case DBPUT_AUTO_COMMIT: - auto_commit = 1; - break; case DBPUT_APPEND: FLAG_CHECK(flag); flag = DB_APPEND; @@ -986,8 +995,6 @@ tcl_DbPut(interp, objc, objv, dbp) } key.data = ktmp; } - if (auto_commit) - flag |= DB_AUTO_COMMIT; ret = _CopyObjBytes(interp, objv[objc-1], &dtmp, &data.size, &freedata); if (ret != 0) { result = _ReturnSetup(interp, ret, @@ -1026,11 +1033,11 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) { static const char *dbgetopts[] = { #ifdef CONFIG_TEST - "-degree2", - "-dirty", + "-data_buf_size", "-multi", + "-read_committed", + "-read_uncommitted", #endif - "-auto_commit", "-consume", "-consume_wait", "-get_both", @@ -1044,11 +1051,11 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) }; enum dbgetopts { #ifdef CONFIG_TEST - DBGET_DEGREE2, - DBGET_DIRTY, + DBGET_DATA_BUF_SIZE, DBGET_MULTI, + DBGET_READ_COMMITTED, + DBGET_READ_UNCOMMITTED, #endif - DBGET_AUTO_COMMIT, DBGET_CONSUME, DBGET_CONSUME_WAIT, DBGET_BOTH, @@ -1065,24 +1072,25 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) DB_TXN *txn; Tcl_Obj **elemv, *retlist; db_recno_t precno, recno; - u_int32_t aflag, flag, cflag, isdup, mflag, rmw; + u_int32_t flag, cflag, isdup, mflag, rmw; int elemc, end, endarg, freekey, freedata, i; int optindex, result, ret, useglob, useprecno, userecno; char *arg, *pattern, *prefix, msg[MSG_SIZE]; void *dtmp, *ktmp; #ifdef CONFIG_TEST - int bufsize; + int bufsize, data_buf_size; #endif result = TCL_OK; freekey = freedata = 0; - aflag = cflag = endarg = flag = mflag = rmw = 0; + cflag = endarg = flag = mflag = rmw = 0; useglob = userecno = 0; txn = NULL; pattern = prefix = NULL; dtmp = ktmp = NULL; #ifdef CONFIG_TEST COMPQUIET(bufsize, 0); + data_buf_size = 0; #endif if (objc < 3) { @@ -1118,23 +1126,28 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) i++; switch ((enum dbgetopts)optindex) { #ifdef CONFIG_TEST - case DBGET_DIRTY: - rmw |= DB_DIRTY_READ; - break; - case DBGET_DEGREE2: - rmw |= DB_DEGREE_2; + case DBGET_DATA_BUF_SIZE: + result = + Tcl_GetIntFromObj(interp, objv[i], &data_buf_size); + if (result != TCL_OK) + goto out; + i++; break; case DBGET_MULTI: mflag |= DB_MULTIPLE; - result = Tcl_GetIntFromObj(interp, objv[i], &bufsize); + result = + Tcl_GetIntFromObj(interp, objv[i], &bufsize); if (result != TCL_OK) goto out; i++; break; -#endif - case DBGET_AUTO_COMMIT: - aflag |= DB_AUTO_COMMIT; + case DBGET_READ_COMMITTED: + rmw |= DB_READ_COMMITTED; + break; + case DBGET_READ_UNCOMMITTED: + rmw |= DB_READ_UNCOMMITTED; break; +#endif case DBGET_BOTH: /* * Change 'end' and make sure we aren't already past @@ -1276,6 +1289,22 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) result = TCL_ERROR; goto out; } +#ifdef CONFIG_TEST + if (data_buf_size != 0 && flag == DB_GET_BOTH) { + Tcl_SetResult(interp, + "Only one of -data_buf_size or -get_both can be specified.\n", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } + if (data_buf_size != 0 && mflag != 0) { + Tcl_SetResult(interp, + "Only one of -data_buf_size or -multi can be specified.\n", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } +#endif if (useglob && flag == DB_GET_BOTH) { Tcl_SetResult(interp, "Only one of -glob or -get_both can be specified.\n", @@ -1309,8 +1338,23 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) * instead of a cursor operation. */ if (pattern == NULL && (isdup == 0 || mflag != 0 || +#ifdef CONFIG_TEST + data_buf_size != 0 || +#endif flag == DB_SET_RECNO || flag == DB_GET_BOTH || flag == DB_CONSUME || flag == DB_CONSUME_WAIT)) { +#ifdef CONFIG_TEST + if (data_buf_size == 0) { + F_CLR(&save, DB_DBT_USERMEM); + F_SET(&save, DB_DBT_MALLOC); + } else { + (void)__os_malloc( + NULL, (size_t)data_buf_size, &save.data); + save.ulen = (u_int32_t)data_buf_size; + F_CLR(&save, DB_DBT_MALLOC); + F_SET(&save, DB_DBT_USERMEM); + } +#endif if (flag == DB_GET_BOTH) { if (userecno) { result = _GetUInt32(interp, @@ -1327,14 +1371,14 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) * the allocated key space in a tmp. */ ret = _CopyObjBytes(interp, objv[objc-2], - &ktmp, &key.size, &freekey); + &key.data, &key.size, &freekey); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_DBGET(ret), "db get"); goto out; } - key.data = ktmp; } + ktmp = key.data; /* * Already checked args above. Fill in key and save. * Save is used in the dbp->get call below to fill in @@ -1378,14 +1422,14 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) * the allocated key space in a tmp. */ ret = _CopyObjBytes(interp, objv[objc-1], - &ktmp, &key.size, &freekey); + &key.data, &key.size, &freekey); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_DBGET(ret), "db get"); goto out; } - key.data = ktmp; } + ktmp = key.data; #ifdef CONFIG_TEST if (mflag & DB_MULTIPLE) { if ((ret = __os_malloc(dbp->dbenv, @@ -1417,7 +1461,7 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) } else { _debug_check(); ret = dbp->get(dbp, - txn, &key, &data, flag | aflag | rmw | mflag); + txn, &key, &data, flag | rmw | mflag); } result = _ReturnSetup(interp, ret, DB_RETOK_DBGET(ret), "db get"); @@ -1487,15 +1531,15 @@ tcl_DbGet(interp, objc, objv, dbp, ispget) * key pointers. So, we need to store * the allocated key space in a tmp. */ - ret = _CopyObjBytes(interp, objv[objc-1], &ktmp, + ret = _CopyObjBytes(interp, objv[objc-1], &key.data, &key.size, &freekey); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_DBGET(ret), "db get"); return (result); } - key.data = ktmp; } + ktmp = key.data; ret = dbp->cursor(dbp, txn, &dbc, 0); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db cursor"); if (result == TCL_ERROR) @@ -1634,13 +1678,11 @@ tcl_DbDelete(interp, objc, objv, dbp) DB *dbp; /* Database pointer */ { static const char *dbdelopts[] = { - "-auto_commit", "-glob", "-txn", NULL }; enum dbdelopts { - DBDEL_AUTO_COMMIT, DBDEL_GLOB, DBDEL_TXN }; @@ -1656,7 +1698,6 @@ tcl_DbDelete(interp, objc, objv, dbp) result = TCL_OK; freekey = 0; - flag = 0; pattern = prefix = NULL; txn = NULL; if (objc < 3) { @@ -1667,17 +1708,17 @@ tcl_DbDelete(interp, objc, objv, dbp) ktmp = NULL; memset(&key, 0, sizeof(key)); /* - * The first arg must be -auto_commit, -glob, -txn or a list of keys. + * The first arg must be -glob, -txn or a list of keys. */ i = 2; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], dbdelopts, "option", TCL_EXACT, &optindex) != TCL_OK) { /* - * If we don't have a -auto_commit, -glob or -txn, - * then the remaining args must be exact keys. - * Reset the result so we don't get an errant error - * message if there is another error. + * If we don't have a -glob or -txn, then the remaining + * args must be exact keys. Reset the result so we + * don't get an errant error message if there is another + * error. */ if (IS_HELP(objv[i]) == TCL_OK) return (TCL_OK); @@ -1704,9 +1745,6 @@ tcl_DbDelete(interp, objc, objv, dbp) result = TCL_ERROR; } break; - case DBDEL_AUTO_COMMIT: - flag |= DB_AUTO_COMMIT; - break; case DBDEL_GLOB: /* * Get the pattern. Get the prefix and use cursors to @@ -1741,8 +1779,6 @@ tcl_DbDelete(interp, objc, objv, dbp) * * If we have a pattern AND more keys to process, there is an error. * Either we have some number of exact keys, or we have a pattern. - * - * If we have a pattern and an auto commit flag, there is an error. */ if (pattern == NULL) { if (i != (objc - 1)) { @@ -1758,13 +1794,6 @@ tcl_DbDelete(interp, objc, objv, dbp) result = TCL_ERROR; goto out; } - if (flag & DB_AUTO_COMMIT) { - Tcl_SetResult(interp, - "Cannot use -auto_commit and patterns.\n", - TCL_STATIC); - result = TCL_ERROR; - goto out; - } } /* @@ -1796,7 +1825,7 @@ tcl_DbDelete(interp, objc, objv, dbp) key.data = ktmp; } _debug_check(); - ret = dbp->del(dbp, txn, &key, flag); + ret = dbp->del(dbp, txn, &key, 0); /* * If we have any error, set up return result and stop * processing keys. @@ -1889,8 +1918,8 @@ tcl_DbCursor(interp, objc, objv, dbp, dbcp) { static const char *dbcuropts[] = { #ifdef CONFIG_TEST - "-degree_2", - "-dirty", + "-read_committed", + "-read_uncommitted", "-update", #endif "-txn", @@ -1898,8 +1927,8 @@ tcl_DbCursor(interp, objc, objv, dbp, dbcp) }; enum dbcuropts { #ifdef CONFIG_TEST - DBCUR_DEGREE2, - DBCUR_DIRTY, + DBCUR_READ_COMMITTED, + DBCUR_READ_UNCOMMITTED, DBCUR_UPDATE, #endif DBCUR_TXN @@ -1922,11 +1951,11 @@ tcl_DbCursor(interp, objc, objv, dbp, dbcp) i++; switch ((enum dbcuropts)optindex) { #ifdef CONFIG_TEST - case DBCUR_DEGREE2: - flag |= DB_DEGREE_2; + case DBCUR_READ_COMMITTED: + flag |= DB_READ_COMMITTED; break; - case DBCUR_DIRTY: - flag |= DB_DIRTY_READ; + case DBCUR_READ_UNCOMMITTED: + flag |= DB_READ_UNCOMMITTED; break; case DBCUR_UPDATE: flag |= DB_WRITECURSOR; @@ -1974,14 +2003,14 @@ tcl_DbAssociate(interp, objc, objv, dbp) DB *dbp; { static const char *dbaopts[] = { - "-auto_commit", "-create", + "-immutable_key", "-txn", NULL }; enum dbaopts { - DBA_AUTO_COMMIT, DBA_CREATE, + DBA_IMMUTABLE_KEY, DBA_TXN }; DB *sdbp; @@ -2037,12 +2066,12 @@ tcl_DbAssociate(interp, objc, objv, dbp) } i++; switch ((enum dbaopts)optindex) { - case DBA_AUTO_COMMIT: - flag |= DB_AUTO_COMMIT; - break; case DBA_CREATE: flag |= DB_CREATE; break; + case DBA_IMMUTABLE_KEY: + flag |= DB_IMMUTABLE_KEY; + break; case DBA_TXN: if (i > (objc - 1)) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); @@ -2190,7 +2219,7 @@ tcl_second_call(dbp, pkey, data, skey) Tcl_DecrRefCount(dobj); if (result != TCL_OK) { - __db_err(dbp->dbenv, + __db_errx(dbp->dbenv, "Tcl callback function failed with code %d", result); return (EINVAL); } @@ -2549,15 +2578,15 @@ tcl_DbGetOpenFlags(interp, objc, objv, dbp) u_int32_t flag; char *arg; } open_flags[] = { - { DB_AUTO_COMMIT, "-auto_commit" }, - { DB_CREATE, "-create" }, - { DB_DEGREE_2, "-degree_2" }, - { DB_DIRTY_READ, "-dirty" }, - { DB_EXCL, "-excl" }, - { DB_NOMMAP, "-nommap" }, - { DB_RDONLY, "-rdonly" }, - { DB_THREAD, "-thread" }, - { DB_TRUNCATE, "-truncate" }, + { DB_AUTO_COMMIT, "-auto_commit" }, + { DB_CREATE, "-create" }, + { DB_EXCL, "-excl" }, + { DB_NOMMAP, "-nommap" }, + { DB_RDONLY, "-rdonly" }, + { DB_READ_COMMITTED, "-read_committed" }, + { DB_READ_UNCOMMITTED, "-read_uncommitted" }, + { DB_THREAD, "-thread" }, + { DB_TRUNCATE, "-truncate" }, { 0, NULL } }; @@ -2805,22 +2834,19 @@ tcl_DbTruncate(interp, objc, objv, dbp) DB *dbp; /* Database pointer */ { static const char *dbcuropts[] = { - "-auto_commit", "-txn", NULL }; enum dbcuropts { - DBTRUNC_AUTO_COMMIT, DBTRUNC_TXN }; DB_TXN *txn; Tcl_Obj *res; - u_int32_t count, flag; + u_int32_t count; int i, optindex, result, ret; char *arg, msg[MSG_SIZE]; txn = NULL; - flag = 0; result = TCL_OK; i = 2; @@ -2832,9 +2858,6 @@ tcl_DbTruncate(interp, objc, objv, dbp) } i++; switch ((enum dbcuropts)optindex) { - case DBTRUNC_AUTO_COMMIT: - flag |= DB_AUTO_COMMIT; - break; case DBTRUNC_TXN: if (i == objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); @@ -2858,7 +2881,7 @@ tcl_DbTruncate(interp, objc, objv, dbp) goto out; _debug_check(); - ret = dbp->truncate(dbp, txn, &count, flag); + ret = dbp->truncate(dbp, txn, &count, 0); if (ret != 0) result = _ErrorSetup(interp, ret, "db truncate"); @@ -2869,3 +2892,280 @@ tcl_DbTruncate(interp, objc, objv, dbp) out: return (result); } + +#ifdef CONFIG_TEST +/* + * tcl_DbCompact -- + */ +static int +tcl_DbCompact(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + static const char *dbcuropts[] = { + "-fillpercent", + "-freespace", + "-freeonly", + "-pages", + "-start", + "-stop", + "-timeout", + "-txn", + NULL + }; + enum dbcuropts { + DBREORG_FILLFACTOR, + DBREORG_FREESPACE, + DBREORG_FREEONLY, + DBREORG_PAGES, + DBREORG_START, + DBREORG_STOP, + DBREORG_TIMEOUT, + DBREORG_TXN + }; + DBTCL_INFO *ip; + DBT *key, end, start, stop; + DBTYPE type; + DB_TXN *txn; + Tcl_Obj *myobj, *retlist; + db_recno_t recno, srecno; + u_int32_t arg, fillfactor, flags, pages, timeout; + char *carg, msg[MSG_SIZE]; + int freekey, i, optindex, result, ret; + void *kp; + + flags = 0; + result = TCL_OK; + txn = NULL; + (void)dbp->get_type(dbp, &type); + memset(&start, 0, sizeof(start)); + memset(&stop, 0, sizeof(stop)); + memset(&end, 0, sizeof(end)); + ip = (DBTCL_INFO *)dbp->api_internal; + fillfactor = pages = timeout = 0; + + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbcuropts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + goto out; + } + i++; + switch ((enum dbcuropts)optindex) { + case DBREORG_FILLFACTOR: + if (i == objc) { + Tcl_WrongNumArgs(interp, + 2, objv, "?-fillfactor number?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &arg); + if (result != TCL_OK) + goto out; + i++; + fillfactor = arg; + break; + case DBREORG_FREESPACE: + LF_SET(DB_FREE_SPACE); + break; + + case DBREORG_FREEONLY: + LF_SET(DB_FREELIST_ONLY); + break; + + case DBREORG_PAGES: + if (i == objc) { + Tcl_WrongNumArgs(interp, + 2, objv, "?-pages number?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &arg); + if (result != TCL_OK) + goto out; + i++; + pages = arg; + break; + case DBREORG_TIMEOUT: + if (i == objc) { + Tcl_WrongNumArgs(interp, + 2, objv, "?-timeout number?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &arg); + if (result != TCL_OK) + goto out; + i++; + timeout = arg; + break; + + case DBREORG_START: + case DBREORG_STOP: + if (i == objc) { + Tcl_WrongNumArgs(interp, 1, objv, + "?-args? -start/stop key"); + result = TCL_ERROR; + goto out; + } + if ((enum dbcuropts)optindex == DBREORG_START) { + key = &start; + key->data = &recno; + } else { + key = &stop; + key->data = &srecno; + } + if (type == DB_RECNO || type == DB_QUEUE) { + result = _GetUInt32( + interp, objv[i], key->data); + if (result == TCL_OK) { + key->size = sizeof(db_recno_t); + } else + goto out; + } else { + ret = _CopyObjBytes(interp, objv[i], + &key->data, &key->size, &freekey); + if (ret != 0) + goto err; + if (freekey == 0) { + if ((ret = __os_malloc(NULL, + key->size, &kp)) != 0) + goto err; + + memcpy(kp, key->data, key->size); + key->data = kp; + key->ulen = key->size; + } + } + i++; + break; + case DBREORG_TXN: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + carg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(carg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "Compact: Invalid txn: %s\n", carg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + } + if (result != TCL_OK) + break; + } + if (result != TCL_OK) + goto out; + + if (ip->i_cdata == NULL) + if ((ret = __os_calloc(dbp->dbenv, + 1, sizeof(DB_COMPACT), &ip->i_cdata)) != 0) { + Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + goto out; + } + + ip->i_cdata->compact_fillpercent = fillfactor; + ip->i_cdata->compact_timeout = timeout; + ip->i_cdata->compact_pages = pages; + + _debug_check(); + ret = dbp->compact(dbp, txn, &start, &stop, ip->i_cdata, flags, &end); + result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret), "dbp compact"); + if (result == TCL_ERROR) + goto out; + + retlist = Tcl_NewListObj(0, NULL); + if (ret != 0) + goto out; + if (type == DB_RECNO || type == DB_QUEUE) { + if (end.size == 0) + recno = 0; + else + recno = *((db_recno_t *)end.data); + myobj = Tcl_NewWideIntObj((Tcl_WideInt)recno); + } else + myobj = Tcl_NewByteArrayObj(end.data, (int)end.size); + result = Tcl_ListObjAppendElement(interp, retlist, myobj); + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); + + if (0) { +err: result = _ReturnSetup(interp, + ret, DB_RETOK_DBCGET(ret), "dbc compact"); + } +out: + if (start.data != NULL && start.data != &recno) + __os_free(NULL, start.data); + if (stop.data != NULL && stop.data != &srecno) + __os_free(NULL, stop.data); + if (end.data != NULL) + __os_free(NULL, end.data); + + return (result); +} + +/* + * tcl_DbCompactStat + */ +static int +tcl_DbCompactStat(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + DBTCL_INFO *ip; + + COMPQUIET(objc, 0); + COMPQUIET(objv, NULL); + + ip = (DBTCL_INFO *)dbp->api_internal; + + return (tcl_CompactStat(interp, ip)); +} + +/* + * PUBLIC: int tcl_CompactStat __P((Tcl_Interp *, DBTCL_INFO *)); + */ +int +tcl_CompactStat(interp, ip) + Tcl_Interp *interp; /* Interpreter */ + DBTCL_INFO *ip; +{ + DB_COMPACT *rp; + Tcl_Obj *res; + int result; + char msg[MSG_SIZE]; + + result = TCL_OK; + rp = NULL; + + _debug_check(); + if ((rp = ip->i_cdata) == NULL) { + snprintf(msg, MSG_SIZE, + "Compact stat: No stats available\n"); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + goto error; + } + + res = Tcl_NewObj(); + + MAKE_STAT_LIST("Pages freed", rp->compact_pages_free); + MAKE_STAT_LIST("Pages truncated", rp->compact_pages_truncated); + MAKE_STAT_LIST("Pages examined", rp->compact_pages_examine); + MAKE_STAT_LIST("Levels removed", rp->compact_levels); + MAKE_STAT_LIST("Deadlocks encountered", rp->compact_deadlock); + + Tcl_SetObjResult(interp, res); +error: + return (result); +} +#endif diff --git a/db/tcl/tcl_db_pkg.c b/db/tcl/tcl_db_pkg.c index ce55df842..398507b4b 100644 --- a/db/tcl/tcl_db_pkg.c +++ b/db/tcl/tcl_db_pkg.c @@ -1,27 +1,22 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_db_pkg.c,v 11.190 2004/10/27 16:48:32 bostic Exp $ + * $Id: tcl_db_pkg.c,v 12.36 2006/09/08 19:22:21 bostic Exp $ */ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> -#include <tcl.h> -#endif - #ifdef CONFIG_TEST -#define DB_DBM_HSEARCH 1 +#define DB_DBM_HSEARCH 1 #endif #include "db_int.h" +#ifndef NO_SYSTEM_INCLUDES +#include <tcl.h> +#endif #include "dbinc/db_page.h" #include "dbinc/hash.h" #include "dbinc/tcl_db.h" @@ -41,12 +36,16 @@ static int bdb_DbOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, static int bdb_DbRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); static int bdb_DbRename __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); static int bdb_Version __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); + +#ifdef HAVE_64BIT_TYPES static int bdb_SeqOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBTCL_INFO *, DB_SEQUENCE **)); +#endif #ifdef CONFIG_TEST static int bdb_DbUpgrade __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); static int bdb_DbVerify __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int bdb_GetConfig __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); static int bdb_Handles __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); static int bdb_MsgType __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); @@ -58,8 +57,6 @@ static void * tcl_db_malloc __P((size_t)); static void * tcl_db_realloc __P((void *, size_t)); static int tcl_dup_compare __P((DB *, const DBT *, const DBT *)); static u_int32_t tcl_h_hash __P((DB *, const void *, u_int32_t)); -static int tcl_rep_send __P((DB_ENV *, - const DBT *, const DBT *, const DB_LSN *, int, u_int32_t)); #endif /* @@ -124,6 +121,7 @@ berkdb_Cmd(notused, interp, objc, objv) static const char *berkdbcmds[] = { #ifdef CONFIG_TEST "dbverify", + "getconfig", "handles", "msgtype", "upgrade", @@ -133,7 +131,7 @@ berkdb_Cmd(notused, interp, objc, objv) "env", "envremove", "open", -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES "sequence", #endif "version", @@ -155,6 +153,7 @@ berkdb_Cmd(notused, interp, objc, objv) enum berkdbcmds { #ifdef CONFIG_TEST BDB_DBVERIFY, + BDB_GETCONFIG, BDB_HANDLES, BDB_MSGTYPE, BDB_UPGRADE, @@ -164,7 +163,7 @@ berkdb_Cmd(notused, interp, objc, objv) BDB_ENV, BDB_ENVREMOVE, BDB_OPEN, -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES BDB_SEQUENCE, #endif BDB_VERSION, @@ -179,12 +178,12 @@ berkdb_Cmd(notused, interp, objc, objv) }; static int env_id = 0; static int db_id = 0; -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES static int seq_id = 0; #endif DB *dbp; -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES DB_SEQUENCE *seq; #endif #ifdef CONFIG_TEST @@ -220,6 +219,9 @@ berkdb_Cmd(notused, interp, objc, objv) case BDB_DBVERIFY: result = bdb_DbVerify(interp, objc, objv); break; + case BDB_GETCONFIG: + result = bdb_GetConfig(interp, objc, objv); + break; case BDB_HANDLES: result = bdb_Handles(interp, objc, objv); break; @@ -285,7 +287,7 @@ berkdb_Cmd(notused, interp, objc, objv) result = TCL_ERROR; } break; -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES case BDB_SEQUENCE: snprintf(newname, sizeof(newname), "seq%d", seq_id); ip = _NewInfo(interp, NULL, newname, I_SEQ); @@ -391,15 +393,16 @@ bdb_EnvOpen(interp, objc, objv, ip, env) "-cdb", "-cdb_alldb", "-client_timeout", + "-event", "-lock", "-lock_conflict", "-lock_detect", - "-lock_max", "-lock_max_locks", "-lock_max_lockers", "-lock_max_objects", "-lock_timeout", "-log", + "-log_filemode", "-log_buffer", "-log_inmemory", "-log_max", @@ -409,14 +412,17 @@ bdb_EnvOpen(interp, objc, objv, ip, env) "-mpool_max_write", "-mpool_mmap_size", "-mpool_nommap", + "-multiversion", "-overwrite", "-region_init", + "-rep", "-rep_client", "-rep_master", "-rep_transport", "-server", "-server_timeout", "-set_intermediate_dir", + "-snapshot", "-thread", "-time_notgranted", "-txn_timeout", @@ -437,6 +443,7 @@ bdb_EnvOpen(interp, objc, objv, ip, env) "-private", "-recover", "-recover_fatal", + "-register", "-shm_key", "-system_mem", "-tmp_dir", @@ -458,15 +465,16 @@ bdb_EnvOpen(interp, objc, objv, ip, env) ENV_CDB, ENV_CDB_ALLDB, ENV_CLIENT_TO, + ENV_EVENT, ENV_LOCK, ENV_CONFLICT, ENV_DETECT, - ENV_LOCK_MAX, ENV_LOCK_MAX_LOCKS, ENV_LOCK_MAX_LOCKERS, ENV_LOCK_MAX_OBJECTS, ENV_LOCK_TIMEOUT, ENV_LOG, + ENV_LOG_FILEMODE, ENV_LOG_BUFFER, ENV_LOG_INMEMORY, ENV_LOG_MAX, @@ -476,14 +484,17 @@ bdb_EnvOpen(interp, objc, objv, ip, env) ENV_MPOOL_MAX_WRITE, ENV_MPOOL_MMAP_SIZE, ENV_MPOOL_NOMMAP, + ENV_MULTIVERSION, ENV_OVERWRITE, ENV_REGION_INIT, + ENV_REP, ENV_REP_CLIENT, ENV_REP_MASTER, ENV_REP_TRANSPORT, ENV_SERVER, ENV_SERVER_TO, ENV_SET_INTERMEDIATE_DIR, + ENV_SNAPSHOT, ENV_THREAD, ENV_TIME_NOTGRANTED, ENV_TXN_TIMEOUT, @@ -504,6 +515,7 @@ bdb_EnvOpen(interp, objc, objv, ip, env) ENV_PRIVATE, ENV_RECOVER, ENV_RECOVER_FATAL, + ENV_REGISTER, ENV_SHM_KEY, ENV_SYSTEM_MEM, ENV_TMP_DIR, @@ -545,8 +557,7 @@ bdb_EnvOpen(interp, objc, objv, ip, env) * Meanwhile, there's no strong reason to enable DB_THREAD when not * testing. */ - open_flags = DB_JOINENV; - + open_flags = 0; logmaxset = logbufset = 0; if (objc <= 2) { @@ -615,21 +626,13 @@ bdb_EnvOpen(interp, objc, objv, ip, env) * From here on we must 'goto error' in order to clean up the * env from db_env_create. */ - if (server != NULL) { - (*env)->set_errpfx((*env), ip->i_name); - (*env)->set_errcall((*env), _ErrorFunc); - if ((ret = (*env)->set_rpc_server((*env), NULL, server, - client_to, server_to, 0)) != 0) { - result = TCL_ERROR; - goto error; - } - } else { - /* - * Create the environment handle before parsing the args - * since we'll be modifying the environment as we parse. - */ - (*env)->set_errpfx((*env), ip->i_name); - (*env)->set_errcall((*env), _ErrorFunc); + (*env)->set_errpfx((*env), ip->i_name); + (*env)->set_errcall((*env), _ErrorFunc); + if (server != NULL && + (ret = (*env)->set_rpc_server((*env), NULL, server, + client_to, server_to, 0)) != 0) { + result = TCL_ERROR; + goto error; } /* Hang our info pointer on the env handle, so we can do callbacks. */ @@ -672,14 +675,12 @@ bdb_EnvOpen(interp, objc, objv, ip, env) break; case ENV_CDB: FLD_SET(open_flags, DB_INIT_CDB | DB_INIT_MPOOL); - FLD_CLR(open_flags, DB_JOINENV); break; case ENV_CDB_ALLDB: FLD_SET(set_flags, DB_CDB_ALLDB); break; case ENV_LOCK: FLD_SET(open_flags, DB_INIT_LOCK | DB_INIT_MPOOL); - FLD_CLR(open_flags, DB_JOINENV); break; case ENV_CONFLICT: /* @@ -772,7 +773,15 @@ bdb_EnvOpen(interp, objc, objv, ip, env) result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock_detect"); break; - case ENV_LOCK_MAX: + case ENV_EVENT: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-event eventproc"); + result = TCL_ERROR; + break; + } + result = tcl_EventNotify(interp, *env, objv[i++], ip); + break; case ENV_LOCK_MAX_LOCKS: case ENV_LOCK_MAX_LOCKERS: case ENV_LOCK_MAX_OBJECTS: @@ -786,10 +795,6 @@ bdb_EnvOpen(interp, objc, objv, ip, env) if (result == TCL_OK) { _debug_check(); switch ((enum envopen)optindex) { - case ENV_LOCK_MAX: - ret = (*env)->set_lk_max(*env, - uintarg); - break; case ENV_LOCK_MAX_LOCKS: ret = (*env)->set_lk_max_locks(*env, uintarg); @@ -838,7 +843,6 @@ bdb_EnvOpen(interp, objc, objv, ip, env) break; case ENV_LOG: FLD_SET(open_flags, DB_INIT_LOG | DB_INIT_MPOOL); - FLD_CLR(open_flags, DB_JOINENV); break; case ENV_LOG_BUFFER: if (i >= objc) { @@ -865,6 +869,22 @@ bdb_EnvOpen(interp, objc, objv, ip, env) } } break; + case ENV_LOG_FILEMODE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-log_filemode mode?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &uintarg); + if (result == TCL_OK) { + _debug_check(); + ret = + (*env)->set_lg_filemode(*env, (int)uintarg); + result = _ReturnSetup(interp, ret, + DB_RETOK_STD(ret), "log_filemode"); + } + break; case ENV_LOG_INMEMORY: FLD_SET(set_flags, DB_LOG_INMEMORY); break; @@ -962,6 +982,9 @@ bdb_EnvOpen(interp, objc, objv, ip, env) case ENV_MPOOL_NOMMAP: FLD_SET(set_flags, DB_NOMMAP); break; + case ENV_MULTIVERSION: + FLD_SET(set_flags, DB_MULTIVERSION); + break; case ENV_OVERWRITE: FLD_SET(set_flags, DB_OVERWRITE); break; @@ -987,6 +1010,9 @@ bdb_EnvOpen(interp, objc, objv, ip, env) DB_RETOK_STD(ret), "set_intermediate_dir"); } break; + case ENV_REP: + FLD_SET(open_flags, DB_INIT_REP); + break; case ENV_REP_CLIENT: rep_flags = DB_REP_CLIENT; FLD_SET(open_flags, DB_INIT_REP); @@ -1002,49 +1028,19 @@ bdb_EnvOpen(interp, objc, objv, ip, env) result = TCL_ERROR; break; } - - /* - * Store the objects containing the machine ID - * and the procedure name. We don't need to crack - * the send procedure out now, but we do convert the - * machine ID to an int, since set_rep_transport needs - * it. Even so, it'll be easier later to deal with - * the Tcl_Obj *, so we save that, not the int. - * - * Note that we Tcl_IncrRefCount both objects - * independently; Tcl is free to discard the list - * that they're bundled into. - */ - result = Tcl_ListObjGetElements(interp, objv[i++], + result = Tcl_ListObjGetElements(interp, objv[i], &myobjc, &myobjv); - if (myobjc != 2) { - Tcl_SetResult(interp, - "List must be {envid sendproc}", - TCL_STATIC); - result = TCL_ERROR; - break; - } - - FLD_SET(open_flags, DB_INIT_REP); - /* - * Check that the machine ID is an int. Note that - * we do want to use GetIntFromObj; the machine - * ID is explicitly an int, not a u_int32_t. - */ - ip->i_rep_eid = myobjv[0]; - Tcl_IncrRefCount(ip->i_rep_eid); - result = Tcl_GetIntFromObj(interp, - ip->i_rep_eid, &intarg); - if (result != TCL_OK) + if (result == TCL_OK) + i++; + else break; - - ip->i_rep_send = myobjv[1]; - Tcl_IncrRefCount(ip->i_rep_send); - _debug_check(); - ret = (*env)->set_rep_transport(*env, - intarg, tcl_rep_send); - result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), - "set_rep_transport"); + result = tcl_RepTransport(interp, myobjc, myobjv, + *env, ip); + if (result == TCL_OK) + FLD_SET(open_flags, DB_INIT_REP); + break; + case ENV_SNAPSHOT: + FLD_SET(set_flags, DB_TXN_SNAPSHOT); break; case ENV_THREAD: /* Enable DB_THREAD when specified in testing. */ @@ -1076,19 +1072,21 @@ bdb_EnvOpen(interp, objc, objv, ip, env) case ENV_TXN: FLD_SET(open_flags, DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN); - FLD_CLR(open_flags, DB_JOINENV); /* Make sure we have an arg to check against! */ - if (i < objc) { + while (i < objc) { arg = Tcl_GetStringFromObj(objv[i], NULL); if (strcmp(arg, "nosync") == 0) { FLD_SET(set_flags, DB_TXN_NOSYNC); i++; - } + } else if (strcmp(arg, "snapshot") == 0) { + FLD_SET(set_flags, DB_TXN_SNAPSHOT); + i++; + } else + break; } break; case ENV_CREATE: FLD_SET(open_flags, DB_CREATE | DB_INIT_MPOOL); - FLD_CLR(open_flags, DB_JOINENV); break; case ENV_ENCRYPT_AES: /* Make sure we have an arg to check against! */ @@ -1145,7 +1143,6 @@ bdb_EnvOpen(interp, objc, objv, ip, env) break; case ENV_PRIVATE: FLD_SET(open_flags, DB_PRIVATE | DB_INIT_MPOOL); - FLD_CLR(open_flags, DB_JOINENV); break; case ENV_RECOVER: FLD_SET(open_flags, DB_RECOVER); @@ -1153,6 +1150,9 @@ bdb_EnvOpen(interp, objc, objv, ip, env) case ENV_RECOVER_FATAL: FLD_SET(open_flags, DB_RECOVER_FATAL); break; + case ENV_REGISTER: + FLD_SET(open_flags, DB_REGISTER); + break; case ENV_SYSTEM_MEM: FLD_SET(open_flags, DB_SYSTEM_MEM); break; @@ -1378,13 +1378,13 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) static const char *bdbopen[] = { #ifdef CONFIG_TEST "-btcompare", - "-dirty", "-dupcompare", "-hashproc", "-lorder", "-minkey", "-nommap", "-notdurable", + "-read_uncommitted", "-revsplitoff", "-test", "-thread", @@ -1411,6 +1411,7 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) "-len", "-maxsize", "-mode", + "-multiversion", "-nelem", "-pad", "-pagesize", @@ -1430,13 +1431,13 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) enum bdbopen { #ifdef CONFIG_TEST TCL_DB_BTCOMPARE, - TCL_DB_DIRTY, TCL_DB_DUPCOMPARE, TCL_DB_HASHPROC, TCL_DB_LORDER, TCL_DB_MINKEY, TCL_DB_NOMMAP, TCL_DB_NOTDURABLE, + TCL_DB_READ_UNCOMMITTED, TCL_DB_REVSPLIT, TCL_DB_TEST, TCL_DB_THREAD, @@ -1463,6 +1464,7 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) TCL_DB_LEN, TCL_DB_MAXSIZE, TCL_DB_MODE, + TCL_DB_MULTIVERSION, TCL_DB_NELEM, TCL_DB_PAD, TCL_DB_PAGESIZE, @@ -1624,9 +1626,6 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "set_bt_compare"); break; - case TCL_DB_DIRTY: - open_flags |= DB_DIRTY_READ; - break; case TCL_DB_DUPCOMPARE: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, @@ -1701,6 +1700,9 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) case TCL_DB_NOTDURABLE: set_flags |= DB_TXN_NOT_DURABLE; break; + case TCL_DB_READ_UNCOMMITTED: + open_flags |= DB_READ_UNCOMMITTED; + break; case TCL_DB_REVSPLIT: set_flags |= DB_REVSPLITOFF; break; @@ -1876,6 +1878,9 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) DB_RETOK_STD(ret), "set_h_ffactor"); } break; + case TCL_DB_MULTIVERSION: + open_flags |= DB_MULTIVERSION; + break; case TCL_DB_NELEM: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, @@ -2102,6 +2107,8 @@ bdb_DbOpen(interp, objc, objv, ip, dbp) * arrays for the subdb. */ db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; if (i != objc) { subdbtmp = Tcl_GetByteArrayFromObj(objv[i++], &subdblen); @@ -2169,7 +2176,7 @@ error: return (result); } -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES /* * bdb_SeqOpen -- * Implements the "Seq_create/Seq_open" command. @@ -2183,7 +2190,6 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) DB_SEQUENCE **seqp; /* DB_SEQUENCE handle */ { static const char *seqopen[] = { - "-auto_commit", "-cachesize", "-create", "-inc", @@ -2191,13 +2197,13 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) "-dec", "-max", "-min", + "-thread", "-txn", "-wrap", "--", NULL } ; enum seqopen { - TCL_SEQ_AUTO_COMMIT, TCL_SEQ_CACHESIZE, TCL_SEQ_CREATE, TCL_SEQ_INC, @@ -2205,6 +2211,7 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) TCL_SEQ_DEC, TCL_SEQ_MAX, TCL_SEQ_MIN, + TCL_SEQ_THREAD, TCL_SEQ_TXN, TCL_SEQ_WRAP, TCL_SEQ_ENDARG @@ -2215,12 +2222,14 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) DB_TXN *txn; db_recno_t recno; db_seq_t min, max, value; + Tcl_WideInt tcl_value; u_int32_t flags, oflags; int cache, endarg, i, optindex, result, ret, setrange, setvalue, v; char *arg, *db, msg[MSG_SIZE]; COMPQUIET(ip, NULL); COMPQUIET(value, 0); + *seqp = NULL; if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "?args?"); @@ -2250,9 +2259,6 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) i++; result = TCL_OK; switch ((enum seqopen)optindex) { - case TCL_SEQ_AUTO_COMMIT: - oflags |= DB_AUTO_COMMIT; - break; case TCL_SEQ_CREATE: oflags |= DB_CREATE; break; @@ -2276,7 +2282,9 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) break; } result = - Tcl_GetWideIntFromObj(interp, objv[i++], &value); + Tcl_GetWideIntFromObj( + interp, objv[i++], &tcl_value); + value = tcl_value; setvalue = 1; break; case TCL_SEQ_DEC: @@ -2291,8 +2299,9 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) } if ((result = Tcl_GetWideIntFromObj(interp, - objv[i++], &max)) != TCL_OK) + objv[i++], &tcl_value)) != TCL_OK) goto error; + max = tcl_value; setrange = 1; break; case TCL_SEQ_MIN: @@ -2304,10 +2313,14 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) } if ((result = Tcl_GetWideIntFromObj(interp, - objv[i++], &min)) != TCL_OK) + objv[i++], &tcl_value)) != TCL_OK) goto error; + min = tcl_value; setrange = 1; break; + case TCL_SEQ_THREAD: + oflags |= DB_THREAD; + break; case TCL_SEQ_TXN: if (i > (objc - 1)) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); @@ -2355,17 +2368,13 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) } (void)dbp->get_type(dbp, &type); - memset(&key, 0, sizeof(key)); if (type == DB_QUEUE || type == DB_RECNO) { result = _GetUInt32(interp, objv[i++], &recno); if (result != TCL_OK) return (result); - key.data = &recno; - key.size = sizeof(recno); - } else { - key.data = Tcl_GetByteArrayFromObj(objv[i++], &v); - key.size = (u_int32_t)v; - } + DB_INIT_DBT(key, &recno, sizeof(recno)); + } else + DB_INIT_DBT(key, Tcl_GetByteArrayFromObj(objv[i++], &v), v); ret = db_sequence_create(seqp, dbp, 0); if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "sequence create")) != TCL_OK) { @@ -2401,7 +2410,8 @@ bdb_SeqOpen(interp, objc, objv, ip, seqp) goto error; if (0) { -error: (void)(*seqp)->close(*seqp, 0); +error: if (*seqp != NULL) + (void)(*seqp)->close(*seqp, 0); *seqp = NULL; } return (result); @@ -2559,6 +2569,8 @@ bdb_DbRemove(interp, objc, objv) * arrays for the subdb. */ db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; if (i != objc) { subdbtmp = Tcl_GetByteArrayFromObj(objv[i++], &subdblen); @@ -2685,10 +2697,10 @@ bdb_DbRename(interp, objc, objv) } i++; switch ((enum bdbmv)optindex) { - case TCL_DBMV_AUTOCOMMIT: - iflags |= DB_AUTO_COMMIT; - _debug_check(); - break; + case TCL_DBMV_AUTOCOMMIT: + iflags |= DB_AUTO_COMMIT; + _debug_check(); + break; case TCL_DBMV_ENCRYPT: set_flags |= DB_ENCRYPT; _debug_check(); @@ -2766,6 +2778,8 @@ bdb_DbRename(interp, objc, objv) * arrays for the subdb. */ db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; if (i == objc - 2) { subdbtmp = Tcl_GetByteArrayFromObj(objv[i++], &subdblen); @@ -3125,6 +3139,70 @@ error: #ifdef CONFIG_TEST /* + * bdb_GetConfig -- + * Implements the getconfig command. + */ +#define ADD_CONFIG_NAME(name) \ + conf = NewStringObj(name, strlen(name)); \ + if (Tcl_ListObjAppendElement(interp, res, conf) != TCL_OK) \ + return (TCL_ERROR); + +static int +bdb_GetConfig(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + Tcl_Obj *res, *conf; + + /* + * No args. Error if we have some + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return (TCL_ERROR); + } + res = Tcl_NewListObj(0, NULL); + conf = NULL; + + /* + * This command conditionally adds strings in based on + * how DB is configured so that the test suite can make + * decisions based on that. For now only implement the + * configuration pieces we need. + */ +#ifdef DEBUG + ADD_CONFIG_NAME("debug"); +#endif +#ifdef DEBUG_ROP + ADD_CONFIG_NAME("debug_rop"); +#endif +#ifdef DEBUG_WOP + ADD_CONFIG_NAME("debug_wop"); +#endif +#ifdef HAVE_HASH + ADD_CONFIG_NAME("hash"); +#endif +#ifdef HAVE_QUEUE + ADD_CONFIG_NAME("queue"); +#endif +#ifdef HAVE_REPLICATION + ADD_CONFIG_NAME("rep"); +#endif +#ifdef HAVE_REPLICATION_THREADS + ADD_CONFIG_NAME("repmgr"); +#endif +#ifdef HAVE_RPC + ADD_CONFIG_NAME("rpc"); +#endif +#ifdef HAVE_VERIFY + ADD_CONFIG_NAME("verify"); +#endif + Tcl_SetObjResult(interp, res); + return (TCL_OK); +} + +/* * bdb_Handles -- * Implements the handles command. */ @@ -3146,8 +3224,7 @@ bdb_Handles(interp, objc, objv) } res = Tcl_NewListObj(0, NULL); - for (p = LIST_FIRST(&__db_infohead); p != NULL; - p = LIST_NEXT(p, entries)) { + LIST_FOREACH(p, &__db_infohead, entries) { handle = NewStringObj(p->i_name, strlen(p->i_name)); if (Tcl_ListObjAppendElement(interp, res, handle) != TCL_OK) return (TCL_ERROR); @@ -3178,10 +3255,12 @@ bdb_MsgType(interp, objc, objv) */ static const char *msgnames[] = { "no_type", "alive", "alive_req", "all_req", + "bulk_log", "bulk_page", "dupmaster", "file", "file_fail", "file_req", "log", "log_more", "log_req", "master_req", "newclient", "newfile", "newmaster", "newsite", "page", - "page_fail", "page_req", "update", "update_req", + "page_fail", "page_more", "page_req", + "rerequest", "update", "update_req", "verify", "verify_fail", "verify_req", "vote1", "vote2", NULL }; @@ -3194,7 +3273,7 @@ bdb_MsgType(interp, objc, objv) return (TCL_ERROR); } - ret = _CopyObjBytes(interp, objv[2], (void **)&rp, &len, &freerp); + ret = _CopyObjBytes(interp, objv[2], &rp, &len, &freerp); if (ret != TCL_OK) { Tcl_SetResult(interp, "msgtype: bad control message", TCL_STATIC); @@ -3387,8 +3466,7 @@ tcl_compare_callback(dbp, dbta, dbtb, procobj, errname) * So, drop core. If we're not running with diagnostic * mode, panic--and always return a negative number. :-) */ -panic: __db_err(dbp->dbenv, "Tcl %s callback failed", errname); - DB_ASSERT(0); +panic: __db_errx(dbp->dbenv, "Tcl %s callback failed", errname); return (__db_panic(dbp->dbenv, DB_RUNRECOVERY)); } @@ -3439,24 +3517,20 @@ tcl_h_hash(dbp, buf, len) Tcl_DecrRefCount(objv[1]); return ((u_int32_t)hval); -panic: /* - * We drop core on error, in diagnostic mode. See the comment in - * tcl_compare_callback. - */ - __db_err(dbp->dbenv, "Tcl h_hash callback failed"); - (void)__db_panic(dbp->dbenv, DB_RUNRECOVERY); - - DB_ASSERT(0); +panic: __db_errx(dbp->dbenv, "Tcl h_hash callback failed"); - /* NOTREACHED */ + (void)__db_panic(dbp->dbenv, DB_RUNRECOVERY); return (0); } /* * tcl_rep_send -- * Replication send callback. + * + * PUBLIC: int tcl_rep_send __P((DB_ENV *, + * PUBLIC: const DBT *, const DBT *, const DB_LSN *, int, u_int32_t)); */ -static int +int tcl_rep_send(dbenv, control, rec, lsnp, eid, flags) DB_ENV *dbenv; const DBT *control, *rec; @@ -3465,11 +3539,13 @@ tcl_rep_send(dbenv, control, rec, lsnp, eid, flags) u_int32_t flags; { #define TCLDB_SENDITEMS 7 +#define TCLDB_MAXREPFLAGS 32 DBTCL_INFO *ip; Tcl_Interp *interp; Tcl_Obj *control_o, *eid_o, *flags_o, *lsn_o, *origobj, *rec_o; - Tcl_Obj *myobjv[2], *resobj, *objv[TCLDB_SENDITEMS]; - int myobjc, result, ret; + Tcl_Obj *lsnobj[2], *myobjv[TCLDB_MAXREPFLAGS], *objv[TCLDB_SENDITEMS]; + Tcl_Obj *resobj; + int i, myobjc, result, ret; ip = (DBTCL_INFO *)dbenv->app_private; interp = ip->i_interp; @@ -3484,18 +3560,34 @@ tcl_rep_send(dbenv, control, rec, lsnp, eid, flags) eid_o = Tcl_NewIntObj(eid); Tcl_IncrRefCount(eid_o); + myobjv[myobjc = 0] = NULL; + if (flags == 0) + myobjv[myobjc++] = NewStringObj("none", strlen("none")); + if (LF_ISSET(DB_REP_ANYWHERE)) + myobjv[myobjc++] = NewStringObj("any", strlen("any")); + if (LF_ISSET(DB_REP_NOBUFFER)) + myobjv[myobjc++] = NewStringObj("nobuffer", strlen("nobuffer")); if (LF_ISSET(DB_REP_PERMANENT)) - flags_o = NewStringObj("perm", strlen("perm")); - else if (LF_ISSET(DB_REP_NOBUFFER)) - flags_o = NewStringObj("nobuffer", strlen("nobuffer")); - else - flags_o = NewStringObj("none", strlen("none")); + myobjv[myobjc++] = NewStringObj("perm", strlen("perm")); + if (LF_ISSET(DB_REP_REREQUEST)) + myobjv[myobjc++] = + NewStringObj("rerequest", strlen("rerequest")); + /* + * If we're given an unrecognized flag send "unknown". + */ + if (myobjc == 0) + myobjv[myobjc++] = NewStringObj("unknown", strlen("unknown")); + for (i = 0; i < myobjc; i++) + Tcl_IncrRefCount(myobjv[i]); + flags_o = Tcl_NewListObj(myobjc, myobjv); Tcl_IncrRefCount(flags_o); - myobjc = 2; - myobjv[0] = Tcl_NewLongObj((long)lsnp->file); - myobjv[1] = Tcl_NewLongObj((long)lsnp->offset); - lsn_o = Tcl_NewListObj(myobjc, myobjv); + lsnobj[0] = Tcl_NewLongObj((long)lsnp->file); + Tcl_IncrRefCount(lsnobj[0]); + lsnobj[1] = Tcl_NewLongObj((long)lsnp->offset); + Tcl_IncrRefCount(lsnobj[1]); + lsn_o = Tcl_NewListObj(2, lsnobj); + Tcl_IncrRefCount(lsn_o); objv[1] = control_o; objv[2] = rec_o; @@ -3520,7 +3612,7 @@ tcl_rep_send(dbenv, control, rec, lsnp, eid, flags) * this error should only happen if the Tcl callback is * somehow invalid, which is a fatal scripting bug. */ -err: __db_err(dbenv, "Tcl rep_send failure"); +err: __db_errx(dbenv, "Tcl rep_send failure"); return (EINVAL); } @@ -3534,7 +3626,12 @@ err: __db_err(dbenv, "Tcl rep_send failure"); Tcl_DecrRefCount(control_o); Tcl_DecrRefCount(rec_o); Tcl_DecrRefCount(eid_o); + for (i = 0; i < myobjc; i++) + Tcl_DecrRefCount(myobjv[i]); Tcl_DecrRefCount(flags_o); + Tcl_DecrRefCount(lsnobj[0]); + Tcl_DecrRefCount(lsnobj[1]); + Tcl_DecrRefCount(lsn_o); return (ret); } diff --git a/db/tcl/tcl_dbcursor.c b/db/tcl/tcl_dbcursor.c index f0ca788f4..1e40afa83 100644 --- a/db/tcl/tcl_dbcursor.c +++ b/db/tcl/tcl_dbcursor.c @@ -1,23 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_dbcursor.c,v 11.65 2004/10/07 16:48:39 bostic Exp $ + * $Id: tcl_dbcursor.c,v 12.11 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" /* @@ -383,11 +378,13 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) { static const char *dbcgetopts[] = { #ifdef CONFIG_TEST - "-degree_2", - "-dirty", + "-data_buf_size", "-get_both_range", + "-key_buf_size", "-multi", "-multi_key", + "-read_committed", + "-read_uncommitted", #endif "-current", "-first", @@ -409,11 +406,13 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) }; enum dbcgetopts { #ifdef CONFIG_TEST - DBCGET_DEGREE2, - DBCGET_DIRTY, + DBCGET_DATA_BUF_SIZE, DBCGET_BOTH_RANGE, + DBCGET_KEY_BUF_SIZE, DBCGET_MULTI, DBCGET_MULTI_KEY, + DBCGET_READ_COMMITTED, + DBCGET_READ_UNCOMMITTED, #endif DBCGET_CURRENT, DBCGET_FIRST, @@ -442,9 +441,9 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) u_int32_t flag, op; int elemc, freekey, freedata, i, optindex, result, ret; #ifdef CONFIG_TEST - int bufsize; + int data_buf_size, key_buf_size; - bufsize = 0; + data_buf_size = key_buf_size = 0; #endif COMPQUIET(dtmp, NULL); COMPQUIET(ktmp, NULL); @@ -452,14 +451,15 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) result = TCL_OK; flag = 0; freekey = freedata = 0; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + memset(&pdata, 0, sizeof(DBT)); if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?"); return (TCL_ERROR); } - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); /* * Get the command name index from the object based on the options * defined above. @@ -480,105 +480,110 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) break; } i++; + +#define FLAG_CHECK2_STDARG \ + (DB_RMW | DB_MULTIPLE | DB_MULTIPLE_KEY | DB_READ_UNCOMMITTED) + switch ((enum dbcgetopts)optindex) { #ifdef CONFIG_TEST - case DBCGET_DEGREE2: - flag |= DB_DEGREE_2; - break; - case DBCGET_DIRTY: - flag |= DB_DIRTY_READ; + case DBCGET_DATA_BUF_SIZE: + result = + Tcl_GetIntFromObj(interp, objv[i], &data_buf_size); + if (result != TCL_OK) + goto out; + i++; break; case DBCGET_BOTH_RANGE: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_GET_BOTH_RANGE; break; + case DBCGET_KEY_BUF_SIZE: + result = + Tcl_GetIntFromObj(interp, objv[i], &key_buf_size); + if (result != TCL_OK) + goto out; + i++; + break; case DBCGET_MULTI: flag |= DB_MULTIPLE; - result = Tcl_GetIntFromObj(interp, objv[i], &bufsize); + result = + Tcl_GetIntFromObj(interp, objv[i], &data_buf_size); if (result != TCL_OK) goto out; i++; break; case DBCGET_MULTI_KEY: flag |= DB_MULTIPLE_KEY; - result = Tcl_GetIntFromObj(interp, objv[i], &bufsize); + result = + Tcl_GetIntFromObj(interp, objv[i], &data_buf_size); if (result != TCL_OK) goto out; i++; break; + case DBCGET_READ_COMMITTED: + flag |= DB_READ_COMMITTED; + break; + case DBCGET_READ_UNCOMMITTED: + flag |= DB_READ_UNCOMMITTED; + break; #endif case DBCGET_RMW: flag |= DB_RMW; break; case DBCGET_CURRENT: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_CURRENT; break; case DBCGET_FIRST: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_FIRST; break; case DBCGET_LAST: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_LAST; break; case DBCGET_NEXT: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_NEXT; break; case DBCGET_PREV: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_PREV; break; case DBCGET_PREVNODUP: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_PREV_NODUP; break; case DBCGET_NEXTNODUP: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_NEXT_NODUP; break; case DBCGET_NEXTDUP: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_NEXT_DUP; break; case DBCGET_BOTH: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_GET_BOTH; break; case DBCGET_RECNO: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_GET_RECNO; break; case DBCGET_JOIN: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_JOIN_ITEM; break; case DBCGET_SET: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_SET; break; case DBCGET_SETRANGE: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_SET_RANGE; break; case DBCGET_SETRECNO: - FLAG_CHECK2(flag, - DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ); + FLAG_CHECK2(flag, FLAG_CHECK2_STDARG); flag |= DB_SET_RECNO; break; case DBCGET_PART: @@ -714,9 +719,10 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) goto out; } #ifdef CONFIG_TEST - if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) { - (void)__os_malloc(NULL, (size_t)bufsize, &data.data); - data.ulen = (u_int32_t)bufsize; + if (data_buf_size != 0) { + (void)__os_malloc( + NULL, (size_t)data_buf_size, &data.data); + data.ulen = (u_int32_t)data_buf_size; data.flags |= DB_DBT_USERMEM; } else #endif @@ -748,11 +754,20 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) result = TCL_ERROR; goto out; } - key.flags |= DB_DBT_MALLOC; #ifdef CONFIG_TEST - if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) { - (void)__os_malloc(NULL, (size_t)bufsize, &data.data); - data.ulen = (u_int32_t)bufsize; + if (key_buf_size != 0) { + (void)__os_malloc( + NULL, (size_t)key_buf_size, &key.data); + key.ulen = (u_int32_t)key_buf_size; + key.flags |= DB_DBT_USERMEM; + } else +#endif + key.flags |= DB_DBT_MALLOC; +#ifdef CONFIG_TEST + if (data_buf_size != 0) { + (void)__os_malloc( + NULL, (size_t)data_buf_size, &data.data); + data.ulen = (u_int32_t)data_buf_size; data.flags |= DB_DBT_USERMEM; } else #endif @@ -760,7 +775,6 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) } _debug_check(); - memset(&pdata, 0, sizeof(DBT)); if (ispget) { F_SET(&pdata, DB_DBT_MALLOC); ret = dbc->c_pget(dbc, &key, &data, &pdata, flag); @@ -803,18 +817,26 @@ tcl_DbcGet(interp, objc, objv, dbc, ispget) key.data, key.size, data.data, data.size); } } +out1: + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); + /* + * If DB_DBT_MALLOC is set we need to free if DB allocated anything. + * If DB_DBT_USERMEM is set we need to free it because + * we allocated it (for data_buf_size/key_buf_size). That + * allocation does not apply to the pdata DBT. + */ +out: if (key.data != NULL && F_ISSET(&key, DB_DBT_MALLOC)) __os_ufree(dbc->dbp->dbenv, key.data); + if (key.data != NULL && F_ISSET(&key, DB_DBT_USERMEM)) + __os_free(dbc->dbp->dbenv, key.data); if (data.data != NULL && F_ISSET(&data, DB_DBT_MALLOC)) __os_ufree(dbc->dbp->dbenv, data.data); + if (data.data != NULL && F_ISSET(&data, DB_DBT_USERMEM)) + __os_free(dbc->dbp->dbenv, data.data); if (pdata.data != NULL && F_ISSET(&pdata, DB_DBT_MALLOC)) __os_ufree(dbc->dbp->dbenv, pdata.data); -out1: - if (result == TCL_OK) - Tcl_SetObjResult(interp, retlist); -out: - if (data.data != NULL && flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) - __os_free(dbc->dbp->dbenv, data.data); if (freedata) __os_free(NULL, dtmp); if (freekey) diff --git a/db/tcl/tcl_env.c b/db/tcl/tcl_env.c index e513b961d..ac18c40cf 100644 --- a/db/tcl/tcl_env.c +++ b/db/tcl/tcl_env.c @@ -1,24 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_env.c,v 11.121 2004/10/07 16:48:39 bostic Exp $ + * $Id: tcl_env.c,v 12.29 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" -#include "dbinc/db_shash.h" #include "dbinc/lock.h" #include "dbinc/txn.h" #include "dbinc/tcl_db.h" @@ -55,6 +49,8 @@ env_Cmd(clientData, interp, objc, objv) "attributes", "errfile", "errpfx", + "event", + "id_reset", "lock_detect", "lock_id", "lock_id_free", @@ -71,18 +67,23 @@ env_Cmd(clientData, interp, objc, objv) "log_get", "log_put", "log_stat", + "lsn_reset", "mpool", "mpool_stat", "mpool_sync", "mpool_trickle", - "mutex", + "rep_config", "rep_elect", "rep_flush", + "rep_get_config", "rep_limit", "rep_process_message", "rep_request", "rep_start", "rep_stat", + "rep_sync", + "rep_transport", + "repmgr", "rpcid", "set_flags", "test", @@ -92,6 +93,7 @@ env_Cmd(clientData, interp, objc, objv) "txn_timeout", "verbose", #endif + "cdsgroup", "close", "dbremove", "dbrename", @@ -103,6 +105,7 @@ env_Cmd(clientData, interp, objc, objv) "get_home", "get_lg_bsize", "get_lg_dir", + "get_lg_filemode", "get_lg_max", "get_lg_regionmax", "get_lk_detect", @@ -121,6 +124,7 @@ env_Cmd(clientData, interp, objc, objv) "get_tx_max", "get_tx_timestamp", "get_verbose", + "set_data_dir", "txn", "txn_checkpoint", NULL @@ -130,6 +134,8 @@ env_Cmd(clientData, interp, objc, objv) ENVATTR, ENVERRFILE, ENVERRPFX, + ENVEVENT, + ENVIDRESET, ENVLKDETECT, ENVLKID, ENVLKFREEID, @@ -146,18 +152,23 @@ env_Cmd(clientData, interp, objc, objv) ENVLOGGET, ENVLOGPUT, ENVLOGSTAT, + ENVLSNRESET, ENVMP, ENVMPSTAT, ENVMPSYNC, ENVTRICKLE, - ENVMUTEX, + ENVREPCONFIG, ENVREPELECT, ENVREPFLUSH, + ENVREPGETCONFIG, ENVREPLIMIT, ENVREPPROCMESS, ENVREPREQUEST, ENVREPSTART, ENVREPSTAT, + ENVREPSYNC, + ENVREPTRANSPORT, + ENVREPMGR, ENVRPCID, ENVSETFLAGS, ENVTEST, @@ -167,6 +178,7 @@ env_Cmd(clientData, interp, objc, objv) ENVTXNTIMEOUT, ENVVERB, #endif + ENVCDSGROUP, ENVCLOSE, ENVDBREMOVE, ENVDBRENAME, @@ -178,6 +190,7 @@ env_Cmd(clientData, interp, objc, objv) ENVGETHOME, ENVGETLGBSIZE, ENVGETLGDIR, + ENVGETLGFILEMODE, ENVGETLGMAX, ENVGETLGREGIONMAX, ENVGETLKDETECT, @@ -196,12 +209,13 @@ env_Cmd(clientData, interp, objc, objv) ENVGETTXMAX, ENVGETTXTIMESTAMP, ENVGETVERBOSE, + ENVSETDATADIR, ENVTXN, ENVTXNCKP }; DBTCL_INFO *envip; DB_ENV *dbenv; - Tcl_Obj *res, *myobjv[3]; + Tcl_Obj *myobjv[3], *res; char newname[MSG_SIZE]; int cmdindex, i, intvalue1, intvalue2, ncache, result, ret; u_int32_t bytes, gbytes, value; @@ -209,12 +223,14 @@ env_Cmd(clientData, interp, objc, objv) long shm_key; time_t timeval; const char *strval, **dirs; + char *strarg; #ifdef CONFIG_TEST DBTCL_INFO *logcip; DB_LOGC *logc; - char *strarg; + Tcl_Obj **repobjv; u_int32_t lockid; long newval, otherval; + int repobjc; #endif Tcl_ResetResult(interp); @@ -246,6 +262,22 @@ env_Cmd(clientData, interp, objc, objv) res = NULL; switch ((enum envcmds)cmdindex) { #ifdef CONFIG_TEST + case ENVEVENT: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_EventNotify(interp, dbenv, objv[2], envip); + break; + case ENVIDRESET: + result = tcl_EnvIdReset(interp, objc, objv, dbenv); + break; + case ENVLSNRESET: + result = tcl_EnvLsnReset(interp, objc, objv, dbenv); + break; case ENVLKDETECT: result = tcl_LockDetect(interp, objc, objv, dbenv); break; @@ -367,12 +399,32 @@ env_Cmd(clientData, interp, objc, objv) case ENVMP: result = tcl_Mp(interp, objc, objv, dbenv, envip); break; + case ENVREPCONFIG: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_RepConfig(interp, dbenv, objv[2]); + break; case ENVREPELECT: result = tcl_RepElect(interp, objc, objv, dbenv); break; case ENVREPFLUSH: result = tcl_RepFlush(interp, objc, objv, dbenv); break; + case ENVREPGETCONFIG: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_RepGetConfig(interp, dbenv, objv[2]); + break; case ENVREPLIMIT: result = tcl_RepLimit(interp, objc, objv, dbenv); break; @@ -388,6 +440,23 @@ env_Cmd(clientData, interp, objc, objv) case ENVREPSTAT: result = tcl_RepStat(interp, objc, objv, dbenv); break; + case ENVREPSYNC: + result = tcl_RepSync(interp, objc, objv, dbenv); + break; + case ENVREPTRANSPORT: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = Tcl_ListObjGetElements(interp, objv[2], + &repobjc, &repobjv); + if (result == TCL_OK) + result = tcl_RepTransport(interp, + repobjc, repobjv, dbenv, envip); + break; + case ENVREPMGR: + result = tcl_RepMgr(interp, objc, objv, dbenv); + break; case ENVRPCID: /* * No args for this. Error if there are some. @@ -427,9 +496,6 @@ env_Cmd(clientData, interp, objc, objv) case ENVTXNTIMEOUT: result = tcl_TxnTimeout(interp, objc, objv, dbenv); break; - case ENVMUTEX: - result = tcl_Mutex(interp, objc, objv, dbenv, envip); - break; case ENVATTR: result = tcl_EnvAttr(interp, objc, objv, dbenv); break; @@ -480,6 +546,9 @@ env_Cmd(clientData, interp, objc, objv) result = tcl_EnvVerbose(interp, dbenv, objv[2], objv[3]); break; #endif + case ENVCDSGROUP: + result = tcl_CDSGroup(interp, objc, objv, dbenv, envip); + break; case ENVCLOSE: /* * No args for this. Error if there are some. @@ -581,6 +650,16 @@ env_Cmd(clientData, interp, objc, objv) "env get_lg_dir")) == TCL_OK) res = NewStringObj(strval, strlen(strval)); break; + case ENVGETLGFILEMODE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lg_filemode(dbenv, &intvalue1); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lg_filemode")) == TCL_OK) + res = Tcl_NewLongObj((long)intvalue1); + break; case ENVGETLGMAX: if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, NULL); @@ -675,9 +754,9 @@ env_Cmd(clientData, interp, objc, objv) Tcl_WrongNumArgs(interp, 1, objv, NULL); return (TCL_ERROR); } - ret = dbenv->get_rep_limit(dbenv, &gbytes, &bytes); + ret = dbenv->rep_get_limit(dbenv, &gbytes, &bytes); if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), - "env get_rep_limit")) == TCL_OK) { + "env rep_get_limit")) == TCL_OK) { myobjv[0] = Tcl_NewLongObj((long)gbytes); myobjv[1] = Tcl_NewLongObj((long)bytes); res = Tcl_NewListObj(2, myobjv); @@ -698,7 +777,7 @@ env_Cmd(clientData, interp, objc, objv) Tcl_WrongNumArgs(interp, 1, objv, NULL); return (TCL_ERROR); } - ret = dbenv->get_tas_spins(dbenv, &value); + ret = dbenv->mutex_get_tas_spins(dbenv, &value); if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env get_tas_spins")) == TCL_OK) res = Tcl_NewLongObj((long)value); @@ -739,6 +818,18 @@ env_Cmd(clientData, interp, objc, objv) case ENVGETVERBOSE: result = env_GetVerbose(interp, objc, objv, dbenv); break; + case ENVSETDATADIR: + /* + * One args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "pfx"); + return (TCL_ERROR); + } + strarg = Tcl_GetStringFromObj(objv[2], NULL); + ret = dbenv->set_data_dir(dbenv, strarg); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env set data dir")); case ENVTXN: result = tcl_Txn(interp, objc, objv, dbenv, envip); break; @@ -1040,7 +1131,6 @@ _EnvInfoDelete(interp, envip) case I_ENV: case I_LOCK: case I_LOGC: - case I_MUTEX: case I_NDBM: case I_PG: case I_SEQ: @@ -1061,6 +1151,111 @@ _EnvInfoDelete(interp, envip) #ifdef CONFIG_TEST /* + * PUBLIC: int tcl_EnvIdReset __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *)); + * + * tcl_EnvIdReset -- + * Implements the ENV->fileid_reset command. + */ +int +tcl_EnvIdReset(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* arg count */ + Tcl_Obj * CONST* objv; /* args */ + DB_ENV *dbenv; /* Database pointer */ +{ + static const char *idwhich[] = { + "-encrypt", + NULL + }; + enum idwhich { + IDENCRYPT + }; + int enc, i, result, ret; + u_int32_t flags; + char *file; + + result = TCL_OK; + flags = 0; + i = 2; + Tcl_SetResult(interp, "0", TCL_STATIC); + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-encrypt? filename"); + return (TCL_ERROR); + } else if (objc > 3) { + /* + * If there is an arg, make sure it is the right one. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], idwhich, "option", + TCL_EXACT, &enc) != TCL_OK) + return (IS_HELP(objv[2])); + switch ((enum idwhich)enc) { + case IDENCRYPT: + flags |= DB_ENCRYPT; + break; + } + i = 3; + } + file = Tcl_GetStringFromObj(objv[i], NULL); + ret = dbenv->fileid_reset(dbenv, file, flags); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "fileid reset"); + return (result); +} + +/* + * PUBLIC: int tcl_EnvLsnReset __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *)); + * + * tcl_EnvLsnReset -- + * Implements the ENV->lsn_reset command. + */ +int +tcl_EnvLsnReset(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* arg count */ + Tcl_Obj * CONST* objv; /* args */ + DB_ENV *dbenv; /* Database pointer */ +{ + static const char *lsnwhich[] = { + "-encrypt", + NULL + }; + enum lsnwhich { + IDENCRYPT + }; + int enc, i, result, ret; + u_int32_t flags; + char *file; + + result = TCL_OK; + flags = 0; + i = 2; + Tcl_SetResult(interp, "0", TCL_STATIC); + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-encrypt? filename"); + return (TCL_ERROR); + } else if (objc > 3) { + /* + * If there is an arg, make sure it is the right one. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], lsnwhich, "option", + TCL_EXACT, &enc) != TCL_OK) + return (IS_HELP(objv[2])); + + switch ((enum lsnwhich)enc) { + case IDENCRYPT: + flags |= DB_ENCRYPT; + break; + } + i = 3; + } + file = Tcl_GetStringFromObj(objv[i], NULL); + ret = dbenv->lsn_reset(dbenv, file, flags); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lsn reset"); + return (result); +} + +/* * PUBLIC: int tcl_EnvVerbose __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, * PUBLIC: Tcl_Obj *)); * @@ -1076,15 +1271,17 @@ tcl_EnvVerbose(interp, dbenv, which, onoff) static const char *verbwhich[] = { "deadlock", "recovery", + "register", "rep", "wait", NULL }; enum verbwhich { - ENVVERB_DEAD, - ENVVERB_REC, - ENVVERB_REP, - ENVVERB_WAIT + ENVVERB_DEADLOCK, + ENVVERB_RECOVERY, + ENVVERB_REGISTER, + ENVVERB_REPLICATION, + ENVVERB_WAITSFOR }; static const char *verbonoff[] = { "off", @@ -1103,16 +1300,19 @@ tcl_EnvVerbose(interp, dbenv, which, onoff) return (IS_HELP(which)); switch ((enum verbwhich)optindex) { - case ENVVERB_DEAD: + case ENVVERB_DEADLOCK: wh = DB_VERB_DEADLOCK; break; - case ENVVERB_REC: + case ENVVERB_RECOVERY: wh = DB_VERB_RECOVERY; break; - case ENVVERB_REP: + case ENVVERB_REGISTER: + wh = DB_VERB_REGISTER; + break; + case ENVVERB_REPLICATION: wh = DB_VERB_REPLICATION; break; - case ENVVERB_WAIT: + case ENVVERB_WAITSFOR: wh = DB_VERB_WAITSFOR; break; default: @@ -1228,6 +1428,42 @@ err: } /* + * tcl_EventNotify -- + * Call DB_ENV->set_event_notify(). + * + * PUBLIC: int tcl_EventNotify __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, + * PUBLIC: DBTCL_INFO *)); + * + * Note that this normally can/should be achieved as an argument to + * berkdb env, but we need to test changing the event function on + * the fly. + */ +int +tcl_EventNotify(interp, dbenv, eobj, ip) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; + Tcl_Obj *eobj; /* The event proc */ + DBTCL_INFO *ip; +{ + int ret; + + /* + * We don't need to crack the event procedure out now. + */ + /* + * If we're replacing an existing event proc, decrement it now. + */ + if (ip->i_event != NULL) + Tcl_DecrRefCount(ip->i_event); + ip->i_event = eobj; + Tcl_IncrRefCount(ip->i_event); + _debug_check(); + ret = dbenv->set_event_notify(dbenv, _EventFunc); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env event")); +} + +/* * PUBLIC: int tcl_EnvSetFlags __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, * PUBLIC: Tcl_Obj *)); * @@ -1248,6 +1484,7 @@ tcl_EnvSetFlags(interp, dbenv, which, onoff) "-dsync_log", "-log_inmemory", "-log_remove", + "-multiversion", "-nolock", "-nommap", "-nopanic", @@ -1264,6 +1501,7 @@ tcl_EnvSetFlags(interp, dbenv, which, onoff) ENVSF_DSYNCLOG, ENVSF_LOG_INMEMORY, ENVSF_LOG_REMOVE, + ENVSF_MULTIVERSION, ENVSF_NOLOCK, ENVSF_NOMMAP, ENVSF_NOPANIC, @@ -1307,6 +1545,9 @@ tcl_EnvSetFlags(interp, dbenv, which, onoff) case ENVSF_LOG_REMOVE: wh = DB_LOG_AUTOREMOVE; break; + case ENVSF_MULTIVERSION: + wh = DB_MULTIVERSION; + break; case ENVSF_NOLOCK: wh = DB_NOLOCKING; break; @@ -1346,7 +1587,7 @@ tcl_EnvSetFlags(interp, dbenv, which, onoff) } ret = dbenv->set_flags(dbenv, wh, on); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), - "env set verbose")); + "env set flags")); } /* @@ -1383,6 +1624,7 @@ tcl_EnvTest(interp, objc, objv, dbenv) "postlogmeta", "postopen", "postsync", + "recycle", "subdb_lock", NULL }; @@ -1397,6 +1639,7 @@ tcl_EnvTest(interp, objc, objv, dbenv) ENVTEST_POSTLOGMETA, ENVTEST_POSTOPEN, ENVTEST_POSTSYNC, + ENVTEST_RECYCLE, ENVTEST_SUBDB_LOCKS }; int *loc, optindex, result, testval; @@ -1446,11 +1689,11 @@ tcl_EnvTest(interp, objc, objv, dbenv) } switch ((enum envtestat)optindex) { case ENVTEST_ELECTINIT: - DB_ASSERT(loc == &dbenv->test_abort); + DB_ASSERT(dbenv, loc == &dbenv->test_abort); testval = DB_TEST_ELECTINIT; break; case ENVTEST_ELECTVOTE1: - DB_ASSERT(loc == &dbenv->test_abort); + DB_ASSERT(dbenv, loc == &dbenv->test_abort); testval = DB_TEST_ELECTVOTE1; break; case ENVTEST_NONE: @@ -1477,8 +1720,12 @@ tcl_EnvTest(interp, objc, objv, dbenv) case ENVTEST_POSTSYNC: testval = DB_TEST_POSTSYNC; break; + case ENVTEST_RECYCLE: + DB_ASSERT(dbenv, loc == &dbenv->test_copy); + testval = DB_TEST_RECYCLE; + break; case ENVTEST_SUBDB_LOCKS: - DB_ASSERT(loc == &dbenv->test_abort); + DB_ASSERT(dbenv, loc == &dbenv->test_abort); testval = DB_TEST_SUBDB_LOCKS; break; default: @@ -1594,6 +1841,8 @@ env_DbRemove(interp, objc, objv, dbenv) * arrays for the subdb. */ db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; if (i != objc) { subdbtmp = Tcl_GetByteArrayFromObj(objv[i++], &subdblen); @@ -1723,6 +1972,8 @@ env_DbRename(interp, objc, objv, dbenv) * arrays for the subdb. */ db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; if (i == objc - 2) { subdbtmp = Tcl_GetByteArrayFromObj(objv[i++], &subdblen); @@ -1788,6 +2039,7 @@ env_GetFlags(interp, objc, objv, dbenv) { DB_DSYNC_LOG, "-dsync_log" }, { DB_LOG_AUTOREMOVE, "-log_remove" }, { DB_LOG_INMEMORY, "-log_inmemory" }, + { DB_MULTIVERSION, "-multiversion" }, { DB_NOLOCKING, "-nolock" }, { DB_NOMMAP, "-nommap" }, { DB_NOPANIC, "-nopanic" }, @@ -1845,20 +2097,21 @@ env_GetOpenFlag(interp, objc, objv, dbenv) u_int32_t flag; char *arg; } open_flags[] = { + { DB_CREATE, "-create" }, { DB_INIT_CDB, "-cdb" }, { DB_INIT_LOCK, "-lock" }, { DB_INIT_LOG, "-log" }, { DB_INIT_MPOOL, "-mpool" }, { DB_INIT_TXN, "-txn" }, - { DB_RECOVER, "-recover" }, - { DB_RECOVER_FATAL, "-recover_fatal" }, - { DB_USE_ENVIRON, "-use_environ" }, - { DB_USE_ENVIRON_ROOT, "-use_environ_root" }, - { DB_CREATE, "-create" }, { DB_LOCKDOWN, "-lockdown" }, { DB_PRIVATE, "-private" }, + { DB_RECOVER, "-recover" }, + { DB_RECOVER_FATAL, "-recover_fatal" }, + { DB_REGISTER, "-register" }, { DB_SYSTEM_MEM, "-system_mem" }, { DB_THREAD, "-thread" }, + { DB_USE_ENVIRON, "-use_environ" }, + { DB_USE_ENVIRON_ROOT, "-use_environ_root" }, { 0, NULL } }; @@ -2058,6 +2311,7 @@ env_GetVerbose(interp, objc, objv, dbenv) } verbose_flags[] = { { DB_VERB_DEADLOCK, "deadlock" }, { DB_VERB_RECOVERY, "recovery" }, + { DB_VERB_REGISTER, "register" }, { DB_VERB_REPLICATION, "rep" }, { DB_VERB_WAITSFOR, "wait" }, { 0, NULL } @@ -2086,7 +2340,7 @@ env_GetVerbose(interp, objc, objv, dbenv) ret = dbenv->get_verbose(dbenv, which, &onoff); err: if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), - "env get_timeout")) == 0) { + "env get_verbose")) == 0) { answer = onoff ? "on" : "off"; res = NewStringObj(answer, strlen(answer)); Tcl_SetObjResult(interp, res); diff --git a/db/tcl/tcl_internal.c b/db/tcl/tcl_internal.c index 6927b3018..d1071c71c 100644 --- a/db/tcl/tcl_internal.c +++ b/db/tcl/tcl_internal.c @@ -1,23 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_internal.c,v 11.70 2004/10/25 18:04:44 bostic Exp $ + * $Id: tcl_internal.c,v 12.13 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" #include "dbinc/db_page.h" #include "dbinc/db_am.h" @@ -59,9 +54,9 @@ _NewInfo(interp, anyp, name, type) enum INFOTYPE type; { DBTCL_INFO *p; - int i, ret; + int ret; - if ((ret = __os_malloc(NULL, sizeof(DBTCL_INFO), &p)) != 0) { + if ((ret = __os_calloc(NULL, sizeof(DBTCL_INFO), 1, &p)) != 0) { Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); return (NULL); } @@ -73,21 +68,7 @@ _NewInfo(interp, anyp, name, type) } p->i_interp = interp; p->i_anyp = anyp; - p->i_data = 0; - p->i_data2 = 0; p->i_type = type; - p->i_parent = NULL; - p->i_err = NULL; - p->i_errpfx = NULL; - p->i_lockobj.data = NULL; - p->i_btcompare = NULL; - p->i_dupcompare = NULL; - p->i_hashproc = NULL; - p->i_second_call = NULL; - p->i_rep_eid = NULL; - p->i_rep_send = NULL; - for (i = 0; i < MAX_ID; i++) - p->i_otherid[i] = 0; LIST_INSERT_HEAD(&__db_infohead, p, entries); return (p); @@ -102,8 +83,7 @@ _NameToPtr(name) { DBTCL_INFO *p; - for (p = LIST_FIRST(&__db_infohead); p != NULL; - p = LIST_NEXT(p, entries)) + LIST_FOREACH(p, &__db_infohead, entries) if (strcmp(name, p->i_name) == 0) return (p->i_anyp); return (NULL); @@ -118,8 +98,7 @@ _PtrToInfo(ptr) { DBTCL_INFO *p; - for (p = LIST_FIRST(&__db_infohead); p != NULL; - p = LIST_NEXT(p, entries)) + LIST_FOREACH(p, &__db_infohead, entries) if (p->i_anyp == ptr) return (p); return (NULL); @@ -134,8 +113,7 @@ _NameToInfo(name) { DBTCL_INFO *p; - for (p = LIST_FIRST(&__db_infohead); p != NULL; - p = LIST_NEXT(p, entries)) + LIST_FOREACH(p, &__db_infohead, entries) if (strcmp(name, p->i_name) == 0) return (p); return (NULL); @@ -167,7 +145,7 @@ _DeleteInfo(p) LIST_REMOVE(p, entries); if (p->i_lockobj.data != NULL) __os_free(NULL, p->i_lockobj.data); - if (p->i_err != NULL && p->i_err != stderr) { + if (p->i_err != NULL && p->i_err != stderr && p->i_err != stdout) { (void)fclose(p->i_err); p->i_err = NULL; } @@ -243,7 +221,7 @@ _SetListElemInt(interp, list, elem1, elem2) * library, it's likely because we don't have a 64-bit type, and trying to * use int64_t is going to result in syntax errors. */ -#ifdef HAVE_SEQUENCE +#ifdef HAVE_64BIT_TYPES /* * PUBLIC: int _SetListElemWideInt __P((Tcl_Interp *, * PUBLIC: Tcl_Obj *, void *, int64_t)); @@ -267,7 +245,7 @@ _SetListElemWideInt(interp, list, elem1, elem2) return (TCL_ERROR); return (Tcl_ListObjAppendElement(interp, list, thislist)); } -#endif /* HAVE_SEQUENCE */ +#endif /* HAVE_64BIT_TYPES */ /* * PUBLIC: int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *, @@ -522,6 +500,107 @@ _ErrorFunc(dbenv, pfx, msg) return; } +/* + * PUBLIC: void _EventFunc __P((DB_ENV *, u_int32_t, void *)); + */ +void +_EventFunc(dbenv, event, info) + DB_ENV *dbenv; + u_int32_t event; + void *info; +{ +#define TCLDB_EVENTITEMS 2 /* Event name and any info */ +#define TCLDB_SENDEVENT 2 + DBTCL_INFO *ip; + Tcl_Interp *interp; + Tcl_Obj *event_o, *origobj; + Tcl_Obj *myobjv[TCLDB_EVENTITEMS], *objv[TCLDB_SENDEVENT]; + int i, myobjc, result; + + ip = (DBTCL_INFO *)dbenv->app_private; + interp = ip->i_interp; + if (ip->i_event == NULL) + return; + objv[0] = ip->i_event; + + /* + * Most events don't have additional info. Assume none + * and handle individually those that do. + */ + myobjv[1] = NULL; + myobjc = 1; + switch (event) { + case DB_EVENT_PANIC: + /* + * Info is the original error code. + */ + myobjv[0] = NewStringObj("panic", strlen("panic")); + myobjv[myobjc++] = Tcl_NewIntObj(*(int *)info); + break; + case DB_EVENT_REP_CLIENT: + myobjv[0] = NewStringObj("rep_client", strlen("rep_client")); + break; + case DB_EVENT_REP_MASTER: + myobjv[0] = NewStringObj("rep_master", strlen("rep_master")); + break; + case DB_EVENT_REP_NEWMASTER: + /* + * Info is the EID of the new master. + */ + myobjv[0] = NewStringObj("newmaster", strlen("newmaster")); + myobjv[myobjc++] = Tcl_NewIntObj(*(int *)info); + break; + case DB_EVENT_REP_STARTUPDONE: + myobjv[0] = NewStringObj("startupdone", strlen("startupdone")); + break; + case DB_EVENT_WRITE_FAILED: + myobjv[0] = + NewStringObj("write_failed", strlen("write_failed")); + break; + default: + __db_errx(dbenv, "Tcl unknown event %lu", (u_long)event); + return; + } + + for (i = 0; i < myobjc; i++) + Tcl_IncrRefCount(myobjv[i]); + + event_o = Tcl_NewListObj(myobjc, myobjv); + Tcl_IncrRefCount(event_o); + objv[1] = event_o; + + /* + * We really want to return the original result to the + * user. So, save the result obj here, and then after + * we've taken care of the Tcl_EvalObjv, set the result + * back to this original result. + */ + origobj = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(origobj); + result = Tcl_EvalObjv(interp, TCLDB_SENDEVENT, objv, 0); + if (result != TCL_OK) { + /* + * XXX + * This probably isn't the right error behavior, but + * this error should only happen if the Tcl callback is + * somehow invalid, which is a fatal scripting bug. + * The event handler is a void function so we either + * just return or abort. + * For now, abort. + */ + __db_errx(dbenv, "Tcl event failure"); + abort(); + } + + Tcl_SetObjResult(interp, origobj); + Tcl_DecrRefCount(origobj); + for (i = 0; i < myobjc; i++) + Tcl_DecrRefCount(myobjv[i]); + Tcl_DecrRefCount(event_o); + + return; +} + #define INVALID_LSNMSG "Invalid LSN with %d parts. Should have 2.\n" /* @@ -631,7 +710,7 @@ _GetFlagsList(interp, flags, fnp) * into one). If this is the case, we screwed up badly * somehow. */ - DB_ASSERT(result == TCL_OK); + DB_ASSERT(NULL, result == TCL_OK); } return (newlist); @@ -670,14 +749,14 @@ _debug_check() * memory. */ /* - * PUBLIC: int _CopyObjBytes __P((Tcl_Interp *, Tcl_Obj *obj, void **, + * PUBLIC: int _CopyObjBytes __P((Tcl_Interp *, Tcl_Obj *obj, void *, * PUBLIC: u_int32_t *, int *)); */ int _CopyObjBytes(interp, obj, newp, sizep, freep) Tcl_Interp *interp; Tcl_Obj *obj; - void **newp; + void *newp; u_int32_t *sizep; int *freep; { @@ -695,7 +774,7 @@ _CopyObjBytes(interp, obj, newp, sizep, freep) *sizep = (u_int32_t)len; if (ret == TCL_ERROR) { Tcl_ResetResult(interp); - *newp = tmp; + *(void **)newp = tmp; return (0); } @@ -707,7 +786,7 @@ _CopyObjBytes(interp, obj, newp, sizep, freep) if ((ret = __os_malloc(NULL, (size_t)len, &new)) != 0) return (ret); memcpy(new, tmp, (size_t)len); - *newp = new; + *(void **)newp = new; *freep = 1; return (0); } diff --git a/db/tcl/tcl_lock.c b/db/tcl/tcl_lock.c index 4a3de36bd..bc73bf81b 100644 --- a/db/tcl/tcl_lock.c +++ b/db/tcl/tcl_lock.c @@ -1,23 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_lock.c,v 11.59 2004/10/07 16:48:39 bostic Exp $ + * $Id: tcl_lock.c,v 12.6 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" /* @@ -259,10 +254,14 @@ tcl_LockStat(interp, objc, objv, envp) MAKE_STAT_LIST("Maximum number of lockers so far", sp->st_maxnlockers); MAKE_STAT_LIST("Current number of objects", sp->st_nobjects); MAKE_STAT_LIST("Maximum number of objects so far", sp->st_maxnobjects); - MAKE_STAT_LIST("Number of conflicts", sp->st_nconflicts); MAKE_STAT_LIST("Lock requests", sp->st_nrequests); MAKE_STAT_LIST("Lock releases", sp->st_nreleases); - MAKE_STAT_LIST("Lock requests that would have waited", sp->st_nnowaits); + MAKE_STAT_LIST("Lock upgrades", sp->st_nupgrade); + MAKE_STAT_LIST("Lock downgrades", sp->st_ndowngrade); + MAKE_STAT_LIST("Number of conflicted locks for which we waited", + sp->st_lock_wait); + MAKE_STAT_LIST("Number of conflicted locks for which we did not wait", + sp->st_lock_nowait); MAKE_STAT_LIST("Deadlocks detected", sp->st_ndeadlocks); MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); diff --git a/db/tcl/tcl_log.c b/db/tcl/tcl_log.c index 68c678101..650f632c9 100644 --- a/db/tcl/tcl_log.c +++ b/db/tcl/tcl_log.c @@ -1,26 +1,20 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_log.c,v 11.61 2004/04/05 20:18:32 bostic Exp $ + * $Id: tcl_log.c,v 12.10 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/log.h" #include "dbinc/tcl_db.h" -#include "dbinc/txn.h" #ifdef CONFIG_TEST static int tcl_LogcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_LOGC *)); @@ -382,6 +376,7 @@ tcl_LogStat(interp, objc, objv, envp) MAKE_STAT_LIST("Log file mode", sp->st_mode); MAKE_STAT_LIST("Log record cache size", sp->st_lg_bsize); MAKE_STAT_LIST("Current log file size", sp->st_lg_size); + MAKE_STAT_LIST("Log file records written", sp->st_record); MAKE_STAT_LIST("Mbytes written", sp->st_w_mbytes); MAKE_STAT_LIST("Bytes written (over Mb)", sp->st_w_bytes); MAKE_STAT_LIST("Mbytes written since checkpoint", sp->st_wc_mbytes); @@ -390,7 +385,8 @@ tcl_LogStat(interp, objc, objv, envp) MAKE_STAT_LIST("Times log written", sp->st_wcount); MAKE_STAT_LIST("Times log written because cache filled up", sp->st_wcount_fill); - MAKE_STAT_LIST("Times log flushed", sp->st_scount); + MAKE_STAT_LIST("Times log read from disk", sp->st_rcount); + MAKE_STAT_LIST("Times log flushed to disk", sp->st_scount); MAKE_STAT_LIST("Current log file number", sp->st_cur_file); MAKE_STAT_LIST("Current log file offset", sp->st_cur_offset); MAKE_STAT_LIST("On-disk log file number", sp->st_disk_file); @@ -421,14 +417,18 @@ logc_Cmd(clientData, interp, objc, objv) static const char *logccmds[] = { "close", "get", + "version", NULL }; enum logccmds { LOGCCLOSE, - LOGCGET + LOGCGET, + LOGCVERSION }; DB_LOGC *logc; DBTCL_INFO *logcip; + Tcl_Obj *res; + u_int32_t version; int cmdindex, result, ret; Tcl_ResetResult(interp); @@ -477,7 +477,24 @@ logc_Cmd(clientData, interp, objc, objv) case LOGCGET: result = tcl_LogcGet(interp, objc, objv, logc); break; + case LOGCVERSION: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = logc->version(logc, &version, 0); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "logc version")) == TCL_OK) { + res = Tcl_NewIntObj((int)version); + Tcl_SetObjResult(interp, res); + } + break; } + return (result); } diff --git a/db/tcl/tcl_mp.c b/db/tcl/tcl_mp.c index 29691a31c..ce205728a 100644 --- a/db/tcl/tcl_mp.c +++ b/db/tcl/tcl_mp.c @@ -1,23 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_mp.c,v 11.58 2004/10/07 16:48:39 bostic Exp $ + * $Id: tcl_mp.c,v 12.7 2006/09/11 14:53:42 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" /* @@ -160,6 +155,7 @@ tcl_Mp(interp, objc, objv, envp, envip) static const char *mpopts[] = { "-create", "-mode", + "-multiversion", "-nommap", "-pagesize", "-rdonly", @@ -168,6 +164,7 @@ tcl_Mp(interp, objc, objv, envp, envip) enum mpopts { MPCREATE, MPMODE, + MPMULTIVERSION, MPNOMMAP, MPPAGE, MPRDONLY @@ -203,13 +200,10 @@ tcl_Mp(interp, objc, objv, envp, envip) case MPCREATE: flag |= DB_CREATE; break; - case MPNOMMAP: - flag |= DB_NOMMAP; - break; - case MPPAGE: + case MPMODE: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, - "?-pagesize size?"); + "?-mode mode?"); result = TCL_ERROR; break; } @@ -219,15 +213,18 @@ tcl_Mp(interp, objc, objv, envp, envip) * set up, and we'll bail out below. If ok, * the mode is set and we go on. */ - result = Tcl_GetIntFromObj(interp, objv[i++], &pgsize); + result = Tcl_GetIntFromObj(interp, objv[i++], &mode); break; - case MPRDONLY: - flag |= DB_RDONLY; + case MPMULTIVERSION: + flag |= DB_MULTIVERSION; break; - case MPMODE: + case MPNOMMAP: + flag |= DB_NOMMAP; + break; + case MPPAGE: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, - "?-mode mode?"); + "?-pagesize size?"); result = TCL_ERROR; break; } @@ -237,7 +234,10 @@ tcl_Mp(interp, objc, objv, envp, envip) * set up, and we'll bail out below. If ok, * the mode is set and we go on. */ - result = Tcl_GetIntFromObj(interp, objv[i++], &mode); + result = Tcl_GetIntFromObj(interp, objv[i++], &pgsize); + break; + case MPRDONLY: + flag |= DB_RDONLY; break; } if (result != TCL_OK) @@ -374,6 +374,9 @@ tcl_MpStat(interp, objc, objv, envp) sp->st_hash_max_wait); MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); + MAKE_STAT_LIST("Buffers frozen", sp->st_mvcc_frozen); + MAKE_STAT_LIST("Buffers thawed", sp->st_mvcc_thawed); + MAKE_STAT_LIST("Frozen buffers freed", sp->st_mvcc_freed); MAKE_STAT_LIST("Page allocations", sp->st_alloc); MAKE_STAT_LIST("Buckets examined during allocation", sp->st_alloc_buckets); @@ -382,6 +385,7 @@ tcl_MpStat(interp, objc, objv, envp) MAKE_STAT_LIST("Pages examined during allocation", sp->st_alloc_pages); MAKE_STAT_LIST("Maximum pages examined during allocation", sp->st_alloc_max_pages); + MAKE_STAT_LIST("Threads waiting on buffer I/O", sp->st_io_wait); /* * Save global stat list as res1. The MAKE_STAT_LIST @@ -587,24 +591,30 @@ tcl_MpGet(interp, objc, objv, mp, mpip) { static const char *mpget[] = { "-create", + "-dirty", "-last", "-new", + "-txn", NULL }; enum mpget { MPGET_CREATE, + MPGET_DIRTY, MPGET_LAST, - MPGET_NEW + MPGET_NEW, + MPGET_TXN }; DBTCL_INFO *ip; Tcl_Obj *res; + DB_TXN *txn; db_pgno_t pgno; u_int32_t flag; int i, ipgno, optindex, result, ret; - char newname[MSG_SIZE]; + char *arg, msg[MSG_SIZE], newname[MSG_SIZE]; void *page; + txn = NULL; result = TCL_OK; memset(newname, 0, MSG_SIZE); i = 2; @@ -627,12 +637,30 @@ tcl_MpGet(interp, objc, objv, mp, mpip) case MPGET_CREATE: flag |= DB_MPOOL_CREATE; break; + case MPGET_DIRTY: + flag |= DB_MPOOL_DIRTY; + break; case MPGET_LAST: flag |= DB_MPOOL_LAST; break; case MPGET_NEW: flag |= DB_MPOOL_NEW; break; + case MPGET_TXN: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "mpool get: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; } if (result != TCL_OK) goto error; @@ -662,7 +690,7 @@ tcl_MpGet(interp, objc, objv, mp, mpip) } _debug_check(); pgno = (db_pgno_t)ipgno; - ret = mp->get(mp, &pgno, flag, &page); + ret = mp->get(mp, &pgno, NULL, flag, &page); result = _ReturnSetup(interp, ret, DB_RETOK_MPGET(ret), "mpool get"); if (result == TCL_ERROR) _DeleteInfo(ip); @@ -789,14 +817,10 @@ tcl_Pg(interp, objc, objv, page, mp, pgip, putop) int putop; /* Operation */ { static const char *pgopt[] = { - "-clean", - "-dirty", "-discard", NULL }; enum pgopt { - PGCLEAN, - PGDIRTY, PGDISCARD }; u_int32_t flag; @@ -811,12 +835,6 @@ tcl_Pg(interp, objc, objv, page, mp, pgip, putop) return (IS_HELP(objv[i])); i++; switch ((enum pgopt)optindex) { - case PGCLEAN: - flag |= DB_MPOOL_CLEAN; - break; - case PGDIRTY: - flag |= DB_MPOOL_DIRTY; - break; case PGDISCARD: flag |= DB_MPOOL_DISCARD; break; diff --git a/db/tcl/tcl_rep.c b/db/tcl/tcl_rep.c index e0e6a1a88..036171a0c 100644 --- a/db/tcl/tcl_rep.c +++ b/db/tcl/tcl_rep.c @@ -1,27 +1,166 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_rep.c,v 11.106 2004/10/14 18:09:00 bostic Exp $ + * $Id: tcl_rep.c,v 12.25 2006/09/07 08:06:37 alexg Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" #ifdef CONFIG_TEST /* + * tcl_RepConfig -- + * Call DB_ENV->rep_set_config(). + * + * PUBLIC: int tcl_RepConfig + * PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *)); + */ +int +tcl_RepConfig(interp, dbenv, list) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; /* Environment pointer */ + Tcl_Obj *list; /* {which on|off} */ +{ + static const char *confwhich[] = { + "bulk", + "delayclient", + "noautoinit", + "nowait", + NULL + }; + enum confwhich { + REPCONF_BULK, + REPCONF_DELAYCLIENT, + REPCONF_NOAUTOINIT, + REPCONF_NOWAIT + }; + static const char *confonoff[] = { + "off", + "on", + NULL + }; + enum confonoff { + REPCONF_OFF, + REPCONF_ON + }; + Tcl_Obj **myobjv, *onoff, *which; + int myobjc, on, optindex, result, ret; + u_int32_t wh; + + result = Tcl_ListObjGetElements(interp, list, &myobjc, &myobjv); + which = myobjv[0]; + onoff = myobjv[1]; + if (result != TCL_OK) + return (result); + if (Tcl_GetIndexFromObj(interp, which, confwhich, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(which)); + + switch ((enum confwhich)optindex) { + case REPCONF_NOAUTOINIT: + wh = DB_REP_CONF_NOAUTOINIT; + break; + case REPCONF_BULK: + wh = DB_REP_CONF_BULK; + break; + case REPCONF_DELAYCLIENT: + wh = DB_REP_CONF_DELAYCLIENT; + break; + case REPCONF_NOWAIT: + wh = DB_REP_CONF_NOWAIT; + break; + default: + return (TCL_ERROR); + } + if (Tcl_GetIndexFromObj(interp, onoff, confonoff, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(onoff)); + switch ((enum confonoff)optindex) { + case REPCONF_OFF: + on = 0; + break; + case REPCONF_ON: + on = 1; + break; + default: + return (TCL_ERROR); + } + ret = dbenv->rep_set_config(dbenv, wh, on); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env rep_config")); +} + +/* + * tcl_RepGetConfig -- + * Call DB_ENV->rep_get_config(). + * + * PUBLIC: int tcl_RepGetConfig + * PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *)); + */ +int +tcl_RepGetConfig(interp, dbenv, which) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; /* Environment pointer */ + Tcl_Obj *which; /* which flag */ +{ + static const char *confwhich[] = { + "bulk", + "delayclient", + "noautoinit", + "nowait", + NULL + }; + enum confwhich { + REPGCONF_BULK, + REPGCONF_DELAYCLIENT, + REPGCONF_NOAUTOINIT, + REPGCONF_NOWAIT + }; + Tcl_Obj *res; + int on, optindex, result, ret; + u_int32_t wh; + + if (Tcl_GetIndexFromObj(interp, which, confwhich, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(which)); + + res = NULL; + switch ((enum confwhich)optindex) { + case REPGCONF_BULK: + wh = DB_REP_CONF_BULK; + break; + case REPGCONF_DELAYCLIENT: + wh = DB_REP_CONF_DELAYCLIENT; + break; + case REPGCONF_NOAUTOINIT: + wh = DB_REP_CONF_NOAUTOINIT; + break; + case REPGCONF_NOWAIT: + wh = DB_REP_CONF_NOWAIT; + break; + default: + return (TCL_ERROR); + } + ret = dbenv->rep_get_config(dbenv, wh, &on); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env rep_config")) == TCL_OK) { + res = Tcl_NewIntObj(on); + Tcl_SetObjResult(interp, res); + } + return (result); +} +#endif + +#ifdef CONFIG_TEST +/* * tcl_RepElect -- * Call DB_ENV->rep_elect(). * @@ -53,8 +192,16 @@ tcl_RepElect(interp, objc, objv, dbenv) return (result); _debug_check(); - if ((ret = dbenv->rep_elect(dbenv, nsites, nvotes, - pri, timeout, &eid, 0)) != 0) + + if ((ret = dbenv->rep_set_priority(dbenv, pri)) != 0) + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env rep_elect (rep_set_priority)")); + if ((ret = dbenv->rep_set_timeout(dbenv, DB_REP_ELECTION_TIMEOUT, + timeout)) != 0) + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env rep_elect (rep_set_timeout)")); + + if ((ret = dbenv->rep_elect(dbenv, nsites, nvotes, &eid, 0)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_elect")); @@ -93,8 +240,35 @@ tcl_RepFlush(interp, objc, objv, dbenv) #endif #ifdef CONFIG_TEST /* + * tcl_RepSync -- + * Call DB_ENV->rep_sync(). + * + * PUBLIC: int tcl_RepSync + * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); + */ +int +tcl_RepSync(interp, objc, objv, dbenv) + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; + DB_ENV *dbenv; +{ + int ret; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + + _debug_check(); + ret = dbenv->rep_sync(dbenv, 0); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_sync")); +} +#endif +#ifdef CONFIG_TEST +/* * tcl_RepLimit -- - * Call DB_ENV->set_rep_limit(). + * Call DB_ENV->rep_set_limit(). * * PUBLIC: int tcl_RepLimit * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); @@ -120,7 +294,7 @@ tcl_RepLimit(interp, objc, objv, dbenv) return (result); _debug_check(); - if ((ret = dbenv->set_rep_limit(dbenv, gbytes, bytes)) != 0) + if ((ret = dbenv->rep_set_limit(dbenv, gbytes, bytes)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env set_rep_limit")); @@ -169,6 +343,71 @@ tcl_RepRequest(interp, objc, objv, dbenv) #ifdef CONFIG_TEST /* + * tcl_RepTransport -- + * Call DB_ENV->rep_set_transport(). + * + * PUBLIC: int tcl_RepTransport __P((Tcl_Interp *, int, Tcl_Obj * CONST *, + * PUBLIC: DB_ENV *, DBTCL_INFO *)); + * + * Note that this normally can/should be achieved as an argument to + * berkdb env, but we need to test changing the transport function on + * the fly. + */ +int +tcl_RepTransport(interp, objc, objv, dbenv, ip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; + DBTCL_INFO *ip; +{ + int intarg, result, ret; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, "{id transport_func"); + return (TCL_ERROR); + } + + /* + * Store the objects containing the machine ID + * and the procedure name. We don't need to crack + * the send procedure out now, but we do convert the + * machine ID to an int, since rep_set_transport needs + * it. Even so, it'll be easier later to deal with + * the Tcl_Obj *, so we save that, not the int. + * + * Note that we Tcl_IncrRefCount both objects + * independently; Tcl is free to discard the list + * that they're bundled into. + */ + + /* + * Check that the machine ID is an int. Note that + * we do want to use GetIntFromObj; the machine + * ID is explicitly an int, not a u_int32_t. + */ + if (ip->i_rep_eid != NULL) + Tcl_DecrRefCount(ip->i_rep_eid); + ip->i_rep_eid = objv[0]; + Tcl_IncrRefCount(ip->i_rep_eid); + result = Tcl_GetIntFromObj(interp, + ip->i_rep_eid, &intarg); + if (result != TCL_OK) + return (result); + + if (ip->i_rep_send != NULL) + Tcl_DecrRefCount(ip->i_rep_send); + ip->i_rep_send = objv[1]; + Tcl_IncrRefCount(ip->i_rep_send); + _debug_check(); + ret = dbenv->rep_set_transport(dbenv, intarg, tcl_rep_send); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env rep_transport")); +} +#endif + +#ifdef CONFIG_TEST +/* * tcl_RepStart -- * Call DB_ENV->rep_start(). * @@ -309,6 +548,7 @@ tcl_RepProcessMessage(interp, objc, objv, dbenv) * {NEWMASTER #} - NEWMASTER and its ID. * {NEWSITE 0} - NEWSITE, no other info needed. * {STARTUPDONE 0} - STARTUPDONE, no other info needed. + * {IGNORE {LSN list}} - IGNORE and this msg's LSN. * {ISPERM {LSN list}} - ISPERM and the perm LSN. * {NOTPERM {LSN list}} - NOTPERM and this msg's LSN. */ @@ -328,6 +568,14 @@ tcl_RepProcessMessage(interp, objc, objv, dbenv) (u_char *)"HOLDELECTION", (int)strlen("HOLDELECTION")); myobjv[1] = Tcl_NewIntObj(0); break; + case DB_REP_IGNORE: + myobjv[0] = Tcl_NewLongObj((long)permlsn.file); + myobjv[1] = Tcl_NewLongObj((long)permlsn.offset); + lsnlist = Tcl_NewListObj(myobjc, myobjv); + myobjv[0] = Tcl_NewByteArrayObj( + (u_char *)"IGNORE", (int)strlen("IGNORE")); + myobjv[1] = lsnlist; + break; case DB_REP_ISPERM: myobjv[0] = Tcl_NewLongObj((long)permlsn.file); myobjv[1] = Tcl_NewLongObj((long)permlsn.offset); @@ -354,11 +602,6 @@ tcl_RepProcessMessage(interp, objc, objv, dbenv) (u_char *)"NOTPERM", (int)strlen("NOTPERM")); myobjv[1] = lsnlist; break; - case DB_REP_STARTUPDONE: - myobjv[0] = Tcl_NewByteArrayObj( - (u_char *)"STARTUPDONE", (int)strlen("STARTUPDONE")); - myobjv[1] = Tcl_NewIntObj(0); - break; default: msg = db_strerror(ret); Tcl_AppendResult(interp, msg, NULL); @@ -400,8 +643,8 @@ tcl_RepStat(interp, objc, objv, dbenv) int myobjc, result, ret; char *arg; - result = TCL_OK; flag = 0; + result = TCL_OK; if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, NULL); @@ -439,6 +682,13 @@ tcl_RepStat(interp, objc, objv, dbenv) MAKE_STAT_LIST("Client", 1); MAKE_STAT_LSN("Next LSN expected", &sp->st_next_lsn); MAKE_STAT_LSN("First missed LSN", &sp->st_waiting_lsn); + MAKE_STAT_LIST("Bulk buffer fills", sp->st_bulk_fills); + MAKE_STAT_LIST("Bulk buffer overflows", sp->st_bulk_overflows); + MAKE_STAT_LIST("Bulk records stored", sp->st_bulk_records); + MAKE_STAT_LIST("Bulk buffer transfers", sp->st_bulk_transfers); + MAKE_STAT_LIST("Client service requests", sp->st_client_svc_req); + MAKE_STAT_LIST("Client service req misses", sp->st_client_svc_miss); + MAKE_STAT_LIST("Client rerequests", sp->st_client_rerequests); MAKE_STAT_LIST("Duplicate master conditions", sp->st_dupmasters); MAKE_STAT_LIST("Environment ID", sp->st_env_id); MAKE_STAT_LIST("Environment priority", sp->st_env_priority); @@ -480,10 +730,293 @@ tcl_RepStat(interp, objc, objv, dbenv) MAKE_STAT_LIST("Election priority", sp->st_election_priority); MAKE_STAT_LIST("Election tiebreaker", sp->st_election_tiebreaker); MAKE_STAT_LIST("Election votes", sp->st_election_votes); + MAKE_STAT_LIST("Election seconds", sp->st_election_sec); + MAKE_STAT_LIST("Election usecs", sp->st_election_usec); Tcl_SetObjResult(interp, res); error: __os_ufree(dbenv, sp); return (result); } + +/* + * tcl_RepMgr -- + * Configure and start the Replication Manager. + * + * PUBLIC: int tcl_RepMgr + * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); + */ +int +tcl_RepMgr(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; /* Environment pointer */ +{ + static const char *rmgr[] = { + "-ack", + "-local", + "-msgth", + "-nsites", + "-pri", + "-remote", + "-start", + "-timeout", + NULL + }; + enum rmgr { + RMGR_ACK, + RMGR_LOCAL, + RMGR_MSGTH, + RMGR_NSITES, + RMGR_PRI, + RMGR_REMOTE, + RMGR_START, + RMGR_TIMEOUT + }; + Tcl_Obj **myobjv; + long to; + int ack, i, myobjc, optindex, result, ret, totype; + u_int32_t msgth, remote_flag, start_flag, uintarg; + char *arg; + + result = TCL_OK; + ack = ret = totype = 0; + msgth = 1; + remote_flag = start_flag = 0; + + if (objc <= 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + /* + * Get the command name index from the object based on the bdbcmds + * defined above. + */ + i = 2; + while (i < objc) { + Tcl_ResetResult(interp); + if (Tcl_GetIndexFromObj(interp, objv[i], rmgr, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + goto error; + } + i++; + switch ((enum rmgr)optindex) { + case RMGR_ACK: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-ack policy?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(arg, "all") == 0) + ack = DB_REPMGR_ACKS_ALL; + else if (strcmp(arg, "allpeers") == 0) + ack = DB_REPMGR_ACKS_ALL_PEERS; + else if (strcmp(arg, "none") == 0) + ack = DB_REPMGR_ACKS_NONE; + else if (strcmp(arg, "one") == 0) + ack = DB_REPMGR_ACKS_ONE; + else if (strcmp(arg, "onepeer") == 0) + ack = DB_REPMGR_ACKS_ONE_PEER; + else if (strcmp(arg, "quorum") == 0) + ack = DB_REPMGR_ACKS_QUORUM; + else { + Tcl_AddErrorInfo(interp, + "ack: illegal policy"); + result = TCL_ERROR; + break; + } + _debug_check(); + ret = dbenv->repmgr_set_ack_policy(dbenv, ack); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "ack"); + break; + case RMGR_LOCAL: + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + if (myobjc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-local {host port}?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(myobjv[0], NULL); + if ((result = _GetUInt32(interp, myobjv[1], &uintarg)) + != TCL_OK) + break; + _debug_check(); + /* + * No flags for now. + */ + ret = dbenv->repmgr_set_local_site(dbenv, + arg, uintarg, 0); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "repmgr_set_local_site"); + break; + case RMGR_MSGTH: + if (i >= objc) { + Tcl_WrongNumArgs( + interp, 2, objv, "?-msgth nth?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &msgth); + break; + case RMGR_NSITES: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-nsites num_sites?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &uintarg); + if (result == TCL_OK) { + _debug_check(); + ret = dbenv->rep_set_nsites(dbenv, uintarg); + } + break; + case RMGR_PRI: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-pri priority?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, objv[i++], &uintarg); + if (result == TCL_OK) { + _debug_check(); + ret = dbenv-> + rep_set_priority(dbenv, (int)uintarg); + } + break; + case RMGR_REMOTE: + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + if (myobjc != 2 && myobjc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-remote {host port [peer]}?"); + result = TCL_ERROR; + break; + } + /* + * Get the flag first so we can reuse 'arg'. + */ + if (myobjc == 3) { + arg = Tcl_GetStringFromObj(myobjv[2], NULL); + if (strcmp(arg, "peer") == 0) + remote_flag = DB_REPMGR_PEER; + else { + Tcl_AddErrorInfo(interp, + "remote: illegal flag"); + result = TCL_ERROR; + break; + } + } + arg = Tcl_GetStringFromObj(myobjv[0], NULL); + if ((result = _GetUInt32(interp, myobjv[1], &uintarg)) + != TCL_OK) + break; + _debug_check(); + ret = dbenv->repmgr_add_remote_site(dbenv, + arg, uintarg, NULL, remote_flag); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "repmgr_add_remote_site"); + break; + case RMGR_START: + if (i >= objc) { + Tcl_WrongNumArgs( + interp, 2, objv, "?-start state?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(arg, "master") == 0) + start_flag = DB_REP_MASTER; + else if (strcmp(arg, "client") == 0) + start_flag = DB_REP_CLIENT; + else if (strcmp(arg, "elect") == 0) + start_flag = DB_REP_ELECTION; + else if (strcmp(arg, "full_elect") == 0) + start_flag = DB_REP_FULL_ELECTION; + else { + Tcl_AddErrorInfo( + interp, "start: illegal state"); + result = TCL_ERROR; + break; + } + /* + * Some config functions need to be called + * before repmgr_start. So finish parsing all + * the args and call repmgr_start at the end. + */ + break; + case RMGR_TIMEOUT: + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + if (myobjc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-timeout {type to}?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(myobjv[0], NULL); + if (strcmp(arg, "ack") == 0) + totype = DB_REP_ACK_TIMEOUT; + else if (strcmp(arg, "elect") == 0) + totype = DB_REP_ELECTION_TIMEOUT; + else if (strcmp(arg, "elect_retry") == 0) + totype = DB_REP_ELECTION_RETRY; + else if (strcmp(arg, "conn_retry") == 0) + totype = DB_REP_CONNECTION_RETRY; + else { + Tcl_AddErrorInfo(interp, + "timeout: illegal type"); + result = TCL_ERROR; + break; + } + if ((result = Tcl_GetLongFromObj( + interp, myobjv[1], &to)) != TCL_OK) + break; + _debug_check(); + ret = dbenv->rep_set_timeout(dbenv, totype, + (db_timeout_t)to); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "rep_set_timeout"); + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + } + /* + * Only call repmgr_start if needed. The user may use this + * call just to reconfigure, change policy, etc. + */ + if (start_flag != 0 && result == TCL_OK) { + _debug_check(); + ret = dbenv->repmgr_start(dbenv, (int)msgth, start_flag); + result = _ReturnSetup( + interp, ret, DB_RETOK_STD(ret), "repmgr_start"); + } +error: + return (result); +} #endif diff --git a/db/tcl/tcl_seq.c b/db/tcl/tcl_seq.c index de3e4dd61..2fc43f7d6 100644 --- a/db/tcl/tcl_seq.c +++ b/db/tcl/tcl_seq.c @@ -1,23 +1,19 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 2004-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_seq.c,v 11.12 2004/10/25 18:02:56 bostic Exp $ + * $Id: tcl_seq.c,v 12.6 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#ifdef HAVE_64BIT_TYPES -#ifdef HAVE_SEQUENCE +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" #include "dbinc_auto/sequence_ext.h" @@ -291,13 +287,11 @@ tcl_SeqGet(interp, objc, objv, seq) DB_SEQUENCE *seq; /* Sequence pointer */ { static const char *seqgetopts[] = { - "-auto_commit", "-nosync", "-txn", NULL }; enum seqgetopts { - SEQGET_AUTO_COMMIT, SEQGET_NOSYNC, SEQGET_TXN }; @@ -336,9 +330,6 @@ tcl_SeqGet(interp, objc, objv, seq) } i++; switch ((enum seqgetopts)optindex) { - case SEQGET_AUTO_COMMIT: - aflag |= DB_AUTO_COMMIT; - break; case SEQGET_NOSYNC: aflag |= DB_TXN_NOSYNC; break; @@ -394,13 +385,11 @@ tcl_SeqRemove(interp, objc, objv, seq, ip) DBTCL_INFO *ip; /* Info pointer */ { static const char *seqgetopts[] = { - "-auto_commit", "-nosync", "-txn", NULL }; enum seqgetopts { - SEQGET_AUTO_COMMIT, SEQGET_NOSYNC, SEQGET_TXN }; @@ -439,9 +428,6 @@ tcl_SeqRemove(interp, objc, objv, seq, ip) } i++; switch ((enum seqgetopts)optindex) { - case SEQGET_AUTO_COMMIT: - aflag |= DB_AUTO_COMMIT; - break; case SEQGET_NOSYNC: aflag |= DB_TXN_NOSYNC; break; @@ -523,4 +509,4 @@ tcl_SeqGetFlags(interp, objc, objv, seq) return (result); } -#endif /* HAVE_SEQUENCE */ +#endif /* HAVE_64BIT_TYPES */ diff --git a/db/tcl/tcl_txn.c b/db/tcl/tcl_txn.c index b819c24b7..a3712172f 100644 --- a/db/tcl/tcl_txn.c +++ b/db/tcl/tcl_txn.c @@ -1,23 +1,18 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_txn.c,v 11.70 2004/10/27 16:48:32 bostic Exp $ + * $Id: tcl_txn.c,v 12.16 2006/09/11 14:53:42 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" static int tcl_TxnCommit __P((Tcl_Interp *, @@ -142,28 +137,32 @@ tcl_Txn(interp, objc, objv, envp, envip) { static const char *txnopts[] = { #ifdef CONFIG_TEST - "-degree_2", - "-dirty", "-lock_timeout", + "-read_committed", + "-read_uncommitted", "-txn_timeout", #endif "-nosync", "-nowait", "-parent", + "-snapshot", "-sync", + "-wrnosync", NULL }; enum txnopts { #ifdef CONFIG_TEST - TXNDEGREE2, - TXNDIRTY, - TXN_LOCK_TIMEOUT, - TXN_TIMEOUT, + TXNLOCK_TIMEOUT, + TXNREAD_COMMITTED, + TXNREAD_UNCOMMITTED, + TXNTIMEOUT, #endif TXNNOSYNC, TXNNOWAIT, TXNPARENT, - TXNSYNC + TXNSNAPSHOT, + TXNSYNC, + TXNWRNOSYNC }; DBTCL_INFO *ip; DB_TXN *parent; @@ -196,35 +195,33 @@ tcl_Txn(interp, objc, objv, envp, envip) i++; switch ((enum txnopts)optindex) { #ifdef CONFIG_TEST - case TXNDEGREE2: - flag |= DB_DEGREE_2; - break; - case TXNDIRTY: - flag |= DB_DIRTY_READ; - break; - case TXN_LOCK_TIMEOUT: + case TXNLOCK_TIMEOUT: lk_timeflag = DB_SET_LOCK_TIMEOUT; - goto getit; - case TXN_TIMEOUT: + goto get_timeout; + case TXNTIMEOUT: tx_timeflag = DB_SET_TXN_TIMEOUT; -getit: if (i >= objc) { +get_timeout: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn_timestamp time?"); return (TCL_ERROR); } result = Tcl_GetLongFromObj(interp, objv[i++], (long *) - ((enum txnopts)optindex == TXN_LOCK_TIMEOUT ? + ((enum txnopts)optindex == TXNLOCK_TIMEOUT ? &lk_time : &tx_time)); if (result != TCL_OK) return (TCL_ERROR); break; + case TXNREAD_COMMITTED: + flag |= DB_READ_COMMITTED; + break; + case TXNREAD_UNCOMMITTED: + flag |= DB_READ_UNCOMMITTED; + break; #endif case TXNNOSYNC: - FLAG_CHECK2(flag, DB_DIRTY_READ); flag |= DB_TXN_NOSYNC; break; case TXNNOWAIT: - FLAG_CHECK2(flag, DB_DIRTY_READ); flag |= DB_TXN_NOWAIT; break; case TXNPARENT: @@ -244,10 +241,15 @@ getit: if (i >= objc) { return (TCL_ERROR); } break; + case TXNSNAPSHOT: + flag |= DB_TXN_SNAPSHOT; + break; case TXNSYNC: - FLAG_CHECK2(flag, DB_DIRTY_READ); flag |= DB_TXN_SYNC; break; + case TXNWRNOSYNC: + flag |= DB_TXN_WRITE_NOSYNC; + break; } } snprintf(newname, sizeof(newname), "%s.txn%d", @@ -304,6 +306,63 @@ getit: if (i >= objc) { } /* + * tcl_CDSGroup -- + * + * PUBLIC: int tcl_CDSGroup __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); + */ +int +tcl_CDSGroup(interp, objc, objv, envp, envip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ + DBTCL_INFO *envip; /* Info pointer */ +{ + DBTCL_INFO *ip; + DB_TXN *txn; + Tcl_Obj *res; + int result, ret; + char newname[MSG_SIZE]; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "env cdsgroup"); + return (TCL_ERROR); + } + + result = TCL_OK; + memset(newname, 0, MSG_SIZE); + + snprintf(newname, sizeof(newname), "%s.txn%d", + envip->i_name, envip->i_envtxnid); + ip = _NewInfo(interp, NULL, newname, I_TXN); + if (ip == NULL) { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + return (TCL_ERROR); + } + _debug_check(); + ret = envp->cdsgroup_begin(envp, &txn); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "cdsgroup"); + if (result == TCL_ERROR) + _DeleteInfo(ip); + else { + /* + * Success. Set up return. Set up new info + * and command widget for this txn. + */ + envip->i_envtxnid++; + ip->i_parent = envip; + _SetInfoData(ip, txn); + (void)Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)txn_Cmd, (ClientData)txn, NULL); + res = NewStringObj(newname, strlen(newname)); + Tcl_SetObjResult(interp, res); + } + return (result); +} + +/* * tcl_TxnStat -- * * PUBLIC: int tcl_TxnStat __P((Tcl_Interp *, int, @@ -350,18 +409,19 @@ tcl_TxnStat(interp, objc, objv, envp) MAKE_STAT_LSN("LSN of last checkpoint", &sp->st_last_ckp); MAKE_STAT_LIST("Time of last checkpoint", sp->st_time_ckp); MAKE_STAT_LIST("Last txn ID allocated", sp->st_last_txnid); - MAKE_STAT_LIST("Max Txns", sp->st_maxtxns); + MAKE_STAT_LIST("Maximum txns", sp->st_maxtxns); MAKE_STAT_LIST("Number aborted txns", sp->st_naborts); - MAKE_STAT_LIST("Number active txns", sp->st_nactive); - MAKE_STAT_LIST("Maximum active txns", sp->st_maxnactive); MAKE_STAT_LIST("Number txns begun", sp->st_nbegins); MAKE_STAT_LIST("Number committed txns", sp->st_ncommits); + MAKE_STAT_LIST("Number active txns", sp->st_nactive); + MAKE_STAT_LIST("Number of snapshot txns", sp->st_nsnapshot); MAKE_STAT_LIST("Number restored txns", sp->st_nrestores); + MAKE_STAT_LIST("Maximum active txns", sp->st_maxnactive); + MAKE_STAT_LIST("Maximum snapshot txns", sp->st_maxnsnapshot); MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); for (i = 0, p = sp->st_txnarray; i < sp->st_nactive; i++, p++) - for (ip = LIST_FIRST(&__db_infohead); ip != NULL; - ip = LIST_NEXT(ip, entries)) { + LIST_FOREACH(ip, &__db_infohead, entries) { if (ip->i_type != I_TXN) continue; if (ip->i_type == I_TXN && @@ -428,18 +488,24 @@ txn_Cmd(clientData, interp, objc, objv) static const char *txncmds[] = { #ifdef CONFIG_TEST "discard", + "getname", "id", "prepare", + "setname", #endif "abort", "commit", + "getname", + "setname", NULL }; enum txncmds { #ifdef CONFIG_TEST TXNDISCARD, + TXNGETNAME, TXNID, TXNPREPARE, + TXNSETNAME, #endif TXNABORT, TXNCOMMIT @@ -449,7 +515,9 @@ txn_Cmd(clientData, interp, objc, objv) Tcl_Obj *res; int cmdindex, result, ret; #ifdef CONFIG_TEST - u_int8_t *gid; + u_int8_t *gid, garray[DB_XIDDATASIZE]; + int length; + const char *name; #endif Tcl_ResetResult(interp); @@ -503,8 +571,9 @@ txn_Cmd(clientData, interp, objc, objv) return (TCL_ERROR); } _debug_check(); - gid = (u_int8_t *)Tcl_GetByteArrayFromObj(objv[2], NULL); - ret = txnp->prepare(txnp, gid); + gid = (u_int8_t *)Tcl_GetByteArrayFromObj(objv[2], &length); + memcpy(garray, gid, (size_t)length); + ret = txnp->prepare(txnp, garray); /* * !!! * DB_TXN->prepare commits all outstanding children. But it @@ -516,6 +585,27 @@ txn_Cmd(clientData, interp, objc, objv) result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "txn prepare"); break; + case TXNGETNAME: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = txnp->get_name(txnp, &name); + if ((result = _ReturnSetup( + interp, ret, DB_RETOK_STD(ret), "txn getname")) == TCL_OK) + res = NewStringObj(name, strlen(name)); + break; + case TXNSETNAME: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return (TCL_ERROR); + } + _debug_check(); + ret = txnp->set_name(txnp, Tcl_GetStringFromObj(objv[2], NULL)); + result = + _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "setname"); + break; #endif case TXNABORT: if (objc != 2) { @@ -557,11 +647,13 @@ tcl_TxnCommit(interp, objc, objv, txnp, txnip) static const char *commitopt[] = { "-nosync", "-sync", + "-wrnosync", NULL }; enum commitopt { + COMNOSYNC, COMSYNC, - COMNOSYNC + COMWRNOSYNC }; u_int32_t flag; int optindex, result, ret; @@ -580,13 +672,14 @@ tcl_TxnCommit(interp, objc, objv, txnp, txnip) return (IS_HELP(objv[2])); switch ((enum commitopt)optindex) { case COMSYNC: - FLAG_CHECK(flag); flag = DB_TXN_SYNC; break; case COMNOSYNC: - FLAG_CHECK(flag); flag = DB_TXN_NOSYNC; break; + case COMWRNOSYNC: + flag = DB_TXN_WRITE_NOSYNC; + break; } } diff --git a/db/tcl/tcl_util.c b/db/tcl/tcl_util.c index 13a6d6a9d..90935f27e 100644 --- a/db/tcl/tcl_util.c +++ b/db/tcl/tcl_util.c @@ -1,32 +1,21 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1999-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1999-2006 + * Oracle Corporation. All rights reserved. * - * $Id: tcl_util.c,v 11.43 2004/06/10 17:20:57 bostic Exp $ + * $Id: tcl_util.c,v 12.5 2006/08/24 14:46:33 bostic Exp $ */ #include "db_config.h" +#include "db_int.h" #ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> #include <tcl.h> #endif - -#include "db_int.h" #include "dbinc/tcl_db.h" /* - * Prototypes for procedures defined later in this file: - */ -static int mutex_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); - -/* * bdb_RandCommand -- * Implements rand* functions. * @@ -119,250 +108,3 @@ bdb_RandCommand(interp, objc, objv) Tcl_SetObjResult(interp, res); return (result); } - -/* - * - * tcl_Mutex -- - * Opens an env mutex. - * - * PUBLIC: int tcl_Mutex __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, - * PUBLIC: DBTCL_INFO *)); - */ -int -tcl_Mutex(interp, objc, objv, envp, envip) - Tcl_Interp *interp; /* Interpreter */ - int objc; /* How many arguments? */ - Tcl_Obj *CONST objv[]; /* The argument objects */ - DB_ENV *envp; /* Environment pointer */ - DBTCL_INFO *envip; /* Info pointer */ -{ - DBTCL_INFO *ip; - Tcl_Obj *res; - _MUTEX_DATA *md; - int i, nitems, mode, result, ret; - char newname[MSG_SIZE]; - - md = NULL; - result = TCL_OK; - ret = 0; - - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "mode nitems"); - return (TCL_ERROR); - } - result = Tcl_GetIntFromObj(interp, objv[2], &mode); - if (result != TCL_OK) - return (TCL_ERROR); - result = Tcl_GetIntFromObj(interp, objv[3], &nitems); - if (result != TCL_OK) - return (TCL_ERROR); - - memset(newname, 0, MSG_SIZE); - snprintf(newname, sizeof(newname), - "%s.mutex%d", envip->i_name, envip->i_envmutexid); - ip = _NewInfo(interp, NULL, newname, I_MUTEX); - if (ip == NULL) { - Tcl_SetResult(interp, "Could not set up info", - TCL_STATIC); - return (TCL_ERROR); - } - /* - * Set up mutex. - */ - /* - * Map in the region. - * - * XXX - * We don't bother doing this "right", i.e., using the shalloc - * functions, just grab some memory knowing that it's correctly - * aligned. - */ - _debug_check(); - if (__os_calloc(NULL, 1, sizeof(_MUTEX_DATA), &md) != 0) - goto posixout; - md->env = envp; - md->size = sizeof(_MUTEX_ENTRY) * (u_int)nitems; - - md->reginfo.dbenv = envp; - md->reginfo.type = REGION_TYPE_MUTEX; - md->reginfo.id = INVALID_REGION_ID; - md->reginfo.flags = REGION_CREATE_OK | REGION_JOIN_OK; - if ((ret = __db_r_attach(envp, &md->reginfo, md->size)) != 0) - goto posixout; - md->marray = md->reginfo.addr; - - /* Initialize a created region. */ - if (F_ISSET(&md->reginfo, REGION_CREATE)) - for (i = 0; i < nitems; i++) { - md->marray[i].val = 0; - if ((ret = __db_mutex_init_int(envp, - &md->marray[i].m, i, 0)) != 0) - goto posixout; - } - R_UNLOCK(envp, &md->reginfo); - - /* - * Success. Set up return. Set up new info - * and command widget for this mutex. - */ - envip->i_envmutexid++; - ip->i_parent = envip; - _SetInfoData(ip, md); - (void)Tcl_CreateObjCommand(interp, newname, - (Tcl_ObjCmdProc *)mutex_Cmd, (ClientData)md, NULL); - res = NewStringObj(newname, strlen(newname)); - Tcl_SetObjResult(interp, res); - - return (TCL_OK); - -posixout: - if (ret > 0) - (void)Tcl_PosixError(interp); - result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mutex"); - _DeleteInfo(ip); - - if (md != NULL) { - if (md->reginfo.addr != NULL) - (void)__db_r_detach(md->env, &md->reginfo, 0); - __os_free(md->env, md); - } - return (result); -} - -/* - * mutex_Cmd -- - * Implements the "mutex" widget. - */ -static int -mutex_Cmd(clientData, interp, objc, objv) - ClientData clientData; /* Mutex handle */ - Tcl_Interp *interp; /* Interpreter */ - int objc; /* How many arguments? */ - Tcl_Obj *CONST objv[]; /* The argument objects */ -{ - static const char *mxcmds[] = { - "close", - "get", - "getval", - "release", - "setval", - NULL - }; - enum mxcmds { - MXCLOSE, - MXGET, - MXGETVAL, - MXRELE, - MXSETVAL - }; - DB_ENV *dbenv; - DBTCL_INFO *envip, *mpip; - _MUTEX_DATA *mp; - Tcl_Obj *res; - int cmdindex, id, result, newval; - - Tcl_ResetResult(interp); - mp = (_MUTEX_DATA *)clientData; - mpip = _PtrToInfo((void *)mp); - envip = mpip->i_parent; - dbenv = envip->i_envp; - result = TCL_OK; - - if (mp == NULL) { - Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC); - return (TCL_ERROR); - } - if (mpip == NULL) { - Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC); - return (TCL_ERROR); - } - - /* - * Get the command name index from the object based on the dbcmds - * defined above. - */ - if (Tcl_GetIndexFromObj(interp, - objv[1], mxcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) - return (IS_HELP(objv[1])); - - res = NULL; - switch ((enum mxcmds)cmdindex) { - case MXCLOSE: - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); - return (TCL_ERROR); - } - _debug_check(); - (void)__db_r_detach(mp->env, &mp->reginfo, 0); - res = Tcl_NewIntObj(0); - (void)Tcl_DeleteCommand(interp, mpip->i_name); - _DeleteInfo(mpip); - __os_free(mp->env, mp); - break; - case MXRELE: - /* - * Check for 1 arg. Error if different. - */ - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "id"); - return (TCL_ERROR); - } - result = Tcl_GetIntFromObj(interp, objv[2], &id); - if (result != TCL_OK) - break; - MUTEX_UNLOCK(dbenv, &mp->marray[id].m); - res = Tcl_NewIntObj(0); - break; - case MXGET: - /* - * Check for 1 arg. Error if different. - */ - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "id"); - return (TCL_ERROR); - } - result = Tcl_GetIntFromObj(interp, objv[2], &id); - if (result != TCL_OK) - break; - MUTEX_LOCK(dbenv, &mp->marray[id].m); - res = Tcl_NewIntObj(0); - break; - case MXGETVAL: - /* - * Check for 1 arg. Error if different. - */ - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "id"); - return (TCL_ERROR); - } - result = Tcl_GetIntFromObj(interp, objv[2], &id); - if (result != TCL_OK) - break; - res = Tcl_NewLongObj((long)mp->marray[id].val); - break; - case MXSETVAL: - /* - * Check for 2 args. Error if different. - */ - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "id val"); - return (TCL_ERROR); - } - result = Tcl_GetIntFromObj(interp, objv[2], &id); - if (result != TCL_OK) - break; - result = Tcl_GetIntFromObj(interp, objv[3], &newval); - if (result != TCL_OK) - break; - mp->marray[id].val = newval; - res = Tcl_NewIntObj(0); - break; - } - /* - * Only set result if we have a res. Otherwise, lower - * functions have already done so. - */ - if (result == TCL_OK && res) - Tcl_SetObjResult(interp, res); - return (result); -} |