2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 2006, 2012 Oracle and/or its affiliates. All rights reserved.
10 * NOTE: This example is a simplified version of the rep_mgr.c
11 * example that can be found in the db/examples/c/ex_rep/mgr directory.
13 * This example is intended only as an aid in learning Replication Manager
14 * concepts. It is not complete in that many features are not exercised
15 * in it, nor are many error conditions properly handled.
24 #define sleep(s) Sleep(1000 * (s))
32 extern int getopt(int, char * const *, const char *);
35 #define CACHESIZE (10 * 1024 * 1024)
36 #define DATABASE "quote.db"
43 const char *progname = "ex_rep_gsg_repmgr";
45 int create_env(const char *, DB_ENV **);
46 int env_init(DB_ENV *, const char *);
47 int doloop (DB_ENV *);
48 int print_stocks(DB *);
49 static void event_callback(DB_ENV *, u_int32_t, void *);
55 fprintf(stderr, "usage: %s ", progname);
56 fprintf(stderr, "-h home -l|-L host:port\n");
57 fprintf(stderr, "\t\t[-r host:port][-p priority]\n");
58 fprintf(stderr, "where:\n");
59 fprintf(stderr, "\t-h identifies the environment home directory ");
60 fprintf(stderr, "(required).\n");
61 fprintf(stderr, "\t-l identifies the host and port used by this ");
62 fprintf(stderr, "site (required unless L is specified).\n");
63 fprintf(stderr, "\t-L identifies the local site as group creator. \n");
64 fprintf(stderr, "\t-r identifies another site participating in ");
65 fprintf(stderr, "this replication group\n");
66 fprintf(stderr, "\t-p identifies the election priority used by ");
67 fprintf(stderr, "this replica.\n");
72 main(int argc, char *argv[])
78 char ch, *host, *portstr;
79 int local_is_set, ret, is_group_creator;
81 /* Used to track whether this is a replica or a master. */
85 ret = local_is_set = is_group_creator = 0;
88 my_app_data.is_master = 0; /* Assume that we start as a replica */
90 if ((ret = create_env(progname, &dbenv)) != 0)
93 /* Make APP_DATA available through the environment handle. */
94 dbenv->app_private = &my_app_data;
96 /* Default priority is 100. */
97 dbenv->rep_set_priority(dbenv, 100);
98 /* Permanent messages require at least one ack. */
99 dbenv->repmgr_set_ack_policy(dbenv, DB_REPMGR_ACKS_ONE);
100 /* Give 500 microseconds to receive the ack. */
101 dbenv->rep_set_timeout(dbenv, DB_REP_ACK_TIMEOUT, 500);
103 /* Collect the command line options. */
104 while ((ch = getopt(argc, argv, "h:l:L:p:r:")) != EOF)
109 /* Set the host and port used by this environment. */
111 is_group_creator = 1; /* FALLTHROUGH */
113 host = strtok(optarg, ":");
114 if ((portstr = strtok(NULL, ":")) == NULL) {
115 fprintf(stderr, "Bad host specification.\n");
118 port = (unsigned short)atoi(portstr);
120 dbenv->repmgr_site(dbenv, host, port, &dbsite, 0)) != 0){
121 fprintf(stderr, "Could not set local address %s:%d.\n",
125 dbsite->set_config(dbsite, DB_LOCAL_SITE, 1);
126 if (is_group_creator)
127 dbsite->set_config(dbsite, DB_GROUP_CREATOR, 1);
129 if ((ret = dbsite->close(dbsite)) != 0) {
130 dbenv->err(dbenv, ret, "DB_SITE->close");
135 /* Set this replica's election priority. */
137 dbenv->rep_set_priority(dbenv, atoi(optarg));
139 /* Identify another site in the replication group. */
141 host = strtok(optarg, ":");
142 if ((portstr = strtok(NULL, ":")) == NULL) {
143 fprintf(stderr, "Bad host specification.\n");
146 port = (unsigned short)atoi(portstr);
147 if ((ret = dbenv->repmgr_site(dbenv, host, port, &dbsite, 0)) != 0) {
148 dbenv->err(dbenv, ret, "DB_ENV->repmgr_site");
151 dbsite->set_config(dbsite, DB_BOOTSTRAP_HELPER, 1);
152 if ((ret = dbsite->close(dbsite)) != 0) {
153 dbenv->err(dbenv, ret, "DB_SITE->close");
162 /* Error check command line. */
163 if (home == NULL || !local_is_set)
166 if ((ret = env_init(dbenv, home)) != 0)
169 if ((ret = dbenv->repmgr_start(dbenv, 3, DB_REP_ELECTION)) != 0)
172 if ((ret = doloop(dbenv)) != 0) {
173 dbenv->err(dbenv, ret, "Application failed");
177 err: if (dbenv != NULL)
178 (void)dbenv->close(dbenv, 0);
184 /* Create and configure an environment handle. */
186 create_env(const char *progname, DB_ENV **dbenvp)
191 if ((ret = db_env_create(&dbenv, 0)) != 0) {
192 fprintf(stderr, "can't create env handle: %s\n",
197 dbenv->set_errfile(dbenv, stderr);
198 dbenv->set_errpfx(dbenv, progname);
199 (void)dbenv->set_event_notify(dbenv, event_callback);
205 /* Open and configure an environment. */
207 env_init(DB_ENV *dbenv, const char *home)
212 (void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0);
213 (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1);
223 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0)
224 dbenv->err(dbenv, ret, "can't open environment");
229 * A callback used to determine whether the local environment is a
230 * replica or a master. This is called by the Replication Manager
231 * when the local environment changes state.
234 event_callback(DB_ENV *dbenv, u_int32_t which, void *info)
236 APP_DATA *app = dbenv->app_private;
238 info = NULL; /* Currently unused. */
241 case DB_EVENT_REP_MASTER:
245 case DB_EVENT_REP_CLIENT:
249 case DB_EVENT_REP_STARTUPDONE: /* FALLTHROUGH */
250 case DB_EVENT_REP_NEWMASTER:
255 dbenv->errx(dbenv, "ignoring event %d", which);
260 * Provides the main data processing function for our application.
261 * This function provides a command line prompt to which the user
262 * can provide a ticker string and a stock price. Once a value is
263 * entered to the application, the application writes the value to
264 * the database and then displays the entire database.
269 doloop(DB_ENV *dbenv)
274 char buf[BUFSIZE], *rbuf;
280 memset(&key, 0, sizeof(key));
281 memset(&data, 0, sizeof(data));
282 app_data = dbenv->app_private;
286 if ((ret = db_create(&dbp, dbenv, 0)) != 0)
289 flags = DB_AUTO_COMMIT;
290 if (app_data->is_master)
292 if ((ret = dbp->open(dbp,
293 NULL, DATABASE, NULL, DB_BTREE, flags, 0)) != 0) {
296 "No stock database yet available.\n");
297 if ((ret = dbp->close(dbp, 0)) != 0) {
298 dbenv->err(dbenv, ret, "DB->close");
305 dbenv->err(dbenv, ret, "DB->open");
310 printf("QUOTESERVER%s> ",
311 app_data->is_master ? "" : " (read-only)");
314 if (fgets(buf, sizeof(buf), stdin) == NULL)
316 if (strtok(&buf[0], " \t\n") == NULL) {
317 switch ((ret = print_stocks(dbp))) {
320 case DB_REP_HANDLE_DEAD:
321 (void)dbp->close(dbp, DB_NOSYNC);
323 dbenv->errx(dbenv, "Got a dead replication handle");
326 dbp->err(dbp, ret, "Error traversing data");
330 rbuf = strtok(NULL, " \t\n");
331 if (rbuf == NULL || rbuf[0] == '\0') {
332 if (strncmp(buf, "exit", 4) == 0 ||
333 strncmp(buf, "quit", 4) == 0)
335 dbenv->errx(dbenv, "Format: TICKER VALUE");
339 if (!app_data->is_master) {
340 dbenv->errx(dbenv, "Can't update at client");
345 key.size = (u_int32_t)strlen(buf);
348 data.size = (u_int32_t)strlen(rbuf);
350 if ((ret = dbp->put(dbp,
351 NULL, &key, &data, 0)) != 0) {
352 dbp->err(dbp, ret, "DB->put");
357 err: if (dbp != NULL)
358 (void)dbp->close(dbp, DB_NOSYNC);
363 /* Display all the stock quote information in the database. */
365 print_stocks(DB *dbp)
369 #define MAXKEYSIZE 10
370 #define MAXDATASIZE 20
371 char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1];
373 u_int32_t keysize, datasize;
375 if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) {
376 dbp->err(dbp, ret, "can't open cursor");
380 memset(&key, 0, sizeof(key));
381 memset(&data, 0, sizeof(data));
383 printf("\tSymbol\tPrice\n");
384 printf("\t======\t=====\n");
386 for (ret = dbc->c_get(dbc, &key, &data, DB_FIRST);
388 ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) {
389 keysize = key.size > MAXKEYSIZE ? MAXKEYSIZE : key.size;
390 memcpy(keybuf, key.data, keysize);
391 keybuf[keysize] = '\0';
393 datasize = data.size >= MAXDATASIZE ? MAXDATASIZE : data.size;
394 memcpy(databuf, data.data, datasize);
395 databuf[datasize] = '\0';
397 printf("\t%s\t%s\n", keybuf, databuf);
402 if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
409 case DB_LOCK_DEADLOCK: