2
2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 2005-2009 Oracle. All rights reserved.
4
* Copyright (c) 2005, 2010 Oracle and/or its affiliates. All rights reserved.
9
9
#include "db_config.h"
11
#define __INCLUDE_NETWORKING 1
12
11
#include "db_int.h"
14
13
#define INITIAL_SITES_ALLOCATION 10 /* Arbitrary guess. */
178
177
* PUBLIC: int __repmgr_new_site __P((ENV *, REPMGR_SITE**,
179
* PUBLIC: const char *, u_int, int));
178
* PUBLIC: const char *, u_int, int, int));
181
180
* Manipulates the process-local copy of the sites list. So, callers should
182
181
* hold the db_rep->mutex (except for single-threaded, pre-open configuration).
185
__repmgr_new_site(env, sitep, host, port, state)
184
__repmgr_new_site(env, sitep, host, port, state, peer)
187
186
REPMGR_SITE **sitep;
188
187
const char *host;
193
193
REPMGR_SITE *site;
579
581
if ((ret = __mutex_alloc(env, MTX_REPMGR, 0, &rep->mtx_repmgr)) != 0)
582
DB_ASSERT(env, rep->siteaddr_seq == 0 && db_rep->siteaddr_seq == 0);
583
rep->netaddr_off = INVALID_ROFF;
584
rep->siteaddr_seq = 0;
584
DB_ASSERT(env, rep->siteinfo_seq == 0 && db_rep->siteinfo_seq == 0);
585
rep->siteinfo_off = INVALID_ROFF;
586
rep->siteinfo_seq = 0;
585
587
if ((ret = __repmgr_share_netaddrs(env, rep, 0, db_rep->site_cnt)) != 0)
587
rep->peer = db_rep->peer;
589
590
if ((host = db_rep->my_addr.host) != NULL) {
590
591
sz = strlen(host) + 1;
670
if (rep->netaddr_off != INVALID_ROFF) {
671
p = R_ADDR(infop, rep->netaddr_off);
671
if (rep->siteinfo_off != INVALID_ROFF) {
672
p = R_ADDR(infop, rep->siteinfo_off);
673
674
/* For each address in the shared list ... */
674
675
for (; i < rep->site_cnt; i++) {
675
host = R_ADDR(infop, p[i].host);
676
host = R_ADDR(infop, p[i].addr.host);
677
RPRINT(env, DB_VERB_REPMGR_MISC,
678
(env, "Site %s:%lu found at EID %u",
679
host, (u_long)p[i].port, i));
678
RPRINT(env, (env, DB_VERB_REPMGR_MISC,
679
"Site %s:%lu found at EID %u",
680
host, (u_long)p[i].addr.port, i));
681
682
* Find it in the local list. Everything before 'i'
682
683
* already matches the shared list, and is therefore in
683
684
* the right place. So we only need to search starting
685
* from 'i'. When found, local peer value will be used
686
* because it is assumed to be "fresher".
686
688
for (j = i; j < db_rep->site_cnt; j++) {
687
689
addrp = &db_rep->sites[j].net_addr;
688
690
if (strcmp(host, addrp->host) == 0 &&
689
p[i].port == addrp->port)
691
p[i].addr.port == addrp->port)
696
* When not found in local list, copy peer value
693
699
if (j == db_rep->site_cnt &&
694
700
(ret = __repmgr_new_site(env, &unused,
695
host, p[i].port, SITE_IDLE)) != 0)
701
host, p[i].addr.port, SITE_IDLE, p[i].peer)) != 0)
697
703
DB_ASSERT(env, j < db_rep->site_cnt);
701
707
temp = db_rep->sites[j];
702
708
db_rep->sites[j] = db_rep->sites[i];
703
709
db_rep->sites[i] = temp;
706
* Keep peer pointer in sync with swapped
709
if (db_rep->peer == (int)j)
710
db_rep->peer = (int)i;
711
else if (db_rep->peer == (int)i)
712
db_rep->peer = (int)j;
716
713
if ((ret = __repmgr_share_netaddrs(env, rep, i, db_rep->site_cnt)) != 0)
720
* Assume that any config settings I've made locally are "fresher" than
721
* anything lying around in the shared region, so the local setting
724
if (IS_VALID_EID(db_rep->peer))
725
rep->peer = db_rep->peer;
726
db_rep->siteaddr_seq = rep->siteaddr_seq;
716
db_rep->siteinfo_seq = rep->siteinfo_seq;
729
719
MUTEX_UNLOCK(env, rep->mtx_repmgr);
769
* Copy network address information from the indicated local array slots into
759
* Copy network address information from the indicated local array slots,
760
* and peer information changes from any of the local array slots, into the
772
763
* PUBLIC: int __repmgr_share_netaddrs __P((ENV *, void *, u_int, u_int));
804
795
for (i = start; i < limit; i++) {
805
796
if (rep->site_cnt >= rep->site_max) {
806
797
/* Table is full, we need more space. */
807
if (rep->netaddr_off == INVALID_ROFF) {
798
if (rep->siteinfo_off == INVALID_ROFF) {
808
799
n = INITIAL_SITES_ALLOCATION;
809
sz = n * sizeof(SITEADDR);
800
sz = n * sizeof(SITEINFO);
810
801
if ((ret = __env_alloc(infop,
811
802
sz, &shared_array)) != 0)
814
805
n = 2 * rep->site_max;
815
sz = n * sizeof(SITEADDR);
806
sz = n * sizeof(SITEINFO);
816
807
if ((ret = __env_alloc(infop,
817
808
sz, &shared_array)) != 0)
819
orig = R_ADDR(infop, rep->netaddr_off);
810
orig = R_ADDR(infop, rep->siteinfo_off);
820
811
memcpy(shared_array, orig,
821
sizeof(SITEADDR) * rep->site_cnt);
812
sizeof(SITEINFO) * rep->site_cnt);
822
813
__env_alloc_free(infop, orig);
824
rep->netaddr_off = R_OFFSET(infop, shared_array);
815
rep->siteinfo_off = R_OFFSET(infop, shared_array);
825
816
rep->site_max = n;
827
shared_array = R_ADDR(infop, rep->netaddr_off);
818
shared_array = R_ADDR(infop, rep->siteinfo_off);
829
820
DB_ASSERT(env, rep->site_cnt < rep->site_max &&
830
rep->netaddr_off != INVALID_ROFF);
821
rep->siteinfo_off != INVALID_ROFF);
832
823
host = db_rep->sites[i].net_addr.host;
833
824
sz = strlen(host) + 1;
836
827
eid = (int)rep->site_cnt++;
837
828
(void)strcpy(hostbuf, host);
838
shared_array[eid].host = R_OFFSET(infop, hostbuf);
839
shared_array[eid].port = db_rep->sites[i].net_addr.port;
840
RPRINT(env, DB_VERB_REPMGR_MISC,
841
(env, "EID %d is assigned for site %s:%lu",
842
eid, host, (u_long)shared_array[eid].port));
829
shared_array[eid].addr.host = R_OFFSET(infop, hostbuf);
830
shared_array[eid].addr.port = db_rep->sites[i].net_addr.port;
831
shared_array[eid].peer =
832
F_ISSET(&db_rep->sites[i], SITE_IS_PEER) ? TRUE : FALSE;
833
RPRINT(env, (env, DB_VERB_REPMGR_MISC,
834
"EID %d is assigned for site %s:%lu",
835
eid, host, (u_long)shared_array[eid].addr.port));
839
/* Get any peer information changes from local copy. */
840
if (rep->siteinfo_off != INVALID_ROFF) {
841
shared_array = R_ADDR(infop, rep->siteinfo_off);
842
for (i = 0; i < rep->site_cnt; i++) {
843
if (!F_ISSET(&db_rep->sites[i], SITE_IS_PEER) &&
844
shared_array[i].peer) {
845
shared_array[i].peer = FALSE;
847
} else if (F_ISSET(&db_rep->sites[i], SITE_IS_PEER) &&
848
!shared_array[i].peer) {
849
shared_array[i].peer = TRUE;
849
858
MUTEX_UNLOCK(env, renv->mtx_regenv);
854
* Copy into our local list any newly added remote site addresses that we
863
* Copy into our local list any newly added/changed remote site
864
* configuration information.
857
866
* !!! Caller must hold db_rep->mutex and mtx_repmgr locks.
874
883
db_rep = env->rep_handle;
875
884
rep = db_rep->region;
877
if (rep->netaddr_off == INVALID_ROFF)
886
if (rep->siteinfo_off == INVALID_ROFF)
880
889
infop = env->reginfo;
881
base = R_ADDR(infop, rep->netaddr_off);
890
base = R_ADDR(infop, rep->siteinfo_off);
891
/* Update existing local site peer values with shared values. */
892
for (i = 0; i < db_rep->site_cnt; i++) {
895
F_SET(&db_rep->sites[i], SITE_IS_PEER);
897
F_CLR(&db_rep->sites[i], SITE_IS_PEER);
882
899
for (i = db_rep->site_cnt; i < rep->site_cnt; i++) {
884
host = R_ADDR(infop, p->host);
901
host = R_ADDR(infop, p->addr.host);
885
902
if ((ret = __repmgr_new_site(env,
886
&site, host, p->port, SITE_IDLE)) != 0)
903
&site, host, p->addr.port, SITE_IDLE, p->peer)) != 0)
888
RPRINT(env, DB_VERB_REPMGR_MISC,
889
(env, "Site %s:%lu found at EID %u",
890
host, (u_long)p->port, i));
905
RPRINT(env, (env, DB_VERB_REPMGR_MISC,
906
"Site %s:%lu found at EID %u",
907
host, (u_long)p->addr.port, i));
893
910
DB_ASSERT(env, db_rep->site_cnt == rep->site_cnt);
894
db_rep->peer = rep->peer;
895
db_rep->siteaddr_seq = rep->siteaddr_seq;
911
db_rep->siteinfo_seq = rep->siteinfo_seq;
1011
* PUBLIC: int __repmgr_master_is_known __P((ENV *));
1014
__repmgr_master_is_known(env)
1021
db_rep = env->rep_handle;
1022
rep = db_rep->region;
1023
master = rep->master_id;
1026
* We are the master, or we know of a master and have a healthy
1029
return (master == SELF_EID || __repmgr_master_connection(env) != NULL);
1033
* PUBLIC: int __repmgr_stable_lsn __P((ENV *, DB_LSN *));
1035
* This function may be called before any of repmgr's threads have
1036
* been started. This code must not be called before env open.
1037
* Currently that is impossible since its only caller is log_archive
1038
* which itself cannot be called before env_open.
1041
__repmgr_stable_lsn(env, stable_lsn)
1051
db_rep = env->rep_handle;
1052
rep = db_rep->region;
1055
LOCK_MUTEX(db_rep->mutex);
1056
for (eid = 0; eid < db_rep->site_cnt; eid++) {
1057
site = SITE_FROM_EID(eid);
1059
* Record the smallest ack'ed LSN from all connected sites.
1060
* If we're a client, ignore the master because the master
1061
* does not maintain nor send out its repmgr perm LSN in
1064
if ((int)eid == rep->master_id)
1066
if (IS_SITE_AVAILABLE(site) &&
1067
!IS_ZERO_LSN(site->max_ack) &&
1068
(IS_ZERO_LSN(min_lsn) ||
1069
LOG_COMPARE(&site->max_ack, &min_lsn) < 0))
1070
min_lsn = site->max_ack;
1072
UNLOCK_MUTEX(db_rep->mutex);
1073
if (!IS_ZERO_LSN(min_lsn) && LOG_COMPARE(&min_lsn, stable_lsn) < 0)
1074
*stable_lsn = min_lsn;
1075
RPRINT(env, (env, DB_VERB_REPMGR_MISC,
1076
"Repmgr_stable_lsn: Returning stable_lsn[%lu][%lu]",
1077
(u_long)stable_lsn->file, (u_long)stable_lsn->offset));