1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2006,2008 Oracle. All rights reserved. 5 * 6 * $Id: rep_common.c,v 12.23 2008/04/04 21:16:36 alanb Exp $ 7 */ 8 9#include <errno.h> 10#include <stdlib.h> 11#include <string.h> 12 13#include <db.h> 14 15#include "rep_common.h" 16 17#define CACHESIZE (10 * 1024 * 1024) 18#define DATABASE "quote.db" 19#define SLEEPTIME 3 20 21#ifdef _WIN32 22#define WIN32_LEAN_AND_MEAN 23#include <windows.h> 24#define sleep(s) Sleep(1000 * (s)) 25#endif 26 27static int print_stocks __P((DB *)); 28 29static int 30print_stocks(dbp) 31 DB *dbp; 32{ 33 DBC *dbc; 34 DBT key, data; 35#define MAXKEYSIZE 10 36#define MAXDATASIZE 20 37 char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1]; 38 int ret, t_ret; 39 u_int32_t keysize, datasize; 40 41 if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) { 42 dbp->err(dbp, ret, "can't open cursor"); 43 return (ret); 44 } 45 46 memset(&key, 0, sizeof(key)); 47 memset(&data, 0, sizeof(data)); 48 49 printf("\tSymbol\tPrice\n"); 50 printf("\t======\t=====\n"); 51 52 for (ret = dbc->get(dbc, &key, &data, DB_FIRST); 53 ret == 0; 54 ret = dbc->get(dbc, &key, &data, DB_NEXT)) { 55 keysize = key.size > MAXKEYSIZE ? MAXKEYSIZE : key.size; 56 memcpy(keybuf, key.data, keysize); 57 keybuf[keysize] = '\0'; 58 59 datasize = data.size >= MAXDATASIZE ? MAXDATASIZE : data.size; 60 memcpy(databuf, data.data, datasize); 61 databuf[datasize] = '\0'; 62 63 printf("\t%s\t%s\n", keybuf, databuf); 64 } 65 printf("\n"); 66 fflush(stdout); 67 68 if ((t_ret = dbc->close(dbc)) != 0 && ret == 0) 69 ret = t_ret; 70 71 switch (ret) { 72 case 0: 73 case DB_NOTFOUND: 74 case DB_LOCK_DEADLOCK: 75 return (0); 76 default: 77 return (ret); 78 } 79} 80 81#define BUFSIZE 1024 82 83int 84doloop(dbenv, shared_data) 85 DB_ENV *dbenv; 86 SHARED_DATA *shared_data; 87{ 88 DB *dbp; 89 DBT key, data; 90 char buf[BUFSIZE], *first, *price; 91 u_int32_t flags; 92 int ret; 93 94 dbp = NULL; 95 ret = 0; 96 memset(&key, 0, sizeof(key)); 97 memset(&data, 0, sizeof(data)); 98 99 for (;;) { 100 printf("QUOTESERVER%s> ", 101 shared_data->is_master ? "" : " (read-only)"); 102 fflush(stdout); 103 104 if (fgets(buf, sizeof(buf), stdin) == NULL) 105 break; 106 107#define DELIM " \t\n" 108 if ((first = strtok(&buf[0], DELIM)) == NULL) { 109 /* Blank input line. */ 110 price = NULL; 111 } else if ((price = strtok(NULL, DELIM)) == NULL) { 112 /* Just one input token. */ 113 if (strncmp(buf, "exit", 4) == 0 || 114 strncmp(buf, "quit", 4) == 0) 115 break; 116 dbenv->errx(dbenv, "Format: TICKER VALUE"); 117 continue; 118 } else { 119 /* Normal two-token input line. */ 120 if (first != NULL && !shared_data->is_master) { 121 dbenv->errx(dbenv, "Can't update at client"); 122 continue; 123 } 124 } 125 126 if (dbp == NULL) { 127 if ((ret = db_create(&dbp, dbenv, 0)) != 0) 128 return (ret); 129 130 /* Set page size small so page allocation is cheap. */ 131 if ((ret = dbp->set_pagesize(dbp, 512)) != 0) 132 goto err; 133 134 flags = DB_AUTO_COMMIT; 135 if (shared_data->is_master) 136 flags |= DB_CREATE; 137 if ((ret = dbp->open(dbp, 138 NULL, DATABASE, NULL, DB_BTREE, flags, 0)) != 0) { 139 if (ret == ENOENT) { 140 printf( 141 "No stock database yet available.\n"); 142 if ((ret = dbp->close(dbp, 0)) != 0) { 143 dbenv->err(dbenv, ret, 144 "DB->close"); 145 goto err; 146 } 147 dbp = NULL; 148 continue; 149 } 150 if (ret == DB_REP_HANDLE_DEAD || 151 ret == DB_LOCK_DEADLOCK) { 152 dbenv->err(dbenv, ret, 153 "please retry the operation"); 154 dbp->close(dbp, DB_NOSYNC); 155 dbp = NULL; 156 continue; 157 } 158 dbenv->err(dbenv, ret, "DB->open"); 159 goto err; 160 } 161 } 162 163 if (first == NULL) 164 switch ((ret = print_stocks(dbp))) { 165 case 0: 166 break; 167 case DB_REP_HANDLE_DEAD: 168 (void)dbp->close(dbp, DB_NOSYNC); 169 dbp = NULL; 170 break; 171 default: 172 dbp->err(dbp, ret, "Error traversing data"); 173 goto err; 174 } 175 else { 176 key.data = first; 177 key.size = (u_int32_t)strlen(first); 178 179 data.data = price; 180 data.size = (u_int32_t)strlen(price); 181 182 if ((ret = dbp->put(dbp, 183 NULL, &key, &data, DB_AUTO_COMMIT)) != 0) { 184 dbp->err(dbp, ret, "DB->put"); 185 goto err; 186 } 187 } 188 } 189 190err: if (dbp != NULL) 191 (void)dbp->close(dbp, DB_NOSYNC); 192 193 return (ret); 194} 195 196int 197create_env(progname, dbenvp) 198 const char *progname; 199 DB_ENV **dbenvp; 200{ 201 DB_ENV *dbenv; 202 int ret; 203 204 if ((ret = db_env_create(&dbenv, 0)) != 0) { 205 fprintf(stderr, "can't create env handle: %s\n", 206 db_strerror(ret)); 207 return (ret); 208 } 209 210 dbenv->set_errfile(dbenv, stderr); 211 dbenv->set_errpfx(dbenv, progname); 212 213 *dbenvp = dbenv; 214 return (0); 215} 216 217/* Open and configure an environment. */ 218int 219env_init(dbenv, home) 220 DB_ENV *dbenv; 221 const char *home; 222{ 223 u_int32_t flags; 224 int ret; 225 226 (void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0); 227 (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1); 228 229 flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | 230 DB_INIT_REP | DB_INIT_TXN | DB_RECOVER | DB_THREAD; 231 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) 232 dbenv->err(dbenv, ret, "can't open environment"); 233 return (ret); 234} 235 236/* 237 * In this application, we specify all communication via the command line. In 238 * a real application, we would expect that information about the other sites 239 * in the system would be maintained in some sort of configuration file. The 240 * critical part of this interface is that we assume at startup that we can 241 * find out 242 * 1) what host/port we wish to listen on for connections, 243 * 2) a (possibly empty) list of other sites we should attempt to connect 244 * to; and 245 * 3) what our Berkeley DB home environment is. 246 * 247 * These pieces of information are expressed by the following flags. 248 * -m host:port (required; m stands for me) 249 * -o host:port (optional; o stands for other; any number of these may be 250 * specified) 251 * -h home directory 252 * -n nsites (optional; number of sites in replication group; defaults to 0 253 * in which case we try to dynamically compute the number of sites in 254 * the replication group) 255 * -p priority (optional: defaults to 100) 256 * -C or -M start up as client or master (optional) 257 */ 258void 259usage(progname) 260 const char *progname; 261{ 262 fprintf(stderr, "usage: %s ", progname); 263 fprintf(stderr, "[-CM][-h home][-o host:port][-m host:port]%s", 264 "[-n nsites][-p priority]\n"); 265 exit(EXIT_FAILURE); 266} 267