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