2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 2001-2002
5
* Sleepycat Software. All rights reserved.
10
#include <sys/types.h>
21
#include "ex_repquote.h"
24
* Process globals (we could put these in the machtab I suppose.
29
static int env_init __P((const char *, const char *, DB_ENV **, machtab_t *,
31
static void usage __P((const char *));
42
enum { MASTER, CLIENT, UNKNOWN } whoami;
46
pthread_t all_thr, conn_thr;
47
repsite_t site, *sitep, self, *selfp;
48
struct sigaction sigact;
49
int maxsites, nsites, ret, priority, totalsites;
51
const char *home, *progname;
52
void *astatus, *cstatus;
54
master_eid = DB_EID_INVALID;
60
maxsites = nsites = ret = totalsites = 0;
63
progname = "ex_repquote";
65
while ((ch = getopt(argc, argv, "Ch:Mm:n:o:p:")) != EOF)
69
master_eid = SELF_EID;
78
if ((myaddr = strdup(optarg)) == NULL) {
80
"System error %s\n", strerror(errno));
84
self.host = strtok(self.host, ":");
85
if ((c = strtok(NULL, ":")) == NULL) {
86
fprintf(stderr, "Bad host specification.\n");
93
totalsites = atoi(optarg);
97
site.host = strtok(site.host, ":");
98
if ((c = strtok(NULL, ":")) == NULL) {
99
fprintf(stderr, "Bad host specification.\n");
103
if (sitep == NULL || nsites >= maxsites) {
104
maxsites = maxsites == 0 ? 10 : 2 * maxsites;
105
if ((sitep = realloc(sitep,
106
maxsites * sizeof(repsite_t))) == NULL) {
107
fprintf(stderr, "System error %s\n",
112
sitep[nsites++] = site;
115
priority = atoi(optarg);
122
/* Error check command line. */
123
if (whoami == UNKNOWN) {
124
fprintf(stderr, "Must specify -M or -C.\n");
135
* Turn off SIGPIPE so that we don't kill processes when they
136
* happen to lose a connection at the wrong time.
138
memset(&sigact, 0, sizeof(sigact));
139
sigact.sa_handler = SIG_IGN;
140
if ((ret = sigaction(SIGPIPE, &sigact, NULL)) != 0) {
142
"Unable to turn off SIGPIPE: %s\n", strerror(ret));
147
* We are hardcoding priorities here that all clients have the
148
* same priority except for a designated master who gets a higher
152
machtab_init(&machtab, priority, totalsites)) != 0)
156
* We can know open our environment, although we're not ready to
157
* begin replicating. However, we want to have a dbenv around
158
* so that we can send it into any of our message handlers.
160
if ((ret = env_init(progname, home, &dbenv, machtab, DB_RECOVER)) != 0)
164
* Now sets up comm infrastructure. There are two phases. First,
165
* we open our port for listening for incoming connections. Then
166
* we attempt to connect to every host we know about.
171
ca.progname = progname;
172
ca.machtab = machtab;
173
ca.port = selfp->port;
174
if ((ret = pthread_create(&conn_thr, NULL, connect_thread, &ca)) != 0)
178
aa.progname = progname;
180
aa.machtab = machtab;
183
if ((ret = pthread_create(&all_thr, NULL, connect_all, &aa)) != 0)
187
* We have now got the entire communication infrastructure set up.
188
* It's time to declare ourselves to be a client or master.
190
if (whoami == MASTER) {
191
if ((ret = dbenv->rep_start(dbenv, NULL, DB_REP_MASTER)) != 0) {
192
dbenv->err(dbenv, ret, "dbenv->rep_start failed");
195
if ((ret = domaster(dbenv, progname)) != 0) {
196
dbenv->err(dbenv, ret, "Master failed");
200
memset(&local, 0, sizeof(local));
202
local.size = strlen(myaddr) + 1;
204
dbenv->rep_start(dbenv, &local, DB_REP_CLIENT)) != 0) {
205
dbenv->err(dbenv, ret, "dbenv->rep_start failed");
208
/* Sleep to give ourselves a minute to find a master. */
210
if ((ret = doclient(dbenv, progname, machtab)) != 0) {
211
dbenv->err(dbenv, ret, "Client failed");
217
/* Wait on the connection threads. */
218
if (pthread_join(all_thr, &astatus) || pthread_join(conn_thr, &cstatus))
221
((int)astatus != EXIT_SUCCESS || (int)cstatus != EXIT_SUCCESS))
224
err: if (machtab != NULL)
227
(void)dbenv->close(dbenv, 0);
232
* In this application, we specify all communication via the command line.
233
* In a real application, we would expect that information about the other
234
* sites in the system would be maintained in some sort of configuration
235
* file. The critical part of this interface is that we assume at startup
236
* that we can find out 1) what host/port we wish to listen on for connections,
237
* 2) a (possibly empty) list of other sites we should attempt to connect to.
238
* 3) whether we are a master or client (if we don't know, we should come up
239
* as a client and see if there is a master out there) and 4) what our
240
* Berkeley DB home environment is.
242
* These pieces of information are expressed by the following flags.
243
* -m host:port (required; m stands for me)
244
* -o host:port (optional; o stands for other; any number of these may be
246
* -[MC] M for master/C for client
248
* -n nsites (optional; number of sites in replication group; defaults to 0
249
* in which case we try to dynamically compute the number of sites in
250
* the replication group.)
251
* -p priority (optional: defaults to 100)
255
const char *progname;
257
fprintf(stderr, "usage: %s ", progname);
258
fprintf(stderr, "[-CM][-h home][-o host:port][-m host:port]%s",
259
"[-n nsites][-p priority]\n");
263
/* Open and configure an environment. */
265
env_init(progname, home, dbenvp, machtab, flags)
266
const char *progname, *home;
275
if ((prefix = malloc(strlen(progname) + 2)) == NULL) {
277
"%s: System error: %s\n", progname, strerror(errno));
280
sprintf(prefix, "%s:", progname);
282
if ((ret = db_env_create(&dbenv, 0)) != 0) {
283
fprintf(stderr, "%s: env create failed: %s\n",
284
progname, db_strerror(ret));
287
dbenv->set_errfile(dbenv, stderr);
288
dbenv->set_errpfx(dbenv, prefix);
289
/* (void)dbenv->set_verbose(dbenv, DB_VERB_REPLICATION, 1); */
290
(void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0);
291
/* (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1); */
293
dbenv->app_private = machtab;
294
(void)dbenv->set_rep_transport(dbenv, SELF_EID, quote_send);
296
flags |= DB_CREATE | DB_THREAD |
297
DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
299
ret = dbenv->open(dbenv, home, flags, 0);