/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1999,2007 Oracle. All rights reserved. * * $Id: tcl_rep.c,v 12.40 2007/06/19 19:43:45 sue Exp $ */ #include "db_config.h" #include "db_int.h" #ifdef HAVE_SYSTEM_INCLUDE_FILES #include #endif #include "dbinc/tcl_db.h" #ifdef CONFIG_TEST /* * tcl_RepConfig -- * Call DB_ENV->rep_set_config(). * * PUBLIC: int tcl_RepConfig * PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *)); */ int tcl_RepConfig(interp, dbenv, list) Tcl_Interp *interp; /* Interpreter */ DB_ENV *dbenv; /* Environment pointer */ Tcl_Obj *list; /* {which on|off} */ { static const char *confwhich[] = { "bulk", "delayclient", "noautoinit", "nowait", NULL }; enum confwhich { REPCONF_BULK, REPCONF_DELAYCLIENT, REPCONF_NOAUTOINIT, REPCONF_NOWAIT }; static const char *confonoff[] = { "off", "on", NULL }; enum confonoff { REPCONF_OFF, REPCONF_ON }; Tcl_Obj **myobjv, *onoff, *which; int myobjc, on, optindex, result, ret; u_int32_t wh; result = Tcl_ListObjGetElements(interp, list, &myobjc, &myobjv); which = myobjv[0]; onoff = myobjv[1]; if (result != TCL_OK) return (result); if (Tcl_GetIndexFromObj(interp, which, confwhich, "option", TCL_EXACT, &optindex) != TCL_OK) return (IS_HELP(which)); switch ((enum confwhich)optindex) { case REPCONF_NOAUTOINIT: wh = DB_REP_CONF_NOAUTOINIT; break; case REPCONF_BULK: wh = DB_REP_CONF_BULK; break; case REPCONF_DELAYCLIENT: wh = DB_REP_CONF_DELAYCLIENT; break; case REPCONF_NOWAIT: wh = DB_REP_CONF_NOWAIT; break; default: return (TCL_ERROR); } if (Tcl_GetIndexFromObj(interp, onoff, confonoff, "option", TCL_EXACT, &optindex) != TCL_OK) return (IS_HELP(onoff)); switch ((enum confonoff)optindex) { case REPCONF_OFF: on = 0; break; case REPCONF_ON: on = 1; break; default: return (TCL_ERROR); } ret = dbenv->rep_set_config(dbenv, wh, on); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_config")); } /* * tcl_RepGetConfig -- * Call DB_ENV->rep_get_config(). * * PUBLIC: int tcl_RepGetConfig * PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *)); */ int tcl_RepGetConfig(interp, dbenv, which) Tcl_Interp *interp; /* Interpreter */ DB_ENV *dbenv; /* Environment pointer */ Tcl_Obj *which; /* which flag */ { static const char *confwhich[] = { "bulk", "delayclient", "noautoinit", "nowait", NULL }; enum confwhich { REPGCONF_BULK, REPGCONF_DELAYCLIENT, REPGCONF_NOAUTOINIT, REPGCONF_NOWAIT }; Tcl_Obj *res; int on, optindex, result, ret; u_int32_t wh; if (Tcl_GetIndexFromObj(interp, which, confwhich, "option", TCL_EXACT, &optindex) != TCL_OK) return (IS_HELP(which)); res = NULL; switch ((enum confwhich)optindex) { case REPGCONF_BULK: wh = DB_REP_CONF_BULK; break; case REPGCONF_DELAYCLIENT: wh = DB_REP_CONF_DELAYCLIENT; break; case REPGCONF_NOAUTOINIT: wh = DB_REP_CONF_NOAUTOINIT; break; case REPGCONF_NOWAIT: wh = DB_REP_CONF_NOWAIT; break; default: return (TCL_ERROR); } ret = dbenv->rep_get_config(dbenv, wh, &on); if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_config")) == TCL_OK) { res = Tcl_NewIntObj(on); Tcl_SetObjResult(interp, res); } return (result); } #endif #ifdef CONFIG_TEST /* * tcl_RepElect -- * Call DB_ENV->rep_elect(). * * PUBLIC: int tcl_RepElect * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepElect(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; /* Environment pointer */ { int nsites, nvotes, pri, result, ret; u_int32_t full_timeout, timeout; if (objc != 6 && objc != 7) { Tcl_WrongNumArgs(interp, 6, objv, "nsites nvotes pri timeout [full_timeout]"); return (TCL_ERROR); } if ((result = Tcl_GetIntFromObj(interp, objv[2], &nsites)) != TCL_OK) return (result); if ((result = Tcl_GetIntFromObj(interp, objv[3], &nvotes)) != TCL_OK) return (result); if ((result = Tcl_GetIntFromObj(interp, objv[4], &pri)) != TCL_OK) return (result); if ((result = _GetUInt32(interp, objv[5], &timeout)) != TCL_OK) return (result); full_timeout = 0; if (objc == 7) if ((result = _GetUInt32(interp, objv[5], &timeout)) != TCL_OK) return (result); _debug_check(); if ((ret = dbenv->rep_set_priority(dbenv, pri)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_elect (rep_set_priority)")); if ((ret = dbenv->rep_set_timeout(dbenv, DB_REP_ELECTION_TIMEOUT, timeout)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_elect (rep_set_timeout)")); if (full_timeout != 0 && (ret = dbenv->rep_set_timeout(dbenv, DB_REP_FULL_ELECTION_TIMEOUT, full_timeout)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_elect (rep_set_timeout)")); ret = dbenv->rep_elect(dbenv, nsites, nvotes, 0); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_elect")); } #endif #ifdef CONFIG_TEST /* * tcl_RepFlush -- * Call DB_ENV->rep_flush(). * * PUBLIC: int tcl_RepFlush * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepFlush(interp, objc, objv, dbenv) Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; DB_ENV *dbenv; { int ret; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } _debug_check(); ret = dbenv->rep_flush(dbenv); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_flush")); } #endif #ifdef CONFIG_TEST /* * tcl_RepSync -- * Call DB_ENV->rep_sync(). * * PUBLIC: int tcl_RepSync * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepSync(interp, objc, objv, dbenv) Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; DB_ENV *dbenv; { int ret; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } _debug_check(); ret = dbenv->rep_sync(dbenv, 0); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_sync")); } #endif #ifdef CONFIG_TEST /* * tcl_RepLease -- * Call DB_ENV->rep_set_lease(). * * PUBLIC: int tcl_RepLease __P((Tcl_Interp *, int, Tcl_Obj * CONST *, * PUBLIC: DB_ENV *)); */ int tcl_RepLease(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; { int result, ret; u_int32_t nsites, skew, timeout; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "{nsites timeout clockskew}"); return (TCL_ERROR); } if ((result = _GetUInt32(interp, objv[0], &nsites)) != TCL_OK) return (result); if ((result = _GetUInt32(interp, objv[1], &timeout)) != TCL_OK) return (result); if ((result = _GetUInt32(interp, objv[2], &skew)) != TCL_OK) return (result); ret = dbenv->rep_set_nsites(dbenv, (int)nsites); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "rep_set_nsites"); if (result != TCL_OK) return (result); ret = dbenv->rep_set_timeout(dbenv, DB_REP_LEASE_TIMEOUT, (db_timeout_t)timeout); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "rep_set_timeout"); if (result != TCL_OK) return (result); _debug_check(); ret = dbenv->rep_set_lease(dbenv, skew, 0); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_set_lease")); } #endif #ifdef CONFIG_TEST /* * tcl_RepLimit -- * Call DB_ENV->rep_set_limit(). * * PUBLIC: int tcl_RepLimit * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepLimit(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; /* Environment pointer */ { int result, ret; u_int32_t bytes, gbytes; if (objc != 4) { Tcl_WrongNumArgs(interp, 4, objv, "gbytes bytes"); return (TCL_ERROR); } if ((result = _GetUInt32(interp, objv[2], &gbytes)) != TCL_OK) return (result); if ((result = _GetUInt32(interp, objv[3], &bytes)) != TCL_OK) return (result); _debug_check(); if ((ret = dbenv->rep_set_limit(dbenv, gbytes, bytes)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env set_rep_limit")); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env set_rep_limit")); } #endif #ifdef CONFIG_TEST /* * tcl_RepRequest -- * Call DB_ENV->set_rep_request(). * * PUBLIC: int tcl_RepRequest * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepRequest(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; /* Environment pointer */ { int result, ret; u_int32_t min, max; if (objc != 4) { Tcl_WrongNumArgs(interp, 4, objv, "min max"); return (TCL_ERROR); } if ((result = _GetUInt32(interp, objv[2], &min)) != TCL_OK) return (result); if ((result = _GetUInt32(interp, objv[3], &max)) != TCL_OK) return (result); _debug_check(); if ((ret = dbenv->set_rep_request(dbenv, min, max)) != 0) return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env set_rep_request")); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env set_rep_request")); } #endif #ifdef CONFIG_TEST /* * tcl_RepNoarchiveTimeout -- * Reset the master update timer, to allow immediate log archiving. * * PUBLIC: int tcl_RepNoarchiveTimeout * PUBLIC: __P((Tcl_Interp *, DB_ENV *)); */ int tcl_RepNoarchiveTimeout(interp, dbenv) Tcl_Interp *interp; /* Interpreter */ DB_ENV *dbenv; /* Environment pointer */ { REGENV *renv; REGINFO *infop; _debug_check(); infop = dbenv->reginfo; renv = infop->primary; REP_SYSTEM_LOCK(dbenv); F_CLR(renv, DB_REGENV_REPLOCKED); renv->op_timestamp = 0; REP_SYSTEM_UNLOCK(dbenv); return (_ReturnSetup(interp, 0, DB_RETOK_STD(0), "env test force noarchive_timeout")); } #endif #ifdef CONFIG_TEST /* * tcl_RepTransport -- * Call DB_ENV->rep_set_transport(). * * PUBLIC: int tcl_RepTransport __P((Tcl_Interp *, int, Tcl_Obj * CONST *, * PUBLIC: DB_ENV *, DBTCL_INFO *)); * * Note that this normally can/should be achieved as an argument to * berkdb env, but we need to test changing the transport function on * the fly. */ int tcl_RepTransport(interp, objc, objv, dbenv, ip) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; DBTCL_INFO *ip; { int intarg, result, ret; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, "{id transport_func"); return (TCL_ERROR); } /* * Store the objects containing the machine ID * and the procedure name. We don't need to crack * the send procedure out now, but we do convert the * machine ID to an int, since rep_set_transport needs * it. Even so, it'll be easier later to deal with * the Tcl_Obj *, so we save that, not the int. * * Note that we Tcl_IncrRefCount both objects * independently; Tcl is free to discard the list * that they're bundled into. */ /* * Check that the machine ID is an int. Note that * we do want to use GetIntFromObj; the machine * ID is explicitly an int, not a u_int32_t. */ if (ip->i_rep_eid != NULL) Tcl_DecrRefCount(ip->i_rep_eid); ip->i_rep_eid = objv[0]; Tcl_IncrRefCount(ip->i_rep_eid); result = Tcl_GetIntFromObj(interp, ip->i_rep_eid, &intarg); if (result != TCL_OK) return (result); if (ip->i_rep_send != NULL) Tcl_DecrRefCount(ip->i_rep_send); ip->i_rep_send = objv[1]; Tcl_IncrRefCount(ip->i_rep_send); _debug_check(); ret = dbenv->rep_set_transport(dbenv, intarg, tcl_rep_send); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_transport")); } #endif #ifdef CONFIG_TEST /* * tcl_RepStart -- * Call DB_ENV->rep_start(). * * PUBLIC: int tcl_RepStart * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); * * Note that this normally can/should be achieved as an argument to * berkdb env, but we need to test forcible upgrading of clients, which * involves calling this on an open environment handle. */ int tcl_RepStart(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; { static const char *tclrpstrt[] = { "-client", "-master", NULL }; enum tclrpstrt { TCL_RPSTRT_CLIENT, TCL_RPSTRT_MASTER }; char *arg; int i, optindex, ret; u_int32_t flag; flag = 0; if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, "[-master/-client]"); return (TCL_ERROR); } i = 2; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], tclrpstrt, "option", TCL_EXACT, &optindex) != TCL_OK) { arg = Tcl_GetStringFromObj(objv[i], NULL); if (arg[0] == '-') return (IS_HELP(objv[i])); else Tcl_ResetResult(interp); break; } i++; switch ((enum tclrpstrt)optindex) { case TCL_RPSTRT_CLIENT: flag = DB_REP_CLIENT; break; case TCL_RPSTRT_MASTER: flag = DB_REP_MASTER; break; } } _debug_check(); ret = dbenv->rep_start(dbenv, NULL, flag); return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_start")); } #endif #ifdef CONFIG_TEST /* * tcl_RepProcessMessage -- * Call DB_ENV->rep_process_message(). * * PUBLIC: int tcl_RepProcessMessage * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepProcessMessage(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; /* Environment pointer */ { DBT control, rec; DB_LSN permlsn; Tcl_Obj *lsnlist, *myobjv[2], *res; void *ctmp, *rtmp; char *msg; int eid; int freectl, freerec, myobjc, result, ret; if (objc != 5) { Tcl_WrongNumArgs(interp, 5, objv, "id control rec"); return (TCL_ERROR); } freectl = freerec = 0; memset(&control, 0, sizeof(control)); memset(&rec, 0, sizeof(rec)); if ((result = Tcl_GetIntFromObj(interp, objv[2], &eid)) != TCL_OK) return (result); ret = _CopyObjBytes(interp, objv[3], &ctmp, &control.size, &freectl); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_REPPMSG(ret), "rep_proc_msg"); return (result); } control.data = ctmp; ret = _CopyObjBytes(interp, objv[4], &rtmp, &rec.size, &freerec); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_REPPMSG(ret), "rep_proc_msg"); goto out; } rec.data = rtmp; _debug_check(); ret = dbenv->rep_process_message(dbenv, &control, &rec, eid, &permlsn); /* * !!! * The TCL API diverges from the C++/Java APIs here. For us, it * is OK to get DUPMASTER and HOLDELECTION for testing purposes. */ result = _ReturnSetup(interp, ret, DB_RETOK_REPPMSG(ret) || ret == DB_REP_DUPMASTER || ret == DB_REP_HOLDELECTION, "env rep_process_message"); if (result != TCL_OK) goto out; /* * We have a valid return. We need to return a variety of information. * It will be one of the following: * {0 0} - Make a 0 return a list for consistent return structure. * {DUPMASTER 0} - DUPMASTER, no other info needed. * {HOLDELECTION 0} - HOLDELECTION, no other info needed. * {NEWMASTER #} - NEWMASTER and its ID. * {NEWSITE 0} - NEWSITE, no other info needed. * {IGNORE {LSN list}} - IGNORE and this msg's LSN. * {ISPERM {LSN list}} - ISPERM and the perm LSN. * {NOTPERM {LSN list}} - NOTPERM and this msg's LSN. */ myobjc = 2; switch (ret) { case 0: myobjv[0] = Tcl_NewIntObj(0); myobjv[1] = Tcl_NewIntObj(0); break; case DB_REP_DUPMASTER: myobjv[0] = Tcl_NewByteArrayObj( (u_char *)"DUPMASTER", (int)strlen("DUPMASTER")); myobjv[1] = Tcl_NewIntObj(0); break; case DB_REP_HOLDELECTION: myobjv[0] = Tcl_NewByteArrayObj( (u_char *)"HOLDELECTION", (int)strlen("HOLDELECTION")); myobjv[1] = Tcl_NewIntObj(0); break; case DB_REP_IGNORE: myobjv[0] = Tcl_NewLongObj((long)permlsn.file); myobjv[1] = Tcl_NewLongObj((long)permlsn.offset); lsnlist = Tcl_NewListObj(myobjc, myobjv); myobjv[0] = Tcl_NewByteArrayObj( (u_char *)"IGNORE", (int)strlen("IGNORE")); myobjv[1] = lsnlist; break; case DB_REP_ISPERM: myobjv[0] = Tcl_NewLongObj((long)permlsn.file); myobjv[1] = Tcl_NewLongObj((long)permlsn.offset); lsnlist = Tcl_NewListObj(myobjc, myobjv); myobjv[0] = Tcl_NewByteArrayObj( (u_char *)"ISPERM", (int)strlen("ISPERM")); myobjv[1] = lsnlist; break; case DB_REP_NEWSITE: myobjv[0] = Tcl_NewByteArrayObj( (u_char *)"NEWSITE", (int)strlen("NEWSITE")); myobjv[1] = Tcl_NewIntObj(0); break; case DB_REP_NOTPERM: myobjv[0] = Tcl_NewLongObj((long)permlsn.file); myobjv[1] = Tcl_NewLongObj((long)permlsn.offset); lsnlist = Tcl_NewListObj(myobjc, myobjv); myobjv[0] = Tcl_NewByteArrayObj( (u_char *)"NOTPERM", (int)strlen("NOTPERM")); myobjv[1] = lsnlist; break; default: msg = db_strerror(ret); Tcl_AppendResult(interp, msg, NULL); Tcl_SetErrorCode(interp, "BerkeleyDB", msg, NULL); result = TCL_ERROR; goto out; } res = Tcl_NewListObj(myobjc, myobjv); if (res != NULL) Tcl_SetObjResult(interp, res); out: if (freectl) __os_free(NULL, ctmp); if (freerec) __os_free(NULL, rtmp); return (result); } #endif #ifdef CONFIG_TEST /* * tcl_RepStat -- * Call DB_ENV->rep_stat(). * * PUBLIC: int tcl_RepStat * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepStat(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; { DB_REP_STAT *sp; Tcl_Obj *myobjv[2], *res, *thislist, *lsnlist; u_int32_t flag; int myobjc, result, ret; char *arg; flag = 0; result = TCL_OK; if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return (TCL_ERROR); } if (objc == 3) { arg = Tcl_GetStringFromObj(objv[2], NULL); if (strcmp(arg, "-clear") == 0) flag = DB_STAT_CLEAR; else { Tcl_SetResult(interp, "db stat: unknown arg", TCL_STATIC); return (TCL_ERROR); } } _debug_check(); ret = dbenv->rep_stat(dbenv, &sp, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "rep stat"); if (result == TCL_ERROR) return (result); /* * Have our stats, now construct the name value * list pairs and free up the memory. */ res = Tcl_NewObj(); #ifdef HAVE_STATISTICS /* * MAKE_STAT_* assumes 'res' and 'error' label. */ if (sp->st_status == DB_REP_MASTER) MAKE_STAT_LIST("Master", 1); else MAKE_STAT_LIST("Client", 1); MAKE_STAT_LSN("Next LSN expected", &sp->st_next_lsn); MAKE_STAT_LSN("First missed LSN", &sp->st_waiting_lsn); MAKE_STAT_LIST("Bulk buffer fills", sp->st_bulk_fills); MAKE_STAT_LIST("Bulk buffer overflows", sp->st_bulk_overflows); MAKE_STAT_LIST("Bulk records stored", sp->st_bulk_records); MAKE_STAT_LIST("Bulk buffer transfers", sp->st_bulk_transfers); MAKE_STAT_LIST("Client service requests", sp->st_client_svc_req); MAKE_STAT_LIST("Client service req misses", sp->st_client_svc_miss); MAKE_STAT_LIST("Client rerequests", sp->st_client_rerequests); MAKE_STAT_LIST("Duplicate master conditions", sp->st_dupmasters); MAKE_STAT_LIST("Environment ID", sp->st_env_id); MAKE_STAT_LIST("Environment priority", sp->st_env_priority); MAKE_STAT_LIST("Generation number", sp->st_gen); MAKE_STAT_LIST("Election generation number", sp->st_egen); MAKE_STAT_LIST("Startup complete", sp->st_startup_complete); MAKE_STAT_LIST("Duplicate log records received", sp->st_log_duplicated); MAKE_STAT_LIST("Current log records queued", sp->st_log_queued); MAKE_STAT_LIST("Maximum log records queued", sp->st_log_queued_max); MAKE_STAT_LIST("Total log records queued", sp->st_log_queued_total); MAKE_STAT_LIST("Log records received", sp->st_log_records); MAKE_STAT_LIST("Log records requested", sp->st_log_requested); MAKE_STAT_LIST("Master environment ID", sp->st_master); MAKE_STAT_LIST("Master changes", sp->st_master_changes); MAKE_STAT_LIST("Messages with bad generation number", sp->st_msgs_badgen); MAKE_STAT_LIST("Messages processed", sp->st_msgs_processed); MAKE_STAT_LIST("Messages ignored for recovery", sp->st_msgs_recover); MAKE_STAT_LIST("Message send failures", sp->st_msgs_send_failures); MAKE_STAT_LIST("Messages sent", sp->st_msgs_sent); MAKE_STAT_LIST("New site messages", sp->st_newsites); MAKE_STAT_LIST("Number of sites in replication group", sp->st_nsites); MAKE_STAT_LIST("Transmission limited", sp->st_nthrottles); MAKE_STAT_LIST("Outdated conditions", sp->st_outdated); MAKE_STAT_LIST("Transactions applied", sp->st_txns_applied); MAKE_STAT_LIST("Next page expected", sp->st_next_pg); MAKE_STAT_LIST("First missed page", sp->st_waiting_pg); MAKE_STAT_LIST("Duplicate pages received", sp->st_pg_duplicated); MAKE_STAT_LIST("Pages received", sp->st_pg_records); MAKE_STAT_LIST("Pages requested", sp->st_pg_requested); MAKE_STAT_LIST("Elections held", sp->st_elections); MAKE_STAT_LIST("Elections won", sp->st_elections_won); MAKE_STAT_LIST("Election phase", sp->st_election_status); MAKE_STAT_LIST("Election winner", sp->st_election_cur_winner); MAKE_STAT_LIST("Election generation number", sp->st_election_gen); MAKE_STAT_LSN("Election max LSN", &sp->st_election_lsn); MAKE_STAT_LIST("Election sites", sp->st_election_nsites); MAKE_STAT_LIST("Election nvotes", sp->st_election_nvotes); MAKE_STAT_LIST("Election priority", sp->st_election_priority); MAKE_STAT_LIST("Election tiebreaker", sp->st_election_tiebreaker); MAKE_STAT_LIST("Election votes", sp->st_election_votes); MAKE_STAT_LIST("Election seconds", sp->st_election_sec); MAKE_STAT_LIST("Election usecs", sp->st_election_usec); MAKE_STAT_LIST("Start-sync operations delayed", sp->st_startsync_delayed); #endif Tcl_SetObjResult(interp, res); error: __os_ufree(dbenv, sp); return (result); } /* * tcl_RepMgr -- * Configure and start the Replication Manager. * * PUBLIC: int tcl_RepMgr * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepMgr(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; /* Environment pointer */ { static const char *rmgr[] = { "-ack", "-local", "-msgth", "-nsites", "-pri", "-remote", "-start", "-timeout", NULL }; enum rmgr { RMGR_ACK, RMGR_LOCAL, RMGR_MSGTH, RMGR_NSITES, RMGR_PRI, RMGR_REMOTE, RMGR_START, RMGR_TIMEOUT }; Tcl_Obj **myobjv; long to; int ack, i, myobjc, optindex, result, ret, totype; u_int32_t msgth, remote_flag, start_flag, uintarg; char *arg; result = TCL_OK; ack = ret = totype = 0; msgth = 1; remote_flag = start_flag = 0; if (objc <= 2) { Tcl_WrongNumArgs(interp, 2, objv, "?args?"); return (TCL_ERROR); } /* * Get the command name index from the object based on the bdbcmds * defined above. */ i = 2; while (i < objc) { Tcl_ResetResult(interp); if (Tcl_GetIndexFromObj(interp, objv[i], rmgr, "option", TCL_EXACT, &optindex) != TCL_OK) { result = IS_HELP(objv[i]); goto error; } i++; switch ((enum rmgr)optindex) { case RMGR_ACK: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-ack policy?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(objv[i++], NULL); if (strcmp(arg, "all") == 0) ack = DB_REPMGR_ACKS_ALL; else if (strcmp(arg, "allpeers") == 0) ack = DB_REPMGR_ACKS_ALL_PEERS; else if (strcmp(arg, "none") == 0) ack = DB_REPMGR_ACKS_NONE; else if (strcmp(arg, "one") == 0) ack = DB_REPMGR_ACKS_ONE; else if (strcmp(arg, "onepeer") == 0) ack = DB_REPMGR_ACKS_ONE_PEER; else if (strcmp(arg, "quorum") == 0) ack = DB_REPMGR_ACKS_QUORUM; else { Tcl_AddErrorInfo(interp, "ack: illegal policy"); result = TCL_ERROR; break; } _debug_check(); ret = dbenv->repmgr_set_ack_policy(dbenv, ack); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "ack"); break; case RMGR_LOCAL: result = Tcl_ListObjGetElements(interp, objv[i], &myobjc, &myobjv); if (result == TCL_OK) i++; else break; if (myobjc != 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-local {host port}?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(myobjv[0], NULL); if ((result = _GetUInt32(interp, myobjv[1], &uintarg)) != TCL_OK) break; _debug_check(); /* * No flags for now. */ ret = dbenv->repmgr_set_local_site(dbenv, arg, uintarg, 0); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "repmgr_set_local_site"); break; case RMGR_MSGTH: if (i >= objc) { Tcl_WrongNumArgs( interp, 2, objv, "?-msgth nth?"); result = TCL_ERROR; break; } result = _GetUInt32(interp, objv[i++], &msgth); break; case RMGR_NSITES: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-nsites num_sites?"); result = TCL_ERROR; break; } result = _GetUInt32(interp, objv[i++], &uintarg); if (result == TCL_OK) { _debug_check(); ret = dbenv-> rep_set_nsites(dbenv, (int)uintarg); } break; case RMGR_PRI: if (i >= objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-pri priority?"); result = TCL_ERROR; break; } result = _GetUInt32(interp, objv[i++], &uintarg); if (result == TCL_OK) { _debug_check(); ret = dbenv-> rep_set_priority(dbenv, (int)uintarg); } break; case RMGR_REMOTE: result = Tcl_ListObjGetElements(interp, objv[i], &myobjc, &myobjv); if (result == TCL_OK) i++; else break; if (myobjc != 2 && myobjc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?-remote {host port [peer]}?"); result = TCL_ERROR; break; } /* * Get the flag first so we can reuse 'arg'. */ if (myobjc == 3) { arg = Tcl_GetStringFromObj(myobjv[2], NULL); if (strcmp(arg, "peer") == 0) remote_flag = DB_REPMGR_PEER; else { Tcl_AddErrorInfo(interp, "remote: illegal flag"); result = TCL_ERROR; break; } } arg = Tcl_GetStringFromObj(myobjv[0], NULL); if ((result = _GetUInt32(interp, myobjv[1], &uintarg)) != TCL_OK) break; _debug_check(); ret = dbenv->repmgr_add_remote_site(dbenv, arg, uintarg, NULL, remote_flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "repmgr_add_remote_site"); break; case RMGR_START: if (i >= objc) { Tcl_WrongNumArgs( interp, 2, objv, "?-start state?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(objv[i++], NULL); if (strcmp(arg, "master") == 0) start_flag = DB_REP_MASTER; else if (strcmp(arg, "client") == 0) start_flag = DB_REP_CLIENT; else if (strcmp(arg, "elect") == 0) start_flag = DB_REP_ELECTION; else { Tcl_AddErrorInfo( interp, "start: illegal state"); result = TCL_ERROR; break; } /* * Some config functions need to be called * before repmgr_start. So finish parsing all * the args and call repmgr_start at the end. */ break; case RMGR_TIMEOUT: result = Tcl_ListObjGetElements(interp, objv[i], &myobjc, &myobjv); if (result == TCL_OK) i++; else break; if (myobjc != 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-timeout {type to}?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(myobjv[0], NULL); if (strcmp(arg, "ack") == 0) totype = DB_REP_ACK_TIMEOUT; else if (strcmp(arg, "elect") == 0) totype = DB_REP_ELECTION_TIMEOUT; else if (strcmp(arg, "elect_retry") == 0) totype = DB_REP_ELECTION_RETRY; else if (strcmp(arg, "conn_retry") == 0) totype = DB_REP_CONNECTION_RETRY; else { Tcl_AddErrorInfo(interp, "timeout: illegal type"); result = TCL_ERROR; break; } if ((result = Tcl_GetLongFromObj( interp, myobjv[1], &to)) != TCL_OK) break; _debug_check(); ret = dbenv->rep_set_timeout(dbenv, totype, (db_timeout_t)to); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "rep_set_timeout"); break; } /* * If, at any time, parsing the args we get an error, * bail out and return. */ if (result != TCL_OK) goto error; } /* * Only call repmgr_start if needed. The user may use this * call just to reconfigure, change policy, etc. */ if (start_flag != 0 && result == TCL_OK) { _debug_check(); ret = dbenv->repmgr_start(dbenv, (int)msgth, start_flag); result = _ReturnSetup( interp, ret, DB_RETOK_STD(ret), "repmgr_start"); } error: return (result); } /* * tcl_RepMgrStat -- * Call DB_ENV->repmgr_stat(). * * PUBLIC: int tcl_RepMgrStat * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); */ int tcl_RepMgrStat(interp, objc, objv, dbenv) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB_ENV *dbenv; { DB_REPMGR_STAT *sp; Tcl_Obj *res; u_int32_t flag; int result, ret; char *arg; flag = 0; result = TCL_OK; if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return (TCL_ERROR); } if (objc == 3) { arg = Tcl_GetStringFromObj(objv[2], NULL); if (strcmp(arg, "-clear") == 0) flag = DB_STAT_CLEAR; else { Tcl_SetResult(interp, "db stat: unknown arg", TCL_STATIC); return (TCL_ERROR); } } _debug_check(); ret = dbenv->repmgr_stat(dbenv, &sp, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "repmgr stat"); if (result == TCL_ERROR) return (result); /* * Have our stats, now construct the name value * list pairs and free up the memory. */ res = Tcl_NewObj(); #ifdef HAVE_STATISTICS /* * MAKE_STAT_* assumes 'res' and 'error' label. */ MAKE_STAT_LIST("Acknowledgement failures", sp->st_perm_failed); MAKE_STAT_LIST("Messages delayed", sp->st_msgs_queued); MAKE_STAT_LIST("Messages discarded", sp->st_msgs_dropped); MAKE_STAT_LIST("Connections dropped", sp->st_connection_drop); MAKE_STAT_LIST("Failed re-connects", sp->st_connect_fail); #endif Tcl_SetObjResult(interp, res); error: __os_ufree(dbenv, sp); return (result); } #endif