diff options
Diffstat (limited to 'bdb/tcl/tcl_txn.c')
-rw-r--r-- | bdb/tcl/tcl_txn.c | 338 |
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 |