1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#ifdef HAVE_SYSTEM_INCLUDE_FILES
13#include <tcl.h>
14#endif
15#include "dbinc/tcl_db.h"
16
17#ifdef CONFIG_TEST
18/*
19 * tcl_RepConfig --
20 *	Call DB_ENV->rep_set_config().
21 *
22 * PUBLIC: int tcl_RepConfig
23 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
24 */
25int
26tcl_RepConfig(interp, dbenv, list)
27	Tcl_Interp *interp;		/* Interpreter */
28	DB_ENV *dbenv;			/* Environment pointer */
29	Tcl_Obj *list;			/* {which on|off} */
30{
31	static const char *confwhich[] = {
32		"bulk",
33		"delayclient",
34		"mgr2sitestrict",
35		"noautoinit",
36		"nowait",
37		NULL
38	};
39	enum confwhich {
40		REPCONF_BULK,
41		REPCONF_DELAYCLIENT,
42		REPCONF_MGR2SITESTRICT,
43		REPCONF_NOAUTOINIT,
44		REPCONF_NOWAIT
45	};
46	static const char *confonoff[] = {
47		"off",
48		"on",
49		NULL
50	};
51	enum confonoff {
52		REPCONF_OFF,
53		REPCONF_ON
54	};
55	Tcl_Obj **myobjv, *onoff, *which;
56	int myobjc, on, optindex, result, ret;
57	u_int32_t wh;
58
59	result = Tcl_ListObjGetElements(interp, list, &myobjc, &myobjv);
60	which = myobjv[0];
61	onoff = myobjv[1];
62	if (result != TCL_OK)
63		return (result);
64	if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
65	    TCL_EXACT, &optindex) != TCL_OK)
66		return (IS_HELP(which));
67
68	switch ((enum confwhich)optindex) {
69	case REPCONF_NOAUTOINIT:
70		wh = DB_REP_CONF_NOAUTOINIT;
71		break;
72	case REPCONF_BULK:
73		wh = DB_REP_CONF_BULK;
74		break;
75	case REPCONF_DELAYCLIENT:
76		wh = DB_REP_CONF_DELAYCLIENT;
77		break;
78	case REPCONF_MGR2SITESTRICT:
79		wh = DB_REPMGR_CONF_2SITE_STRICT;
80		break;
81	case REPCONF_NOWAIT:
82		wh = DB_REP_CONF_NOWAIT;
83		break;
84	default:
85		return (TCL_ERROR);
86	}
87	if (Tcl_GetIndexFromObj(interp, onoff, confonoff, "option",
88	    TCL_EXACT, &optindex) != TCL_OK)
89		return (IS_HELP(onoff));
90	switch ((enum confonoff)optindex) {
91	case REPCONF_OFF:
92		on = 0;
93		break;
94	case REPCONF_ON:
95		on = 1;
96		break;
97	default:
98		return (TCL_ERROR);
99	}
100	ret = dbenv->rep_set_config(dbenv, wh, on);
101	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
102	    "env rep_config"));
103}
104
105/*
106 * tcl_RepGetTwo --
107 *	Call replication getters that return 2 values.
108 *
109 * PUBLIC: int tcl_RepGetTwo
110 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, int));
111 */
112int
113tcl_RepGetTwo(interp, dbenv, op)
114	Tcl_Interp *interp;		/* Interpreter */
115	DB_ENV *dbenv;			/* Environment pointer */
116	int op;				/* which getter */
117{
118	Tcl_Obj *myobjv[2], *res;
119	u_int32_t val1, val2;
120	int myobjc, result, ret;
121
122	ret = 0;
123	val1 = val2 = 0;
124	switch (op) {
125	case DBTCL_GETCLOCK:
126		ret = dbenv->rep_get_clockskew(dbenv, &val1, &val2);
127		break;
128	case DBTCL_GETLIMIT:
129		ret = dbenv->rep_get_limit(dbenv, &val1, &val2);
130		break;
131	case DBTCL_GETREQ:
132		ret = dbenv->rep_get_request(dbenv, &val1, &val2);
133		break;
134	default:
135		return (TCL_ERROR);
136	}
137	if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
138	    "env rep_get")) == TCL_OK) {
139		myobjc = 2;
140		myobjv[0] = Tcl_NewLongObj((long)val1);
141		myobjv[1] = Tcl_NewLongObj((long)val2);
142		res = Tcl_NewListObj(myobjc, myobjv);
143		Tcl_SetObjResult(interp, res);
144	}
145	return (result);
146}
147
148/*
149 * tcl_RepGetConfig --
150 *
151 * PUBLIC: int tcl_RepGetConfig
152 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
153 */
154int
155tcl_RepGetConfig(interp, dbenv, which)
156	Tcl_Interp *interp;		/* Interpreter */
157	DB_ENV *dbenv;			/* Environment pointer */
158	Tcl_Obj *which;			/* which flag */
159{
160	static const char *confwhich[] = {
161		"bulk",
162		"delayclient",
163		"inmem_files",
164		"lease",
165		"mgr2sitestrict",
166		"noautoinit",
167		"nowait",
168		NULL
169	};
170	enum confwhich {
171		REPGCONF_BULK,
172		REPGCONF_DELAYCLIENT,
173		REPGCONF_INMEM_FILES,
174		REPGCONF_LEASE,
175		REPGCONF_MGR2SITESTRICT,
176		REPGCONF_NOAUTOINIT,
177		REPGCONF_NOWAIT
178	};
179	Tcl_Obj *res;
180	int on, optindex, result, ret;
181	u_int32_t wh;
182
183	if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
184	    TCL_EXACT, &optindex) != TCL_OK)
185		return (IS_HELP(which));
186
187	res = NULL;
188	switch ((enum confwhich)optindex) {
189	case REPGCONF_BULK:
190		wh = DB_REP_CONF_BULK;
191		break;
192	case REPGCONF_DELAYCLIENT:
193		wh = DB_REP_CONF_DELAYCLIENT;
194		break;
195	case REPGCONF_INMEM_FILES:
196		wh = DB_REP_CONF_INMEM;
197		break;
198	case REPGCONF_LEASE:
199		wh = DB_REP_CONF_LEASE;
200		break;
201	case REPGCONF_MGR2SITESTRICT:
202		wh = DB_REPMGR_CONF_2SITE_STRICT;
203		break;
204	case REPGCONF_NOAUTOINIT:
205		wh = DB_REP_CONF_NOAUTOINIT;
206		break;
207	case REPGCONF_NOWAIT:
208		wh = DB_REP_CONF_NOWAIT;
209		break;
210	default:
211		return (TCL_ERROR);
212	}
213	ret = dbenv->rep_get_config(dbenv, wh, &on);
214	if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
215	    "env rep_config")) == TCL_OK) {
216		res = Tcl_NewIntObj(on);
217		Tcl_SetObjResult(interp, res);
218	}
219	return (result);
220}
221
222/*
223 * tcl_RepGetTimeout --
224 *	Get various replication timeout values.
225 *
226 * PUBLIC: int tcl_RepGetTimeout
227 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
228 */
229int
230tcl_RepGetTimeout(interp, dbenv, which)
231	Tcl_Interp *interp;		/* Interpreter */
232	DB_ENV *dbenv;			/* Environment pointer */
233	Tcl_Obj *which;			/* which flag */
234{
235	static const char *towhich[] = {
236		"ack",
237		"checkpoint_delay",
238		"connection_retry",
239		"election",
240		"election_retry",
241		"full_election",
242		"heartbeat_monitor",
243		"heartbeat_send",
244		"lease",
245		NULL
246	};
247	enum towhich {
248		REPGTO_ACK,
249		REPGTO_CKP,
250		REPGTO_CONN,
251		REPGTO_ELECT,
252		REPGTO_ELECT_RETRY,
253		REPGTO_FULL,
254		REPGTO_HB_MON,
255		REPGTO_HB_SEND,
256		REPGTO_LEASE
257	};
258	Tcl_Obj *res;
259	int optindex, result, ret, wh;
260	u_int32_t to;
261
262	if (Tcl_GetIndexFromObj(interp, which, towhich, "option",
263	    TCL_EXACT, &optindex) != TCL_OK)
264		return (IS_HELP(which));
265
266	res = NULL;
267	switch ((enum towhich)optindex) {
268	case REPGTO_ACK:
269		wh = DB_REP_ACK_TIMEOUT;
270		break;
271	case REPGTO_CKP:
272		wh = DB_REP_CHECKPOINT_DELAY;
273		break;
274	case REPGTO_CONN:
275		wh = DB_REP_CONNECTION_RETRY;
276		break;
277	case REPGTO_ELECT:
278		wh = DB_REP_ELECTION_TIMEOUT;
279		break;
280	case REPGTO_ELECT_RETRY:
281		wh = DB_REP_ELECTION_RETRY;
282		break;
283	case REPGTO_FULL:
284		wh = DB_REP_FULL_ELECTION_TIMEOUT;
285		break;
286	case REPGTO_HB_MON:
287		wh = DB_REP_HEARTBEAT_MONITOR;
288		break;
289	case REPGTO_HB_SEND:
290		wh = DB_REP_HEARTBEAT_SEND;
291		break;
292	case REPGTO_LEASE:
293		wh = DB_REP_LEASE_TIMEOUT;
294		break;
295	default:
296		return (TCL_ERROR);
297	}
298	ret = dbenv->rep_get_timeout(dbenv, wh, &to);
299	if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
300	    "env rep_config")) == TCL_OK) {
301		res = Tcl_NewLongObj((long)to);
302		Tcl_SetObjResult(interp, res);
303	}
304	return (result);
305}
306#endif
307
308#ifdef CONFIG_TEST
309/*
310 * tcl_RepElect --
311 *	Call DB_ENV->rep_elect().
312 *
313 * PUBLIC: int tcl_RepElect
314 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
315 */
316int
317tcl_RepElect(interp, objc, objv, dbenv)
318	Tcl_Interp *interp;		/* Interpreter */
319	int objc;			/* How many arguments? */
320	Tcl_Obj *CONST objv[];		/* The argument objects */
321	DB_ENV *dbenv;			/* Environment pointer */
322{
323	int result, ret;
324	u_int32_t full_timeout, nsites, nvotes, pri, timeout;
325
326	if (objc != 6 && objc != 7) {
327		Tcl_WrongNumArgs(interp, 6, objv,
328		    "nsites nvotes pri timeout [full_timeout]");
329		return (TCL_ERROR);
330	}
331
332	if ((result = _GetUInt32(interp, objv[2], &nsites)) != TCL_OK)
333		return (result);
334	if ((result = _GetUInt32(interp, objv[3], &nvotes)) != TCL_OK)
335		return (result);
336	if ((result = _GetUInt32(interp, objv[4], &pri)) != TCL_OK)
337		return (result);
338	if ((result = _GetUInt32(interp, objv[5], &timeout)) != TCL_OK)
339		return (result);
340	full_timeout = 0;
341	if (objc == 7)
342		if ((result = _GetUInt32(interp, objv[6], &full_timeout))
343		    != TCL_OK)
344			return (result);
345
346	_debug_check();
347
348	if ((ret = dbenv->rep_set_priority(dbenv, pri)) != 0)
349		return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
350			    "env rep_elect (rep_set_priority)"));
351	if ((ret = dbenv->rep_set_timeout(dbenv, DB_REP_ELECTION_TIMEOUT,
352	    timeout)) != 0)
353		return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
354			    "env rep_elect (rep_set_timeout)"));
355
356	if (full_timeout != 0 && (ret = dbenv->rep_set_timeout(dbenv,
357	    DB_REP_FULL_ELECTION_TIMEOUT, full_timeout)) != 0)
358		return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
359			    "env rep_elect (rep_set_timeout)"));
360
361	ret = dbenv->rep_elect(dbenv, nsites, nvotes, 0);
362	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_elect"));
363}
364#endif
365
366#ifdef CONFIG_TEST
367/*
368 * tcl_RepFlush --
369 *	Call DB_ENV->rep_flush().
370 *
371 * PUBLIC: int tcl_RepFlush
372 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
373 */
374int
375tcl_RepFlush(interp, objc, objv, dbenv)
376	Tcl_Interp *interp;
377	int objc;
378	Tcl_Obj *CONST objv[];
379	DB_ENV *dbenv;
380{
381	int ret;
382
383	if (objc != 2) {
384		Tcl_WrongNumArgs(interp, 2, objv, "");
385		return TCL_ERROR;
386	}
387
388	_debug_check();
389	ret = dbenv->rep_flush(dbenv);
390	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_flush"));
391}
392#endif
393
394#ifdef CONFIG_TEST
395/*
396 * tcl_RepSync --
397 *	Call DB_ENV->rep_sync().
398 *
399 * PUBLIC: int tcl_RepSync
400 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
401 */
402int
403tcl_RepSync(interp, objc, objv, dbenv)
404	Tcl_Interp *interp;
405	int objc;
406	Tcl_Obj *CONST objv[];
407	DB_ENV *dbenv;
408{
409	int ret;
410
411	if (objc != 2) {
412		Tcl_WrongNumArgs(interp, 2, objv, "");
413		return TCL_ERROR;
414	}
415
416	_debug_check();
417	ret = dbenv->rep_sync(dbenv, 0);
418	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_sync"));
419}
420#endif
421
422#ifdef CONFIG_TEST
423/*
424 * tcl_RepLease --
425 *	Call DB_ENV->rep_set_lease().
426 *
427 * PUBLIC: int tcl_RepLease  __P((Tcl_Interp *, int, Tcl_Obj * CONST *,
428 * PUBLIC:    DB_ENV *));
429 */
430int
431tcl_RepLease(interp, objc, objv, dbenv)
432	Tcl_Interp *interp;		/* Interpreter */
433	int objc;			/* How many arguments? */
434	Tcl_Obj *CONST objv[];		/* The argument objects */
435	DB_ENV *dbenv;
436{
437	u_int32_t clock_fast, clock_slow, nsites, timeout;
438	int result, ret;
439
440	COMPQUIET(clock_fast, 0);
441	COMPQUIET(clock_slow, 0);
442
443	if (objc != 4 && objc != 2) {
444		Tcl_WrongNumArgs(interp, 1, objv, "{nsites timeout fast slow}");
445		return (TCL_ERROR);
446	}
447
448	if ((result = _GetUInt32(interp, objv[0], &nsites)) != TCL_OK)
449		return (result);
450	if ((result = _GetUInt32(interp, objv[1], &timeout)) != TCL_OK)
451		return (result);
452	if (objc == 4) {
453		if ((result = _GetUInt32(interp, objv[2], &clock_fast))
454		    != TCL_OK)
455			return (result);
456		if ((result = _GetUInt32(interp, objv[3], &clock_slow))
457		    != TCL_OK)
458			return (result);
459	}
460	ret = dbenv->rep_set_nsites(dbenv, nsites);
461	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
462	    "rep_set_nsites");
463	if (result != TCL_OK)
464		return (result);
465	ret = dbenv->rep_set_timeout(dbenv, DB_REP_LEASE_TIMEOUT,
466	    (db_timeout_t)timeout);
467	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
468	    "rep_set_timeout");
469	ret = dbenv->rep_set_config(dbenv, DB_REP_CONF_LEASE, 1);
470	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
471	    "rep_set_config");
472	if (result != TCL_OK)
473		return (result);
474	if (objc == 4)
475		ret = dbenv->rep_set_clockskew(dbenv, clock_fast, clock_slow);
476	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
477	    "env rep_set_lease"));
478}
479#endif
480
481#ifdef CONFIG_TEST
482/*
483 * tcl_RepInmemFiles --
484 *	Set in-memory replication, which must be done before opening
485 *	environment.
486 *
487 * PUBLIC: int tcl_RepInmemFiles  __P((Tcl_Interp *, DB_ENV *));
488 */
489int
490tcl_RepInmemFiles(interp, dbenv)
491	Tcl_Interp *interp;		/* Interpreter */
492	DB_ENV *dbenv;
493{
494	int ret;
495
496	ret = dbenv->rep_set_config(dbenv, DB_REP_CONF_INMEM, 1);
497	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
498	    "rep_set_config"));
499}
500#endif
501
502#ifdef CONFIG_TEST
503/*
504 * tcl_RepLimit --
505 *	Call DB_ENV->rep_set_limit().
506 *
507 * PUBLIC: int tcl_RepLimit
508 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
509 */
510int
511tcl_RepLimit(interp, objc, objv, dbenv)
512	Tcl_Interp *interp;		/* Interpreter */
513	int objc;			/* How many arguments? */
514	Tcl_Obj *CONST objv[];		/* The argument objects */
515	DB_ENV *dbenv;			/* Environment pointer */
516{
517	int result, ret;
518	u_int32_t bytes, gbytes;
519
520	if (objc != 4) {
521		Tcl_WrongNumArgs(interp, 4, objv, "gbytes bytes");
522		return (TCL_ERROR);
523	}
524
525	if ((result = _GetUInt32(interp, objv[2], &gbytes)) != TCL_OK)
526		return (result);
527	if ((result = _GetUInt32(interp, objv[3], &bytes)) != TCL_OK)
528		return (result);
529
530	_debug_check();
531	if ((ret = dbenv->rep_set_limit(dbenv, gbytes, bytes)) != 0)
532		return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
533		    "env set_rep_limit"));
534
535	return (_ReturnSetup(interp,
536	    ret, DB_RETOK_STD(ret), "env set_rep_limit"));
537}
538#endif
539
540#ifdef CONFIG_TEST
541/*
542 * tcl_RepRequest --
543 *	Call DB_ENV->rep_set_request().
544 *
545 * PUBLIC: int tcl_RepRequest
546 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
547 */
548int
549tcl_RepRequest(interp, objc, objv, dbenv)
550	Tcl_Interp *interp;		/* Interpreter */
551	int objc;			/* How many arguments? */
552	Tcl_Obj *CONST objv[];		/* The argument objects */
553	DB_ENV *dbenv;			/* Environment pointer */
554{
555	int result, ret;
556	long min, max;
557
558	if (objc != 4) {
559		Tcl_WrongNumArgs(interp, 4, objv, "min max");
560		return (TCL_ERROR);
561	}
562
563	if ((result = Tcl_GetLongFromObj(interp, objv[2], &min)) != TCL_OK)
564		return (result);
565	if ((result = Tcl_GetLongFromObj(interp, objv[3], &max)) != TCL_OK)
566		return (result);
567
568	_debug_check();
569	if ((ret = dbenv->rep_set_request(dbenv, (db_timeout_t)min,
570	    (db_timeout_t)max)) != 0)
571		return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
572		    "env rep_request"));
573
574	return (_ReturnSetup(interp,
575	    ret, DB_RETOK_STD(ret), "env rep_request"));
576}
577#endif
578
579#ifdef CONFIG_TEST
580/*
581 * tcl_RepNoarchiveTimeout --
582 *	Reset the master update timer, to allow immediate log archiving.
583 *
584 * PUBLIC: int tcl_RepNoarchiveTimeout
585 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *));
586 */
587int
588tcl_RepNoarchiveTimeout(interp, dbenv)
589	Tcl_Interp *interp;		/* Interpreter */
590	DB_ENV *dbenv;			/* Environment pointer */
591{
592	ENV *env;
593	REGENV *renv;
594	REGINFO *infop;
595
596	env = dbenv->env;
597
598	_debug_check();
599	infop = env->reginfo;
600	renv = infop->primary;
601	REP_SYSTEM_LOCK(env);
602	F_CLR(renv, DB_REGENV_REPLOCKED);
603	renv->op_timestamp = 0;
604	REP_SYSTEM_UNLOCK(env);
605
606	return (_ReturnSetup(interp,
607	    0, DB_RETOK_STD(0), "env test force noarchive_timeout"));
608}
609#endif
610
611#ifdef CONFIG_TEST
612/*
613 * tcl_RepTransport --
614 *	Call DB_ENV->rep_set_transport().
615 *
616 * PUBLIC: int tcl_RepTransport  __P((Tcl_Interp *, int, Tcl_Obj * CONST *,
617 * PUBLIC:    DB_ENV *, DBTCL_INFO *));
618 *
619 *	Note that this normally can/should be achieved as an argument to
620 * berkdb env, but we need to test changing the transport function on
621 * the fly.
622 */
623int
624tcl_RepTransport(interp, objc, objv, dbenv, ip)
625	Tcl_Interp *interp;		/* Interpreter */
626	int objc;			/* How many arguments? */
627	Tcl_Obj *CONST objv[];		/* The argument objects */
628	DB_ENV *dbenv;
629	DBTCL_INFO *ip;
630{
631	int intarg, result, ret;
632
633	if (objc != 2) {
634		Tcl_WrongNumArgs(interp, 2, objv, "{id transport_func");
635		return (TCL_ERROR);
636	}
637
638	/*
639	 * Store the objects containing the machine ID
640	 * and the procedure name.  We don't need to crack
641	 * the send procedure out now, but we do convert the
642	 * machine ID to an int, since rep_set_transport needs
643	 * it.  Even so, it'll be easier later to deal with
644	 * the Tcl_Obj *, so we save that, not the int.
645	 *
646	 * Note that we Tcl_IncrRefCount both objects
647	 * independently;  Tcl is free to discard the list
648	 * that they're bundled into.
649	 */
650
651	/*
652	 * Check that the machine ID is an int.  Note that
653	 * we do want to use GetIntFromObj;  the machine
654	 * ID is explicitly an int, not a u_int32_t.
655	 */
656	if (ip->i_rep_eid != NULL) {
657		Tcl_DecrRefCount(ip->i_rep_eid);
658	}
659	ip->i_rep_eid = objv[0];
660	Tcl_IncrRefCount(ip->i_rep_eid);
661	result = Tcl_GetIntFromObj(interp,
662	    ip->i_rep_eid, &intarg);
663	if (result != TCL_OK)
664		return (result);
665
666	if (ip->i_rep_send != NULL) {
667		Tcl_DecrRefCount(ip->i_rep_send);
668	}
669	ip->i_rep_send = objv[1];
670	Tcl_IncrRefCount(ip->i_rep_send);
671	_debug_check();
672	ret = dbenv->rep_set_transport(dbenv, intarg, tcl_rep_send);
673	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
674	    "env rep_transport"));
675}
676#endif
677
678#ifdef CONFIG_TEST
679/*
680 * tcl_RepStart --
681 *	Call DB_ENV->rep_start().
682 *
683 * PUBLIC: int tcl_RepStart
684 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
685 *
686 *	Note that this normally can/should be achieved as an argument to
687 * berkdb env, but we need to test forcible upgrading of clients, which
688 * involves calling this on an open environment handle.
689 */
690int
691tcl_RepStart(interp, objc, objv, dbenv)
692	Tcl_Interp *interp;		/* Interpreter */
693	int objc;			/* How many arguments? */
694	Tcl_Obj *CONST objv[];		/* The argument objects */
695	DB_ENV *dbenv;
696{
697	static const char *tclrpstrt[] = {
698		"-client",
699		"-master",
700		NULL
701	};
702	enum tclrpstrt {
703		TCL_RPSTRT_CLIENT,
704		TCL_RPSTRT_MASTER
705	};
706	char *arg;
707	int i, optindex, ret;
708	u_int32_t flag;
709
710	flag = 0;
711
712	if (objc != 3) {
713		Tcl_WrongNumArgs(interp, 3, objv, "[-master/-client]");
714		return (TCL_ERROR);
715	}
716
717	i = 2;
718	while (i < objc) {
719		if (Tcl_GetIndexFromObj(interp, objv[i], tclrpstrt,
720		    "option", TCL_EXACT, &optindex) != TCL_OK) {
721			arg = Tcl_GetStringFromObj(objv[i], NULL);
722			if (arg[0] == '-')
723				return (IS_HELP(objv[i]));
724			else
725				Tcl_ResetResult(interp);
726			break;
727		}
728		i++;
729		switch ((enum tclrpstrt)optindex) {
730		case TCL_RPSTRT_CLIENT:
731			flag = DB_REP_CLIENT;
732			break;
733		case TCL_RPSTRT_MASTER:
734			flag = DB_REP_MASTER;
735			break;
736		}
737	}
738
739	_debug_check();
740	ret = dbenv->rep_start(dbenv, NULL, flag);
741	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env rep_start"));
742}
743#endif
744
745#ifdef CONFIG_TEST
746/*
747 * tcl_RepProcessMessage --
748 *	Call DB_ENV->rep_process_message().
749 *
750 * PUBLIC: int tcl_RepProcessMessage
751 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
752 */
753int
754tcl_RepProcessMessage(interp, objc, objv, dbenv)
755	Tcl_Interp *interp;		/* Interpreter */
756	int objc;			/* How many arguments? */
757	Tcl_Obj *CONST objv[];		/* The argument objects */
758	DB_ENV *dbenv;			/* Environment pointer */
759{
760	DBT control, rec;
761	DB_LSN permlsn;
762	Tcl_Obj *lsnlist, *myobjv[2], *res;
763	void *ctmp, *rtmp;
764	char *msg;
765	int eid;
766	int freectl, freerec, myobjc, result, ret;
767
768	if (objc != 5) {
769		Tcl_WrongNumArgs(interp, 5, objv, "id control rec");
770		return (TCL_ERROR);
771	}
772	freectl = freerec = 0;
773
774	memset(&control, 0, sizeof(control));
775	memset(&rec, 0, sizeof(rec));
776
777	if ((result = Tcl_GetIntFromObj(interp, objv[2], &eid)) != TCL_OK)
778		return (result);
779
780	ret = _CopyObjBytes(interp, objv[3], &ctmp,
781	    &control.size, &freectl);
782	if (ret != 0) {
783		result = _ReturnSetup(interp, ret,
784		    DB_RETOK_REPPMSG(ret), "rep_proc_msg");
785		return (result);
786	}
787	control.data = ctmp;
788	ret = _CopyObjBytes(interp, objv[4], &rtmp,
789	    &rec.size, &freerec);
790	if (ret != 0) {
791		result = _ReturnSetup(interp, ret,
792		    DB_RETOK_REPPMSG(ret), "rep_proc_msg");
793		goto out;
794	}
795	rec.data = rtmp;
796	_debug_check();
797	ret = dbenv->rep_process_message(dbenv, &control, &rec, eid, &permlsn);
798	/*
799	 * !!!
800	 * The TCL API diverges from the C++/Java APIs here.  For us, it
801	 * is OK to get DUPMASTER and HOLDELECTION for testing purposes.
802	 */
803	result = _ReturnSetup(interp, ret,
804	    DB_RETOK_REPPMSG(ret) || ret == DB_REP_DUPMASTER ||
805	    ret == DB_REP_HOLDELECTION,
806	    "env rep_process_message");
807
808	if (result != TCL_OK)
809		goto out;
810
811	/*
812	 * We have a valid return.  We need to return a variety of information.
813	 * It will be one of the following:
814	 * {0 0} -  Make a 0 return a list for consistent return structure.
815	 * {DUPMASTER 0} -  DUPMASTER, no other info needed.
816	 * {HOLDELECTION 0} -  HOLDELECTION, no other info needed.
817	 * {NEWMASTER #} - NEWMASTER and its ID.
818	 * {NEWSITE 0} - NEWSITE, no other info needed.
819	 * {IGNORE {LSN list}} - IGNORE and this msg's LSN.
820	 * {ISPERM {LSN list}} - ISPERM and the perm LSN.
821	 * {NOTPERM {LSN list}} - NOTPERM and this msg's LSN.
822	 */
823	myobjc = 2;
824	switch (ret) {
825	case 0:
826		myobjv[0] = Tcl_NewIntObj(0);
827		myobjv[1] = Tcl_NewIntObj(0);
828		break;
829	case DB_REP_DUPMASTER:
830		myobjv[0] = Tcl_NewByteArrayObj(
831		    (u_char *)"DUPMASTER", (int)strlen("DUPMASTER"));
832		myobjv[1] = Tcl_NewIntObj(0);
833		break;
834	case DB_REP_HOLDELECTION:
835		myobjv[0] = Tcl_NewByteArrayObj(
836		    (u_char *)"HOLDELECTION", (int)strlen("HOLDELECTION"));
837		myobjv[1] = Tcl_NewIntObj(0);
838		break;
839	case DB_REP_IGNORE:
840		myobjv[0] = Tcl_NewLongObj((long)permlsn.file);
841		myobjv[1] = Tcl_NewLongObj((long)permlsn.offset);
842		lsnlist = Tcl_NewListObj(myobjc, myobjv);
843		myobjv[0] = Tcl_NewByteArrayObj(
844		    (u_char *)"IGNORE", (int)strlen("IGNORE"));
845		myobjv[1] = lsnlist;
846		break;
847	case DB_REP_ISPERM:
848		myobjv[0] = Tcl_NewLongObj((long)permlsn.file);
849		myobjv[1] = Tcl_NewLongObj((long)permlsn.offset);
850		lsnlist = Tcl_NewListObj(myobjc, myobjv);
851		myobjv[0] = Tcl_NewByteArrayObj(
852		    (u_char *)"ISPERM", (int)strlen("ISPERM"));
853		myobjv[1] = lsnlist;
854		break;
855	case DB_REP_NEWSITE:
856		myobjv[0] = Tcl_NewByteArrayObj(
857		    (u_char *)"NEWSITE", (int)strlen("NEWSITE"));
858		myobjv[1] = Tcl_NewIntObj(0);
859		break;
860	case DB_REP_NOTPERM:
861		myobjv[0] = Tcl_NewLongObj((long)permlsn.file);
862		myobjv[1] = Tcl_NewLongObj((long)permlsn.offset);
863		lsnlist = Tcl_NewListObj(myobjc, myobjv);
864		myobjv[0] = Tcl_NewByteArrayObj(
865		    (u_char *)"NOTPERM", (int)strlen("NOTPERM"));
866		myobjv[1] = lsnlist;
867		break;
868	default:
869		msg = db_strerror(ret);
870		Tcl_AppendResult(interp, msg, NULL);
871		Tcl_SetErrorCode(interp, "BerkeleyDB", msg, NULL);
872		result = TCL_ERROR;
873		goto out;
874	}
875	res = Tcl_NewListObj(myobjc, myobjv);
876	if (res != NULL)
877		Tcl_SetObjResult(interp, res);
878out:
879	if (freectl)
880		__os_free(NULL, ctmp);
881	if (freerec)
882		__os_free(NULL, rtmp);
883
884	return (result);
885}
886#endif
887
888#ifdef CONFIG_TEST
889/*
890 * tcl_RepStat --
891 *	Call DB_ENV->rep_stat().
892 *
893 * PUBLIC: int tcl_RepStat
894 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
895 */
896int
897tcl_RepStat(interp, objc, objv, dbenv)
898	Tcl_Interp *interp;		/* Interpreter */
899	int objc;			/* How many arguments? */
900	Tcl_Obj *CONST objv[];		/* The argument objects */
901	DB_ENV *dbenv;
902{
903	DB_REP_STAT *sp;
904	Tcl_Obj *myobjv[2], *res, *thislist, *lsnlist;
905	u_int32_t flag;
906	int myobjc, result, ret;
907	char *arg, *role;
908
909	flag = 0;
910	result = TCL_OK;
911
912	if (objc > 3) {
913		Tcl_WrongNumArgs(interp, 2, objv, NULL);
914		return (TCL_ERROR);
915	}
916	if (objc == 3) {
917		arg = Tcl_GetStringFromObj(objv[2], NULL);
918		if (strcmp(arg, "-clear") == 0)
919			flag = DB_STAT_CLEAR;
920		else {
921			Tcl_SetResult(interp,
922			    "db stat: unknown arg", TCL_STATIC);
923			return (TCL_ERROR);
924		}
925	}
926
927	_debug_check();
928	ret = dbenv->rep_stat(dbenv, &sp, flag);
929	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
930	    "rep stat");
931	if (result == TCL_ERROR)
932		return (result);
933
934	/*
935	 * Have our stats, now construct the name value
936	 * list pairs and free up the memory.
937	 */
938	res = Tcl_NewObj();
939#ifdef HAVE_STATISTICS
940	/*
941	 * MAKE_STAT_* assumes 'res' and 'error' label.
942	 */
943	if (sp->st_status == DB_REP_MASTER)
944		role = "master";
945	else if (sp->st_status == DB_REP_CLIENT)
946		role = "client";
947	else
948		role = "none";
949	MAKE_STAT_STRLIST("Role", role);
950
951	MAKE_STAT_LSN("Next LSN expected", &sp->st_next_lsn);
952	MAKE_STAT_LSN("First missed LSN", &sp->st_waiting_lsn);
953	MAKE_STAT_LSN("Maximum permanent LSN", &sp->st_max_perm_lsn);
954	MAKE_WSTAT_LIST("Bulk buffer fills", sp->st_bulk_fills);
955	MAKE_WSTAT_LIST("Bulk buffer overflows", sp->st_bulk_overflows);
956	MAKE_WSTAT_LIST("Bulk records stored", sp->st_bulk_records);
957	MAKE_WSTAT_LIST("Bulk buffer transfers", sp->st_bulk_transfers);
958	MAKE_WSTAT_LIST("Client service requests", sp->st_client_svc_req);
959	MAKE_WSTAT_LIST("Client service req misses", sp->st_client_svc_miss);
960	MAKE_WSTAT_LIST("Client rerequests", sp->st_client_rerequests);
961	MAKE_STAT_LIST("Duplicate master conditions", sp->st_dupmasters);
962	MAKE_STAT_LIST("Environment ID", sp->st_env_id);
963	MAKE_STAT_LIST("Environment priority", sp->st_env_priority);
964	MAKE_STAT_LIST("Generation number", sp->st_gen);
965	MAKE_STAT_LIST("Election generation number", sp->st_egen);
966	MAKE_STAT_LIST("Startup complete", sp->st_startup_complete);
967	MAKE_WSTAT_LIST("Duplicate log records received", sp->st_log_duplicated);
968	MAKE_WSTAT_LIST("Current log records queued", sp->st_log_queued);
969	MAKE_WSTAT_LIST("Maximum log records queued", sp->st_log_queued_max);
970	MAKE_WSTAT_LIST("Total log records queued", sp->st_log_queued_total);
971	MAKE_WSTAT_LIST("Log records received", sp->st_log_records);
972	MAKE_WSTAT_LIST("Log records requested", sp->st_log_requested);
973	MAKE_STAT_LIST("Master environment ID", sp->st_master);
974	MAKE_WSTAT_LIST("Master changes", sp->st_master_changes);
975	MAKE_STAT_LIST("Messages with bad generation number",
976	    sp->st_msgs_badgen);
977	MAKE_WSTAT_LIST("Messages processed", sp->st_msgs_processed);
978	MAKE_WSTAT_LIST("Messages ignored for recovery", sp->st_msgs_recover);
979	MAKE_WSTAT_LIST("Message send failures", sp->st_msgs_send_failures);
980	MAKE_WSTAT_LIST("Messages sent", sp->st_msgs_sent);
981	MAKE_WSTAT_LIST("New site messages", sp->st_newsites);
982	MAKE_STAT_LIST("Number of sites in replication group", sp->st_nsites);
983	MAKE_WSTAT_LIST("Transmission limited", sp->st_nthrottles);
984	MAKE_WSTAT_LIST("Outdated conditions", sp->st_outdated);
985	MAKE_WSTAT_LIST("Transactions applied", sp->st_txns_applied);
986	MAKE_STAT_LIST("Next page expected", sp->st_next_pg);
987	MAKE_WSTAT_LIST("First missed page", sp->st_waiting_pg);
988	MAKE_WSTAT_LIST("Duplicate pages received", sp->st_pg_duplicated);
989	MAKE_WSTAT_LIST("Pages received", sp->st_pg_records);
990	MAKE_WSTAT_LIST("Pages requested", sp->st_pg_requested);
991	MAKE_WSTAT_LIST("Elections held", sp->st_elections);
992	MAKE_WSTAT_LIST("Elections won", sp->st_elections_won);
993	MAKE_STAT_LIST("Election phase", sp->st_election_status);
994	MAKE_STAT_LIST("Election winner", sp->st_election_cur_winner);
995	MAKE_STAT_LIST("Election generation number", sp->st_election_gen);
996	MAKE_STAT_LSN("Election max LSN", &sp->st_election_lsn);
997	MAKE_STAT_LIST("Election sites", sp->st_election_nsites);
998	MAKE_STAT_LIST("Election nvotes", sp->st_election_nvotes);
999	MAKE_STAT_LIST("Election priority", sp->st_election_priority);
1000	MAKE_STAT_LIST("Election tiebreaker", sp->st_election_tiebreaker);
1001	MAKE_STAT_LIST("Election votes", sp->st_election_votes);
1002	MAKE_STAT_LIST("Election seconds", sp->st_election_sec);
1003	MAKE_STAT_LIST("Election usecs", sp->st_election_usec);
1004	MAKE_STAT_LIST("Start-sync operations delayed",
1005	    sp->st_startsync_delayed);
1006	MAKE_STAT_LIST("Maximum lease seconds", sp->st_max_lease_sec);
1007	MAKE_STAT_LIST("Maximum lease usecs", sp->st_max_lease_usec);
1008	MAKE_STAT_LIST("File fail cleanups done", sp->st_filefail_cleanups);
1009#endif
1010
1011	Tcl_SetObjResult(interp, res);
1012error:
1013	__os_ufree(dbenv->env, sp);
1014	return (result);
1015}
1016
1017/*
1018 * tcl_RepMgr --
1019 *	Configure and start the Replication Manager.
1020 *
1021 * PUBLIC: int tcl_RepMgr
1022 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
1023 */
1024int
1025tcl_RepMgr(interp, objc, objv, dbenv)
1026	Tcl_Interp *interp;		/* Interpreter */
1027	int objc;			/* How many arguments? */
1028	Tcl_Obj *CONST objv[];		/* The argument objects */
1029	DB_ENV *dbenv;			/* Environment pointer */
1030{
1031	static const char *rmgr[] = {
1032		"-ack",
1033		"-local",
1034		"-msgth",
1035		"-nsites",
1036		"-pri",
1037		"-remote",
1038		"-start",
1039		"-timeout",
1040		NULL
1041	};
1042	enum rmgr {
1043		RMGR_ACK,
1044		RMGR_LOCAL,
1045		RMGR_MSGTH,
1046		RMGR_NSITES,
1047		RMGR_PRI,
1048		RMGR_REMOTE,
1049		RMGR_START,
1050		RMGR_TIMEOUT
1051	};
1052	Tcl_Obj **myobjv;
1053	long to;
1054	int ack, i, myobjc, optindex, result, ret, totype;
1055	u_int32_t msgth, remote_flag, start_flag, uintarg;
1056	char *arg;
1057
1058	result = TCL_OK;
1059	ack = ret = totype = 0;
1060	msgth = 1;
1061	remote_flag = start_flag = 0;
1062
1063	if (objc <= 2) {
1064		Tcl_WrongNumArgs(interp, 2, objv, "?args?");
1065		return (TCL_ERROR);
1066	}
1067	/*
1068	 * Get the command name index from the object based on the bdbcmds
1069	 * defined above.
1070	 */
1071	i = 2;
1072	while (i < objc) {
1073		Tcl_ResetResult(interp);
1074		if (Tcl_GetIndexFromObj(interp, objv[i], rmgr, "option",
1075		    TCL_EXACT, &optindex) != TCL_OK) {
1076			result = IS_HELP(objv[i]);
1077			goto error;
1078		}
1079		i++;
1080		switch ((enum rmgr)optindex) {
1081		case RMGR_ACK:
1082			if (i >= objc) {
1083				Tcl_WrongNumArgs(interp, 2, objv,
1084				    "?-ack policy?");
1085				result = TCL_ERROR;
1086				break;
1087			}
1088			arg = Tcl_GetStringFromObj(objv[i++], NULL);
1089			if (strcmp(arg, "all") == 0)
1090				ack = DB_REPMGR_ACKS_ALL;
1091			else if (strcmp(arg, "allpeers") == 0)
1092				ack = DB_REPMGR_ACKS_ALL_PEERS;
1093			else if (strcmp(arg, "none") == 0)
1094				ack = DB_REPMGR_ACKS_NONE;
1095			else if (strcmp(arg, "one") == 0)
1096				ack = DB_REPMGR_ACKS_ONE;
1097			else if (strcmp(arg, "onepeer") == 0)
1098				ack = DB_REPMGR_ACKS_ONE_PEER;
1099			else if (strcmp(arg, "quorum") == 0)
1100				ack = DB_REPMGR_ACKS_QUORUM;
1101			else {
1102				Tcl_AddErrorInfo(interp,
1103				    "ack: illegal policy");
1104				result = TCL_ERROR;
1105				break;
1106			}
1107			_debug_check();
1108			ret = dbenv->repmgr_set_ack_policy(dbenv, ack);
1109			result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
1110			    "ack");
1111			break;
1112		case RMGR_LOCAL:
1113			result = Tcl_ListObjGetElements(interp, objv[i],
1114			    &myobjc, &myobjv);
1115			if (result == TCL_OK)
1116				i++;
1117			else
1118				break;
1119			if (myobjc != 2) {
1120				Tcl_WrongNumArgs(interp, 2, objv,
1121				    "?-local {host port}?");
1122				result = TCL_ERROR;
1123				break;
1124			}
1125			arg = Tcl_GetStringFromObj(myobjv[0], NULL);
1126			if ((result = _GetUInt32(interp, myobjv[1], &uintarg))
1127			    != TCL_OK)
1128				break;
1129			_debug_check();
1130			/*
1131			 * No flags for now.
1132			 */
1133			ret = dbenv->repmgr_set_local_site(dbenv,
1134			    arg, uintarg, 0);
1135			result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
1136			    "repmgr_set_local_site");
1137			break;
1138		case RMGR_MSGTH:
1139			if (i >= objc) {
1140				Tcl_WrongNumArgs(
1141				    interp, 2, objv, "?-msgth nth?");
1142				result = TCL_ERROR;
1143				break;
1144			}
1145			result = _GetUInt32(interp, objv[i++], &msgth);
1146			break;
1147		case RMGR_NSITES:
1148			if (i >= objc) {
1149				Tcl_WrongNumArgs(interp, 2, objv,
1150				    "?-nsites num_sites?");
1151				result = TCL_ERROR;
1152				break;
1153			}
1154			result = _GetUInt32(interp, objv[i++], &uintarg);
1155			if (result == TCL_OK) {
1156				_debug_check();
1157				ret = dbenv->
1158				    rep_set_nsites(dbenv, uintarg);
1159			}
1160			break;
1161		case RMGR_PRI:
1162			if (i >= objc) {
1163				Tcl_WrongNumArgs(interp, 2, objv,
1164				    "?-pri priority?");
1165				result = TCL_ERROR;
1166				break;
1167			}
1168			result = _GetUInt32(interp, objv[i++], &uintarg);
1169			if (result == TCL_OK) {
1170				_debug_check();
1171				ret = dbenv->
1172				    rep_set_priority(dbenv, uintarg);
1173			}
1174			break;
1175		case RMGR_REMOTE:
1176			result = Tcl_ListObjGetElements(interp, objv[i],
1177			    &myobjc, &myobjv);
1178			if (result == TCL_OK)
1179				i++;
1180			else
1181				break;
1182			if (myobjc != 2 && myobjc != 3) {
1183				Tcl_WrongNumArgs(interp, 2, objv,
1184				    "?-remote {host port [peer]}?");
1185				result = TCL_ERROR;
1186				break;
1187			}
1188			/*
1189			 * Get the flag first so we can reuse 'arg'.
1190			 */
1191			if (myobjc == 3) {
1192				arg = Tcl_GetStringFromObj(myobjv[2], NULL);
1193				if (strcmp(arg, "peer") == 0)
1194					remote_flag = DB_REPMGR_PEER;
1195				else {
1196					Tcl_AddErrorInfo(interp,
1197					    "remote: illegal flag");
1198					result = TCL_ERROR;
1199					break;
1200				}
1201			}
1202			arg = Tcl_GetStringFromObj(myobjv[0], NULL);
1203			if ((result = _GetUInt32(interp, myobjv[1], &uintarg))
1204			    != TCL_OK)
1205				break;
1206			_debug_check();
1207			ret = dbenv->repmgr_add_remote_site(dbenv,
1208			    arg, uintarg, NULL, remote_flag);
1209			result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
1210			    "repmgr_add_remote_site");
1211			break;
1212		case RMGR_START:
1213			if (i >= objc) {
1214				Tcl_WrongNumArgs(
1215				    interp, 2, objv, "?-start state?");
1216				result = TCL_ERROR;
1217				break;
1218			}
1219			arg = Tcl_GetStringFromObj(objv[i++], NULL);
1220			if (strcmp(arg, "master") == 0)
1221				start_flag = DB_REP_MASTER;
1222			else if (strcmp(arg, "client") == 0)
1223				start_flag = DB_REP_CLIENT;
1224			else if (strcmp(arg, "elect") == 0)
1225				start_flag = DB_REP_ELECTION;
1226			else {
1227				Tcl_AddErrorInfo(
1228				    interp, "start: illegal state");
1229				result = TCL_ERROR;
1230				break;
1231			}
1232			/*
1233			 * Some config functions need to be called
1234			 * before repmgr_start.  So finish parsing all
1235			 * the args and call repmgr_start at the end.
1236			 */
1237			break;
1238		case RMGR_TIMEOUT:
1239			result = Tcl_ListObjGetElements(interp, objv[i],
1240			    &myobjc, &myobjv);
1241			if (result == TCL_OK)
1242				i++;
1243			else
1244				break;
1245			if (myobjc != 2) {
1246				Tcl_WrongNumArgs(interp, 2, objv,
1247				    "?-timeout {type to}?");
1248				result = TCL_ERROR;
1249				break;
1250			}
1251			arg = Tcl_GetStringFromObj(myobjv[0], NULL);
1252			if (strcmp(arg, "ack") == 0)
1253				totype = DB_REP_ACK_TIMEOUT;
1254			else if (strcmp(arg, "conn_retry") == 0)
1255				totype = DB_REP_CONNECTION_RETRY;
1256			else if (strcmp(arg, "elect") == 0)
1257				totype = DB_REP_ELECTION_TIMEOUT;
1258			else if (strcmp(arg, "elect_retry") == 0)
1259				totype = DB_REP_ELECTION_RETRY;
1260			else if (strcmp(arg, "heartbeat_monitor") == 0)
1261				totype = DB_REP_HEARTBEAT_MONITOR;
1262			else if (strcmp(arg, "heartbeat_send") == 0)
1263				totype = DB_REP_HEARTBEAT_SEND;
1264			else {
1265				Tcl_AddErrorInfo(interp,
1266				    "timeout: illegal type");
1267				result = TCL_ERROR;
1268				break;
1269			}
1270			if ((result = Tcl_GetLongFromObj(
1271			   interp, myobjv[1], &to)) != TCL_OK)
1272				break;
1273			_debug_check();
1274			ret = dbenv->rep_set_timeout(dbenv, totype,
1275			    (db_timeout_t)to);
1276			result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
1277			    "rep_set_timeout");
1278			break;
1279		}
1280		/*
1281		 * If, at any time, parsing the args we get an error,
1282		 * bail out and return.
1283		 */
1284		if (result != TCL_OK)
1285			goto error;
1286	}
1287	/*
1288	 * Only call repmgr_start if needed.  The user may use this
1289	 * call just to reconfigure, change policy, etc.
1290	 */
1291	if (start_flag != 0 && result == TCL_OK) {
1292		_debug_check();
1293		ret = dbenv->repmgr_start(dbenv, (int)msgth, start_flag);
1294		result = _ReturnSetup(
1295		    interp, ret, DB_RETOK_REPMGR_START(ret), "repmgr_start");
1296	}
1297error:
1298	return (result);
1299}
1300
1301/*
1302 * tcl_RepMgrSiteList --
1303 *	Call DB_ENV->repmgr_site_list().
1304 *
1305 * PUBLIC: int tcl_RepMgrSiteList
1306 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
1307 */
1308int
1309tcl_RepMgrSiteList(interp, objc, objv, dbenv)
1310	Tcl_Interp *interp;		/* Interpreter */
1311	int objc;			/* How many arguments? */
1312	Tcl_Obj *CONST objv[];		/* The argument objects */
1313	DB_ENV *dbenv;
1314{
1315	DB_REPMGR_SITE *sp;
1316	Tcl_Obj *myobjv[4], *res, *thislist;
1317	u_int count, i;
1318	char *st;
1319	int myobjc, result, ret;
1320
1321	result = TCL_OK;
1322
1323	if (objc > 2) {
1324		Tcl_WrongNumArgs(interp, 2, objv, NULL);
1325		return (TCL_ERROR);
1326	}
1327
1328	_debug_check();
1329	ret = dbenv->repmgr_site_list(dbenv, &count, &sp);
1330	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
1331	    "repmgr sitelist");
1332	if (result == TCL_ERROR)
1333		return (result);
1334
1335	/*
1336	 * Have our sites, now construct the {eid host port status}
1337	 * tuples and free up the memory.
1338	 */
1339	res = Tcl_NewObj();
1340
1341	for (i = 0; i < count; ++i) {
1342		/*
1343		 * MAKE_SITE_LIST assumes 'res' and 'error' label.
1344		 */
1345		if (sp[i].status == DB_REPMGR_CONNECTED)
1346			st = "connected";
1347		else if (sp[i].status == DB_REPMGR_DISCONNECTED)
1348			st = "disconnected";
1349		else
1350			st = "unknown";
1351		MAKE_SITE_LIST(sp[i].eid, sp[i].host, sp[i].port, st);
1352	}
1353
1354	Tcl_SetObjResult(interp, res);
1355error:
1356	__os_ufree(dbenv->env, sp);
1357	return (result);
1358}
1359
1360/*
1361 * tcl_RepMgrStat --
1362 *	Call DB_ENV->repmgr_stat().
1363 *
1364 * PUBLIC: int tcl_RepMgrStat
1365 * PUBLIC:     __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *));
1366 */
1367int
1368tcl_RepMgrStat(interp, objc, objv, dbenv)
1369	Tcl_Interp *interp;		/* Interpreter */
1370	int objc;			/* How many arguments? */
1371	Tcl_Obj *CONST objv[];		/* The argument objects */
1372	DB_ENV *dbenv;
1373{
1374	DB_REPMGR_STAT *sp;
1375	Tcl_Obj *res;
1376	u_int32_t flag;
1377	int result, ret;
1378	char *arg;
1379
1380	flag = 0;
1381	result = TCL_OK;
1382
1383	if (objc > 3) {
1384		Tcl_WrongNumArgs(interp, 2, objv, NULL);
1385		return (TCL_ERROR);
1386	}
1387	if (objc == 3) {
1388		arg = Tcl_GetStringFromObj(objv[2], NULL);
1389		if (strcmp(arg, "-clear") == 0)
1390			flag = DB_STAT_CLEAR;
1391		else {
1392			Tcl_SetResult(interp,
1393			    "db stat: unknown arg", TCL_STATIC);
1394			return (TCL_ERROR);
1395		}
1396	}
1397
1398	_debug_check();
1399	ret = dbenv->repmgr_stat(dbenv, &sp, flag);
1400	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
1401	    "repmgr stat");
1402	if (result == TCL_ERROR)
1403		return (result);
1404
1405	/*
1406	 * Have our stats, now construct the name value
1407	 * list pairs and free up the memory.
1408	 */
1409	res = Tcl_NewObj();
1410#ifdef HAVE_STATISTICS
1411	/*
1412	 * MAKE_STAT_* assumes 'res' and 'error' label.
1413	 */
1414	MAKE_WSTAT_LIST("Acknowledgement failures", sp->st_perm_failed);
1415	MAKE_WSTAT_LIST("Messages delayed", sp->st_msgs_queued);
1416	MAKE_WSTAT_LIST("Messages discarded", sp->st_msgs_dropped);
1417	MAKE_WSTAT_LIST("Connections dropped", sp->st_connection_drop);
1418	MAKE_WSTAT_LIST("Failed re-connects", sp->st_connect_fail);
1419#endif
1420
1421	Tcl_SetObjResult(interp, res);
1422error:
1423	__os_ufree(dbenv->env, sp);
1424	return (result);
1425}
1426#endif
1427