• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/db-4.8.30/examples_c/ex_rep_gsg/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2006-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9/*
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.
12 *
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.
16 *
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <errno.h>
22#ifndef _WIN32
23#include <unistd.h>
24#endif
25
26#include <db.h>
27
28#ifdef _WIN32
29extern int getopt(int, char * const *, const char *);
30#endif
31
32#define	CACHESIZE (10 * 1024 * 1024)
33#define	DATABASE "quote.db"
34#define	SLEEPTIME 3
35
36typedef struct {
37    int is_master;
38} APP_DATA;
39
40const char *progname = "ex_rep_gsg_repmgr";
41
42int create_env(const char *, DB_ENV **);
43int env_init(DB_ENV *, const char *);
44int doloop (DB_ENV *);
45int print_stocks(DB *);
46static void event_callback(DB_ENV *, u_int32_t, void *);
47
48/* Usage function */
49static void
50usage()
51{
52    fprintf(stderr, "usage: %s ", progname);
53    fprintf(stderr, "-h home -l host:port -n nsites\n");
54    fprintf(stderr, "\t\t[-r host:port][-p priority]\n");
55    fprintf(stderr, "where:\n");
56    fprintf(stderr, "\t-h identifies the environment home directory ");
57    fprintf(stderr, "(required).\n");
58    fprintf(stderr, "\t-l identifies the host and port used by this ");
59    fprintf(stderr, "site (required).\n");
60    fprintf(stderr, "\t-n identifies the number of sites in this ");
61    fprintf(stderr, "replication group (required).\n");
62    fprintf(stderr, "\t-r identifies another site participating in ");
63    fprintf(stderr, "this replication group\n");
64    fprintf(stderr, "\t-p identifies the election priority used by ");
65    fprintf(stderr, "this replica.\n");
66    exit(EXIT_FAILURE);
67}
68
69int
70main(int argc, char *argv[])
71{
72    DB_ENV *dbenv;
73    extern char *optarg;
74    const char *home;
75    char ch, *host, *portstr;
76    int local_is_set, ret, totalsites;
77    u_int16_t port;
78    /* Used to track whether this is a replica or a master. */
79    APP_DATA my_app_data;
80
81    dbenv = NULL;
82    ret = local_is_set = totalsites = 0;
83    home = NULL;
84
85    my_app_data.is_master = 0;  /* Assume that we start as a replica */
86
87    if ((ret = create_env(progname, &dbenv)) != 0)
88	goto err;
89
90    /* Make APP_DATA available through the environment handle. */
91    dbenv->app_private = &my_app_data;
92
93    /* Default priority is 100. */
94    dbenv->rep_set_priority(dbenv, 100);
95    /* Permanent messages require at least one ack. */
96    dbenv->repmgr_set_ack_policy(dbenv, DB_REPMGR_ACKS_ONE);
97    /* Give 500 microseconds to receive the ack. */
98    dbenv->rep_set_timeout(dbenv, DB_REP_ACK_TIMEOUT, 500);
99
100    /* Collect the command line options. */
101    while ((ch = getopt(argc, argv, "h:l:n:p:r:")) != EOF)
102	switch (ch) {
103	case 'h':
104	    home = optarg;
105	    break;
106	/* Set the host and port used by this environment. */
107	case 'l':
108	    host = strtok(optarg, ":");
109	    if ((portstr = strtok(NULL, ":")) == NULL) {
110		fprintf(stderr, "Bad host specification.\n");
111		goto err;
112	    }
113	    port = (unsigned short)atoi(portstr);
114	    if (dbenv->repmgr_set_local_site(dbenv, host, port, 0) != 0) {
115		fprintf(stderr,
116		    "Could not set local address %s.\n", host);
117		goto err;
118	    }
119	    local_is_set = 1;
120	    break;
121	/* Set the number of sites in this replication group. */
122	case 'n':
123	    totalsites = atoi(optarg);
124	    if ((ret = dbenv->rep_set_nsites(dbenv, totalsites)) != 0)
125		dbenv->err(dbenv, ret, "set_nsites");
126	    break;
127	/* Set this replica's election priority. */
128	case 'p':
129	    dbenv->rep_set_priority(dbenv, atoi(optarg));
130	    break;
131	/* Identify another site in the replication group. */
132	case 'r':
133	    host = strtok(optarg, ":");
134	    if ((portstr = strtok(NULL, ":")) == NULL) {
135		fprintf(stderr, "Bad host specification.\n");
136		goto err;
137	    }
138	    port = (unsigned short)atoi(portstr);
139	    if (dbenv->repmgr_add_remote_site(dbenv, host, port, 0, 0) != 0) {
140		fprintf(stderr,
141		    "Could not add site %s.\n", host);
142		goto err;
143	    }
144	    break;
145	case '?':
146	default:
147	    usage();
148	}
149
150    /* Error check command line. */
151    if (home == NULL || !local_is_set || !totalsites)
152	usage();
153
154    if ((ret = env_init(dbenv, home)) != 0)
155	goto err;
156
157    if ((ret = dbenv->repmgr_start(dbenv, 3, DB_REP_ELECTION)) != 0)
158	goto err;
159
160    if ((ret = doloop(dbenv)) != 0) {
161	dbenv->err(dbenv, ret, "Application failed");
162	goto err;
163    }
164
165err: if (dbenv != NULL)
166	(void)dbenv->close(dbenv, 0);
167
168    return (ret);
169
170}
171
172/* Create and configure an environment handle. */
173int
174create_env(const char *progname, DB_ENV **dbenvp)
175{
176    DB_ENV *dbenv;
177    int ret;
178
179    if ((ret = db_env_create(&dbenv, 0)) != 0) {
180	fprintf(stderr, "can't create env handle: %s\n",
181	    db_strerror(ret));
182	return (ret);
183    }
184
185    dbenv->set_errfile(dbenv, stderr);
186    dbenv->set_errpfx(dbenv, progname);
187    (void)dbenv->set_event_notify(dbenv, event_callback);
188
189    *dbenvp = dbenv;
190    return (0);
191}
192
193/* Open and configure an environment. */
194int
195env_init(DB_ENV *dbenv, const char *home)
196{
197    u_int32_t flags;
198    int ret;
199
200    (void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0);
201    (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1);
202
203    flags = DB_CREATE |
204	DB_INIT_LOCK |
205	DB_INIT_LOG |
206	DB_INIT_MPOOL |
207	DB_INIT_REP |
208	DB_INIT_TXN |
209	DB_RECOVER |
210	DB_THREAD;
211    if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0)
212	dbenv->err(dbenv, ret, "can't open environment");
213    return (ret);
214}
215
216/*
217 * A callback used to determine whether the local environment is a
218 * replica or a master. This is called by the Replication Manager
219 * when the local environment changes state.
220 */
221static void
222event_callback(DB_ENV *dbenv, u_int32_t which, void *info)
223{
224    APP_DATA *app = dbenv->app_private;
225
226    info = NULL;                /* Currently unused. */
227
228    switch (which) {
229    case DB_EVENT_REP_MASTER:
230	app->is_master = 1;
231	break;
232
233    case DB_EVENT_REP_CLIENT:
234	app->is_master = 0;
235	break;
236
237    case DB_EVENT_REP_STARTUPDONE: /* FALLTHROUGH */
238    case DB_EVENT_REP_NEWMASTER:
239	/* Ignore. */
240	break;
241
242    default:
243	dbenv->errx(dbenv, "ignoring event %d", which);
244    }
245}
246
247/*
248 * Provides the main data processing function for our application.
249 * This function provides a command line prompt to which the user
250 * can provide a ticker string and a stock price.  Once a value is
251 * entered to the application, the application writes the value to
252 * the database and then displays the entire database.
253 */
254#define	   BUFSIZE 1024
255
256int
257doloop(DB_ENV *dbenv)
258{
259    DB *dbp;
260    APP_DATA *app_data;
261    DBT key, data;
262    char buf[BUFSIZE], *rbuf;
263    int ret;
264    u_int32_t flags;
265
266    dbp = NULL;
267    ret = 0;
268    memset(&key, 0, sizeof(key));
269    memset(&data, 0, sizeof(data));
270    app_data = dbenv->app_private;
271
272    for (;;) {
273	if (dbp == NULL) {
274	    if ((ret = db_create(&dbp, dbenv, 0)) != 0)
275		return (ret);
276
277	    flags = DB_AUTO_COMMIT;
278	    if (app_data->is_master)
279		flags |= DB_CREATE;
280	    if ((ret = dbp->open(dbp,
281		NULL, DATABASE, NULL, DB_BTREE, flags, 0)) != 0) {
282		if (ret == ENOENT) {
283		    printf(
284		      "No stock database yet available.\n");
285		    if ((ret = dbp->close(dbp, 0)) != 0) {
286			dbenv->err(dbenv, ret, "DB->close");
287			goto err;
288		    }
289		    dbp = NULL;
290		    sleep(SLEEPTIME);
291		    continue;
292		}
293		dbenv->err(dbenv, ret, "DB->open");
294		goto err;
295	    }
296	}
297
298	printf("QUOTESERVER%s> ",
299	    app_data->is_master ? "" : " (read-only)");
300	fflush(stdout);
301
302	if (fgets(buf, sizeof(buf), stdin) == NULL)
303	    break;
304	if (strtok(&buf[0], " \t\n") == NULL) {
305	    switch ((ret = print_stocks(dbp))) {
306	    case 0:
307		continue;
308	    case DB_REP_HANDLE_DEAD:
309		(void)dbp->close(dbp, DB_NOSYNC);
310		dbp = NULL;
311                dbenv->errx(dbenv, "Got a dead replication handle");
312		continue;
313	    default:
314		dbp->err(dbp, ret, "Error traversing data");
315		goto err;
316	    }
317	}
318	rbuf = strtok(NULL, " \t\n");
319	if (rbuf == NULL || rbuf[0] == '\0') {
320	    if (strncmp(buf, "exit", 4) == 0 ||
321		strncmp(buf, "quit", 4) == 0)
322		break;
323	    dbenv->errx(dbenv, "Format: TICKER VALUE");
324	    continue;
325	}
326
327	if (!app_data->is_master) {
328	    dbenv->errx(dbenv, "Can't update at client");
329	    continue;
330	}
331
332	key.data = buf;
333	key.size = (u_int32_t)strlen(buf);
334
335	data.data = rbuf;
336	data.size = (u_int32_t)strlen(rbuf);
337
338	if ((ret = dbp->put(dbp,
339	    NULL, &key, &data, 0)) != 0) {
340	    dbp->err(dbp, ret, "DB->put");
341	    goto err;
342	}
343    }
344
345err: if (dbp != NULL)
346	(void)dbp->close(dbp, DB_NOSYNC);
347
348    return (ret);
349}
350
351/* Display all the stock quote information in the database. */
352int
353print_stocks(DB *dbp)
354{
355    DBC *dbc;
356    DBT key, data;
357#define	   MAXKEYSIZE    10
358#define	   MAXDATASIZE    20
359    char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1];
360    int ret, t_ret;
361    u_int32_t keysize, datasize;
362
363    if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) {
364	dbp->err(dbp, ret, "can't open cursor");
365	return (ret);
366    }
367
368    memset(&key, 0, sizeof(key));
369    memset(&data, 0, sizeof(data));
370
371    printf("\tSymbol\tPrice\n");
372    printf("\t======\t=====\n");
373
374    for (ret = dbc->c_get(dbc, &key, &data, DB_FIRST);
375	ret == 0;
376	ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) {
377	keysize = key.size > MAXKEYSIZE ? MAXKEYSIZE : key.size;
378	memcpy(keybuf, key.data, keysize);
379	keybuf[keysize] = '\0';
380
381	datasize = data.size >= MAXDATASIZE ? MAXDATASIZE : data.size;
382	memcpy(databuf, data.data, datasize);
383	databuf[datasize] = '\0';
384
385	printf("\t%s\t%s\n", keybuf, databuf);
386    }
387    printf("\n");
388    fflush(stdout);
389
390    if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
391	ret = t_ret;
392
393    switch (ret) {
394    case 0:
395    case DB_NOTFOUND:
396	return (0);
397    case DB_LOCK_DEADLOCK:
398	return (0);
399    default:
400	return (ret);
401    }
402}
403
404