summaryrefslogtreecommitdiff
path: root/bdb/tcl/tcl_txn.c
diff options
context:
space:
mode:
Diffstat (limited to 'bdb/tcl/tcl_txn.c')
-rw-r--r--bdb/tcl/tcl_txn.c338
1 files changed, 261 insertions, 77 deletions
diff --git a/bdb/tcl/tcl_txn.c b/bdb/tcl/tcl_txn.c
index dfe6b6cf60f..b5fab637943 100644
--- a/bdb/tcl/tcl_txn.c
+++ b/bdb/tcl/tcl_txn.c
@@ -1,14 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1999, 2000
+ * Copyright (c) 1999-2001
* Sleepycat Software. All rights reserved.
*/
#include "db_config.h"
#ifndef lint
-static const char revid[] = "$Id: tcl_txn.c,v 11.24 2000/12/31 19:26:23 bostic Exp $";
+static const char revid[] = "$Id: tcl_txn.c,v 11.57 2002/08/06 06:21:36 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -20,13 +20,11 @@ static const char revid[] = "$Id: tcl_txn.c,v 11.24 2000/12/31 19:26:23 bostic E
#endif
#include "db_int.h"
-#include "tcl_db.h"
+#include "dbinc/tcl_db.h"
-/*
- * Prototypes for procedures defined later in this file:
- */
-static int tcl_TxnCommit __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
- DB_TXN *, DBTCL_INFO *));
+static int tcl_TxnCommit __P((Tcl_Interp *,
+ int, Tcl_Obj * CONST *, DB_TXN *, DBTCL_INFO *));
+static int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST *));
/*
* _TxnInfoDelete --
@@ -39,7 +37,7 @@ static int tcl_TxnCommit __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
*/
void
_TxnInfoDelete(interp, txnip)
- Tcl_Interp *interp; /* Interpreter */
+ Tcl_Interp *interp; /* Interpreter */
DBTCL_INFO *txnip; /* Info for txn */
{
DBTCL_INFO *nextp, *p;
@@ -115,8 +113,9 @@ tcl_TxnCheckpoint(interp, objc, objv, envp)
}
}
_debug_check();
- ret = txn_checkpoint(envp, (u_int32_t)kb, (u_int32_t)min, 0);
- result = _ReturnSetup(interp, ret, "txn checkpoint");
+ ret = envp->txn_checkpoint(envp, (u_int32_t)kb, (u_int32_t)min, 0);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn checkpoint");
return (result);
}
@@ -135,6 +134,11 @@ tcl_Txn(interp, objc, objv, envp, envip)
DBTCL_INFO *envip; /* Info pointer */
{
static char *txnopts[] = {
+#if CONFIG_TEST
+ "-dirty",
+ "-lock_timeout",
+ "-txn_timeout",
+#endif
"-nosync",
"-nowait",
"-parent",
@@ -142,16 +146,22 @@ tcl_Txn(interp, objc, objv, envp, envip)
NULL
};
enum txnopts {
- TXN_NOSYNC,
- TXN_NOWAIT,
- TXN_PARENT,
- TXN_SYNC
+#if CONFIG_TEST
+ TXNDIRTY,
+ TXN_LOCK_TIMEOUT,
+ TXN_TIMEOUT,
+#endif
+ TXNNOSYNC,
+ TXNNOWAIT,
+ TXNPARENT,
+ TXNSYNC
};
DBTCL_INFO *ip;
DB_TXN *parent;
DB_TXN *txn;
Tcl_Obj *res;
- u_int32_t flag;
+ db_timeout_t lk_time, tx_time;
+ u_int32_t flag, lk_timeflag, tx_timeflag;
int i, optindex, result, ret;
char *arg, msg[MSG_SIZE], newname[MSG_SIZE];
@@ -160,6 +170,7 @@ tcl_Txn(interp, objc, objv, envp, envip)
parent = NULL;
flag = 0;
+ lk_timeflag = tx_timeflag = 0;
i = 2;
while (i < objc) {
if (Tcl_GetIndexFromObj(interp, objv[i],
@@ -168,7 +179,37 @@ tcl_Txn(interp, objc, objv, envp, envip)
}
i++;
switch ((enum txnopts)optindex) {
- case TXN_PARENT:
+#ifdef CONFIG_TEST
+ case TXNDIRTY:
+ flag |= DB_DIRTY_READ;
+ break;
+ case TXN_LOCK_TIMEOUT:
+ lk_timeflag = DB_SET_LOCK_TIMEOUT;
+ goto getit;
+ case TXN_TIMEOUT:
+ tx_timeflag = DB_SET_TXN_TIMEOUT;
+getit:
+ if (i >= objc) {
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "?-txn_timestamp time?");
+ return (TCL_ERROR);
+ }
+ result = Tcl_GetLongFromObj(interp, objv[i++],
+ (long *)(optindex == TXN_LOCK_TIMEOUT ?
+ &lk_time : &tx_time));
+ if (result != TCL_OK)
+ return (TCL_ERROR);
+ 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:
if (i == objc) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-parent txn?");
@@ -185,18 +226,10 @@ tcl_Txn(interp, objc, objv, envp, envip)
return (TCL_ERROR);
}
break;
- case TXN_NOWAIT:
- FLAG_CHECK(flag);
- flag |= DB_TXN_NOWAIT;
- break;
- case TXN_SYNC:
- FLAG_CHECK(flag);
+ case TXNSYNC:
+ FLAG_CHECK2(flag, DB_DIRTY_READ);
flag |= DB_TXN_SYNC;
break;
- case TXN_NOSYNC:
- FLAG_CHECK(flag);
- flag |= DB_TXN_NOSYNC;
- break;
}
}
snprintf(newname, sizeof(newname), "%s.txn%d",
@@ -208,8 +241,9 @@ tcl_Txn(interp, objc, objv, envp, envip)
return (TCL_ERROR);
}
_debug_check();
- ret = txn_begin(envp, parent, &txn, flag);
- result = _ReturnSetup(interp, ret, "txn");
+ ret = envp->txn_begin(envp, parent, &txn, flag);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn");
if (result == TCL_ERROR)
_DeleteInfo(ip);
else {
@@ -227,6 +261,24 @@ tcl_Txn(interp, objc, objv, envp, envip)
(Tcl_ObjCmdProc *)txn_Cmd, (ClientData)txn, NULL);
res = Tcl_NewStringObj(newname, strlen(newname));
Tcl_SetObjResult(interp, res);
+ if (tx_timeflag != 0) {
+ ret = txn->set_timeout(txn, tx_time, tx_timeflag);
+ if (ret != 0) {
+ result =
+ _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "set_timeout");
+ _DeleteInfo(ip);
+ }
+ }
+ if (lk_timeflag != 0) {
+ ret = txn->set_timeout(txn, lk_time, lk_timeflag);
+ if (ret != 0) {
+ result =
+ _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "set_timeout");
+ _DeleteInfo(ip);
+ }
+ }
}
return (result);
}
@@ -244,21 +296,6 @@ tcl_TxnStat(interp, objc, objv, envp)
Tcl_Obj *CONST objv[]; /* The argument objects */
DB_ENV *envp; /* Environment pointer */
{
-#define MAKE_STAT_LSN(s, lsn) \
-do { \
- myobjc = 2; \
- myobjv[0] = Tcl_NewIntObj((lsn)->file); \
- myobjv[1] = Tcl_NewIntObj((lsn)->offset); \
- lsnlist = Tcl_NewListObj(myobjc, myobjv); \
- myobjc = 2; \
- myobjv[0] = Tcl_NewStringObj((s), strlen(s)); \
- myobjv[1] = lsnlist; \
- thislist = Tcl_NewListObj(myobjc, myobjv); \
- result = Tcl_ListObjAppendElement(interp, res, thislist); \
- if (result != TCL_OK) \
- goto error; \
-} while (0);
-
DBTCL_INFO *ip;
DB_TXN_ACTIVE *p;
DB_TXN_STAT *sp;
@@ -275,8 +312,9 @@ do { \
return (TCL_ERROR);
}
_debug_check();
- ret = txn_stat(envp, &sp, NULL);
- result = _ReturnSetup(interp, ret, "txn stat");
+ ret = envp->txn_stat(envp, &sp, 0);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn stat");
if (result == TCL_ERROR)
return (result);
@@ -290,14 +328,15 @@ do { \
*/
MAKE_STAT_LIST("Region size", sp->st_regsize);
MAKE_STAT_LSN("LSN of last checkpoint", &sp->st_last_ckp);
- MAKE_STAT_LSN("LSN of pending checkpoint", &sp->st_pending_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("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 restored txns", sp->st_nrestores);
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++)
@@ -306,7 +345,7 @@ do { \
if (ip->i_type != I_TXN)
continue;
if (ip->i_type == I_TXN &&
- (txn_id(ip->i_txnp) == p->txnid)) {
+ (ip->i_txnp->id(ip->i_txnp) == p->txnid)) {
MAKE_STAT_LSN(ip->i_name, &p->lsn);
if (p->parentid != 0)
MAKE_STAT_STRLIST("Parent",
@@ -318,40 +357,78 @@ do { \
}
Tcl_SetObjResult(interp, res);
error:
- __os_free(sp, sizeof(*sp));
+ free(sp);
return (result);
}
/*
- * txn_Cmd --
- * Implements the "txn" widget.
+ * tcl_TxnTimeout --
*
- * PUBLIC: int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
+ * PUBLIC: int tcl_TxnTimeout __P((Tcl_Interp *, int,
+ * PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
*/
int
+tcl_TxnTimeout(interp, objc, objv, envp)
+ Tcl_Interp *interp; /* Interpreter */
+ int objc; /* How many arguments? */
+ Tcl_Obj *CONST objv[]; /* The argument objects */
+ DB_ENV *envp; /* Environment pointer */
+{
+ long timeout;
+ int result, ret;
+
+ /*
+ * One arg, the timeout.
+ */
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?timeout?");
+ return (TCL_ERROR);
+ }
+ result = Tcl_GetLongFromObj(interp, objv[2], &timeout);
+ if (result != TCL_OK)
+ return (result);
+ _debug_check();
+ ret = envp->set_timeout(envp, (u_int32_t)timeout, DB_SET_TXN_TIMEOUT);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "lock timeout");
+ return (result);
+}
+
+/*
+ * txn_Cmd --
+ * Implements the "txn" widget.
+ */
+static int
txn_Cmd(clientData, interp, objc, objv)
- ClientData clientData; /* Txn handle */
- Tcl_Interp *interp; /* Interpreter */
- int objc; /* How many arguments? */
- Tcl_Obj *CONST objv[]; /* The argument objects */
+ ClientData clientData; /* Txn handle */
+ Tcl_Interp *interp; /* Interpreter */
+ int objc; /* How many arguments? */
+ Tcl_Obj *CONST objv[]; /* The argument objects */
{
static char *txncmds[] = {
- "abort",
- "commit",
+#if CONFIG_TEST
+ "discard",
"id",
"prepare",
+#endif
+ "abort",
+ "commit",
NULL
};
enum txncmds {
- TXNABORT,
- TXNCOMMIT,
+#if CONFIG_TEST
+ TXNDISCARD,
TXNID,
- TXNPREPARE
+ TXNPREPARE,
+#endif
+ TXNABORT,
+ TXNCOMMIT
};
DBTCL_INFO *txnip;
DB_TXN *txnp;
Tcl_Obj *res;
int cmdindex, result, ret;
+ u_int8_t *gid;
Tcl_ResetResult(interp);
txnp = (DB_TXN *)clientData;
@@ -376,38 +453,64 @@ txn_Cmd(clientData, interp, objc, objv)
res = NULL;
switch ((enum txncmds)cmdindex) {
+#if CONFIG_TEST
+ case TXNDISCARD:
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, NULL);
+ return (TCL_ERROR);
+ }
+ _debug_check();
+ ret = txnp->discard(txnp, 0);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn discard");
+ _TxnInfoDelete(interp, txnip);
+ (void)Tcl_DeleteCommand(interp, txnip->i_name);
+ _DeleteInfo(txnip);
+ break;
case TXNID:
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return (TCL_ERROR);
}
_debug_check();
- ret = txn_id(txnp);
+ ret = txnp->id(txnp);
res = Tcl_NewIntObj(ret);
break;
case TXNPREPARE:
- if (objc != 2) {
+ if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return (TCL_ERROR);
}
_debug_check();
- ret = txn_prepare(txnp);
- result = _ReturnSetup(interp, ret, "txn prepare");
- break;
- case TXNCOMMIT:
- result = tcl_TxnCommit(interp, objc, objv, txnp, txnip);
+ gid = (u_int8_t *)Tcl_GetByteArrayFromObj(objv[2], NULL);
+ ret = txnp->prepare(txnp, gid);
+ /*
+ * !!!
+ * DB_TXN->prepare commits all outstanding children. But it
+ * does NOT destroy the current txn handle. So, we must call
+ * _TxnInfoDelete to recursively remove all nested txn handles,
+ * we do not call _DeleteInfo on ourselves.
+ */
_TxnInfoDelete(interp, txnip);
- (void)Tcl_DeleteCommand(interp, txnip->i_name);
- _DeleteInfo(txnip);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn prepare");
break;
+#endif
case TXNABORT:
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return (TCL_ERROR);
}
_debug_check();
- ret = txn_abort(txnp);
- result = _ReturnSetup(interp, ret, "txn abort");
+ ret = txnp->abort(txnp);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn abort");
+ _TxnInfoDelete(interp, txnip);
+ (void)Tcl_DeleteCommand(interp, txnip->i_name);
+ _DeleteInfo(txnip);
+ break;
+ case TXNCOMMIT:
+ result = tcl_TxnCommit(interp, objc, objv, txnp, txnip);
_TxnInfoDelete(interp, txnip);
(void)Tcl_DeleteCommand(interp, txnip->i_name);
_DeleteInfo(txnip);
@@ -424,9 +527,9 @@ txn_Cmd(clientData, interp, objc, objv)
static int
tcl_TxnCommit(interp, objc, objv, txnp, txnip)
- Tcl_Interp *interp; /* Interpreter */
- int objc; /* How many arguments? */
- Tcl_Obj *CONST objv[]; /* The argument objects */
+ Tcl_Interp *interp; /* Interpreter */
+ int objc; /* How many arguments? */
+ Tcl_Obj *CONST objv[]; /* The argument objects */
DB_TXN *txnp; /* Transaction pointer */
DBTCL_INFO *txnip; /* Info pointer */
{
@@ -467,7 +570,88 @@ tcl_TxnCommit(interp, objc, objv, txnp, txnip)
}
_debug_check();
- ret = txn_commit(txnp, flag);
- result = _ReturnSetup(interp, ret, "txn commit");
+ ret = txnp->commit(txnp, flag);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn commit");
+ return (result);
+}
+
+#if CONFIG_TEST
+/*
+ * tcl_TxnRecover --
+ *
+ * PUBLIC: int tcl_TxnRecover __P((Tcl_Interp *, int,
+ * PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
+ */
+int
+tcl_TxnRecover(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 */
+{
+#define DO_PREPLIST(count) \
+for (i = 0; i < count; i++) { \
+ 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); \
+ } \
+ envip->i_envtxnid++; \
+ ip->i_parent = envip; \
+ p = &prep[i]; \
+ _SetInfoData(ip, p->txn); \
+ Tcl_CreateObjCommand(interp, newname, \
+ (Tcl_ObjCmdProc *)txn_Cmd, (ClientData)p->txn, NULL); \
+ result = _SetListElem(interp, res, newname, strlen(newname), \
+ p->gid, DB_XIDDATASIZE); \
+ if (result != TCL_OK) \
+ goto error; \
+}
+
+ DBTCL_INFO *ip;
+ DB_PREPLIST prep[DBTCL_PREP], *p;
+ Tcl_Obj *res;
+ long count, i;
+ int result, ret;
+ char newname[MSG_SIZE];
+
+ result = TCL_OK;
+ /*
+ * No args for this. Error if there are some.
+ */
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ return (TCL_ERROR);
+ }
+ _debug_check();
+ ret = envp->txn_recover(envp, prep, DBTCL_PREP, &count, DB_FIRST);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn recover");
+ if (result == TCL_ERROR)
+ return (result);
+ res = Tcl_NewObj();
+ DO_PREPLIST(count);
+
+ /*
+ * If count returned is the maximum size we have, then there
+ * might be more. Keep going until we get them all.
+ */
+ while (count == DBTCL_PREP) {
+ ret = envp->txn_recover(
+ envp, prep, DBTCL_PREP, &count, DB_NEXT);
+ result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
+ "txn recover");
+ if (result == TCL_ERROR)
+ return (result);
+ DO_PREPLIST(count);
+ }
+ Tcl_SetObjResult(interp, res);
+error:
return (result);
}
+#endif