rep_util.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:20k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 2001-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: rep_util.c,v 1.51 2002/09/05 02:30:00 margo Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "dbinc/db_page.h"
  17. #include "dbinc/btree.h"
  18. #include "dbinc/fop.h"
  19. #include "dbinc/hash.h"
  20. #include "dbinc/log.h"
  21. #include "dbinc/qam.h"
  22. #include "dbinc/rep.h"
  23. #include "dbinc/txn.h"
  24. /*
  25.  * rep_util.c:
  26.  * Miscellaneous replication-related utility functions, including
  27.  * those called by other subsystems.
  28.  */
  29. static int __rep_cmp_bylsn __P((const void *, const void *));
  30. static int __rep_cmp_bypage __P((const void *, const void *));
  31. #ifdef REP_DIAGNOSTIC
  32. static void __rep_print_logmsg __P((DB_ENV *, const DBT *, DB_LSN *));
  33. #endif
  34. /*
  35.  * __rep_check_alloc --
  36.  * Make sure the array of TXN_REC entries is of at least size n.
  37.  * (This function is called by the __*_getpgnos() functions in
  38.  * *.src.)
  39.  *
  40.  * PUBLIC: int __rep_check_alloc __P((DB_ENV *, TXN_RECS *, int));
  41.  */
  42. int
  43. __rep_check_alloc(dbenv, r, n)
  44. DB_ENV *dbenv;
  45. TXN_RECS *r;
  46. int n;
  47. {
  48. int nalloc, ret;
  49. while (r->nalloc < r->npages + n) {
  50. nalloc = r->nalloc == 0 ? 20 : r->nalloc * 2;
  51. if ((ret = __os_realloc(dbenv, nalloc * sizeof(LSN_PAGE),
  52.     &r->array)) != 0)
  53. return (ret);
  54. r->nalloc = nalloc;
  55. }
  56. return (0);
  57. }
  58. /*
  59.  * __rep_send_message --
  60.  * This is a wrapper for sending a message.  It takes care of constructing
  61.  * the REP_CONTROL structure and calling the user's specified send function.
  62.  *
  63.  * PUBLIC: int __rep_send_message __P((DB_ENV *, int,
  64.  * PUBLIC:     u_int32_t, DB_LSN *, const DBT *, u_int32_t));
  65.  */
  66. int
  67. __rep_send_message(dbenv, eid, rtype, lsnp, dbtp, flags)
  68. DB_ENV *dbenv;
  69. int eid;
  70. u_int32_t rtype;
  71. DB_LSN *lsnp;
  72. const DBT *dbtp;
  73. u_int32_t flags;
  74. {
  75. DB_REP *db_rep;
  76. REP *rep;
  77. DBT cdbt, scrap_dbt;
  78. REP_CONTROL cntrl;
  79. u_int32_t send_flags;
  80. int ret;
  81. db_rep = dbenv->rep_handle;
  82. rep = db_rep->region;
  83. /* Set up control structure. */
  84. memset(&cntrl, 0, sizeof(cntrl));
  85. if (lsnp == NULL)
  86. ZERO_LSN(cntrl.lsn);
  87. else
  88. cntrl.lsn = *lsnp;
  89. cntrl.rectype = rtype;
  90. cntrl.flags = flags;
  91. cntrl.rep_version = DB_REPVERSION;
  92. cntrl.log_version = DB_LOGVERSION;
  93. MUTEX_LOCK(dbenv, db_rep->mutexp);
  94. cntrl.gen = rep->gen;
  95. MUTEX_UNLOCK(dbenv, db_rep->mutexp);
  96. memset(&cdbt, 0, sizeof(cdbt));
  97. cdbt.data = &cntrl;
  98. cdbt.size = sizeof(cntrl);
  99. /* Don't assume the send function will be tolerant of NULL records. */
  100. if (dbtp == NULL) {
  101. memset(&scrap_dbt, 0, sizeof(DBT));
  102. dbtp = &scrap_dbt;
  103. }
  104. send_flags = (LF_ISSET(DB_PERMANENT) ? DB_REP_PERMANENT : 0);
  105. #if 0
  106. __rep_print_message(dbenv, eid, &cntrl, "rep_send_message");
  107. #endif
  108. #ifdef REP_DIAGNOSTIC
  109. if (rtype == REP_LOG)
  110. __rep_print_logmsg(dbenv, dbtp, lsnp);
  111. #endif
  112. ret = db_rep->rep_send(dbenv, &cdbt, dbtp, eid, send_flags);
  113. /*
  114.  * We don't hold the rep lock, so this could miscount if we race.
  115.  * I don't think it's worth grabbing the mutex for that bit of
  116.  * extra accuracy.
  117.  */
  118. if (ret == 0)
  119. rep->stat.st_msgs_sent++;
  120. else
  121. rep->stat.st_msgs_send_failures++;
  122. return (ret);
  123. }
  124. #ifdef REP_DIAGNOSTIC
  125. /*
  126.  * __rep_print_logmsg --
  127.  * This is a debugging routine for printing out log records that
  128.  * we are about to transmit to a client.
  129.  */
  130. static void
  131. __rep_print_logmsg(dbenv, logdbt, lsnp)
  132. DB_ENV *dbenv;
  133. const DBT *logdbt;
  134. DB_LSN *lsnp;
  135. {
  136. /* Static structures to hold the printing functions. */
  137. static int (**ptab)__P((DB_ENV *,
  138.     DBT *, DB_LSN *, db_recops, void *)) = NULL;
  139. size_t ptabsize = 0;
  140. if (ptabsize == 0) {
  141. /* Initialize the table. */
  142. (void)__bam_init_print(dbenv, &ptab, &ptabsize);
  143. (void)__crdel_init_print(dbenv, &ptab, &ptabsize);
  144. (void)__db_init_print(dbenv, &ptab, &ptabsize);
  145. (void)__dbreg_init_print(dbenv, &ptab, &ptabsize);
  146. (void)__fop_init_print(dbenv, &ptab, &ptabsize);
  147. (void)__qam_init_print(dbenv, &ptab, &ptabsize);
  148. (void)__ham_init_print(dbenv, &ptab, &ptabsize);
  149. (void)__txn_init_print(dbenv, &ptab, &ptabsize);
  150. }
  151. (void)__db_dispatch(dbenv,
  152.     ptab, ptabsize, (DBT *)logdbt, lsnp, DB_TXN_PRINT, NULL);
  153. }
  154. #endif
  155. /*
  156.  * __rep_new_master --
  157.  * Called after a master election to sync back up with a new master.
  158.  * It's possible that we already know of this new master in which case
  159.  * we don't need to do anything.
  160.  *
  161.  * This is written assuming that this message came from the master; we
  162.  * need to enforce that in __rep_process_record, but right now, we have
  163.  * no way to identify the master.
  164.  *
  165.  * PUBLIC: int __rep_new_master __P((DB_ENV *, REP_CONTROL *, int));
  166.  */
  167. int
  168. __rep_new_master(dbenv, cntrl, eid)
  169. DB_ENV *dbenv;
  170. REP_CONTROL *cntrl;
  171. int eid;
  172. {
  173. DB_LOG *dblp;
  174. DB_LOGC *logc;
  175. DB_LSN last_lsn, lsn;
  176. DB_REP *db_rep;
  177. DBT dbt;
  178. LOG *lp;
  179. REP *rep;
  180. int change, ret, t_ret;
  181. db_rep = dbenv->rep_handle;
  182. rep = db_rep->region;
  183. MUTEX_LOCK(dbenv, db_rep->mutexp);
  184. ELECTION_DONE(rep);
  185. change = rep->gen != cntrl->gen || rep->master_id != eid;
  186. if (change) {
  187. rep->gen = cntrl->gen;
  188. rep->master_id = eid;
  189. F_SET(rep, REP_F_RECOVER);
  190. rep->stat.st_master_changes++;
  191. }
  192. MUTEX_UNLOCK(dbenv, db_rep->mutexp);
  193. if (!change)
  194. return (0);
  195. /*
  196.  * If the master changed, we need to start the process of
  197.  * figuring out what our last valid log record is.  However,
  198.  * if both the master and we agree that the max LSN is 0,0,
  199.  * then there is no recovery to be done.  If we are at 0 and
  200.  * the master is not, then we just need to request all the log
  201.  * records from the master.
  202.  */
  203. dblp = dbenv->lg_handle;
  204. lp = dblp->reginfo.primary;
  205. R_LOCK(dbenv, &dblp->reginfo);
  206. last_lsn = lsn = lp->lsn;
  207. if (last_lsn.offset > sizeof(LOGP))
  208. last_lsn.offset -= lp->len;
  209. R_UNLOCK(dbenv, &dblp->reginfo);
  210. if (IS_INIT_LSN(lsn) || IS_ZERO_LSN(lsn)) {
  211. empty: MUTEX_LOCK(dbenv, db_rep->mutexp);
  212. F_CLR(rep, REP_F_RECOVER);
  213. MUTEX_UNLOCK(dbenv, db_rep->mutexp);
  214. if (IS_INIT_LSN(cntrl->lsn))
  215. ret = 0;
  216. else
  217. ret = __rep_send_message(dbenv, rep->master_id,
  218.     REP_ALL_REQ, &lsn, NULL, 0);
  219. if (ret == 0)
  220. ret = DB_REP_NEWMASTER;
  221. return (ret);
  222. } else if (last_lsn.offset <= sizeof(LOGP)) {
  223. /*
  224.  * We have just changed log files and need to set lastlsn
  225.  * to the last record in the previous log files.
  226.  */
  227. if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
  228. return (ret);
  229. memset(&dbt, 0, sizeof(dbt));
  230. ret = logc->get(logc, &last_lsn, &dbt, DB_LAST);
  231. if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
  232. ret = t_ret;
  233. if (ret == DB_NOTFOUND)
  234. goto empty;
  235. if (ret != 0)
  236. return (ret);
  237. }
  238. R_LOCK(dbenv, &dblp->reginfo);
  239. lp->verify_lsn = last_lsn;
  240. R_UNLOCK(dbenv, &dblp->reginfo);
  241. if ((ret = __rep_send_message(dbenv,
  242.     eid, REP_VERIFY_REQ, &last_lsn, NULL, 0)) != 0)
  243. return (ret);
  244. return (DB_REP_NEWMASTER);
  245. }
  246. /*
  247.  * __rep_lockpgno_init
  248.  * Create a dispatch table for acquiring locks on each log record.
  249.  *
  250.  * PUBLIC: int __rep_lockpgno_init __P((DB_ENV *,
  251.  * PUBLIC:     int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *),
  252.  * PUBLIC:     size_t *));
  253.  */
  254. int
  255. __rep_lockpgno_init(dbenv, dtabp, dtabsizep)
  256. DB_ENV *dbenv;
  257. int (***dtabp)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  258. size_t *dtabsizep;
  259. {
  260. int ret;
  261. /* Initialize dispatch table. */
  262. *dtabsizep = 0;
  263. *dtabp = NULL;
  264. if ((ret = __bam_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  265.     (ret = __crdel_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  266.     (ret = __db_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  267.     (ret = __dbreg_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  268.     (ret = __fop_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  269.     (ret = __qam_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  270.     (ret = __ham_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
  271.     (ret = __txn_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0)
  272. return (ret);
  273. return (0);
  274. }
  275. /*
  276.  * __rep_unlockpages --
  277.  * Unlock the pages locked in __rep_lockpages.
  278.  *
  279.  * PUBLIC: int __rep_unlockpages __P((DB_ENV *, u_int32_t));
  280.  */
  281. int
  282. __rep_unlockpages(dbenv, lid)
  283. DB_ENV *dbenv;
  284. u_int32_t lid;
  285. {
  286. DB_LOCKREQ req, *lvp;
  287. req.op = DB_LOCK_PUT_ALL;
  288. return (dbenv->lock_vec(dbenv, lid, 0, &req, 1, &lvp));
  289. }
  290. /*
  291.  * __rep_lockpages --
  292.  * Called to gather and lock pages in preparation for both
  293.  * single transaction apply as well as client synchronization
  294.  * with a new master.  A non-NULL key_lsn means that we're locking
  295.  * in order to apply a single log record during client recovery
  296.  * to the joint LSN.  A non-NULL max_lsn means that we are applying
  297.  * a transaction whose commit is at max_lsn.
  298.  *
  299.  * PUBLIC: int __rep_lockpages __P((DB_ENV *,
  300.  * PUBLIC:     int (**)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *),
  301.  * PUBLIC:     size_t, DB_LSN *, DB_LSN *, TXN_RECS *, u_int32_t));
  302.  */
  303. int
  304. __rep_lockpages(dbenv, dtab, dtabsize, key_lsn, max_lsn, recs, lid)
  305. DB_ENV *dbenv;
  306. int (**dtab)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  307. size_t dtabsize;
  308. DB_LSN *key_lsn, *max_lsn;
  309. TXN_RECS *recs;
  310. u_int32_t lid;
  311. {
  312. DBT data_dbt, lo;
  313. DB_LOCK l;
  314. DB_LOCKREQ *lvp;
  315. DB_LOGC *logc;
  316. DB_LSN tmp_lsn;
  317. TXN_RECS tmp, *t;
  318. db_pgno_t cur_pgno;
  319. linfo_t locks;
  320. int i, ret, t_ret, unique;
  321. u_int32_t cur_fid;
  322. /*
  323.  * There are two phases:  First, we have to traverse backwards through
  324.  * the log records gathering the list of all the pages accessed.  Once
  325.  * we have this information we can acquire all the locks we need.
  326.  */
  327. /* Initialization */
  328. memset(&locks, 0, sizeof(locks));
  329. ret = 0;
  330. t = recs != NULL ? recs : &tmp;
  331. t->npages = t->nalloc = 0;
  332. t->array = NULL;
  333. /*
  334.  * We've got to be in one mode or the other; else life will either
  335.  * be excessively boring or overly exciting.
  336.  */
  337. DB_ASSERT(key_lsn != NULL || max_lsn != NULL);
  338. DB_ASSERT(key_lsn == NULL || max_lsn == NULL);
  339. /*
  340.  * Phase 1:  Fill in the pgno array.
  341.  */
  342. memset(&data_dbt, 0, sizeof(data_dbt));
  343. if (F_ISSET(dbenv, DB_ENV_THREAD))
  344. F_SET(&data_dbt, DB_DBT_REALLOC);
  345. /* Single transaction apply. */
  346. if (max_lsn != NULL) {
  347. DB_ASSERT(0); /* XXX */
  348. /*
  349. tmp_lsn = *max_lsn;
  350. if ((ret = __rep_apply_thread(dbenv, dtab, dtabsize,
  351.     &data_dbt, &tmp_lsn, t)) != 0)
  352. goto err;
  353. */
  354. }
  355. /* In recovery. */
  356. if (key_lsn != NULL) {
  357. if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
  358. goto err;
  359. ret = logc->get(logc, key_lsn, &data_dbt, DB_SET);
  360. /* Save lsn values, since dispatch functions can change them. */
  361. tmp_lsn = *key_lsn;
  362. ret = __db_dispatch(dbenv,
  363.     dtab, dtabsize, &data_dbt, &tmp_lsn, DB_TXN_GETPGNOS, t);
  364. if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
  365. ret = t_ret;
  366. /*
  367.  * If ret == DB_DELETED, this record refers to a temporary
  368.  * file and there's nothing to apply.
  369.  */
  370. if (ret == DB_DELETED) {
  371. ret = 0;
  372. goto out;
  373. } else if (ret != 0)
  374. goto err;
  375. }
  376. if (t->npages == 0)
  377. goto out;
  378. /* Phase 2: Write lock all the pages. */
  379. /* Sort the entries in the array by page number. */
  380. qsort(t->array, t->npages, sizeof(LSN_PAGE), __rep_cmp_bypage);
  381. /* Count the number of unique pages. */
  382. cur_fid = DB_LOGFILEID_INVALID;
  383. cur_pgno = PGNO_INVALID;
  384. unique = 0;
  385. for (i = 0; i < t->npages; i++) {
  386. if (F_ISSET(&t->array[i], LSN_PAGE_NOLOCK))
  387. continue;
  388. if (t->array[i].pgdesc.pgno != cur_pgno ||
  389.     t->array[i].fid != cur_fid) {
  390. cur_pgno = t->array[i].pgdesc.pgno;
  391. cur_fid = t->array[i].fid;
  392. unique++;
  393. }
  394. }
  395. if (unique == 0)
  396. goto out;
  397. /* Handle single lock case specially, else allocate space for locks. */
  398. if (unique == 1) {
  399. memset(&lo, 0, sizeof(lo));
  400. lo.data = &t->array[0].pgdesc;
  401. lo.size = sizeof(t->array[0].pgdesc);
  402. ret = dbenv->lock_get(dbenv, lid, 0, &lo, DB_LOCK_WRITE, &l);
  403. goto out2;
  404. }
  405. /* Multi-lock case. */
  406. locks.n = unique;
  407. if ((ret = __os_calloc(dbenv,
  408.     unique, sizeof(DB_LOCKREQ), &locks.reqs)) != 0)
  409. goto err;
  410. if ((ret = __os_calloc(dbenv, unique, sizeof(DBT), &locks.objs)) != 0)
  411. goto err;
  412. unique = 0;
  413. cur_fid = DB_LOGFILEID_INVALID;
  414. cur_pgno = PGNO_INVALID;
  415. for (i = 0; i < t->npages; i++) {
  416. if (F_ISSET(&t->array[i], LSN_PAGE_NOLOCK))
  417. continue;
  418. if (t->array[i].pgdesc.pgno != cur_pgno ||
  419.     t->array[i].fid != cur_fid) {
  420. cur_pgno = t->array[i].pgdesc.pgno;
  421. cur_fid = t->array[i].fid;
  422. locks.reqs[unique].op = DB_LOCK_GET;
  423. locks.reqs[unique].mode = DB_LOCK_WRITE;
  424. locks.reqs[unique].obj = &locks.objs[unique];
  425. locks.objs[unique].data = &t->array[i].pgdesc;
  426. locks.objs[unique].size = sizeof(t->array[i].pgdesc);
  427. unique++;
  428. }
  429. }
  430. /* Finally, get the locks. */
  431. if ((ret =
  432.     dbenv->lock_vec(dbenv, lid, 0, locks.reqs, unique, &lvp)) != 0) {
  433. /*
  434.  * If we were unsuccessful, unlock any locks we acquired before
  435.  * the error and return the original error value.
  436.  */
  437. (void)__rep_unlockpages(dbenv, lid);
  438. }
  439. err:
  440. out: if (locks.objs != NULL)
  441. __os_free(dbenv, locks.objs);
  442. if (locks.reqs != NULL)
  443. __os_free(dbenv, locks.reqs);
  444. /*
  445.  * Before we return, sort by LSN so that we apply records in the
  446.  * right order.
  447.  */
  448. qsort(t->array, t->npages, sizeof(LSN_PAGE), __rep_cmp_bylsn);
  449. out2: if ((ret != 0 || recs == NULL) && t->nalloc != 0) {
  450. __os_free(dbenv, t->array);
  451. t->array = NULL;
  452. t->npages = t->nalloc = 0;
  453. }
  454. if (F_ISSET(&data_dbt, DB_DBT_REALLOC) && data_dbt.data != NULL)
  455. __os_ufree(dbenv, data_dbt.data);
  456. return (ret);
  457. }
  458. /*
  459.  * __rep_cmp_bypage and __rep_cmp_bylsn --
  460.  * Sort functions for qsort.  "bypage" sorts first by page numbers and
  461.  * then by the LSN.  "bylsn" sorts first by the LSN, then by page numbers.
  462.  */
  463. static int
  464. __rep_cmp_bypage(a, b)
  465. const void *a, *b;
  466. {
  467. LSN_PAGE *ap, *bp;
  468. ap = (LSN_PAGE *)a;
  469. bp = (LSN_PAGE *)b;
  470. if (ap->fid < bp->fid)
  471. return (-1);
  472. if (ap->fid > bp->fid)
  473. return (1);
  474. if (ap->pgdesc.pgno < bp->pgdesc.pgno)
  475. return (-1);
  476. if (ap->pgdesc.pgno > bp->pgdesc.pgno)
  477. return (1);
  478. if (ap->lsn.file < bp->lsn.file)
  479. return (-1);
  480. if (ap->lsn.file > bp->lsn.file)
  481. return (1);
  482. if (ap->lsn.offset < bp->lsn.offset)
  483. return (-1);
  484. if (ap->lsn.offset > bp->lsn.offset)
  485. return (1);
  486. return (0);
  487. }
  488. static int
  489. __rep_cmp_bylsn(a, b)
  490. const void *a, *b;
  491. {
  492. LSN_PAGE *ap, *bp;
  493. ap = (LSN_PAGE *)a;
  494. bp = (LSN_PAGE *)b;
  495. if (ap->lsn.file < bp->lsn.file)
  496. return (-1);
  497. if (ap->lsn.file > bp->lsn.file)
  498. return (1);
  499. if (ap->lsn.offset < bp->lsn.offset)
  500. return (-1);
  501. if (ap->lsn.offset > bp->lsn.offset)
  502. return (1);
  503. if (ap->fid < bp->fid)
  504. return (-1);
  505. if (ap->fid > bp->fid)
  506. return (1);
  507. if (ap->pgdesc.pgno < bp->pgdesc.pgno)
  508. return (-1);
  509. if (ap->pgdesc.pgno > bp->pgdesc.pgno)
  510. return (1);
  511. return (0);
  512. }
  513. /*
  514.  * __rep_is_client
  515.  * Used by other subsystems to figure out if this is a replication
  516.  * client sites.
  517.  *
  518.  * PUBLIC: int __rep_is_client __P((DB_ENV *));
  519.  */
  520. int
  521. __rep_is_client(dbenv)
  522. DB_ENV *dbenv;
  523. {
  524. DB_REP *db_rep;
  525. REP *rep;
  526. int ret;
  527. if ((db_rep = dbenv->rep_handle) == NULL)
  528. return (0);
  529. rep = db_rep->region;
  530. MUTEX_LOCK(dbenv, db_rep->mutexp);
  531. ret = F_ISSET(rep, REP_F_UPGRADE | REP_F_LOGSONLY);
  532. MUTEX_UNLOCK(dbenv, db_rep->mutexp);
  533. return (ret);
  534. }
  535. /*
  536.  * __rep_send_vote
  537.  * Send this site's vote for the election.
  538.  *
  539.  * PUBLIC: int __rep_send_vote __P((DB_ENV *, DB_LSN *, int, int, int));
  540.  */
  541. int
  542. __rep_send_vote(dbenv, lsnp, nsites, pri, tiebreaker)
  543. DB_ENV *dbenv;
  544. DB_LSN *lsnp;
  545. int nsites, pri, tiebreaker;
  546. {
  547. DBT vote_dbt;
  548. REP_VOTE_INFO vi;
  549. memset(&vi, 0, sizeof(vi));
  550. vi.priority = pri;
  551. vi.nsites = nsites;
  552. vi.tiebreaker = tiebreaker;
  553. memset(&vote_dbt, 0, sizeof(vote_dbt));
  554. vote_dbt.data = &vi;
  555. vote_dbt.size = sizeof(vi);
  556. return (__rep_send_message(dbenv,
  557.     DB_EID_BROADCAST, REP_VOTE1, lsnp, &vote_dbt, 0));
  558. }
  559. /*
  560.  * __rep_grow_sites --
  561.  * Called to allocate more space in the election tally information.
  562.  * Called with the rep mutex held.  We need to call the region mutex, so
  563.  * we need to make sure that we *never* acquire those mutexes in the
  564.  * opposite order.
  565.  *
  566.  * PUBLIC: int __rep_grow_sites __P((DB_ENV *dbenv, int nsites));
  567.  */
  568. int
  569. __rep_grow_sites(dbenv, nsites)
  570. DB_ENV *dbenv;
  571. int nsites;
  572. {
  573. REGENV *renv;
  574. REGINFO *infop;
  575. REP *rep;
  576. int nalloc, ret, *tally;
  577. rep = ((DB_REP *)dbenv->rep_handle)->region;
  578. /*
  579.  * Allocate either twice the current allocation or nsites,
  580.  * whichever is more.
  581.  */
  582. nalloc = 2 * rep->asites;
  583. if (nalloc < nsites)
  584. nalloc = nsites;
  585. infop = dbenv->reginfo;
  586. renv = infop->primary;
  587. MUTEX_LOCK(dbenv, &renv->mutex);
  588. if ((ret = __db_shalloc(infop->addr,
  589.     sizeof(nalloc * sizeof(int)), sizeof(int), &tally)) == 0) {
  590. if (rep->tally_off != INVALID_ROFF)
  591.  __db_shalloc_free(infop->addr,
  592.     R_ADDR(infop, rep->tally_off));
  593. rep->asites = nalloc;
  594. rep->nsites = nsites;
  595. rep->tally_off = R_OFFSET(infop, tally);
  596. }
  597. MUTEX_UNLOCK(dbenv, &renv->mutex);
  598. return (ret);
  599. }
  600. #ifdef NOTYET
  601. static int __rep_send_file __P((DB_ENV *, DBT *, u_int32_t));
  602. /*
  603.  * __rep_send_file --
  604.  * Send an entire file, one block at a time.
  605.  */
  606. static int
  607. __rep_send_file(dbenv, rec, eid)
  608. DB_ENV *dbenv;
  609. DBT *rec;
  610. u_int32_t eid;
  611. {
  612. DB *dbp;
  613. DB_LOCK lk;
  614. DB_MPOOLFILE *mpf;
  615. DBC *dbc;
  616. DBT rec_dbt;
  617. PAGE *pagep;
  618. db_pgno_t last_pgno, pgno;
  619. int ret, t_ret;
  620. dbp = NULL;
  621. dbc = NULL;
  622. pagep = NULL;
  623. mpf = NULL;
  624. LOCK_INIT(lk);
  625. if ((ret = db_create(&dbp, dbenv, 0)) != 0)
  626. goto err;
  627. if ((ret = dbp->open(dbp, rec->data, NULL, DB_UNKNOWN, 0, 0)) != 0)
  628. goto err;
  629. if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
  630. goto err;
  631. /*
  632.  * Force last_pgno to some value that will let us read the meta-dat
  633.  * page in the following loop.
  634.  */
  635. memset(&rec_dbt, 0, sizeof(rec_dbt));
  636. last_pgno = 1;
  637. for (pgno = 0; pgno <= last_pgno; pgno++) {
  638. if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lk)) != 0)
  639. goto err;
  640. if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0)
  641. goto err;
  642. if (pgno == 0)
  643. last_pgno = ((DBMETA *)pagep)->last_pgno;
  644. rec_dbt.data = pagep;
  645. rec_dbt.size = dbp->pgsize;
  646. if ((ret = __rep_send_message(dbenv, eid,
  647.     REP_FILE, NULL, &rec_dbt, pgno == last_pgno)) != 0)
  648. goto err;
  649. ret = mpf->put(mpf, pagep, 0);
  650. pagep = NULL;
  651. if (ret != 0)
  652. goto err;
  653. ret = __LPUT(dbc, lk);
  654. LOCK_INIT(lk);
  655. if (ret != 0)
  656. goto err;
  657. }
  658. err: if (LOCK_ISSET(lk) && (t_ret = __LPUT(dbc, lk)) != 0 && ret == 0)
  659. ret = t_ret;
  660. if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  661. ret = t_ret;
  662. if (pagep != NULL && (t_ret = mpf->put(mpf, pagep, 0)) != 0 && ret == 0)
  663. ret = t_ret;
  664. if (dbp != NULL && (t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
  665. ret = t_ret;
  666. return (ret);
  667. }
  668. #endif
  669. #if 0
  670. /*
  671.  * PUBLIC: void __rep_print_message __P((DB_ENV *, int, REP_CONTROL *, char *));
  672.  */
  673. void
  674. __rep_print_message(dbenv, eid, rp, str)
  675. DB_ENV *dbenv;
  676. int eid;
  677. REP_CONTROL *rp;
  678. char *str;
  679. {
  680. char *type;
  681. switch (rp->rectype) {
  682. case REP_ALIVE:
  683. type = "alive";
  684. break;
  685. case REP_ALIVE_REQ:
  686. type = "alive_req";
  687. break;
  688. case REP_ALL_REQ:
  689. type = "all_req";
  690. break;
  691. case REP_ELECT:
  692. type = "elect";
  693. break;
  694. case REP_FILE:
  695. type = "file";
  696. break;
  697. case REP_FILE_REQ:
  698. type = "file_req";
  699. break;
  700. case REP_LOG:
  701. type = "log";
  702. break;
  703. case REP_LOG_MORE:
  704. type = "log_more";
  705. break;
  706. case REP_LOG_REQ:
  707. type = "log_req";
  708. break;
  709. case REP_MASTER_REQ:
  710. type = "master_req";
  711. break;
  712. case REP_NEWCLIENT:
  713. type = "newclient";
  714. break;
  715. case REP_NEWFILE:
  716. type = "newfile";
  717. break;
  718. case REP_NEWMASTER:
  719. type = "newmaster";
  720. break;
  721. case REP_NEWSITE:
  722. type = "newsite";
  723. break;
  724. case REP_PAGE:
  725. type = "page";
  726. break;
  727. case REP_PAGE_REQ:
  728. type = "page_req";
  729. break;
  730. case REP_PLIST:
  731. type = "plist";
  732. break;
  733. case REP_PLIST_REQ:
  734. type = "plist_req";
  735. break;
  736. case REP_VERIFY:
  737. type = "verify";
  738. break;
  739. case REP_VERIFY_FAIL:
  740. type = "verify_fail";
  741. break;
  742. case REP_VERIFY_REQ:
  743. type = "verify_req";
  744. break;
  745. case REP_VOTE1:
  746. type = "vote1";
  747. break;
  748. case REP_VOTE2:
  749. type = "vote2";
  750. break;
  751. default:
  752. type = "NOTYPE";
  753. break;
  754. }
  755. printf("%s %s: gen = %d eid %d, type %s, LSN [%u][%u]n",
  756.     dbenv->db_home, str, rp->gen, eid, type, rp->lsn.file,
  757.     rp->lsn.offset);
  758. }
  759. #endif