tcl_mp.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:20k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2001
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: tcl_mp.c,v 11.39 2002/08/06 06:21:27 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 "dbinc/tcl_db.h"
  19. /*
  20.  * Prototypes for procedures defined later in this file:
  21.  */
  22. static int      mp_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
  23. static int      pg_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
  24. static int      tcl_MpGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  25.     DB_MPOOLFILE *, DBTCL_INFO *));
  26. static int      tcl_Pg __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  27.     void *, DB_MPOOLFILE *, DBTCL_INFO *, int));
  28. static int      tcl_PgInit __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  29.     void *, DBTCL_INFO *));
  30. static int      tcl_PgIsset __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  31.     void *, DBTCL_INFO *));
  32. /*
  33.  * _MpInfoDelete --
  34.  * Removes "sub" mp page info structures that are children
  35.  * of this mp.
  36.  *
  37.  * PUBLIC: void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
  38.  */
  39. void
  40. _MpInfoDelete(interp, mpip)
  41. Tcl_Interp *interp; /* Interpreter */
  42. DBTCL_INFO *mpip; /* Info for mp */
  43. {
  44. DBTCL_INFO *nextp, *p;
  45. for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
  46. /*
  47.  * Check if this info structure "belongs" to this
  48.  * mp.  Remove its commands and info structure.
  49.  */
  50. nextp = LIST_NEXT(p, entries);
  51.  if (p->i_parent == mpip && p->i_type == I_PG) {
  52. (void)Tcl_DeleteCommand(interp, p->i_name);
  53. _DeleteInfo(p);
  54. }
  55. }
  56. }
  57. #if CONFIG_TEST
  58. /*
  59.  * tcl_MpSync --
  60.  *
  61.  * PUBLIC: int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
  62.  */
  63. int
  64. tcl_MpSync(interp, objc, objv, envp)
  65. Tcl_Interp *interp; /* Interpreter */
  66. int objc; /* How many arguments? */
  67. Tcl_Obj *CONST objv[]; /* The argument objects */
  68. DB_ENV *envp; /* Environment pointer */
  69. {
  70. DB_LSN lsn, *lsnp;
  71. int result, ret;
  72. result = TCL_OK;
  73. lsnp = NULL;
  74. /*
  75.  * No flags, must be 3 args.
  76.  */
  77. if (objc == 3) {
  78. result = _GetLsn(interp, objv[2], &lsn);
  79. if (result == TCL_ERROR)
  80. return (result);
  81. lsnp = &lsn;
  82. }
  83. else if (objc != 2) {
  84. Tcl_WrongNumArgs(interp, 2, objv, "lsn");
  85. return (TCL_ERROR);
  86. }
  87. _debug_check();
  88. ret = envp->memp_sync(envp, lsnp);
  89. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp sync");
  90. return (result);
  91. }
  92. /*
  93.  * tcl_MpTrickle --
  94.  *
  95.  * PUBLIC: int tcl_MpTrickle __P((Tcl_Interp *, int,
  96.  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
  97.  */
  98. int
  99. tcl_MpTrickle(interp, objc, objv, envp)
  100. Tcl_Interp *interp; /* Interpreter */
  101. int objc; /* How many arguments? */
  102. Tcl_Obj *CONST objv[]; /* The argument objects */
  103. DB_ENV *envp; /* Environment pointer */
  104. {
  105. int pages;
  106. int percent;
  107. int result;
  108. int ret;
  109. Tcl_Obj *res;
  110. result = TCL_OK;
  111. /*
  112.  * No flags, must be 3 args.
  113.  */
  114. if (objc != 3) {
  115. Tcl_WrongNumArgs(interp, 2, objv, "percent");
  116. return (TCL_ERROR);
  117. }
  118. result = Tcl_GetIntFromObj(interp, objv[2], &percent);
  119. if (result == TCL_ERROR)
  120. return (result);
  121. _debug_check();
  122. ret = envp->memp_trickle(envp, percent, &pages);
  123. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp trickle");
  124. if (result == TCL_ERROR)
  125. return (result);
  126. res = Tcl_NewIntObj(pages);
  127. Tcl_SetObjResult(interp, res);
  128. return (result);
  129. }
  130. /*
  131.  * tcl_Mp --
  132.  *
  133.  * PUBLIC: int tcl_Mp __P((Tcl_Interp *, int,
  134.  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
  135.  */
  136. int
  137. tcl_Mp(interp, objc, objv, envp, envip)
  138. Tcl_Interp *interp; /* Interpreter */
  139. int objc; /* How many arguments? */
  140. Tcl_Obj *CONST objv[]; /* The argument objects */
  141. DB_ENV *envp; /* Environment pointer */
  142. DBTCL_INFO *envip; /* Info pointer */
  143. {
  144. static char *mpopts[] = {
  145. "-create",
  146. "-mode",
  147. "-nommap",
  148. "-pagesize",
  149. "-rdonly",
  150.  NULL
  151. };
  152. enum mpopts {
  153. MPCREATE,
  154. MPMODE,
  155. MPNOMMAP,
  156. MPPAGE,
  157. MPRDONLY
  158. };
  159. DBTCL_INFO *ip;
  160. DB_MPOOLFILE *mpf;
  161. Tcl_Obj *res;
  162. u_int32_t flag;
  163. int i, pgsize, mode, optindex, result, ret;
  164. char *file, newname[MSG_SIZE];
  165. result = TCL_OK;
  166. i = 2;
  167. flag = 0;
  168. mode = 0;
  169. pgsize = 0;
  170. memset(newname, 0, MSG_SIZE);
  171. while (i < objc) {
  172. if (Tcl_GetIndexFromObj(interp, objv[i],
  173.     mpopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
  174. /*
  175.  * Reset the result so we don't get an errant
  176.  * error message if there is another error.
  177.  * This arg is the file name.
  178.  */
  179. if (IS_HELP(objv[i]) == TCL_OK)
  180. return (TCL_OK);
  181. Tcl_ResetResult(interp);
  182. break;
  183. }
  184. i++;
  185. switch ((enum mpopts)optindex) {
  186. case MPCREATE:
  187. flag |= DB_CREATE;
  188. break;
  189. case MPNOMMAP:
  190. flag |= DB_NOMMAP;
  191. break;
  192. case MPPAGE:
  193. if (i >= objc) {
  194. Tcl_WrongNumArgs(interp, 2, objv,
  195.     "?-pagesize size?");
  196. result = TCL_ERROR;
  197. break;
  198. }
  199. /*
  200.  * Don't need to check result here because
  201.  * if TCL_ERROR, the error message is already
  202.  * set up, and we'll bail out below.  If ok,
  203.  * the mode is set and we go on.
  204.  */
  205. result = Tcl_GetIntFromObj(interp, objv[i++], &pgsize);
  206. break;
  207. case MPRDONLY:
  208. flag |= DB_RDONLY;
  209. break;
  210. case MPMODE:
  211. if (i >= objc) {
  212. Tcl_WrongNumArgs(interp, 2, objv,
  213.     "?-mode mode?");
  214. result = TCL_ERROR;
  215. break;
  216. }
  217. /*
  218.  * Don't need to check result here because
  219.  * if TCL_ERROR, the error message is already
  220.  * set up, and we'll bail out below.  If ok,
  221.  * the mode is set and we go on.
  222.  */
  223. result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
  224. break;
  225. }
  226. if (result != TCL_OK)
  227. goto error;
  228. }
  229. /*
  230.  * Any left over arg is a file name.  It better be the last arg.
  231.  */
  232. file = NULL;
  233. if (i != objc) {
  234. if (i != objc - 1) {
  235. Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?");
  236. result = TCL_ERROR;
  237. goto error;
  238. }
  239. file = Tcl_GetStringFromObj(objv[i++], NULL);
  240. }
  241. snprintf(newname, sizeof(newname), "%s.mp%d",
  242.     envip->i_name, envip->i_envmpid);
  243. ip = _NewInfo(interp, NULL, newname, I_MP);
  244. if (ip == NULL) {
  245. Tcl_SetResult(interp, "Could not set up info",
  246.     TCL_STATIC);
  247. return (TCL_ERROR);
  248. }
  249. _debug_check();
  250. if ((ret = envp->memp_fcreate(envp, &mpf, 0)) != 0) {
  251. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mpool");
  252. _DeleteInfo(ip);
  253. goto error;
  254. }
  255. /*
  256.  * XXX
  257.  * Interface doesn't currently support DB_MPOOLFILE configuration.
  258.  */
  259. if ((ret = mpf->open(mpf, file, flag, mode, (size_t)pgsize)) != 0) {
  260. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mpool");
  261. _DeleteInfo(ip);
  262. (void)mpf->close(mpf, 0);
  263. goto error;
  264. }
  265. /*
  266.  * Success.  Set up return.  Set up new info and command widget for
  267.  * this mpool.
  268.  */
  269. envip->i_envmpid++;
  270. ip->i_parent = envip;
  271. ip->i_pgsz = pgsize;
  272. _SetInfoData(ip, mpf);
  273. Tcl_CreateObjCommand(interp, newname,
  274.     (Tcl_ObjCmdProc *)mp_Cmd, (ClientData)mpf, NULL);
  275. res = Tcl_NewStringObj(newname, strlen(newname));
  276. Tcl_SetObjResult(interp, res);
  277. error:
  278. return (result);
  279. }
  280. /*
  281.  * tcl_MpStat --
  282.  *
  283.  * PUBLIC: int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
  284.  */
  285. int
  286. tcl_MpStat(interp, objc, objv, envp)
  287. Tcl_Interp *interp; /* Interpreter */
  288. int objc; /* How many arguments? */
  289. Tcl_Obj *CONST objv[]; /* The argument objects */
  290. DB_ENV *envp; /* Environment pointer */
  291. {
  292. DB_MPOOL_STAT *sp;
  293. DB_MPOOL_FSTAT **fsp, **savefsp;
  294. int result;
  295. int ret;
  296. Tcl_Obj *res;
  297. Tcl_Obj *res1;
  298. result = TCL_OK;
  299. savefsp = NULL;
  300. /*
  301.  * No args for this.  Error if there are some.
  302.  */
  303. if (objc != 2) {
  304. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  305. return (TCL_ERROR);
  306. }
  307. _debug_check();
  308. ret = envp->memp_stat(envp, &sp, &fsp, 0);
  309. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp stat");
  310. if (result == TCL_ERROR)
  311. return (result);
  312. /*
  313.  * Have our stats, now construct the name value
  314.  * list pairs and free up the memory.
  315.  */
  316. res = Tcl_NewObj();
  317. /*
  318.  * MAKE_STAT_LIST assumes 'res' and 'error' label.
  319.  */
  320. MAKE_STAT_LIST("Cache size (gbytes)", sp->st_gbytes);
  321. MAKE_STAT_LIST("Cache size (bytes)", sp->st_bytes);
  322. MAKE_STAT_LIST("Number of caches", sp->st_ncache);
  323. MAKE_STAT_LIST("Region size", sp->st_regsize);
  324. MAKE_STAT_LIST("Pages mapped into address space", sp->st_map);
  325. MAKE_STAT_LIST("Cache hits", sp->st_cache_hit);
  326. MAKE_STAT_LIST("Cache misses", sp->st_cache_miss);
  327. MAKE_STAT_LIST("Pages created", sp->st_page_create);
  328. MAKE_STAT_LIST("Pages read in", sp->st_page_in);
  329. MAKE_STAT_LIST("Pages written", sp->st_page_out);
  330. MAKE_STAT_LIST("Clean page evictions", sp->st_ro_evict);
  331. MAKE_STAT_LIST("Dirty page evictions", sp->st_rw_evict);
  332. MAKE_STAT_LIST("Dirty pages trickled", sp->st_page_trickle);
  333. MAKE_STAT_LIST("Cached pages", sp->st_pages);
  334. MAKE_STAT_LIST("Cached clean pages", sp->st_page_clean);
  335. MAKE_STAT_LIST("Cached dirty pages", sp->st_page_dirty);
  336. MAKE_STAT_LIST("Hash buckets", sp->st_hash_buckets);
  337. MAKE_STAT_LIST("Hash lookups", sp->st_hash_searches);
  338. MAKE_STAT_LIST("Longest hash chain found", sp->st_hash_longest);
  339. MAKE_STAT_LIST("Hash elements examined", sp->st_hash_examined);
  340. MAKE_STAT_LIST("Number of hash bucket nowaits", sp->st_hash_nowait);
  341. MAKE_STAT_LIST("Number of hash bucket waits", sp->st_hash_wait);
  342. MAKE_STAT_LIST("Maximum number of hash bucket waits",
  343.     sp->st_hash_max_wait);
  344. MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
  345. MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
  346. MAKE_STAT_LIST("Page allocations", sp->st_alloc);
  347. MAKE_STAT_LIST("Buckets examined during allocation",
  348.     sp->st_alloc_buckets);
  349. MAKE_STAT_LIST("Maximum buckets examined during allocation",
  350.     sp->st_alloc_max_buckets);
  351. MAKE_STAT_LIST("Pages examined during allocation", sp->st_alloc_pages);
  352. MAKE_STAT_LIST("Maximum pages examined during allocation",
  353.     sp->st_alloc_max_pages);
  354. /*
  355.  * Save global stat list as res1.  The MAKE_STAT_LIST
  356.  * macro assumes 'res' so we'll use that to build up
  357.  * our per-file sublist.
  358.  */
  359. res1 = res;
  360. for (savefsp = fsp; fsp != NULL && *fsp != NULL; fsp++) {
  361. res = Tcl_NewObj();
  362. result = _SetListElem(interp, res, "File Name",
  363.     strlen("File Name"), (*fsp)->file_name,
  364.     strlen((*fsp)->file_name));
  365. if (result != TCL_OK)
  366. goto error;
  367. MAKE_STAT_LIST("Page size", (*fsp)->st_pagesize);
  368. MAKE_STAT_LIST("Pages mapped into address space",
  369.     (*fsp)->st_map);
  370. MAKE_STAT_LIST("Cache hits", (*fsp)->st_cache_hit);
  371. MAKE_STAT_LIST("Cache misses", (*fsp)->st_cache_miss);
  372. MAKE_STAT_LIST("Pages created", (*fsp)->st_page_create);
  373. MAKE_STAT_LIST("Pages read in", (*fsp)->st_page_in);
  374. MAKE_STAT_LIST("Pages written", (*fsp)->st_page_out);
  375. /*
  376.  * Now that we have a complete "per-file" stat list, append
  377.  * that to the other list.
  378.  */
  379. result = Tcl_ListObjAppendElement(interp, res1, res);
  380. if (result != TCL_OK)
  381. goto error;
  382. }
  383. Tcl_SetObjResult(interp, res1);
  384. error:
  385. free(sp);
  386. if (savefsp != NULL)
  387. free(savefsp);
  388. return (result);
  389. }
  390. /*
  391.  * mp_Cmd --
  392.  * Implements the "mp" widget.
  393.  */
  394. static int
  395. mp_Cmd(clientData, interp, objc, objv)
  396. ClientData clientData; /* Mp handle */
  397. Tcl_Interp *interp; /* Interpreter */
  398. int objc; /* How many arguments? */
  399. Tcl_Obj *CONST objv[]; /* The argument objects */
  400. {
  401. static char *mpcmds[] = {
  402. "close",
  403. "fsync",
  404. "get",
  405. NULL
  406. };
  407. enum mpcmds {
  408. MPCLOSE,
  409. MPFSYNC,
  410. MPGET
  411. };
  412. DB_MPOOLFILE *mp;
  413. int cmdindex, length, result, ret;
  414. DBTCL_INFO *mpip;
  415. Tcl_Obj *res;
  416. char *obj_name;
  417. Tcl_ResetResult(interp);
  418. mp = (DB_MPOOLFILE *)clientData;
  419. obj_name = Tcl_GetStringFromObj(objv[0], &length);
  420. mpip = _NameToInfo(obj_name);
  421. result = TCL_OK;
  422. if (mp == NULL) {
  423. Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
  424. return (TCL_ERROR);
  425. }
  426. if (mpip == NULL) {
  427. Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC);
  428. return (TCL_ERROR);
  429. }
  430. /*
  431.  * Get the command name index from the object based on the dbcmds
  432.  * defined above.
  433.  */
  434. if (Tcl_GetIndexFromObj(interp,
  435.     objv[1], mpcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  436. return (IS_HELP(objv[1]));
  437. res = NULL;
  438. switch ((enum mpcmds)cmdindex) {
  439. case MPCLOSE:
  440. if (objc != 2) {
  441. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  442. return (TCL_ERROR);
  443. }
  444. _debug_check();
  445. ret = mp->close(mp, 0);
  446. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  447.     "mp close");
  448. _MpInfoDelete(interp, mpip);
  449. (void)Tcl_DeleteCommand(interp, mpip->i_name);
  450. _DeleteInfo(mpip);
  451. break;
  452. case MPFSYNC:
  453. if (objc != 2) {
  454. Tcl_WrongNumArgs(interp, 1, objv, NULL);
  455. return (TCL_ERROR);
  456. }
  457. _debug_check();
  458. ret = mp->sync(mp);
  459. res = Tcl_NewIntObj(ret);
  460. break;
  461. case MPGET:
  462. result = tcl_MpGet(interp, objc, objv, mp, mpip);
  463. break;
  464. }
  465. /*
  466.  * Only set result if we have a res.  Otherwise, lower
  467.  * functions have already done so.
  468.  */
  469. if (result == TCL_OK && res)
  470. Tcl_SetObjResult(interp, res);
  471. return (result);
  472. }
  473. /*
  474.  * tcl_MpGet --
  475.  */
  476. static int
  477. tcl_MpGet(interp, objc, objv, mp, mpip)
  478. Tcl_Interp *interp; /* Interpreter */
  479. int objc; /* How many arguments? */
  480. Tcl_Obj *CONST objv[]; /* The argument objects */
  481. DB_MPOOLFILE *mp; /* mp pointer */
  482. DBTCL_INFO *mpip; /* mp info pointer */
  483. {
  484. static char *mpget[] = {
  485. "-create",
  486. "-last",
  487. "-new",
  488. NULL
  489. };
  490. enum mpget {
  491. MPGET_CREATE,
  492. MPGET_LAST,
  493. MPGET_NEW
  494. };
  495. DBTCL_INFO *ip;
  496. Tcl_Obj *res;
  497. db_pgno_t pgno;
  498. u_int32_t flag;
  499. int i, ipgno, optindex, result, ret;
  500. char newname[MSG_SIZE];
  501. void *page;
  502. result = TCL_OK;
  503. memset(newname, 0, MSG_SIZE);
  504. i = 2;
  505. flag = 0;
  506. while (i < objc) {
  507. if (Tcl_GetIndexFromObj(interp, objv[i],
  508.     mpget, "option", TCL_EXACT, &optindex) != TCL_OK) {
  509. /*
  510.  * Reset the result so we don't get an errant
  511.  * error message if there is another error.
  512.  * This arg is the page number.
  513.  */
  514. if (IS_HELP(objv[i]) == TCL_OK)
  515. return (TCL_OK);
  516. Tcl_ResetResult(interp);
  517. break;
  518. }
  519. i++;
  520. switch ((enum mpget)optindex) {
  521. case MPGET_CREATE:
  522. flag |= DB_MPOOL_CREATE;
  523. break;
  524. case MPGET_LAST:
  525. flag |= DB_MPOOL_LAST;
  526. break;
  527. case MPGET_NEW:
  528. flag |= DB_MPOOL_NEW;
  529. break;
  530. }
  531. if (result != TCL_OK)
  532. goto error;
  533. }
  534. /*
  535.  * Any left over arg is a page number.  It better be the last arg.
  536.  */
  537. ipgno = 0;
  538. if (i != objc) {
  539. if (i != objc - 1) {
  540. Tcl_WrongNumArgs(interp, 2, objv, "?args? ?pgno?");
  541. result = TCL_ERROR;
  542. goto error;
  543. }
  544. result = Tcl_GetIntFromObj(interp, objv[i++], &ipgno);
  545. if (result != TCL_OK)
  546. goto error;
  547. }
  548. snprintf(newname, sizeof(newname), "%s.pg%d",
  549.     mpip->i_name, mpip->i_mppgid);
  550. ip = _NewInfo(interp, NULL, newname, I_PG);
  551. if (ip == NULL) {
  552. Tcl_SetResult(interp, "Could not set up info",
  553.     TCL_STATIC);
  554. return (TCL_ERROR);
  555. }
  556. _debug_check();
  557. pgno = ipgno;
  558. ret = mp->get(mp, &pgno, flag, &page);
  559. result = _ReturnSetup(interp, ret, DB_RETOK_MPGET(ret), "mpool get");
  560. if (result == TCL_ERROR)
  561. _DeleteInfo(ip);
  562. else {
  563. /*
  564.  * Success.  Set up return.  Set up new info
  565.  * and command widget for this mpool.
  566.  */
  567. mpip->i_mppgid++;
  568. ip->i_parent = mpip;
  569. ip->i_pgno = pgno;
  570. ip->i_pgsz = mpip->i_pgsz;
  571. _SetInfoData(ip, page);
  572. Tcl_CreateObjCommand(interp, newname,
  573.     (Tcl_ObjCmdProc *)pg_Cmd, (ClientData)page, NULL);
  574. res = Tcl_NewStringObj(newname, strlen(newname));
  575. Tcl_SetObjResult(interp, res);
  576. }
  577. error:
  578. return (result);
  579. }
  580. /*
  581.  * pg_Cmd --
  582.  * Implements the "pg" widget.
  583.  */
  584. static int
  585. pg_Cmd(clientData, interp, objc, objv)
  586. ClientData clientData; /* Page handle */
  587. Tcl_Interp *interp; /* Interpreter */
  588. int objc; /* How many arguments? */
  589. Tcl_Obj *CONST objv[]; /* The argument objects */
  590. {
  591. static char *pgcmds[] = {
  592. "init",
  593. "is_setto",
  594. "pgnum",
  595. "pgsize",
  596. "put",
  597. "set",
  598. NULL
  599. };
  600. enum pgcmds {
  601. PGINIT,
  602. PGISSET,
  603. PGNUM,
  604. PGSIZE,
  605. PGPUT,
  606. PGSET
  607. };
  608. DB_MPOOLFILE *mp;
  609. int cmdindex, length, result;
  610. char *obj_name;
  611. void *page;
  612. DBTCL_INFO *pgip;
  613. Tcl_Obj *res;
  614. Tcl_ResetResult(interp);
  615. page = (void *)clientData;
  616. obj_name = Tcl_GetStringFromObj(objv[0], &length);
  617. pgip = _NameToInfo(obj_name);
  618. mp = NAME_TO_MP(pgip->i_parent->i_name);
  619. result = TCL_OK;
  620. if (page == NULL) {
  621. Tcl_SetResult(interp, "NULL page pointer", TCL_STATIC);
  622. return (TCL_ERROR);
  623. }
  624. if (mp == NULL) {
  625. Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
  626. return (TCL_ERROR);
  627. }
  628. if (pgip == NULL) {
  629. Tcl_SetResult(interp, "NULL page info pointer", TCL_STATIC);
  630. return (TCL_ERROR);
  631. }
  632. /*
  633.  * Get the command name index from the object based on the dbcmds
  634.  * defined above.
  635.  */
  636. if (Tcl_GetIndexFromObj(interp,
  637.     objv[1], pgcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  638. return (IS_HELP(objv[1]));
  639. res = NULL;
  640. switch ((enum pgcmds)cmdindex) {
  641. case PGNUM:
  642. res = Tcl_NewLongObj((long)pgip->i_pgno);
  643. break;
  644. case PGSIZE:
  645. res = Tcl_NewLongObj(pgip->i_pgsz);
  646. break;
  647. case PGSET:
  648. case PGPUT:
  649. result = tcl_Pg(interp, objc, objv, page, mp, pgip,
  650.     cmdindex == PGSET ? 0 : 1);
  651. break;
  652. case PGINIT:
  653. result = tcl_PgInit(interp, objc, objv, page, pgip);
  654. break;
  655. case PGISSET:
  656. result = tcl_PgIsset(interp, objc, objv, page, pgip);
  657. break;
  658. }
  659. /*
  660.  * Only set result if we have a res.  Otherwise, lower
  661.  * functions have already done so.
  662.  */
  663. if (result == TCL_OK && res)
  664. Tcl_SetObjResult(interp, res);
  665. return (result);
  666. }
  667. static int
  668. tcl_Pg(interp, objc, objv, page, mp, pgip, putop)
  669. Tcl_Interp *interp; /* Interpreter */
  670. int objc; /* How many arguments? */
  671. Tcl_Obj *CONST objv[]; /* The argument objects */
  672. void *page; /* Page pointer */
  673. DB_MPOOLFILE *mp; /* Mpool pointer */
  674. DBTCL_INFO *pgip; /* Info pointer */
  675. int putop; /* Operation */
  676. {
  677. static char *pgopt[] = {
  678. "-clean",
  679. "-dirty",
  680. "-discard",
  681. NULL
  682. };
  683. enum pgopt {
  684. PGCLEAN,
  685. PGDIRTY,
  686. PGDISCARD
  687. };
  688. u_int32_t flag;
  689. int i, optindex, result, ret;
  690. result = TCL_OK;
  691. i = 2;
  692. flag = 0;
  693. while (i < objc) {
  694. if (Tcl_GetIndexFromObj(interp, objv[i],
  695.     pgopt, "option", TCL_EXACT, &optindex) != TCL_OK)
  696. return (IS_HELP(objv[i]));
  697. i++;
  698. switch ((enum pgopt)optindex) {
  699. case PGCLEAN:
  700. flag |= DB_MPOOL_CLEAN;
  701. break;
  702. case PGDIRTY:
  703. flag |= DB_MPOOL_DIRTY;
  704. break;
  705. case PGDISCARD:
  706. flag |= DB_MPOOL_DISCARD;
  707. break;
  708. }
  709. }
  710. _debug_check();
  711. if (putop)
  712. ret = mp->put(mp, page, flag);
  713. else
  714. ret = mp->set(mp, page, flag);
  715. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "page");
  716. if (putop) {
  717. (void)Tcl_DeleteCommand(interp, pgip->i_name);
  718. _DeleteInfo(pgip);
  719. }
  720. return (result);
  721. }
  722. static int
  723. tcl_PgInit(interp, objc, objv, page, pgip)
  724. Tcl_Interp *interp; /* Interpreter */
  725. int objc; /* How many arguments? */
  726. Tcl_Obj *CONST objv[]; /* The argument objects */
  727. void *page; /* Page pointer */
  728. DBTCL_INFO *pgip; /* Info pointer */
  729. {
  730. Tcl_Obj *res;
  731. size_t pgsz;
  732. long *p, *endp, newval;
  733. int length, result;
  734. u_char *s;
  735. result = TCL_OK;
  736. if (objc != 3) {
  737. Tcl_WrongNumArgs(interp, 2, objv, "val");
  738. return (TCL_ERROR);
  739. }
  740. pgsz = pgip->i_pgsz;
  741. result = Tcl_GetLongFromObj(interp, objv[2], &newval);
  742. if (result != TCL_OK) {
  743. s = Tcl_GetByteArrayFromObj(objv[2], &length);
  744. if (s == NULL)
  745. return (TCL_ERROR);
  746. memcpy(page, s,
  747.     ((size_t)length < pgsz) ? (size_t)length : pgsz);
  748. result = TCL_OK;
  749. } else {
  750. p = (long *)page;
  751. for (endp = p + (pgsz / sizeof(long)); p < endp; p++)
  752. *p = newval;
  753. }
  754. res = Tcl_NewIntObj(0);
  755. Tcl_SetObjResult(interp, res);
  756. return (result);
  757. }
  758. static int
  759. tcl_PgIsset(interp, objc, objv, page, pgip)
  760. Tcl_Interp *interp; /* Interpreter */
  761. int objc; /* How many arguments? */
  762. Tcl_Obj *CONST objv[]; /* The argument objects */
  763. void *page; /* Page pointer */
  764. DBTCL_INFO *pgip; /* Info pointer */
  765. {
  766. Tcl_Obj *res;
  767. size_t pgsz;
  768. long *p, *endp, newval;
  769. int length, result;
  770. u_char *s;
  771. result = TCL_OK;
  772. if (objc != 3) {
  773. Tcl_WrongNumArgs(interp, 2, objv, "val");
  774. return (TCL_ERROR);
  775. }
  776. pgsz = pgip->i_pgsz;
  777. result = Tcl_GetLongFromObj(interp, objv[2], &newval);
  778. if (result != TCL_OK) {
  779. if ((s = Tcl_GetByteArrayFromObj(objv[2], &length)) == NULL)
  780. return (TCL_ERROR);
  781. result = TCL_OK;
  782. if (memcmp(page, s,
  783.     ((size_t)length < pgsz) ? (size_t)length : pgsz ) != 0) {
  784. res = Tcl_NewIntObj(0);
  785. Tcl_SetObjResult(interp, res);
  786. return (result);
  787. }
  788. } else {
  789. p = (long *)page;
  790. /*
  791.  * If any value is not the same, return 0 (is not set to
  792.  * this value).  Otherwise, if we finish the loop, we return 1
  793.  * (is set to this value).
  794.  */
  795. for (endp = p + (pgsz/sizeof(long)); p < endp; p++)
  796. if (*p != newval) {
  797. res = Tcl_NewIntObj(0);
  798. Tcl_SetObjResult(interp, res);
  799. return (result);
  800. }
  801. }
  802. res = Tcl_NewIntObj(1);
  803. Tcl_SetObjResult(interp, res);
  804. return (result);
  805. }
  806. #endif