/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1999, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ #ifndef _DB_TCL_DB_H_ #define _DB_TCL_DB_H_ #if defined(__cplusplus) extern "C" { #endif #define MSG_SIZE 100 /* Message size */ enum INFOTYPE { I_AUX, I_DB, I_DBC, I_DBSTREAM, I_ENV, I_LOCK, I_LOGC, I_MP, I_NDBM, I_PG, I_SEQ, I_TXN}; #define MAX_ID 8 /* Maximum number of sub-id's we need */ #define DBTCL_PREP 64 /* Size of txn_recover preplist */ #define DBTCL_DBM 1 #define DBTCL_NDBM 2 #define DBTCL_GETCLOCK 0 #define DBTCL_GETINQUEUE_MAX 1 #define DBTCL_GETINQUEUE_REDZONE 2 #define DBTCL_GETLIMIT 3 #define DBTCL_GETREQ 4 #define DBTCL_MUT_ALIGN 0 #define DBTCL_MUT_INCR 1 #define DBTCL_MUT_INIT 2 #define DBTCL_MUT_MAX 3 #define DBTCL_MUT_TAS 4 /* * Data structure to record information about events that have occurred. Tcl * command "env event_info" can retrieve all the information except the number * of times, and "env event_count" can retrieve the number of times a specific * event is fired. We added "env event_count" instead of merging the times * information into "env event_info" to avoid breaking the existing tests. * Tcl command "env event_info -clear" can be used to reset the info. * * Besides the bit flag that records the fact that an event type occurred, some * event types have associated "info" and we record that here too. When new * event types are invented that have associated info, we should add a field * here to record that info as well, so that it can be returned to the script * with the "env event_info" results. */ typedef struct dbtcl_event_info { u_int32_t events; /* Bit flag on for each event fired. */ int panic_error; int newmaster_eid; int added_eid; int removed_eid; pid_t attached_process; int connected_eid; DB_REPMGR_CONN_ERR conn_broken_info; DB_REPMGR_CONN_ERR conn_failed_try_info; DB_LSN sync_point; size_t count[32]; /* The number of times for each event. */ } DBTCL_EVENT_INFO; /* * Why use a home grown package over the Tcl_Hash functions? * * We could have implemented the stuff below without maintaining our * own list manipulation, efficiently hashing it with the available * Tcl functions (Tcl_CreateHashEntry, Tcl_GetHashValue, etc). I chose * not to do so for these reasons: * * We still need the information below. Using the hashing only removes * us from needing the next/prev pointers. We still need the structure * itself because we need more than one value associated with a widget. * We need to keep track of parent pointers for sub-widgets (like cursors) * so we can correctly close. We need to keep track of individual widget's * id counters for any sub-widgets they may have. We need to be able to * associate the name/client data outside the scope of the widget. * * So, is it better to use the hashing rather than * the linear list we have now? I decided against it for the simple reason * that to access the structure would require two calls. The first is * Tcl_FindHashEntry(table, key) and then, once we have the entry, we'd * have to do Tcl_GetHashValue(entry) to get the pointer of the structure. * * I believe the number of simultaneous DB widgets in existence at one time * is not going to be that large (more than several dozen) such that * linearly searching the list is not going to impact performance in a * noticeable way. Should performance be impacted due to the size of the * info list, then perhaps it is time to revisit this decision. */ typedef struct dbtcl_info { LIST_ENTRY(dbtcl_info) entries; Tcl_Interp *i_interp; char *i_name; enum INFOTYPE i_type; union infop { DB *dbp; DBC *dbcp; DB_ENV *envp; DB_LOCK *lock; DB_LOGC *logc; DB_MPOOLFILE *mp; DB_STREAM *dbsp; DB_TXN *txnp; void *anyp; } un; union data { int anydata; db_pgno_t pgno; /* For I_MP. */ u_int32_t lockid; /* For I_LOCK. */ DBTCL_EVENT_INFO *event_info; /* For I_ENV. */ DB_TXN_TOKEN *commit_token; /* For I_TXN. */ } und; union data2 { int anydata; int pagesz; /* For I_MP. */ DB_COMPACT *c_data; /* For I_DB. */ db_mutex_t mutex; /* Protects event_info (I_ENV). */ } und2; DBT i_lockobj; FILE *i_err; char *i_errpfx; FILE *i_msg; /* Callbacks--Tcl_Objs containing proc names */ Tcl_Obj *i_compare; Tcl_Obj *i_dupcompare; Tcl_Obj *i_foreign_call; Tcl_Obj *i_hashproc; Tcl_Obj *i_isalive; Tcl_Obj *i_part_callback; Tcl_Obj *i_rep_send; Tcl_Obj *i_rep_view; Tcl_Obj *i_second_call; /* Environment ID for the i_rep_send callback. */ Tcl_Obj *i_rep_eid; struct dbtcl_info *i_parent; int i_otherid[MAX_ID]; /* Heap dbs have an associated recno db, and secondary db. */ DB *hrdbp; DB *hsdbp; } DBTCL_INFO; #define i_anyp un.anyp #define i_dbp un.dbp #define i_dbcp un.dbcp #define i_dbsp un.dbsp #define i_envp un.envp #define i_lock un.lock #define i_logc un.logc #define i_mp un.mp #define i_pagep un.anyp #define i_txnp un.txnp #define i_data und.anydata #define i_pgno und.pgno #define i_locker und.lockid #define i_event_info und.event_info #define i_commit_token und.commit_token #define i_data2 und2.anydata #define i_pgsz und2.pagesz #define i_cdata und2.c_data #define i_mutex und2.mutex #define i_envtxnid i_otherid[0] #define i_envmpid i_otherid[1] #define i_envlockid i_otherid[2] #define i_envlogcid i_otherid[3] #define i_mppgid i_otherid[0] #define i_dbdbcid i_otherid[0] #define i_dbcdbsid i_otherid[0] extern int __debug_on, __debug_print, __debug_stop, __debug_test; typedef struct dbtcl_global { LIST_HEAD(infohead, dbtcl_info) g_infohead; } DBTCL_GLOBAL; #define __db_infohead __dbtcl_global.g_infohead extern DBTCL_GLOBAL __dbtcl_global; /* * Tcl_NewStringObj takes an "int" length argument, when the typical use is to * call it with a size_t length (for example, returned by strlen). Tcl is in * the wrong, but that doesn't help us much -- cast the argument. */ #define NewStringObj(a, b) \ Tcl_NewStringObj((a), (int)(b)) #define NAME_TO_DB(name) (DB *)_NameToPtr((name)) #define NAME_TO_DBC(name) (DBC *)_NameToPtr((name)) #define NAME_TO_ENV(name) (DB_ENV *)_NameToPtr((name)) #define NAME_TO_LOCK(name) (DB_LOCK *)_NameToPtr((name)) #define NAME_TO_MP(name) (DB_MPOOLFILE *)_NameToPtr((name)) #define NAME_TO_TXN(name) (DB_TXN *)_NameToPtr((name)) #define NAME_TO_SEQUENCE(name) (DB_SEQUENCE *)_NameToPtr((name)) /* * MAKE_STAT_LIST appends a {name value} pair to a result list that MUST be * called 'res' that is a Tcl_Obj * in the local function. This macro also * assumes a label "error" to go to in the event of a Tcl error. For stat * functions this will typically go before the "free" function to free the * stat structure returned by DB. */ #ifdef HAVE_STATISTICS #define MAKE_STAT_LIST(s, v) do { \ result = _SetListElemInt(interp, res, (s), (long)(v)); \ if (result != TCL_OK) \ goto error; \ } while (0) #define MAKE_WSTAT_LIST(s, v) do { \ result = _SetListElemWideInt(interp, res, (s), (int64_t)(v)); \ if (result != TCL_OK) \ goto error; \ } while (0) #else /* These do-nothing versions streamline the code & reduce warning messages. */ #define MAKE_STAT_LIST(s, v) if (0) goto error #define MAKE_WSTAT_LIST(s, v) if (0) goto error #endif /* * MAKE_STAT_LSN appends a {name {LSNfile LSNoffset}} pair to a result list * that MUST be called 'res' that is a Tcl_Obj * in the local * function. This macro also assumes a label "error" to go to * in the even of a Tcl error. For stat functions this will * typically go before the "free" function to free the stat structure * returned by DB. */ #define MAKE_STAT_LSN(s, lsn) do { \ myobjc = 2; \ myobjv[0] = Tcl_NewLongObj((long)(lsn)->file); \ myobjv[1] = Tcl_NewLongObj((long)(lsn)->offset); \ lsnlist = Tcl_NewListObj(myobjc, myobjv); \ myobjc = 2; \ myobjv[0] = Tcl_NewStringObj((s), (int)strlen(s)); \ myobjv[1] = lsnlist; \ thislist = Tcl_NewListObj(myobjc, myobjv); \ result = Tcl_ListObjAppendElement(interp, res, thislist); \ if (result != TCL_OK) \ goto error; \ } while (0) /* * MAKE_STAT_STRLIST appends a {name string} pair to a result list * that MUST be called 'res' that is a Tcl_Obj * in the local * function. This macro also assumes a label "error" to go to * in the even of a Tcl error. For stat functions this will * typically go before the "free" function to free the stat structure * returned by DB. */ #define MAKE_STAT_STRLIST(s,s1) do { \ result = _SetListElem(interp, res, (s), (u_int32_t)strlen(s), \ (s1), (u_int32_t)strlen(s1)); \ if (result != TCL_OK) \ goto error; \ } while (0) /* * MAKE_SITE_LIST appends a {eid host port status} tuple to a result list * that MUST be called 'res' that is a Tcl_Obj * in the local function. * This macro also assumes a label "error" to go to in the event of a Tcl * error. */ #define MAKE_SITE_LIST(e, h, p, s, pr, vw) do { \ myobjc = 6; \ myobjv[0] = Tcl_NewIntObj(e); \ myobjv[1] = Tcl_NewStringObj((h), (int)strlen(h)); \ myobjv[2] = Tcl_NewIntObj((int)p); \ myobjv[3] = Tcl_NewStringObj((s), (int)strlen(s)); \ myobjv[4] = Tcl_NewStringObj((pr), (int)strlen(pr)); \ myobjv[5] = Tcl_NewStringObj((vw), (int)strlen(vw)); \ thislist = Tcl_NewListObj(myobjc, myobjv); \ result = Tcl_ListObjAppendElement(interp, res, thislist); \ if (result != TCL_OK) \ goto error; \ } while (0) /* * FLAG_CHECK checks that the given flag is not set yet. * If it is, it sets up an error message. */ #define FLAG_CHECK(flag) do { \ if ((flag) != 0) { \ Tcl_SetResult(interp, \ " Only 1 policy can be specified.\n", \ TCL_STATIC); \ result = TCL_ERROR; \ break; \ } \ } while (0) /* * FLAG_CHECK2 checks that the given flag is not set yet or is * only set to the given allowed value. * If it is, it sets up an error message. */ #define FLAG_CHECK2(flag, val) do { \ if (((flag) & ~(val)) != 0) { \ Tcl_SetResult(interp, \ " Only 1 policy can be specified.\n", \ TCL_STATIC); \ result = TCL_ERROR; \ break; \ } \ } while (0) /* * IS_HELP checks whether the arg we bombed on is -?, which is a help option. * If it is, we return TCL_OK (but leave the result set to whatever * Tcl_GetIndexFromObj says, which lists all the valid options. Otherwise * return TCL_ERROR. */ #define IS_HELP(s) \ (strcmp(Tcl_GetStringFromObj(s,NULL), "-?") == 0) ? TCL_OK : TCL_ERROR #if defined(__cplusplus) } #endif #include "dbinc_auto/tcl_ext.h" #endif /* !_DB_TCL_DB_H_ */