1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1999-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#ifndef _DB_TCL_DB_H_ 10#define _DB_TCL_DB_H_ 11 12#if defined(__cplusplus) 13extern "C" { 14#endif 15 16#define MSG_SIZE 100 /* Message size */ 17 18enum INFOTYPE { 19 I_DB, I_DBC, I_ENV, I_LOCK, I_LOGC, I_MP, I_NDBM, I_PG, I_SEQ, I_TXN}; 20 21#define MAX_ID 8 /* Maximum number of sub-id's we need */ 22#define DBTCL_PREP 64 /* Size of txn_recover preplist */ 23 24#define DBTCL_DBM 1 25#define DBTCL_NDBM 2 26 27#define DBTCL_GETCLOCK 0 28#define DBTCL_GETLIMIT 1 29#define DBTCL_GETREQ 2 30 31#define DBTCL_MUT_ALIGN 0 32#define DBTCL_MUT_INCR 1 33#define DBTCL_MUT_MAX 2 34#define DBTCL_MUT_TAS 3 35 36/* 37 * Why use a home grown package over the Tcl_Hash functions? 38 * 39 * We could have implemented the stuff below without maintaining our 40 * own list manipulation, efficiently hashing it with the available 41 * Tcl functions (Tcl_CreateHashEntry, Tcl_GetHashValue, etc). I chose 42 * not to do so for these reasons: 43 * 44 * We still need the information below. Using the hashing only removes 45 * us from needing the next/prev pointers. We still need the structure 46 * itself because we need more than one value associated with a widget. 47 * We need to keep track of parent pointers for sub-widgets (like cursors) 48 * so we can correctly close. We need to keep track of individual widget's 49 * id counters for any sub-widgets they may have. We need to be able to 50 * associate the name/client data outside the scope of the widget. 51 * 52 * So, is it better to use the hashing rather than 53 * the linear list we have now? I decided against it for the simple reason 54 * that to access the structure would require two calls. The first is 55 * Tcl_FindHashEntry(table, key) and then, once we have the entry, we'd 56 * have to do Tcl_GetHashValue(entry) to get the pointer of the structure. 57 * 58 * I believe the number of simultaneous DB widgets in existence at one time 59 * is not going to be that large (more than several dozen) such that 60 * linearly searching the list is not going to impact performance in a 61 * noticeable way. Should performance be impacted due to the size of the 62 * info list, then perhaps it is time to revisit this decision. 63 */ 64typedef struct dbtcl_info { 65 LIST_ENTRY(dbtcl_info) entries; 66 Tcl_Interp *i_interp; 67 char *i_name; 68 enum INFOTYPE i_type; 69 union infop { 70 DB *dbp; 71 DBC *dbcp; 72 DB_ENV *envp; 73 DB_LOCK *lock; 74 DB_LOGC *logc; 75 DB_MPOOLFILE *mp; 76 DB_TXN *txnp; 77 void *anyp; 78 } un; 79 union data { 80 int anydata; 81 db_pgno_t pgno; 82 u_int32_t lockid; 83 } und; 84 union data2 { 85 int anydata; 86 int pagesz; 87 DB_COMPACT *c_data; 88 } und2; 89 DBT i_lockobj; 90 FILE *i_err; 91 char *i_errpfx; 92 93 /* Callbacks--Tcl_Objs containing proc names */ 94 Tcl_Obj *i_compare; 95 Tcl_Obj *i_dupcompare; 96 Tcl_Obj *i_event; 97 Tcl_Obj *i_hashproc; 98 Tcl_Obj *i_isalive; 99 Tcl_Obj *i_part_callback; 100 Tcl_Obj *i_rep_send; 101 Tcl_Obj *i_second_call; 102 103 /* Environment ID for the i_rep_send callback. */ 104 Tcl_Obj *i_rep_eid; 105 106 struct dbtcl_info *i_parent; 107 int i_otherid[MAX_ID]; 108} DBTCL_INFO; 109 110#define i_anyp un.anyp 111#define i_dbp un.dbp 112#define i_dbcp un.dbcp 113#define i_envp un.envp 114#define i_lock un.lock 115#define i_logc un.logc 116#define i_mp un.mp 117#define i_pagep un.anyp 118#define i_txnp un.txnp 119 120#define i_data und.anydata 121#define i_pgno und.pgno 122#define i_locker und.lockid 123#define i_data2 und2.anydata 124#define i_pgsz und2.pagesz 125#define i_cdata und2.c_data 126 127#define i_envtxnid i_otherid[0] 128#define i_envmpid i_otherid[1] 129#define i_envlockid i_otherid[2] 130#define i_envlogcid i_otherid[3] 131 132#define i_mppgid i_otherid[0] 133 134#define i_dbdbcid i_otherid[0] 135 136extern int __debug_on, __debug_print, __debug_stop, __debug_test; 137 138typedef struct dbtcl_global { 139 LIST_HEAD(infohead, dbtcl_info) g_infohead; 140} DBTCL_GLOBAL; 141#define __db_infohead __dbtcl_global.g_infohead 142 143extern DBTCL_GLOBAL __dbtcl_global; 144 145/* 146 * Tcl_NewStringObj takes an "int" length argument, when the typical use is to 147 * call it with a size_t length (for example, returned by strlen). Tcl is in 148 * the wrong, but that doesn't help us much -- cast the argument. 149 */ 150#define NewStringObj(a, b) \ 151 Tcl_NewStringObj(a, (int)b) 152 153#define NAME_TO_DB(name) (DB *)_NameToPtr((name)) 154#define NAME_TO_DBC(name) (DBC *)_NameToPtr((name)) 155#define NAME_TO_ENV(name) (DB_ENV *)_NameToPtr((name)) 156#define NAME_TO_LOCK(name) (DB_LOCK *)_NameToPtr((name)) 157#define NAME_TO_MP(name) (DB_MPOOLFILE *)_NameToPtr((name)) 158#define NAME_TO_TXN(name) (DB_TXN *)_NameToPtr((name)) 159#define NAME_TO_SEQUENCE(name) (DB_SEQUENCE *)_NameToPtr((name)) 160 161/* 162 * MAKE_STAT_LIST appends a {name value} pair to a result list that MUST be 163 * called 'res' that is a Tcl_Obj * in the local function. This macro also 164 * assumes a label "error" to go to in the event of a Tcl error. For stat 165 * functions this will typically go before the "free" function to free the 166 * stat structure returned by DB. 167 */ 168#define MAKE_STAT_LIST(s, v) do { \ 169 result = _SetListElemInt(interp, res, (s), (long)(v)); \ 170 if (result != TCL_OK) \ 171 goto error; \ 172} while (0) 173 174#define MAKE_WSTAT_LIST(s, v) do { \ 175 result = _SetListElemWideInt(interp, res, (s), (int64_t)(v)); \ 176 if (result != TCL_OK) \ 177 goto error; \ 178} while (0) 179 180/* 181 * MAKE_STAT_LSN appends a {name {LSNfile LSNoffset}} pair to a result list 182 * that MUST be called 'res' that is a Tcl_Obj * in the local 183 * function. This macro also assumes a label "error" to go to 184 * in the even of a Tcl error. For stat functions this will 185 * typically go before the "free" function to free the stat structure 186 * returned by DB. 187 */ 188#define MAKE_STAT_LSN(s, lsn) do { \ 189 myobjc = 2; \ 190 myobjv[0] = Tcl_NewLongObj((long)(lsn)->file); \ 191 myobjv[1] = Tcl_NewLongObj((long)(lsn)->offset); \ 192 lsnlist = Tcl_NewListObj(myobjc, myobjv); \ 193 myobjc = 2; \ 194 myobjv[0] = Tcl_NewStringObj((s), (int)strlen(s)); \ 195 myobjv[1] = lsnlist; \ 196 thislist = Tcl_NewListObj(myobjc, myobjv); \ 197 result = Tcl_ListObjAppendElement(interp, res, thislist); \ 198 if (result != TCL_OK) \ 199 goto error; \ 200} while (0) 201 202/* 203 * MAKE_STAT_STRLIST appends a {name string} pair to a result list 204 * that MUST be called 'res' that is a Tcl_Obj * in the local 205 * function. This macro also assumes a label "error" to go to 206 * in the even of a Tcl error. For stat functions this will 207 * typically go before the "free" function to free the stat structure 208 * returned by DB. 209 */ 210#define MAKE_STAT_STRLIST(s,s1) do { \ 211 result = _SetListElem(interp, res, (s), (u_int32_t)strlen(s), \ 212 (s1), (u_int32_t)strlen(s1)); \ 213 if (result != TCL_OK) \ 214 goto error; \ 215} while (0) 216 217/* 218 * MAKE_SITE_LIST appends a {eid host port status} tuple to a result list 219 * that MUST be called 'res' that is a Tcl_Obj * in the local function. 220 * This macro also assumes a label "error" to go to in the event of a Tcl 221 * error. 222 */ 223#define MAKE_SITE_LIST(e, h, p, s) do { \ 224 myobjc = 4; \ 225 myobjv[0] = Tcl_NewIntObj(e); \ 226 myobjv[1] = Tcl_NewStringObj((h), (int)strlen(h)); \ 227 myobjv[2] = Tcl_NewIntObj((int)p); \ 228 myobjv[3] = Tcl_NewStringObj((s), (int)strlen(s)); \ 229 thislist = Tcl_NewListObj(myobjc, myobjv); \ 230 result = Tcl_ListObjAppendElement(interp, res, thislist); \ 231 if (result != TCL_OK) \ 232 goto error; \ 233} while (0) 234 235/* 236 * FLAG_CHECK checks that the given flag is not set yet. 237 * If it is, it sets up an error message. 238 */ 239#define FLAG_CHECK(flag) do { \ 240 if ((flag) != 0) { \ 241 Tcl_SetResult(interp, \ 242 " Only 1 policy can be specified.\n", \ 243 TCL_STATIC); \ 244 result = TCL_ERROR; \ 245 break; \ 246 } \ 247} while (0) 248 249/* 250 * FLAG_CHECK2 checks that the given flag is not set yet or is 251 * only set to the given allowed value. 252 * If it is, it sets up an error message. 253 */ 254#define FLAG_CHECK2(flag, val) do { \ 255 if (((flag) & ~(val)) != 0) { \ 256 Tcl_SetResult(interp, \ 257 " Only 1 policy can be specified.\n", \ 258 TCL_STATIC); \ 259 result = TCL_ERROR; \ 260 break; \ 261 } \ 262} while (0) 263 264/* 265 * IS_HELP checks whether the arg we bombed on is -?, which is a help option. 266 * If it is, we return TCL_OK (but leave the result set to whatever 267 * Tcl_GetIndexFromObj says, which lists all the valid options. Otherwise 268 * return TCL_ERROR. 269 */ 270#define IS_HELP(s) \ 271 (strcmp(Tcl_GetStringFromObj(s,NULL), "-?") == 0) ? TCL_OK : TCL_ERROR 272 273#if defined(__cplusplus) 274} 275#endif 276 277#include "dbinc_auto/tcl_ext.h" 278#endif /* !_DB_TCL_DB_H_ */ 279