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

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