tcl_txn.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: tcl_txn.c,v 11.24 2000/12/31 19:26:23 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <tcl.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "tcl_db.h"
  19. /*
  20.  * Prototypes for procedures defined later in this file:
  21.  */
  22. static int      tcl_TxnCommit __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  23.     DB_TXN *, DBTCL_INFO *));
  24. /*
  25.  * _TxnInfoDelete --
  26.  * Removes nested txn info structures that are children
  27.  * of this txn.
  28.  * RECURSIVE:  Transactions can be arbitrarily nested, so we
  29.  * must recurse down until we get them all.
  30.  *
  31.  * PUBLIC: void _TxnInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
  32.  */
  33. void
  34. _TxnInfoDelete(interp, txnip)
  35. Tcl_Interp *interp;             /* Interpreter */
  36. DBTCL_INFO *txnip; /* Info for txn */
  37. {
  38. DBTCL_INFO *nextp, *p;
  39. for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
  40. /*
  41.  * Check if this info structure "belongs" to this
  42.  * txn.  Remove its commands and info structure.
  43.  */
  44. nextp = LIST_NEXT(p, entries);
  45.  if (p->i_parent == txnip && p->i_type == I_TXN) {
  46. _TxnInfoDelete(interp, p);
  47. (void)Tcl_DeleteCommand(interp, p->i_name);
  48. _DeleteInfo(p);
  49. }
  50. }
  51. }
  52. /*
  53.  * tcl_TxnCheckpoint --
  54.  *
  55.  * PUBLIC: int tcl_TxnCheckpoint __P((Tcl_Interp *, int,
  56.  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
  57.  */
  58. int
  59. tcl_TxnCheckpoint(interp, objc, objv, envp)
  60. Tcl_Interp *interp; /* Interpreter */
  61. int objc; /* How many arguments? */
  62. Tcl_Obj *CONST objv[]; /* The argument objects */
  63. DB_ENV *envp; /* Environment pointer */
  64. {
  65. static char *txnckpopts[] = {
  66. "-kbyte", "-min",
  67. NULL
  68. };
  69. enum txnckpopts {
  70. TXNCKP_KB, TXNCKP_MIN
  71. };
  72. int i, kb, min, optindex, result, ret;
  73. result = TCL_OK;
  74. kb = min = 0;
  75. /*
  76.  * Get the flag index from the object based on the options
  77.  * defined above.
  78.  */
  79. i = 2;
  80. while (i < objc) {
  81. if (Tcl_GetIndexFromObj(interp, objv[i],
  82.     txnckpopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
  83. return (IS_HELP(objv[i]));
  84. }
  85. i++;
  86. switch ((enum txnckpopts)optindex) {
  87. case TXNCKP_KB:
  88. if (i == objc) {
  89. Tcl_WrongNumArgs(interp, 2, objv,
  90.     "?-kbyte kb?");
  91. result = TCL_ERROR;
  92. break;
  93. }
  94. result = Tcl_GetIntFromObj(interp, objv[i++], &kb);
  95. break;
  96. case TXNCKP_MIN:
  97. if (i == objc) {
  98. Tcl_WrongNumArgs(interp, 2, objv, "?-min min?");
  99. result = TCL_ERROR;
  100. break;
  101. }
  102. result = Tcl_GetIntFromObj(interp, objv[i++], &min);
  103. break;
  104. }
  105. }
  106. _debug_check();
  107. ret = txn_checkpoint(envp, (u_int32_t)kb, (u_int32_t)min, 0);
  108. result = _ReturnSetup(interp, ret, "txn checkpoint");
  109. return (result);
  110. }
  111. /*
  112.  * tcl_Txn --
  113.  *
  114.  * PUBLIC: int tcl_Txn __P((Tcl_Interp *, int,
  115.  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
  116.  */
  117. int
  118. tcl_Txn(interp, objc, objv, envp, envip)
  119. Tcl_Interp *interp; /* Interpreter */
  120. int objc; /* How many arguments? */
  121. Tcl_Obj *CONST objv[]; /* The argument objects */
  122. DB_ENV *envp; /* Environment pointer */
  123. DBTCL_INFO *envip; /* Info pointer */
  124. {
  125. static char *txnopts[] = {
  126. "-nosync",
  127. "-nowait",
  128. "-parent",
  129. "-sync",
  130. NULL
  131. };
  132. enum txnopts {
  133. TXN_NOSYNC,
  134. TXN_NOWAIT,
  135. TXN_PARENT,
  136. TXN_SYNC
  137. };
  138. DBTCL_INFO *ip;
  139. DB_TXN *parent;
  140. DB_TXN *txn;
  141. Tcl_Obj *res;
  142. u_int32_t flag;
  143. int i, optindex, result, ret;
  144. char *arg, msg[MSG_SIZE], newname[MSG_SIZE];
  145. result = TCL_OK;
  146. memset(newname, 0, MSG_SIZE);
  147. parent = NULL;
  148. flag = 0;
  149. i = 2;
  150. while (i < objc) {
  151. if (Tcl_GetIndexFromObj(interp, objv[i],
  152.     txnopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
  153. return (IS_HELP(objv[i]));
  154. }
  155. i++;
  156. switch ((enum txnopts)optindex) {
  157. case TXN_PARENT:
  158. if (i == objc) {
  159. Tcl_WrongNumArgs(interp, 2, objv,
  160.     "?-parent txn?");
  161. result = TCL_ERROR;
  162. break;
  163. }
  164. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  165. parent = NAME_TO_TXN(arg);
  166. if (parent == NULL) {
  167. snprintf(msg, MSG_SIZE,
  168.     "Invalid parent txn: %sn",
  169.     arg);
  170. Tcl_SetResult(interp, msg, TCL_VOLATILE);
  171. return (TCL_ERROR);
  172. }
  173. break;
  174. case TXN_NOWAIT:
  175. FLAG_CHECK(flag);
  176. flag |= DB_TXN_NOWAIT;
  177. break;
  178. case TXN_SYNC:
  179. FLAG_CHECK(flag);
  180. flag |= DB_TXN_SYNC;
  181. break;
  182. case TXN_NOSYNC:
  183. FLAG_CHECK(flag);
  184. flag |= DB_TXN_NOSYNC;
  185. break;
  186. }
  187. }
  188. snprintf(newname, sizeof(newname), "%s.txn%d",
  189.     envip->i_name, envip->i_envtxnid);
  190. ip = _NewInfo(interp, NULL, newname, I_TXN);
  191. if (ip == NULL) {
  192. Tcl_SetResult(interp, "Could not set up info",
  193.     TCL_STATIC);
  194. return (TCL_ERROR);
  195. }
  196. _debug_check();
  197. ret = txn_begin(envp, parent, &txn, flag);
  198. result = _ReturnSetup(interp, ret, "txn");
  199. if (result == TCL_ERROR)
  200. _DeleteInfo(ip);
  201. else {
  202. /*
  203.  * Success.  Set up return.  Set up new info
  204.  * and command widget for this txn.
  205.  */
  206. envip->i_envtxnid++;
  207. if (parent)
  208. ip->i_parent = _PtrToInfo(parent);
  209. else
  210. ip->i_parent = envip;
  211. _SetInfoData(ip, txn);
  212. Tcl_CreateObjCommand(interp, newname,
  213.     (Tcl_ObjCmdProc *)txn_Cmd, (ClientData)txn, NULL);
  214. res = Tcl_NewStringObj(newname, strlen(newname));
  215. Tcl_SetObjResult(interp, res);
  216. }
  217. return (result);
  218. }
  219. /*
  220.  * tcl_TxnStat --
  221.  *
  222.  * PUBLIC: int tcl_TxnStat __P((Tcl_Interp *, int,
  223.  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
  224.  */
  225. int
  226. tcl_TxnStat(interp, objc, objv, envp)
  227. Tcl_Interp *interp; /* Interpreter */
  228. int objc; /* How many arguments? */
  229. Tcl_Obj *CONST objv[]; /* The argument objects */
  230. DB_ENV *envp; /* Environment pointer */
  231. {
  232. #define MAKE_STAT_LSN(s, lsn)
  233. do {
  234. myobjc = 2;
  235. myobjv[0] = Tcl_NewIntObj((lsn)->file);
  236. myobjv[1] = Tcl_NewIntObj((lsn)->offset);
  237. lsnlist = Tcl_NewListObj(myobjc, myobjv);
  238. myobjc = 2;
  239. myobjv[0] = Tcl_NewStringObj((s), strlen(s));
  240. myobjv[1] = lsnlist;
  241. thislist = Tcl_NewListObj(myobjc, myobjv);
  242. result = Tcl_ListObjAppendElement(interp, res, thislist);
  243. if (result != TCL_OK)
  244. goto error;
  245. } while (0);
  246. DBTCL_INFO *ip;
  247. DB_TXN_ACTIVE *p;
  248. DB_TXN_STAT *sp;
  249. Tcl_Obj *myobjv[2], *res, *thislist, *lsnlist;
  250. u_int32_t i;
  251. int myobjc, result, ret;
  252. result = TCL_OK;
  253. /*
  254.  * No args for this.  Error if there are some.
  255.  */
  256. if (objc != 2) {
  257. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  258. return (TCL_ERROR);
  259. }
  260. _debug_check();
  261. ret = txn_stat(envp, &sp, NULL);
  262. result = _ReturnSetup(interp, ret, "txn stat");
  263. if (result == TCL_ERROR)
  264. return (result);
  265. /*
  266.  * Have our stats, now construct the name value
  267.  * list pairs and free up the memory.
  268.  */
  269. res = Tcl_NewObj();
  270. /*
  271.  * MAKE_STAT_LIST assumes 'res' and 'error' label.
  272.  */
  273. MAKE_STAT_LIST("Region size", sp->st_regsize);
  274. MAKE_STAT_LSN("LSN of last checkpoint", &sp->st_last_ckp);
  275. MAKE_STAT_LSN("LSN of pending checkpoint", &sp->st_pending_ckp);
  276. MAKE_STAT_LIST("Time of last checkpoint", sp->st_time_ckp);
  277. MAKE_STAT_LIST("Last txn ID allocated", sp->st_last_txnid);
  278. MAKE_STAT_LIST("Max Txns", sp->st_maxtxns);
  279. MAKE_STAT_LIST("Number aborted txns", sp->st_naborts);
  280. MAKE_STAT_LIST("Number active txns", sp->st_nactive);
  281. MAKE_STAT_LIST("Number txns begun", sp->st_nbegins);
  282. MAKE_STAT_LIST("Number committed txns", sp->st_ncommits);
  283. MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
  284. MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
  285. for (i = 0, p = sp->st_txnarray; i < sp->st_nactive; i++, p++)
  286. for (ip = LIST_FIRST(&__db_infohead); ip != NULL;
  287.     ip = LIST_NEXT(ip, entries)) {
  288. if (ip->i_type != I_TXN)
  289. continue;
  290. if (ip->i_type == I_TXN &&
  291.     (txn_id(ip->i_txnp) == p->txnid)) {
  292. MAKE_STAT_LSN(ip->i_name, &p->lsn);
  293. if (p->parentid != 0)
  294. MAKE_STAT_STRLIST("Parent",
  295.     ip->i_parent->i_name);
  296. else
  297. MAKE_STAT_LIST("Parent", 0);
  298. break;
  299. }
  300. }
  301. Tcl_SetObjResult(interp, res);
  302. error:
  303. __os_free(sp, sizeof(*sp));
  304. return (result);
  305. }
  306. /*
  307.  * txn_Cmd --
  308.  * Implements the "txn" widget.
  309.  *
  310.  * PUBLIC: int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
  311.  */
  312. int
  313. txn_Cmd(clientData, interp, objc, objv)
  314. ClientData clientData;          /* Txn handle */
  315. Tcl_Interp *interp;             /* Interpreter */
  316. int objc;                       /* How many arguments? */
  317. Tcl_Obj *CONST objv[];          /* The argument objects */
  318. {
  319. static char *txncmds[] = {
  320. "abort",
  321. "commit",
  322. "id",
  323. "prepare",
  324. NULL
  325. };
  326. enum txncmds {
  327. TXNABORT,
  328. TXNCOMMIT,
  329. TXNID,
  330. TXNPREPARE
  331. };
  332. DBTCL_INFO *txnip;
  333. DB_TXN *txnp;
  334. Tcl_Obj *res;
  335. int cmdindex, result, ret;
  336. Tcl_ResetResult(interp);
  337. txnp = (DB_TXN *)clientData;
  338. txnip = _PtrToInfo((void *)txnp);
  339. result = TCL_OK;
  340. if (txnp == NULL) {
  341. Tcl_SetResult(interp, "NULL txn pointer", TCL_STATIC);
  342. return (TCL_ERROR);
  343. }
  344. if (txnip == NULL) {
  345. Tcl_SetResult(interp, "NULL txn info pointer", TCL_STATIC);
  346. return (TCL_ERROR);
  347. }
  348. /*
  349.  * Get the command name index from the object based on the dbcmds
  350.  * defined above.
  351.  */
  352. if (Tcl_GetIndexFromObj(interp,
  353.     objv[1], txncmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  354. return (IS_HELP(objv[1]));
  355. res = NULL;
  356. switch ((enum txncmds)cmdindex) {
  357. case TXNID:
  358. if (objc != 2) {
  359. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  360. return (TCL_ERROR);
  361. }
  362. _debug_check();
  363. ret = txn_id(txnp);
  364. res = Tcl_NewIntObj(ret);
  365. break;
  366. case TXNPREPARE:
  367. if (objc != 2) {
  368. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  369. return (TCL_ERROR);
  370. }
  371. _debug_check();
  372. ret = txn_prepare(txnp);
  373. result = _ReturnSetup(interp, ret, "txn prepare");
  374. break;
  375. case TXNCOMMIT:
  376. result = tcl_TxnCommit(interp, objc, objv, txnp, txnip);
  377. _TxnInfoDelete(interp, txnip);
  378. (void)Tcl_DeleteCommand(interp, txnip->i_name);
  379. _DeleteInfo(txnip);
  380. break;
  381. case TXNABORT:
  382. if (objc != 2) {
  383. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  384. return (TCL_ERROR);
  385. }
  386. _debug_check();
  387. ret = txn_abort(txnp);
  388. result = _ReturnSetup(interp, ret, "txn abort");
  389. _TxnInfoDelete(interp, txnip);
  390. (void)Tcl_DeleteCommand(interp, txnip->i_name);
  391. _DeleteInfo(txnip);
  392. break;
  393. }
  394. /*
  395.  * Only set result if we have a res.  Otherwise, lower
  396.  * functions have already done so.
  397.  */
  398. if (result == TCL_OK && res)
  399. Tcl_SetObjResult(interp, res);
  400. return (result);
  401. }
  402. static int
  403. tcl_TxnCommit(interp, objc, objv, txnp, txnip)
  404. Tcl_Interp *interp;             /* Interpreter */
  405. int objc;                       /* How many arguments? */
  406. Tcl_Obj *CONST objv[];          /* The argument objects */
  407. DB_TXN *txnp; /* Transaction pointer */
  408. DBTCL_INFO *txnip; /* Info pointer */
  409. {
  410. static char *commitopt[] = {
  411. "-nosync",
  412. "-sync",
  413. NULL
  414. };
  415. enum commitopt {
  416. COMSYNC,
  417. COMNOSYNC
  418. };
  419. u_int32_t flag;
  420. int optindex, result, ret;
  421. COMPQUIET(txnip, NULL);
  422. result = TCL_OK;
  423. flag = 0;
  424. if (objc != 2 && objc != 3) {
  425. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  426. return (TCL_ERROR);
  427. }
  428. if (objc == 3) {
  429. if (Tcl_GetIndexFromObj(interp, objv[2], commitopt,
  430.     "option", TCL_EXACT, &optindex) != TCL_OK)
  431. return (IS_HELP(objv[2]));
  432. switch ((enum commitopt)optindex) {
  433. case COMSYNC:
  434. FLAG_CHECK(flag);
  435. flag = DB_TXN_SYNC;
  436. break;
  437. case COMNOSYNC:
  438. FLAG_CHECK(flag);
  439. flag = DB_TXN_NOSYNC;
  440. break;
  441. }
  442. }
  443. _debug_check();
  444. ret = txn_commit(txnp, flag);
  445. result = _ReturnSetup(interp, ret, "txn commit");
  446. return (result);
  447. }