Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

tcl_mp.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: tcl_mp.c,v 12.1 2005/06/16 20:23:48 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <tcl.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 #include "dbinc/tcl_db.h"
00022 
00023 /*
00024  * Prototypes for procedures defined later in this file:
00025  */
00026 #ifdef CONFIG_TEST
00027 static int      mp_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
00028 static int      pg_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
00029 static int      tcl_MpGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
00030     DB_MPOOLFILE *, DBTCL_INFO *));
00031 static int      tcl_Pg __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
00032     void *, DB_MPOOLFILE *, DBTCL_INFO *, int));
00033 static int      tcl_PgInit __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
00034     void *, DBTCL_INFO *));
00035 static int      tcl_PgIsset __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
00036     void *, DBTCL_INFO *));
00037 #endif
00038 
00039 /*
00040  * _MpInfoDelete --
00041  *      Removes "sub" mp page info structures that are children
00042  *      of this mp.
00043  *
00044  * PUBLIC: void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *));
00045  */
00046 void
00047 _MpInfoDelete(interp, mpip)
00048         Tcl_Interp *interp;             /* Interpreter */
00049         DBTCL_INFO *mpip;               /* Info for mp */
00050 {
00051         DBTCL_INFO *nextp, *p;
00052 
00053         for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
00054                 /*
00055                  * Check if this info structure "belongs" to this
00056                  * mp.  Remove its commands and info structure.
00057                  */
00058                 nextp = LIST_NEXT(p, entries);
00059                 if (p->i_parent == mpip && p->i_type == I_PG) {
00060                         (void)Tcl_DeleteCommand(interp, p->i_name);
00061                         _DeleteInfo(p);
00062                 }
00063         }
00064 }
00065 
00066 #ifdef CONFIG_TEST
00067 /*
00068  * tcl_MpSync --
00069  *
00070  * PUBLIC: int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
00071  */
00072 int
00073 tcl_MpSync(interp, objc, objv, envp)
00074         Tcl_Interp *interp;             /* Interpreter */
00075         int objc;                       /* How many arguments? */
00076         Tcl_Obj *CONST objv[];          /* The argument objects */
00077         DB_ENV *envp;                   /* Environment pointer */
00078 {
00079 
00080         DB_LSN lsn, *lsnp;
00081         int result, ret;
00082 
00083         result = TCL_OK;
00084         lsnp = NULL;
00085         /*
00086          * No flags, must be 3 args.
00087          */
00088         if (objc == 3) {
00089                 result = _GetLsn(interp, objv[2], &lsn);
00090                 if (result == TCL_ERROR)
00091                         return (result);
00092                 lsnp = &lsn;
00093         }
00094         else if (objc != 2) {
00095                 Tcl_WrongNumArgs(interp, 2, objv, "lsn");
00096                 return (TCL_ERROR);
00097         }
00098 
00099         _debug_check();
00100         ret = envp->memp_sync(envp, lsnp);
00101         return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp sync"));
00102 }
00103 
00104 /*
00105  * tcl_MpTrickle --
00106  *
00107  * PUBLIC: int tcl_MpTrickle __P((Tcl_Interp *, int,
00108  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
00109  */
00110 int
00111 tcl_MpTrickle(interp, objc, objv, envp)
00112         Tcl_Interp *interp;             /* Interpreter */
00113         int objc;                       /* How many arguments? */
00114         Tcl_Obj *CONST objv[];          /* The argument objects */
00115         DB_ENV *envp;                   /* Environment pointer */
00116 {
00117 
00118         Tcl_Obj *res;
00119         int pages, percent, result, ret;
00120 
00121         result = TCL_OK;
00122         /*
00123          * No flags, must be 3 args.
00124          */
00125         if (objc != 3) {
00126                 Tcl_WrongNumArgs(interp, 2, objv, "percent");
00127                 return (TCL_ERROR);
00128         }
00129 
00130         result = Tcl_GetIntFromObj(interp, objv[2], &percent);
00131         if (result == TCL_ERROR)
00132                 return (result);
00133 
00134         _debug_check();
00135         ret = envp->memp_trickle(envp, percent, &pages);
00136         result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp trickle");
00137         if (result == TCL_ERROR)
00138                 return (result);
00139 
00140         res = Tcl_NewIntObj(pages);
00141         Tcl_SetObjResult(interp, res);
00142         return (result);
00143 
00144 }
00145 
00146 /*
00147  * tcl_Mp --
00148  *
00149  * PUBLIC: int tcl_Mp __P((Tcl_Interp *, int,
00150  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *));
00151  */
00152 int
00153 tcl_Mp(interp, objc, objv, envp, envip)
00154         Tcl_Interp *interp;             /* Interpreter */
00155         int objc;                       /* How many arguments? */
00156         Tcl_Obj *CONST objv[];          /* The argument objects */
00157         DB_ENV *envp;                   /* Environment pointer */
00158         DBTCL_INFO *envip;              /* Info pointer */
00159 {
00160         static const char *mpopts[] = {
00161                 "-create",
00162                 "-mode",
00163                 "-nommap",
00164                 "-pagesize",
00165                 "-rdonly",
00166                  NULL
00167         };
00168         enum mpopts {
00169                 MPCREATE,
00170                 MPMODE,
00171                 MPNOMMAP,
00172                 MPPAGE,
00173                 MPRDONLY
00174         };
00175         DBTCL_INFO *ip;
00176         DB_MPOOLFILE *mpf;
00177         Tcl_Obj *res;
00178         u_int32_t flag;
00179         int i, pgsize, mode, optindex, result, ret;
00180         char *file, newname[MSG_SIZE];
00181 
00182         result = TCL_OK;
00183         i = 2;
00184         flag = 0;
00185         mode = 0;
00186         pgsize = 0;
00187         memset(newname, 0, MSG_SIZE);
00188         while (i < objc) {
00189                 if (Tcl_GetIndexFromObj(interp, objv[i],
00190                     mpopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
00191                         /*
00192                          * Reset the result so we don't get an errant
00193                          * error message if there is another error.
00194                          * This arg is the file name.
00195                          */
00196                         if (IS_HELP(objv[i]) == TCL_OK)
00197                                 return (TCL_OK);
00198                         Tcl_ResetResult(interp);
00199                         break;
00200                 }
00201                 i++;
00202                 switch ((enum mpopts)optindex) {
00203                 case MPCREATE:
00204                         flag |= DB_CREATE;
00205                         break;
00206                 case MPNOMMAP:
00207                         flag |= DB_NOMMAP;
00208                         break;
00209                 case MPPAGE:
00210                         if (i >= objc) {
00211                                 Tcl_WrongNumArgs(interp, 2, objv,
00212                                     "?-pagesize size?");
00213                                 result = TCL_ERROR;
00214                                 break;
00215                         }
00216                         /*
00217                          * Don't need to check result here because
00218                          * if TCL_ERROR, the error message is already
00219                          * set up, and we'll bail out below.  If ok,
00220                          * the mode is set and we go on.
00221                          */
00222                         result = Tcl_GetIntFromObj(interp, objv[i++], &pgsize);
00223                         break;
00224                 case MPRDONLY:
00225                         flag |= DB_RDONLY;
00226                         break;
00227                 case MPMODE:
00228                         if (i >= objc) {
00229                                 Tcl_WrongNumArgs(interp, 2, objv,
00230                                     "?-mode mode?");
00231                                 result = TCL_ERROR;
00232                                 break;
00233                         }
00234                         /*
00235                          * Don't need to check result here because
00236                          * if TCL_ERROR, the error message is already
00237                          * set up, and we'll bail out below.  If ok,
00238                          * the mode is set and we go on.
00239                          */
00240                         result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
00241                         break;
00242                 }
00243                 if (result != TCL_OK)
00244                         goto error;
00245         }
00246         /*
00247          * Any left over arg is a file name.  It better be the last arg.
00248          */
00249         file = NULL;
00250         if (i != objc) {
00251                 if (i != objc - 1) {
00252                         Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?");
00253                         result = TCL_ERROR;
00254                         goto error;
00255                 }
00256                 file = Tcl_GetStringFromObj(objv[i++], NULL);
00257         }
00258 
00259         snprintf(newname, sizeof(newname), "%s.mp%d",
00260             envip->i_name, envip->i_envmpid);
00261         ip = _NewInfo(interp, NULL, newname, I_MP);
00262         if (ip == NULL) {
00263                 Tcl_SetResult(interp, "Could not set up info",
00264                     TCL_STATIC);
00265                 return (TCL_ERROR);
00266         }
00267 
00268         _debug_check();
00269         if ((ret = envp->memp_fcreate(envp, &mpf, 0)) != 0) {
00270                 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mpool");
00271                 _DeleteInfo(ip);
00272                 goto error;
00273         }
00274 
00275         /*
00276          * XXX
00277          * Interface doesn't currently support DB_MPOOLFILE configuration.
00278          */
00279         if ((ret = mpf->open(mpf, file, flag, mode, (size_t)pgsize)) != 0) {
00280                 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "mpool");
00281                 _DeleteInfo(ip);
00282 
00283                 (void)mpf->close(mpf, 0);
00284                 goto error;
00285         }
00286 
00287         /*
00288          * Success.  Set up return.  Set up new info and command widget for
00289          * this mpool.
00290          */
00291         envip->i_envmpid++;
00292         ip->i_parent = envip;
00293         ip->i_pgsz = pgsize;
00294         _SetInfoData(ip, mpf);
00295         (void)Tcl_CreateObjCommand(interp, newname,
00296             (Tcl_ObjCmdProc *)mp_Cmd, (ClientData)mpf, NULL);
00297         res = NewStringObj(newname, strlen(newname));
00298         Tcl_SetObjResult(interp, res);
00299 
00300 error:
00301         return (result);
00302 }
00303 
00304 /*
00305  * tcl_MpStat --
00306  *
00307  * PUBLIC: int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
00308  */
00309 int
00310 tcl_MpStat(interp, objc, objv, envp)
00311         Tcl_Interp *interp;             /* Interpreter */
00312         int objc;                       /* How many arguments? */
00313         Tcl_Obj *CONST objv[];          /* The argument objects */
00314         DB_ENV *envp;                   /* Environment pointer */
00315 {
00316         DB_MPOOL_STAT *sp;
00317         DB_MPOOL_FSTAT **fsp, **savefsp;
00318         int result;
00319         int ret;
00320         Tcl_Obj *res;
00321         Tcl_Obj *res1;
00322 
00323         result = TCL_OK;
00324         savefsp = NULL;
00325         /*
00326          * No args for this.  Error if there are some.
00327          */
00328         if (objc != 2) {
00329                 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00330                 return (TCL_ERROR);
00331         }
00332         _debug_check();
00333         ret = envp->memp_stat(envp, &sp, &fsp, 0);
00334         result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "memp stat");
00335         if (result == TCL_ERROR)
00336                 return (result);
00337 
00338         /*
00339          * Have our stats, now construct the name value
00340          * list pairs and free up the memory.
00341          */
00342         res = Tcl_NewObj();
00343         /*
00344          * MAKE_STAT_LIST assumes 'res' and 'error' label.
00345          */
00346         MAKE_STAT_LIST("Cache size (gbytes)", sp->st_gbytes);
00347         MAKE_STAT_LIST("Cache size (bytes)", sp->st_bytes);
00348         MAKE_STAT_LIST("Number of caches", sp->st_ncache);
00349         MAKE_STAT_LIST("Region size", sp->st_regsize);
00350         MAKE_STAT_LIST("Maximum memory-mapped file size", sp->st_mmapsize);
00351         MAKE_STAT_LIST("Maximum open file descriptors", sp->st_maxopenfd);
00352         MAKE_STAT_LIST("Maximum sequential buffer writes", sp->st_maxwrite);
00353         MAKE_STAT_LIST(
00354             "Sleep after writing maximum buffers", sp->st_maxwrite_sleep);
00355         MAKE_STAT_LIST("Pages mapped into address space", sp->st_map);
00356         MAKE_STAT_LIST("Cache hits", sp->st_cache_hit);
00357         MAKE_STAT_LIST("Cache misses", sp->st_cache_miss);
00358         MAKE_STAT_LIST("Pages created", sp->st_page_create);
00359         MAKE_STAT_LIST("Pages read in", sp->st_page_in);
00360         MAKE_STAT_LIST("Pages written", sp->st_page_out);
00361         MAKE_STAT_LIST("Clean page evictions", sp->st_ro_evict);
00362         MAKE_STAT_LIST("Dirty page evictions", sp->st_rw_evict);
00363         MAKE_STAT_LIST("Dirty pages trickled", sp->st_page_trickle);
00364         MAKE_STAT_LIST("Cached pages", sp->st_pages);
00365         MAKE_STAT_LIST("Cached clean pages", sp->st_page_clean);
00366         MAKE_STAT_LIST("Cached dirty pages", sp->st_page_dirty);
00367         MAKE_STAT_LIST("Hash buckets", sp->st_hash_buckets);
00368         MAKE_STAT_LIST("Hash lookups", sp->st_hash_searches);
00369         MAKE_STAT_LIST("Longest hash chain found", sp->st_hash_longest);
00370         MAKE_STAT_LIST("Hash elements examined", sp->st_hash_examined);
00371         MAKE_STAT_LIST("Number of hash bucket nowaits", sp->st_hash_nowait);
00372         MAKE_STAT_LIST("Number of hash bucket waits", sp->st_hash_wait);
00373         MAKE_STAT_LIST("Maximum number of hash bucket waits",
00374             sp->st_hash_max_wait);
00375         MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
00376         MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
00377         MAKE_STAT_LIST("Page allocations", sp->st_alloc);
00378         MAKE_STAT_LIST("Buckets examined during allocation",
00379             sp->st_alloc_buckets);
00380         MAKE_STAT_LIST("Maximum buckets examined during allocation",
00381             sp->st_alloc_max_buckets);
00382         MAKE_STAT_LIST("Pages examined during allocation", sp->st_alloc_pages);
00383         MAKE_STAT_LIST("Maximum pages examined during allocation",
00384             sp->st_alloc_max_pages);
00385 
00386         /*
00387          * Save global stat list as res1.  The MAKE_STAT_LIST
00388          * macro assumes 'res' so we'll use that to build up
00389          * our per-file sublist.
00390          */
00391         res1 = res;
00392         for (savefsp = fsp; fsp != NULL && *fsp != NULL; fsp++) {
00393                 res = Tcl_NewObj();
00394                 result = _SetListElem(interp, res, "File Name",
00395                     strlen("File Name"), (*fsp)->file_name,
00396                     strlen((*fsp)->file_name));
00397                 if (result != TCL_OK)
00398                         goto error;
00399                 MAKE_STAT_LIST("Page size", (*fsp)->st_pagesize);
00400                 MAKE_STAT_LIST("Pages mapped into address space",
00401                     (*fsp)->st_map);
00402                 MAKE_STAT_LIST("Cache hits", (*fsp)->st_cache_hit);
00403                 MAKE_STAT_LIST("Cache misses", (*fsp)->st_cache_miss);
00404                 MAKE_STAT_LIST("Pages created", (*fsp)->st_page_create);
00405                 MAKE_STAT_LIST("Pages read in", (*fsp)->st_page_in);
00406                 MAKE_STAT_LIST("Pages written", (*fsp)->st_page_out);
00407                 /*
00408                  * Now that we have a complete "per-file" stat list, append
00409                  * that to the other list.
00410                  */
00411                 result = Tcl_ListObjAppendElement(interp, res1, res);
00412                 if (result != TCL_OK)
00413                         goto error;
00414         }
00415         Tcl_SetObjResult(interp, res1);
00416 error:
00417         __os_ufree(envp, sp);
00418         if (savefsp != NULL)
00419                 __os_ufree(envp, savefsp);
00420         return (result);
00421 }
00422 
00423 /*
00424  * mp_Cmd --
00425  *      Implements the "mp" widget.
00426  */
00427 static int
00428 mp_Cmd(clientData, interp, objc, objv)
00429         ClientData clientData;          /* Mp handle */
00430         Tcl_Interp *interp;             /* Interpreter */
00431         int objc;                       /* How many arguments? */
00432         Tcl_Obj *CONST objv[];          /* The argument objects */
00433 {
00434         static const char *mpcmds[] = {
00435                 "close",
00436                 "fsync",
00437                 "get",
00438                 "get_clear_len",
00439                 "get_fileid",
00440                 "get_ftype",
00441                 "get_lsn_offset",
00442                 "get_pgcookie",
00443                 NULL
00444         };
00445         enum mpcmds {
00446                 MPCLOSE,
00447                 MPFSYNC,
00448                 MPGET,
00449                 MPGETCLEARLEN,
00450                 MPGETFILEID,
00451                 MPGETFTYPE,
00452                 MPGETLSNOFFSET,
00453                 MPGETPGCOOKIE
00454         };
00455         DB_MPOOLFILE *mp;
00456         int cmdindex, ftype, length, result, ret;
00457         DBTCL_INFO *mpip;
00458         Tcl_Obj *res;
00459         char *obj_name;
00460         u_int32_t value;
00461         int32_t intval;
00462         u_int8_t fileid[DB_FILE_ID_LEN];
00463         DBT cookie;
00464 
00465         Tcl_ResetResult(interp);
00466         mp = (DB_MPOOLFILE *)clientData;
00467         obj_name = Tcl_GetStringFromObj(objv[0], &length);
00468         mpip = _NameToInfo(obj_name);
00469         result = TCL_OK;
00470 
00471         if (mp == NULL) {
00472                 Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
00473                 return (TCL_ERROR);
00474         }
00475         if (mpip == NULL) {
00476                 Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC);
00477                 return (TCL_ERROR);
00478         }
00479 
00480         /*
00481          * Get the command name index from the object based on the dbcmds
00482          * defined above.
00483          */
00484         if (Tcl_GetIndexFromObj(interp,
00485             objv[1], mpcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
00486                 return (IS_HELP(objv[1]));
00487 
00488         res = NULL;
00489         switch ((enum mpcmds)cmdindex) {
00490         case MPCLOSE:
00491                 if (objc != 2) {
00492                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00493                         return (TCL_ERROR);
00494                 }
00495                 _debug_check();
00496                 ret = mp->close(mp, 0);
00497                 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00498                     "mp close");
00499                 _MpInfoDelete(interp, mpip);
00500                 (void)Tcl_DeleteCommand(interp, mpip->i_name);
00501                 _DeleteInfo(mpip);
00502                 break;
00503         case MPFSYNC:
00504                 if (objc != 2) {
00505                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00506                         return (TCL_ERROR);
00507                 }
00508                 _debug_check();
00509                 ret = mp->sync(mp);
00510                 res = Tcl_NewIntObj(ret);
00511                 break;
00512         case MPGET:
00513                 result = tcl_MpGet(interp, objc, objv, mp, mpip);
00514                 break;
00515         case MPGETCLEARLEN:
00516                 if (objc != 2) {
00517                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00518                         return (TCL_ERROR);
00519                 }
00520                 ret = mp->get_clear_len(mp, &value);
00521                 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00522                     "mp get_clear_len")) == TCL_OK)
00523                         res = Tcl_NewIntObj((int)value);
00524                 break;
00525         case MPGETFILEID:
00526                 if (objc != 2) {
00527                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00528                         return (TCL_ERROR);
00529                 }
00530                 ret = mp->get_fileid(mp, fileid);
00531                 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00532                     "mp get_fileid")) == TCL_OK)
00533                         res = NewStringObj((char *)fileid, DB_FILE_ID_LEN);
00534                 break;
00535         case MPGETFTYPE:
00536                 if (objc != 2) {
00537                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00538                         return (TCL_ERROR);
00539                 }
00540                 ret = mp->get_ftype(mp, &ftype);
00541                 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00542                     "mp get_ftype")) == TCL_OK)
00543                         res = Tcl_NewIntObj(ftype);
00544                 break;
00545         case MPGETLSNOFFSET:
00546                 if (objc != 2) {
00547                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00548                         return (TCL_ERROR);
00549                 }
00550                 ret = mp->get_lsn_offset(mp, &intval);
00551                 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00552                     "mp get_lsn_offset")) == TCL_OK)
00553                         res = Tcl_NewIntObj(intval);
00554                 break;
00555         case MPGETPGCOOKIE:
00556                 if (objc != 2) {
00557                         Tcl_WrongNumArgs(interp, 1, objv, NULL);
00558                         return (TCL_ERROR);
00559                 }
00560                 memset(&cookie, 0, sizeof(DBT));
00561                 ret = mp->get_pgcookie(mp, &cookie);
00562                 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00563                     "mp get_pgcookie")) == TCL_OK)
00564                         res = Tcl_NewByteArrayObj((u_char *)cookie.data,
00565                             (int)cookie.size);
00566                 break;
00567         }
00568         /*
00569          * Only set result if we have a res.  Otherwise, lower
00570          * functions have already done so.
00571          */
00572         if (result == TCL_OK && res)
00573                 Tcl_SetObjResult(interp, res);
00574         return (result);
00575 }
00576 
00577 /*
00578  * tcl_MpGet --
00579  */
00580 static int
00581 tcl_MpGet(interp, objc, objv, mp, mpip)
00582         Tcl_Interp *interp;             /* Interpreter */
00583         int objc;                       /* How many arguments? */
00584         Tcl_Obj *CONST objv[];          /* The argument objects */
00585         DB_MPOOLFILE *mp;               /* mp pointer */
00586         DBTCL_INFO *mpip;               /* mp info pointer */
00587 {
00588         static const char *mpget[] = {
00589                 "-create",
00590                 "-last",
00591                 "-new",
00592                 NULL
00593         };
00594         enum mpget {
00595                 MPGET_CREATE,
00596                 MPGET_LAST,
00597                 MPGET_NEW
00598         };
00599 
00600         DBTCL_INFO *ip;
00601         Tcl_Obj *res;
00602         db_pgno_t pgno;
00603         u_int32_t flag;
00604         int i, ipgno, optindex, result, ret;
00605         char newname[MSG_SIZE];
00606         void *page;
00607 
00608         result = TCL_OK;
00609         memset(newname, 0, MSG_SIZE);
00610         i = 2;
00611         flag = 0;
00612         while (i < objc) {
00613                 if (Tcl_GetIndexFromObj(interp, objv[i],
00614                     mpget, "option", TCL_EXACT, &optindex) != TCL_OK) {
00615                         /*
00616                          * Reset the result so we don't get an errant
00617                          * error message if there is another error.
00618                          * This arg is the page number.
00619                          */
00620                         if (IS_HELP(objv[i]) == TCL_OK)
00621                                 return (TCL_OK);
00622                         Tcl_ResetResult(interp);
00623                         break;
00624                 }
00625                 i++;
00626                 switch ((enum mpget)optindex) {
00627                 case MPGET_CREATE:
00628                         flag |= DB_MPOOL_CREATE;
00629                         break;
00630                 case MPGET_LAST:
00631                         flag |= DB_MPOOL_LAST;
00632                         break;
00633                 case MPGET_NEW:
00634                         flag |= DB_MPOOL_NEW;
00635                         break;
00636                 }
00637                 if (result != TCL_OK)
00638                         goto error;
00639         }
00640         /*
00641          * Any left over arg is a page number.  It better be the last arg.
00642          */
00643         ipgno = 0;
00644         if (i != objc) {
00645                 if (i != objc - 1) {
00646                         Tcl_WrongNumArgs(interp, 2, objv, "?args? ?pgno?");
00647                         result = TCL_ERROR;
00648                         goto error;
00649                 }
00650                 result = Tcl_GetIntFromObj(interp, objv[i++], &ipgno);
00651                 if (result != TCL_OK)
00652                         goto error;
00653         }
00654 
00655         snprintf(newname, sizeof(newname), "%s.pg%d",
00656             mpip->i_name, mpip->i_mppgid);
00657         ip = _NewInfo(interp, NULL, newname, I_PG);
00658         if (ip == NULL) {
00659                 Tcl_SetResult(interp, "Could not set up info",
00660                     TCL_STATIC);
00661                 return (TCL_ERROR);
00662         }
00663         _debug_check();
00664         pgno = (db_pgno_t)ipgno;
00665         ret = mp->get(mp, &pgno, flag, &page);
00666         result = _ReturnSetup(interp, ret, DB_RETOK_MPGET(ret), "mpool get");
00667         if (result == TCL_ERROR)
00668                 _DeleteInfo(ip);
00669         else {
00670                 /*
00671                  * Success.  Set up return.  Set up new info
00672                  * and command widget for this mpool.
00673                  */
00674                 mpip->i_mppgid++;
00675                 ip->i_parent = mpip;
00676                 ip->i_pgno = pgno;
00677                 ip->i_pgsz = mpip->i_pgsz;
00678                 _SetInfoData(ip, page);
00679                 (void)Tcl_CreateObjCommand(interp, newname,
00680                     (Tcl_ObjCmdProc *)pg_Cmd, (ClientData)page, NULL);
00681                 res = NewStringObj(newname, strlen(newname));
00682                 Tcl_SetObjResult(interp, res);
00683         }
00684 error:
00685         return (result);
00686 }
00687 
00688 /*
00689  * pg_Cmd --
00690  *      Implements the "pg" widget.
00691  */
00692 static int
00693 pg_Cmd(clientData, interp, objc, objv)
00694         ClientData clientData;          /* Page handle */
00695         Tcl_Interp *interp;             /* Interpreter */
00696         int objc;                       /* How many arguments? */
00697         Tcl_Obj *CONST objv[];          /* The argument objects */
00698 {
00699         static const char *pgcmds[] = {
00700                 "init",
00701                 "is_setto",
00702                 "pgnum",
00703                 "pgsize",
00704                 "put",
00705                 "set",
00706                 NULL
00707         };
00708         enum pgcmds {
00709                 PGINIT,
00710                 PGISSET,
00711                 PGNUM,
00712                 PGSIZE,
00713                 PGPUT,
00714                 PGSET
00715         };
00716         DB_MPOOLFILE *mp;
00717         int cmdindex, length, result;
00718         char *obj_name;
00719         void *page;
00720         DBTCL_INFO *pgip;
00721         Tcl_Obj *res;
00722 
00723         Tcl_ResetResult(interp);
00724         page = (void *)clientData;
00725         obj_name = Tcl_GetStringFromObj(objv[0], &length);
00726         pgip = _NameToInfo(obj_name);
00727         mp = NAME_TO_MP(pgip->i_parent->i_name);
00728         result = TCL_OK;
00729 
00730         if (page == NULL) {
00731                 Tcl_SetResult(interp, "NULL page pointer", TCL_STATIC);
00732                 return (TCL_ERROR);
00733         }
00734         if (mp == NULL) {
00735                 Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC);
00736                 return (TCL_ERROR);
00737         }
00738         if (pgip == NULL) {
00739                 Tcl_SetResult(interp, "NULL page info pointer", TCL_STATIC);
00740                 return (TCL_ERROR);
00741         }
00742 
00743         /*
00744          * Get the command name index from the object based on the dbcmds
00745          * defined above.
00746          */
00747         if (Tcl_GetIndexFromObj(interp,
00748             objv[1], pgcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
00749                 return (IS_HELP(objv[1]));
00750 
00751         res = NULL;
00752         switch ((enum pgcmds)cmdindex) {
00753         case PGNUM:
00754                 res = Tcl_NewWideIntObj((Tcl_WideInt)pgip->i_pgno);
00755                 break;
00756         case PGSIZE:
00757                 res = Tcl_NewWideIntObj((Tcl_WideInt)pgip->i_pgsz);
00758                 break;
00759         case PGSET:
00760         case PGPUT:
00761                 result = tcl_Pg(interp, objc, objv, page, mp, pgip,
00762                     (enum pgcmds)cmdindex == PGSET ? 0 : 1);
00763                 break;
00764         case PGINIT:
00765                 result = tcl_PgInit(interp, objc, objv, page, pgip);
00766                 break;
00767         case PGISSET:
00768                 result = tcl_PgIsset(interp, objc, objv, page, pgip);
00769                 break;
00770         }
00771 
00772         /*
00773          * Only set result if we have a res.  Otherwise, lower
00774          * functions have already done so.
00775          */
00776         if (result == TCL_OK && res != NULL)
00777                 Tcl_SetObjResult(interp, res);
00778         return (result);
00779 }
00780 
00781 static int
00782 tcl_Pg(interp, objc, objv, page, mp, pgip, putop)
00783         Tcl_Interp *interp;             /* Interpreter */
00784         int objc;                       /* How many arguments? */
00785         Tcl_Obj *CONST objv[];          /* The argument objects */
00786         void *page;                     /* Page pointer */
00787         DB_MPOOLFILE *mp;               /* Mpool pointer */
00788         DBTCL_INFO *pgip;               /* Info pointer */
00789         int putop;                      /* Operation */
00790 {
00791         static const char *pgopt[] = {
00792                 "-clean",
00793                 "-dirty",
00794                 "-discard",
00795                 NULL
00796         };
00797         enum pgopt {
00798                 PGCLEAN,
00799                 PGDIRTY,
00800                 PGDISCARD
00801         };
00802         u_int32_t flag;
00803         int i, optindex, result, ret;
00804 
00805         result = TCL_OK;
00806         i = 2;
00807         flag = 0;
00808         while (i < objc) {
00809                 if (Tcl_GetIndexFromObj(interp, objv[i],
00810                     pgopt, "option", TCL_EXACT, &optindex) != TCL_OK)
00811                         return (IS_HELP(objv[i]));
00812                 i++;
00813                 switch ((enum pgopt)optindex) {
00814                 case PGCLEAN:
00815                         flag |= DB_MPOOL_CLEAN;
00816                         break;
00817                 case PGDIRTY:
00818                         flag |= DB_MPOOL_DIRTY;
00819                         break;
00820                 case PGDISCARD:
00821                         flag |= DB_MPOOL_DISCARD;
00822                         break;
00823                 }
00824         }
00825 
00826         _debug_check();
00827         if (putop)
00828                 ret = mp->put(mp, page, flag);
00829         else
00830                 ret = mp->set(mp, page, flag);
00831 
00832         result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "page");
00833 
00834         if (putop) {
00835                 (void)Tcl_DeleteCommand(interp, pgip->i_name);
00836                 _DeleteInfo(pgip);
00837         }
00838         return (result);
00839 }
00840 
00841 static int
00842 tcl_PgInit(interp, objc, objv, page, pgip)
00843         Tcl_Interp *interp;             /* Interpreter */
00844         int objc;                       /* How many arguments? */
00845         Tcl_Obj *CONST objv[];          /* The argument objects */
00846         void *page;                     /* Page pointer */
00847         DBTCL_INFO *pgip;               /* Info pointer */
00848 {
00849         Tcl_Obj *res;
00850         long *p, *endp, newval;
00851         int length, pgsz, result;
00852         u_char *s;
00853 
00854         result = TCL_OK;
00855         if (objc != 3) {
00856                 Tcl_WrongNumArgs(interp, 2, objv, "val");
00857                 return (TCL_ERROR);
00858         }
00859 
00860         pgsz = pgip->i_pgsz;
00861         result = Tcl_GetLongFromObj(interp, objv[2], &newval);
00862         if (result != TCL_OK) {
00863                 s = Tcl_GetByteArrayFromObj(objv[2], &length);
00864                 if (s == NULL)
00865                         return (TCL_ERROR);
00866                 memcpy(page, s, (size_t)((length < pgsz) ? length : pgsz));
00867                 result = TCL_OK;
00868         } else {
00869                 p = (long *)page;
00870                 for (endp = p + ((u_int)pgsz / sizeof(long)); p < endp; p++)
00871                         *p = newval;
00872         }
00873         res = Tcl_NewIntObj(0);
00874         Tcl_SetObjResult(interp, res);
00875         return (result);
00876 }
00877 
00878 static int
00879 tcl_PgIsset(interp, objc, objv, page, pgip)
00880         Tcl_Interp *interp;             /* Interpreter */
00881         int objc;                       /* How many arguments? */
00882         Tcl_Obj *CONST objv[];          /* The argument objects */
00883         void *page;                     /* Page pointer */
00884         DBTCL_INFO *pgip;               /* Info pointer */
00885 {
00886         Tcl_Obj *res;
00887         long *p, *endp, newval;
00888         int length, pgsz, result;
00889         u_char *s;
00890 
00891         result = TCL_OK;
00892         if (objc != 3) {
00893                 Tcl_WrongNumArgs(interp, 2, objv, "val");
00894                 return (TCL_ERROR);
00895         }
00896 
00897         pgsz = pgip->i_pgsz;
00898         result = Tcl_GetLongFromObj(interp, objv[2], &newval);
00899         if (result != TCL_OK) {
00900                 if ((s = Tcl_GetByteArrayFromObj(objv[2], &length)) == NULL)
00901                         return (TCL_ERROR);
00902                 result = TCL_OK;
00903 
00904                 if (memcmp(page, s,
00905                     (size_t)((length < pgsz) ? length : pgsz)) != 0) {
00906                         res = Tcl_NewIntObj(0);
00907                         Tcl_SetObjResult(interp, res);
00908                         return (result);
00909                 }
00910         } else {
00911                 p = (long *)page;
00912                 /*
00913                  * If any value is not the same, return 0 (is not set to
00914                  * this value).  Otherwise, if we finish the loop, we return 1
00915                  * (is set to this value).
00916                  */
00917                 for (endp = p + ((u_int)pgsz / sizeof(long)); p < endp; p++)
00918                         if (*p != newval) {
00919                                 res = Tcl_NewIntObj(0);
00920                                 Tcl_SetObjResult(interp, res);
00921                                 return (result);
00922                         }
00923         }
00924 
00925         res = Tcl_NewIntObj(1);
00926         Tcl_SetObjResult(interp, res);
00927         return (result);
00928 }
00929 #endif

Generated on Sun Dec 25 12:14:52 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2