mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 09:06:25 +00:00
1691 lines
42 KiB
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
|