/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2001, 2011 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ #include #include #include #include #ifndef _WIN32 #include #endif #include #include "../common/rep_common.h" typedef struct { SHARED_DATA shared_data; } APP_DATA; const char *progname = "ex_rep_mgr"; static void event_callback __P((DB_ENV *, u_int32_t, void *)); int main(argc, argv) int argc; char *argv[]; { DB_ENV *dbenv; DB_SITE *dbsite; SETUP_DATA setup_info; repsite_t *site_list; APP_DATA my_app_data; thread_t ckp_thr, lga_thr; supthr_args sup_args; u_int32_t start_policy; int i, ret, t_ret; memset(&setup_info, 0, sizeof(SETUP_DATA)); setup_info.progname = progname; memset(&my_app_data, 0, sizeof(APP_DATA)); dbenv = NULL; ret = 0; start_policy = DB_REP_ELECTION; if ((ret = create_env(progname, &dbenv)) != 0) goto err; dbenv->app_private = &my_app_data; (void)dbenv->set_event_notify(dbenv, event_callback); /* Parse command line and perform common replication setup. */ if ((ret = common_rep_setup(dbenv, argc, argv, &setup_info)) != 0) goto err; /* Perform repmgr-specific setup based on command line options. */ if (setup_info.role == MASTER) start_policy = DB_REP_MASTER; else if (setup_info.role == CLIENT) start_policy = DB_REP_CLIENT; /* Configure the local site. */ if ((ret = dbenv->repmgr_site(dbenv, setup_info.self.host, setup_info.self.port, &dbsite, 0)) != 0) { dbenv->err(dbenv, ret, "Could not set local site."); goto err; } dbsite->set_config(dbsite, DB_LOCAL_SITE, 1); if (setup_info.self.creator) dbsite->set_config(dbsite, DB_GROUP_CREATOR, 1); if ((ret = dbsite->close(dbsite)) != 0) { dbenv->err(dbenv, ret, "DB_SITE->close"); goto err; } /* Configure the remote site list. */ site_list = setup_info.site_list; for (i = 0; i < setup_info.remotesites; i++) { if ((ret = dbenv->repmgr_site(dbenv, site_list[i].host, site_list[i].port, &dbsite, 0)) != 0) { dbenv->err(dbenv, ret, "Could not add site %s:%d", site_list[i].host, (int)site_list[i].port); goto err; } dbsite->set_config(dbsite, DB_BOOTSTRAP_HELPER, 1); if (site_list[i].peer) dbsite->set_config(dbsite, DB_REPMGR_PEER, 1); if ((ret = dbsite->close(dbsite)) != 0) { dbenv->err(dbenv, ret, "DB_SITE->close"); goto err; } } /* * Configure heartbeat timeouts so that repmgr monitors the * health of the TCP connection. Master sites broadcast a heartbeat * at the frequency specified by the DB_REP_HEARTBEAT_SEND timeout. * Client sites wait for message activity the length of the * DB_REP_HEARTBEAT_MONITOR timeout before concluding that the * connection to the master is lost. The DB_REP_HEARTBEAT_MONITOR * timeout should be longer than the DB_REP_HEARTBEAT_SEND timeout. */ if ((ret = dbenv->rep_set_timeout(dbenv, DB_REP_HEARTBEAT_SEND, 5000000)) != 0) dbenv->err(dbenv, ret, "Could not set heartbeat send timeout.\n"); if ((ret = dbenv->rep_set_timeout(dbenv, DB_REP_HEARTBEAT_MONITOR, 10000000)) != 0) dbenv->err(dbenv, ret, "Could not set heartbeat monitor timeout.\n"); /* * The following repmgr features may also be useful to your * application. See Berkeley DB documentation for more details. * - Two-site strict majority rule - In a two-site replication * group, require both sites to be available to elect a new * master. * - Timeouts - Customize the amount of time repmgr waits * for such things as waiting for acknowledgements or attempting * to reconnect to other sites. * - Site list - return a list of sites currently known to repmgr. */ if ((ret = env_init(dbenv, setup_info.home)) != 0) goto err; /* Start checkpoint and log archive threads. */ sup_args.dbenv = dbenv; sup_args.shared = &my_app_data.shared_data; if ((ret = start_support_threads(dbenv, &sup_args, &ckp_thr, &lga_thr)) != 0) goto err; if ((ret = dbenv->repmgr_start(dbenv, 3, start_policy)) != 0) goto err; if ((ret = doloop(dbenv, &my_app_data.shared_data)) != 0) { dbenv->err(dbenv, ret, "Client failed"); goto err; } /* Finish checkpoint and log archive threads. */ if ((ret = finish_support_threads(&ckp_thr, &lga_thr)) != 0) goto err; /* * We have used the DB_TXN_NOSYNC environment flag for improved * performance without the usual sacrifice of transactional durability, * as discussed in the "Transactional guarantees" page of the Reference * Guide: if one replication site crashes, we can expect the data to * exist at another site. However, in case we shut down all sites * gracefully, we push out the end of the log here so that the most * recent transactions don't mysteriously disappear. */ if ((ret = dbenv->log_flush(dbenv, NULL)) != 0) { dbenv->err(dbenv, ret, "log_flush"); goto err; } err: if (dbenv != NULL && (t_ret = dbenv->close(dbenv, 0)) != 0) { fprintf(stderr, "failure closing env: %s (%d)\n", db_strerror(t_ret), t_ret); if (ret == 0) ret = t_ret; } return (ret); } static void event_callback(dbenv, which, info) DB_ENV *dbenv; u_int32_t which; void *info; { APP_DATA *app = dbenv->app_private; SHARED_DATA *shared = &app->shared_data; int err; switch (which) { case DB_EVENT_PANIC: err = *(int*)info; printf("Got a panic: %s (%d)\n", db_strerror(err), err); abort(); case DB_EVENT_REP_CLIENT: shared->is_master = 0; shared->in_client_sync = 1; break; case DB_EVENT_REP_MASTER: shared->is_master = 1; shared->in_client_sync = 0; break; case DB_EVENT_REP_NEWMASTER: shared->in_client_sync = 1; break; case DB_EVENT_REP_PERM_FAILED: /* * Did not get enough acks to guarantee transaction * durability based on the configured ack policy. This * transaction will be flushed to the master site's * local disk storage for durability. */ printf( "Insufficient acknowledgements to guarantee transaction durability.\n"); break; case DB_EVENT_REP_STARTUPDONE: shared->in_client_sync = 0; break; default: dbenv->errx(dbenv, "ignoring event %d", which); } }