1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2001,2008 Oracle. All rights reserved. 5 * 6 * $Id: rep_mgr.c,v 12.22 2008/01/08 20:58:25 bostic Exp $ 7 */ 8 9#include <sys/types.h> 10#include <signal.h> 11#include <stdlib.h> 12#include <string.h> 13#ifndef _WIN32 14#include <unistd.h> 15#endif 16 17#include <db.h> 18 19#include "../common/rep_common.h" 20 21typedef struct { 22 SHARED_DATA shared_data; 23} APP_DATA; 24 25const char *progname = "ex_rep"; 26 27#ifdef _WIN32 28extern int getopt(int, char * const *, const char *); 29#endif 30 31static void event_callback __P((DB_ENV *, u_int32_t, void *)); 32 33int 34main(argc, argv) 35 int argc; 36 char *argv[]; 37{ 38 extern char *optarg; 39 DB_ENV *dbenv; 40 const char *home; 41 char ch, *host, *portstr; 42 int ret, totalsites, t_ret, got_listen_address, friend; 43 u_int16_t port; 44 APP_DATA my_app_data; 45 u_int32_t start_policy; 46 int priority; 47 48 my_app_data.shared_data.is_master = 0; /* assume start out as client */ 49 dbenv = NULL; 50 ret = got_listen_address = 0; 51 home = "TESTDIR"; 52 53 if ((ret = create_env(progname, &dbenv)) != 0) 54 goto err; 55 dbenv->app_private = &my_app_data; 56 (void)dbenv->set_event_notify(dbenv, event_callback); 57 58 start_policy = DB_REP_ELECTION; /* default */ 59 priority = 100; /* default */ 60 61 while ((ch = getopt(argc, argv, "Cf:h:Mm:n:o:p:v")) != EOF) { 62 friend = 0; 63 switch (ch) { 64 case 'C': 65 start_policy = DB_REP_CLIENT; 66 break; 67 case 'h': 68 home = optarg; 69 break; 70 case 'M': 71 start_policy = DB_REP_MASTER; 72 break; 73 case 'm': 74 host = strtok(optarg, ":"); 75 if ((portstr = strtok(NULL, ":")) == NULL) { 76 fprintf(stderr, "Bad host specification.\n"); 77 goto err; 78 } 79 port = (unsigned short)atoi(portstr); 80 if ((ret = dbenv->repmgr_set_local_site(dbenv, 81 host, port, 0)) != 0) { 82 fprintf(stderr, 83 "Could not set listen address (%d).\n", 84 ret); 85 goto err; 86 } 87 got_listen_address = 1; 88 break; 89 case 'n': 90 totalsites = atoi(optarg); 91 if ((ret = 92 dbenv->rep_set_nsites(dbenv, totalsites)) != 0) 93 dbenv->err(dbenv, ret, "set_nsites"); 94 break; 95 case 'f': 96 friend = 1; /* FALLTHROUGH */ 97 case 'o': 98 host = strtok(optarg, ":"); 99 if ((portstr = strtok(NULL, ":")) == NULL) { 100 fprintf(stderr, "Bad host specification.\n"); 101 goto err; 102 } 103 port = (unsigned short)atoi(portstr); 104 if ((ret = dbenv->repmgr_add_remote_site(dbenv, host, 105 port, NULL, friend ? DB_REPMGR_PEER : 0)) != 0) { 106 dbenv->err(dbenv, ret, 107 "Could not add site %s:%d", host, 108 (int)port); 109 goto err; 110 } 111 break; 112 case 'p': 113 priority = atoi(optarg); 114 break; 115 case 'v': 116 if ((ret = dbenv->set_verbose(dbenv, 117 DB_VERB_REPLICATION, 1)) != 0) 118 goto err; 119 break; 120 case '?': 121 default: 122 usage(progname); 123 } 124 } 125 126 /* Error check command line. */ 127 if ((!got_listen_address) || home == NULL) 128 usage(progname); 129 130 dbenv->rep_set_priority(dbenv, priority); 131 132 if ((ret = env_init(dbenv, home)) != 0) 133 goto err; 134 135 if ((ret = dbenv->repmgr_start(dbenv, 3, start_policy)) != 0) 136 goto err; 137 138 if ((ret = doloop(dbenv, &my_app_data.shared_data)) != 0) { 139 dbenv->err(dbenv, ret, "Client failed"); 140 goto err; 141 } 142 143 /* 144 * We have used the DB_TXN_NOSYNC environment flag for improved 145 * performance without the usual sacrifice of transactional durability, 146 * as discussed in the "Transactional guarantees" page of the Reference 147 * Guide: if one replication site crashes, we can expect the data to 148 * exist at another site. However, in case we shut down all sites 149 * gracefully, we push out the end of the log here so that the most 150 * recent transactions don't mysteriously disappear. 151 */ 152 if ((ret = dbenv->log_flush(dbenv, NULL)) != 0) { 153 dbenv->err(dbenv, ret, "log_flush"); 154 goto err; 155 } 156 157err: 158 if (dbenv != NULL && 159 (t_ret = dbenv->close(dbenv, 0)) != 0) { 160 fprintf(stderr, "failure closing env: %s (%d)\n", 161 db_strerror(t_ret), t_ret); 162 if (ret == 0) 163 ret = t_ret; 164 } 165 166 return (ret); 167} 168 169static void 170event_callback(dbenv, which, info) 171 DB_ENV *dbenv; 172 u_int32_t which; 173 void *info; 174{ 175 APP_DATA *app = dbenv->app_private; 176 SHARED_DATA *shared = &app->shared_data; 177 178 info = NULL; /* Currently unused. */ 179 180 switch (which) { 181 case DB_EVENT_REP_CLIENT: 182 shared->is_master = 0; 183 break; 184 185 case DB_EVENT_REP_MASTER: 186 shared->is_master = 1; 187 break; 188 189 case DB_EVENT_REP_PERM_FAILED: 190 printf("insufficient acks\n"); 191 break; 192 193 case DB_EVENT_REP_STARTUPDONE: /* FALLTHROUGH */ 194 case DB_EVENT_REP_NEWMASTER: 195 /* I don't care about these, for now. */ 196 break; 197 198 default: 199 dbenv->errx(dbenv, "ignoring event %d", which); 200 } 201} 202