libdb/lang/tcl/tcl_rep.c

1691 lines
42 KiB
C

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999, 2011 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
#include "db_config.h"
#include "db_int.h"
#ifdef HAVE_SYSTEM_INCLUDE_FILES
#include <tcl.h>
#endif
#include "dbinc/tcl_db.h"
#ifdef CONFIG_TEST
typedef struct {
const char *name;
u_int32_t value;
} NAMEMAP;
static const NAMEMAP rep_ack_policies[] = {
{"all", DB_REPMGR_ACKS_ALL},
{"allavailable", DB_REPMGR_ACKS_ALL_AVAILABLE},
{"allpeers", DB_REPMGR_ACKS_ALL_PEERS},
{"none", DB_REPMGR_ACKS_NONE},
{"one", DB_REPMGR_ACKS_ONE},
{"onepeer", DB_REPMGR_ACKS_ONE_PEER},
{"quorum", DB_REPMGR_ACKS_QUORUM},
{NULL, 0}
};
static const NAMEMAP rep_config_types[] = {
{"autoinit", DB_REP_CONF_AUTOINIT},
{"autorollback", DB_REP_CONF_AUTOROLLBACK},
{"bulk", DB_REP_CONF_BULK},
{"delayclient", DB_REP_CONF_DELAYCLIENT},
{"inmem", DB_REP_CONF_INMEM},
{"lease", DB_REP_CONF_LEASE},
{"mgr2sitestrict", DB_REPMGR_CONF_2SITE_STRICT},
{"mgrelections", DB_REPMGR_CONF_ELECTIONS},
{"nowait", DB_REP_CONF_NOWAIT},
{NULL, 0}
};
static const NAMEMAP rep_timeout_types[] = {
{"ack", DB_REP_ACK_TIMEOUT},
{"checkpoint_delay", DB_REP_CHECKPOINT_DELAY},
{"connection_retry", DB_REP_CONNECTION_RETRY},
{"election", DB_REP_ELECTION_TIMEOUT},
{"election_retry", DB_REP_ELECTION_RETRY},
{"full_election", DB_REP_FULL_ELECTION_TIMEOUT},
{"heartbeat_monitor", DB_REP_HEARTBEAT_MONITOR},
{"heartbeat_send", DB_REP_HEARTBEAT_SEND},
{"lease", DB_REP_LEASE_TIMEOUT},
{NULL, 0}
};
static int tcl_RepNumberToName __P((const NAMEMAP *, u_int32_t, const char **));
/*
* 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 *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);
if (result != TCL_OK)
return (result);
which = myobjv[0];
onoff = myobjv[1];
if (Tcl_GetIndexFromObjStruct(interp, which,
&rep_config_types[0].name, sizeof(NAMEMAP),
"config type", TCL_EXACT, &optindex) != TCL_OK)
return (IS_HELP(which));
wh = rep_config_types[optindex].value;
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_RepGetTwo --
* Call replication getters that return 2 values.
*
* PUBLIC: int tcl_RepGetTwo
* PUBLIC: __P((Tcl_Interp *, DB_ENV *, int));
*/
int
tcl_RepGetTwo(interp, dbenv, op)
Tcl_Interp *interp; /* Interpreter */
DB_ENV *dbenv; /* Environment pointer */
int op; /* which getter */
{
Tcl_Obj *myobjv[2], *res;
u_int32_t val1, val2;
int myobjc, result, ret;
ret = 0;
val1 = val2 = 0;
switch (op) {
case DBTCL_GETCLOCK:
ret = dbenv->rep_get_clockskew(dbenv, &val1, &val2);
break;
case DBTCL_GETLIMIT:
ret = dbenv->rep_get_limit(dbenv, &val1, &val2);
break;
case DBTCL_GETREQ:
ret = dbenv->rep_get_request(dbenv, &val1, &val2);
break;
default:
return (TCL_ERROR);
}
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"env rep_get")) == TCL_OK) {
myobjc = 2;
myobjv[0] = Tcl_NewLongObj((long)val1);
myobjv[1] = Tcl_NewLongObj((long)val2);
res = Tcl_NewListObj(myobjc, myobjv);
Tcl_SetObjResult(interp, res);
}
return (result);
}
/*
* tcl_RepGetConfig --
*
* 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 */
{
Tcl_Obj *res;
int on, optindex, result, ret;
u_int32_t wh;
if (Tcl_GetIndexFromObjStruct(interp, which,
&rep_config_types[0].name, sizeof(NAMEMAP),
"config type", TCL_EXACT, &optindex) != TCL_OK)
return (IS_HELP(which));
wh = rep_config_types[optindex].value;
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);
}
/*
* tcl_RepGetTimeout --
* Get various replication timeout values.
*
* PUBLIC: int tcl_RepGetTimeout
* PUBLIC: __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
*/
int
tcl_RepGetTimeout(interp, dbenv, which)
Tcl_Interp *interp; /* Interpreter */
DB_ENV *dbenv; /* Environment pointer */
Tcl_Obj *which; /* which flag */
{
Tcl_Obj *res;
int optindex, result, ret, wh;
u_int32_t to;
if (Tcl_GetIndexFromObjStruct(interp, which,
&rep_timeout_types[0].name, sizeof(NAMEMAP),
"timeout type", TCL_EXACT, &optindex) != TCL_OK)
return (IS_HELP(which));
wh = (int)rep_timeout_types[optindex].value;
ret = dbenv->rep_get_timeout(dbenv, wh, &to);
if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"env rep_get_timeout")) == TCL_OK) {
res = Tcl_NewLongObj((long)to);
Tcl_SetObjResult(interp, res);
}
return (result);
}
/*
* tcl_RepGetAckPolicy
* Get Replication Manager acknowledgement policy
*
* PUBLIC: int tcl_RepGetAckPolicy
* PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
*/
int
tcl_RepGetAckPolicy(interp, objc, objv, dbenv)
Tcl_Interp *interp;
int objc;
Tcl_Obj *CONST objv[];
DB_ENV *dbenv;
{
const char *name;
int policy, ret;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "");
return (TCL_ERROR);
}
if ((ret = dbenv->repmgr_get_ack_policy(dbenv, &policy)) != 0 ||
(ret = tcl_RepNumberToName(rep_ack_policies,
(u_int32_t)policy, &name)) != 0)
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"env repmgr_get_ack_policy"));
Tcl_SetObjResult(interp, NewStringObj(name, strlen(name)));
return (TCL_OK);
}
/*
* tcl_RepGetLocalSite
* Get local site address.
*
* PUBLIC: int tcl_RepGetLocalSite
* PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
*/
int
tcl_RepGetLocalSite(interp, objc, objv, dbenv)
Tcl_Interp *interp;
int objc;
Tcl_Obj *CONST objv[];
DB_ENV *dbenv;
{
Tcl_Obj *myobjv[2];
DB_SITE *dbsite;
const char *host;
int ret, t_ret;
u_int port;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "");
return (TCL_ERROR);
}
if ((ret = dbenv->repmgr_local_site(dbenv, &dbsite)) == 0) {
if ((ret = dbsite->get_address(dbsite, &host, &port)) == 0) {
myobjv[0] = NewStringObj(host, strlen(host));
myobjv[1] = Tcl_NewIntObj((int)port);
Tcl_SetObjResult(interp, Tcl_NewListObj(2, myobjv));
}
if ((t_ret = dbsite->close(dbsite)) != 0 && ret == 0)
ret = t_ret;
}
return (ret == 0 ? TCL_OK :
_ReturnSetup(interp, ret,
DB_RETOK_REPMGR_LOCALSITE(ret), "env repmgr_local_site"));
}
/*
* tcl_RepNumberToName
* Map a #define'd int value to the corresponding name.
*/
static int
tcl_RepNumberToName(map, value, namep)
const NAMEMAP *map;
u_int32_t value;
const char **namep;
{
while (map->name) {
if (map->value == value) {
*namep = map->name;
return (0);
}
map++;
}
return (DB_NOTFOUND);
}
#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 result, ret;
u_int32_t full_timeout, nsites, nvotes, pri, timeout;
if (objc != 6 && objc != 7) {
Tcl_WrongNumArgs(interp, 2, objv,
"nsites nvotes pri timeout [full_timeout]");
return (TCL_ERROR);
}
if ((result = _GetUInt32(interp, objv[2], &nsites)) != TCL_OK)
return (result);
if ((result = _GetUInt32(interp, objv[3], &nvotes)) != TCL_OK)
return (result);
if ((result = _GetUInt32(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[6], &full_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;
{
u_int32_t clock_fast, clock_slow, timeout;
int result, ret;
COMPQUIET(clock_fast, 0);
COMPQUIET(clock_slow, 0);
if (objc != 3 && objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "{timeout fast slow}");
return (TCL_ERROR);
}
if ((result = _GetUInt32(interp, objv[0], &timeout)) != TCL_OK)
return (result);
if (objc == 4) {
if ((result = _GetUInt32(interp, objv[1], &clock_fast))
!= TCL_OK)
return (result);
if ((result = _GetUInt32(interp, objv[2], &clock_slow))
!= 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");
ret = dbenv->rep_set_config(dbenv, DB_REP_CONF_LEASE, 1);
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"rep_set_config");
if (result != TCL_OK)
return (result);
if (objc == 3)
ret = dbenv->rep_set_clockskew(dbenv, clock_fast, clock_slow);
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"env rep_set_lease"));
}
#endif
#ifdef CONFIG_TEST
/*
* tcl_RepInmemFiles --
* Set in-memory replication, which must be done before opening
* environment.
*
* PUBLIC: int tcl_RepInmemFiles __P((Tcl_Interp *, DB_ENV *));
*/
int
tcl_RepInmemFiles(interp, dbenv)
Tcl_Interp *interp; /* Interpreter */
DB_ENV *dbenv;
{
int ret;
ret = dbenv->rep_set_config(dbenv, DB_REP_CONF_INMEM, 1);
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"rep_set_config"));
}
#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, 2, 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_RepNSites --
* Call DB_ENV->rep_set_nsites().
*
* PUBLIC: int tcl_RepNSites
* PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
*/
int
tcl_RepNSites(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 nsites;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "nsites");
return (TCL_ERROR);
}
if ((result = _GetUInt32(interp, objv[2], &nsites)) != TCL_OK)
return (result);
_debug_check();
ret = dbenv->rep_set_nsites(dbenv, nsites);
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_nsites"));
}
#endif
#ifdef CONFIG_TEST
/*
* tcl_RepRequest --
* Call DB_ENV->rep_set_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;
long min, max;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "min max");
return (TCL_ERROR);
}
if ((result = Tcl_GetLongFromObj(interp, objv[2], &min)) != TCL_OK)
return (result);
if ((result = Tcl_GetLongFromObj(interp, objv[3], &max)) != TCL_OK)
return (result);
_debug_check();
if ((ret = dbenv->rep_set_request(dbenv, (db_timeout_t)min,
(db_timeout_t)max)) != 0)
return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"env rep_request"));
return (_ReturnSetup(interp,
ret, DB_RETOK_STD(ret), "env 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 */
{
ENV *env;
REGENV *renv;
REGINFO *infop;
env = dbenv->env;
_debug_check();
infop = env->reginfo;
renv = infop->primary;
REP_SYSTEM_LOCK(env);
F_CLR(renv, DB_REGENV_REPLOCKED);
renv->op_timestamp = 0;
REP_SYSTEM_UNLOCK(env);
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, 2, 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, 2, 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, *role;
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)
role = "master";
else if (sp->st_status == DB_REP_CLIENT)
role = "client";
else
role = "none";
MAKE_STAT_STRLIST("Role", role);
MAKE_STAT_LSN("Next LSN expected", &sp->st_next_lsn);
MAKE_STAT_LSN("First missed LSN", &sp->st_waiting_lsn);
MAKE_STAT_LSN("Maximum permanent LSN", &sp->st_max_perm_lsn);
MAKE_WSTAT_LIST("Bulk buffer fills", sp->st_bulk_fills);
MAKE_WSTAT_LIST("Bulk buffer overflows", sp->st_bulk_overflows);
MAKE_WSTAT_LIST("Bulk records stored", sp->st_bulk_records);
MAKE_WSTAT_LIST("Bulk buffer transfers", sp->st_bulk_transfers);
MAKE_WSTAT_LIST("Client service requests", sp->st_client_svc_req);
MAKE_WSTAT_LIST("Client service req misses", sp->st_client_svc_miss);
MAKE_WSTAT_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_WSTAT_LIST("Lease messages sent", sp->st_lease_sends);
MAKE_WSTAT_LIST("Lease checks", sp->st_lease_chk);
MAKE_WSTAT_LIST("Lease check invalid", sp->st_lease_chk_misses);
MAKE_WSTAT_LIST("Lease check refresh", sp->st_lease_chk_refresh);
MAKE_WSTAT_LIST("Duplicate log records received", sp->st_log_duplicated);
MAKE_WSTAT_LIST("Current log records queued", sp->st_log_queued);
MAKE_WSTAT_LIST("Maximum log records queued", sp->st_log_queued_max);
MAKE_WSTAT_LIST("Total log records queued", sp->st_log_queued_total);
MAKE_WSTAT_LIST("Log records received", sp->st_log_records);
MAKE_WSTAT_LIST("Log records requested", sp->st_log_requested);
MAKE_STAT_LIST("Master environment ID", sp->st_master);
MAKE_WSTAT_LIST("Master changes", sp->st_master_changes);
MAKE_STAT_LIST("Messages with bad generation number",
sp->st_msgs_badgen);
MAKE_WSTAT_LIST("Messages processed", sp->st_msgs_processed);
MAKE_WSTAT_LIST("Messages ignored for recovery", sp->st_msgs_recover);
MAKE_WSTAT_LIST("Message send failures", sp->st_msgs_send_failures);
MAKE_WSTAT_LIST("Messages sent", sp->st_msgs_sent);
MAKE_WSTAT_LIST("New site messages", sp->st_newsites);
MAKE_STAT_LIST("Number of sites in replication group", sp->st_nsites);
MAKE_WSTAT_LIST("Transmission limited", sp->st_nthrottles);
MAKE_WSTAT_LIST("Outdated conditions", sp->st_outdated);
MAKE_WSTAT_LIST("Transactions applied", sp->st_txns_applied);
MAKE_STAT_LIST("Next page expected", sp->st_next_pg);
MAKE_WSTAT_LIST("First missed page", sp->st_waiting_pg);
MAKE_WSTAT_LIST("Duplicate pages received", sp->st_pg_duplicated);
MAKE_WSTAT_LIST("Pages received", sp->st_pg_records);
MAKE_WSTAT_LIST("Pages requested", sp->st_pg_requested);
MAKE_WSTAT_LIST("Elections held", sp->st_elections);
MAKE_WSTAT_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_LIST("Election data generation number",
sp->st_election_datagen);
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);
MAKE_STAT_LIST("Maximum lease seconds", sp->st_max_lease_sec);
MAKE_STAT_LIST("Maximum lease usecs", sp->st_max_lease_usec);
MAKE_STAT_LIST("File fail cleanups done", sp->st_filefail_cleanups);
#endif
Tcl_SetObjResult(interp, res);
error:
__os_ufree(dbenv->env, sp);
return (result);
}
/*
* tcl_RepStatPrint --
*
* PUBLIC: int tcl_RepStatPrint __P((Tcl_Interp *, int,
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
*/
int
tcl_RepStatPrint(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 *repstatprtopts[] = {
"-all",
"-clear",
NULL
};
enum repstatprtopts {
REPSTATPRTALL,
REPSTATPRTCLEAR
};
u_int32_t flag;
int i, optindex, result, ret;
result = TCL_OK;
flag = 0;
i = 2;
while (i < objc) {
if (Tcl_GetIndexFromObj(interp, objv[i], repstatprtopts,
"option", TCL_EXACT, &optindex) != TCL_OK) {
result = IS_HELP(objv[i]);
goto error;
}
i++;
switch ((enum repstatprtopts)optindex) {
case REPSTATPRTALL:
flag |= DB_STAT_ALL;
break;
case REPSTATPRTCLEAR:
flag |= DB_STAT_CLEAR;
break;
}
if (result != TCL_OK)
break;
}
if (result != TCL_OK)
goto error;
_debug_check();
ret = dbenv->rep_stat_print(dbenv, flag);
result = _ReturnSetup(interp,
ret, DB_RETOK_STD(ret), "dbenv rep_stat_print");
error:
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",
"-pri",
"-remote",
"-remove",
"-start",
"-timeout",
NULL
};
enum rmgr {
RMGR_ACK,
RMGR_LOCAL,
RMGR_MSGTH,
RMGR_PRI,
RMGR_REMOTE,
RMGR_REMOVE,
RMGR_START,
RMGR_TIMEOUT
};
Tcl_Obj **myobjv;
DB_SITE *dbsite;
long to;
int ack, creator, i, j, legacy, myobjc, optindex;
int peer, result, ret, totype, t_ret;
u_int32_t msgth, start_flag, uintarg;
char *arg;
result = TCL_OK;
ack = ret = totype = 0;
msgth = 1;
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;
}
if (Tcl_GetIndexFromObjStruct(interp, objv[i++],
&rep_ack_policies[0].name, sizeof(NAMEMAP),
"ack policy", TCL_EXACT, &optindex) != TCL_OK) {
result = TCL_ERROR;
break;
}
ack = (int)rep_ack_policies[optindex].value;
_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 || myobjc > 4) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-local {host port [creator][legacy]}?");
result = TCL_ERROR;
break;
}
creator = legacy = 0;
for (j = 2; j < myobjc; j++) {
arg = Tcl_GetString(myobjv[j]);
if (strcmp(arg, "creator") == 0)
creator = 1;
else if (strcmp(arg, "legacy") == 0)
legacy = 1;
else {
Tcl_AddErrorInfo(interp,
"local: illegal flag");
result = TCL_ERROR;
break;
}
}
/* The "arg" is host name, and "uintarg" is port. */
arg = Tcl_GetStringFromObj(myobjv[0], NULL);
if ((result = _GetUInt32(interp, myobjv[1], &uintarg))
!= TCL_OK)
break;
_debug_check();
if ((ret = dbenv->repmgr_site(dbenv,
arg, uintarg, &dbsite, 0)) == 0) {
ret = dbsite->set_config(dbsite,
DB_LOCAL_SITE, 1);
if (ret == 0 && creator)
ret = dbsite->set_config(dbsite,
DB_GROUP_CREATOR, 1);
if (ret == 0 && legacy)
ret = dbsite->set_config(dbsite,
DB_LEGACY, 1);
if ((t_ret = dbsite->close(dbsite)) != 0 &&
ret == 0)
ret = t_ret;
}
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"repmgr_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_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, uintarg);
}
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"rep_set_priority");
break;
case RMGR_REMOTE:
result = Tcl_ListObjGetElements(interp, objv[i],
&myobjc, &myobjv);
if (result == TCL_OK)
i++;
else
break;
if (myobjc < 2 || myobjc > 4) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-remote {host port [peer][legacy]}?");
result = TCL_ERROR;
break;
}
/*
* Get the flags first so we can reuse 'arg'.
*/
legacy = peer = 0;
for (j = 2; j < myobjc; j++) {
arg = Tcl_GetString(myobjv[j]);
if (strcmp(arg, "legacy") == 0)
legacy = 1;
else if (strcmp(arg, "peer") == 0)
peer = 1;
else {
Tcl_AddErrorInfo(interp,
"remote: illegal flag");
result = TCL_ERROR;
break;
}
}
arg = Tcl_GetString(myobjv[0]);
if ((result = _GetUInt32(interp, myobjv[1], &uintarg))
!= TCL_OK)
break;
_debug_check();
/* For now, all "-remote" sites become helpers. */
if ((ret = dbenv->repmgr_site(dbenv,
arg, uintarg, &dbsite, 0)) == 0) {
ret = dbsite->set_config(dbsite,
DB_BOOTSTRAP_HELPER, 1);
if (ret == 0 && legacy)
ret = dbsite->set_config(dbsite,
DB_LEGACY, 1);
if (ret == 0 && peer)
ret = dbsite->set_config(dbsite,
DB_REPMGR_PEER, 1);
if ((t_ret = dbsite->close(dbsite)) != 0 &&
ret == 0)
ret = t_ret;
}
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"repmgr_site");
break;
case RMGR_REMOVE:
result = Tcl_ListObjGetElements(interp, objv[i],
&myobjc, &myobjv);
if (result == TCL_OK)
i++;
else
break;
if (myobjc != 2) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-remove {host port}?");
result = TCL_ERROR;
break;
}
arg = Tcl_GetString(myobjv[0]);
if ((result = _GetUInt32(interp, myobjv[1], &uintarg))
!= TCL_OK)
break;
_debug_check();
if ((ret = dbenv->repmgr_site(dbenv,
arg, uintarg, &dbsite, 0)) == 0)
ret = dbsite->remove(dbsite);
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"repmgr_site->remove");
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;
}
if (Tcl_GetIndexFromObjStruct(interp, myobjv[0],
&rep_timeout_types[0].name, sizeof(NAMEMAP),
"timeout type", TCL_EXACT, &optindex) != TCL_OK) {
result = TCL_ERROR;
break;
}
totype = (int)rep_timeout_types[optindex].value;
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_REPMGR_START(ret), "repmgr_start");
}
error:
return (result);
}
/*
* tcl_RepMgrSiteList --
* Call DB_ENV->repmgr_site_list().
*
* PUBLIC: int tcl_RepMgrSiteList
* PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
*/
int
tcl_RepMgrSiteList(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_SITE *sp;
Tcl_Obj *myobjv[5], *res, *thislist;
u_int count, i;
char *pr, *st;
int myobjc, result, ret;
result = TCL_OK;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 2, objv, NULL);
return (TCL_ERROR);
}
_debug_check();
ret = dbenv->repmgr_site_list(dbenv, &count, &sp);
result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
"repmgr sitelist");
if (result == TCL_ERROR)
return (result);
/*
* Have our sites, now construct the {eid host port status peer}
* tuples and free up the memory.
*/
res = Tcl_NewObj();
for (i = 0; i < count; ++i) {
/*
* MAKE_SITE_LIST assumes 'res' and 'error' label.
*/
if (sp[i].status == DB_REPMGR_CONNECTED)
st = "connected";
else if (sp[i].status == DB_REPMGR_DISCONNECTED)
st = "disconnected";
else
st = "unknown";
if (F_ISSET(&sp[i], DB_REPMGR_ISPEER))
pr = "peer";
else
pr = "non-peer";
MAKE_SITE_LIST(sp[i].eid, sp[i].host, sp[i].port, st, pr);
}
Tcl_SetObjResult(interp, res);
error:
__os_ufree(dbenv->env, sp);
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_WSTAT_LIST("Acknowledgement failures", sp->st_perm_failed);
MAKE_WSTAT_LIST("Messages delayed", sp->st_msgs_queued);
MAKE_WSTAT_LIST("Messages discarded", sp->st_msgs_dropped);
MAKE_WSTAT_LIST("Connections dropped", sp->st_connection_drop);
MAKE_WSTAT_LIST("Failed re-connects", sp->st_connect_fail);
MAKE_WSTAT_LIST("Election threads", sp->st_elect_threads);
MAKE_WSTAT_LIST("Max elect threads", sp->st_max_elect_threads);
#endif
Tcl_SetObjResult(interp, res);
error:
__os_ufree(dbenv->env, sp);
return (result);
}
/*
* tcl_RepMgrStatPrint --
*
* PUBLIC: int tcl_RepMgrStatPrint __P((Tcl_Interp *, int,
* PUBLIC: Tcl_Obj * CONST*, DB_ENV *));
*/
int
tcl_RepMgrStatPrint(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 *repmgrstatprtopts[] = {
"-all",
"-clear",
NULL
};
enum repmgrstatprtopts {
REPMGRSTATPRTALL,
REPMGRSTATPRTCLEAR
};
u_int32_t flag;
int i, optindex, result, ret;
result = TCL_OK;
flag = 0;
i = 2;
while (i < objc) {
if (Tcl_GetIndexFromObj(interp, objv[i], repmgrstatprtopts,
"option", TCL_EXACT, &optindex) != TCL_OK) {
result = IS_HELP(objv[i]);
goto error;
}
i++;
switch ((enum repmgrstatprtopts)optindex) {
case REPMGRSTATPRTALL:
flag |= DB_STAT_ALL;
break;
case REPMGRSTATPRTCLEAR:
flag |= DB_STAT_CLEAR;
break;
}
if (result != TCL_OK)
break;
}
if (result != TCL_OK)
goto error;
_debug_check();
ret = dbenv->repmgr_stat_print(dbenv, flag);
result = _ReturnSetup(interp,
ret, DB_RETOK_STD(ret), "dbenv repmgr_stat_print");
error:
return (result);
}
/*
* tcl_RepApplied -
*
* PUBLIC: int tcl_RepApplied
* PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
*/
int
tcl_RepApplied(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 *repapplied_option_names[] = {
"-timeout",
NULL
};
enum envinfo_options {
REPAPPLIEDTIMEOUT
};
unsigned char *arg;
char msg[MSG_SIZE];
db_timeout_t timeout;
int i, len, ptr, result, ret;
if (objc != 3 && objc != 5) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-timeout t? token");
return (TCL_ERROR);
}
timeout = 0;
i = 2;
if (objc == 5) {
if (Tcl_GetIndexFromObj(interp, objv[i],
repapplied_option_names, "option", TCL_EXACT, &ptr)
!= TCL_OK)
return (IS_HELP(objv[i]));
i++;
switch ((enum envinfo_options)ptr) {
case REPAPPLIEDTIMEOUT:
result = _GetUInt32(interp, objv[i++], &timeout);
if (result != TCL_OK)
return (result);
break;
}
}
arg = Tcl_GetByteArrayFromObj(objv[i], &len);
if (len != DB_TXN_TOKEN_SIZE) {
Tcl_SetErrorCode(interp, "BerkeleyDB",
"Commit token is the wrong size", NULL);
snprintf(msg, MSG_SIZE,
"Bad commit token size %lu, should be %lu",
(u_long)len, (u_long)DB_TXN_TOKEN_SIZE);
Tcl_SetResult(interp, msg, TCL_VOLATILE);
return (TCL_ERROR);
}
_debug_check();
ret = dbenv->txn_applied(dbenv, (DB_TXN_TOKEN*)arg, timeout, 0);
result = _ReturnSetup(interp, ret , DB_RETOK_TXNAPPLIED(ret),
"txn_applied");
return (result);
}
#endif