1<?xml version="1.0" encoding="UTF-8" standalone="no"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6 <title>Program Listing</title> 7 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 8 <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /> 9 <link rel="start" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" /> 10 <link rel="up" href="txnapp.html" title="Chapter��2.��Transactional Application" /> 11 <link rel="prev" href="txnapp.html" title="Chapter��2.��Transactional Application" /> 12 <link rel="next" href="repapp.html" title="Chapter��3.��The DB Replication Manager" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Program Listing</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="txnapp.html">Prev</a>��</td> 22 <th width="60%" align="center">Chapter��2.��Transactional Application</th> 23 <td width="20%" align="right">��<a accesskey="n" href="repapp.html">Next</a></td> 24 </tr> 25 </table> 26 <hr /> 27 </div> 28 <div class="sect1" lang="en" xml:lang="en"> 29 <div class="titlepage"> 30 <div> 31 <div> 32 <h2 class="title" style="clear: both"><a id="simpleprogramlisting"></a>Program Listing</h2> 33 </div> 34 </div> 35 </div> 36 <div class="toc"> 37 <dl> 38 <dt> 39 <span class="sect2"> 40 <a href="simpleprogramlisting.html#main_c">Function: main()</a> 41 </span> 42 </dt> 43 <dt> 44 <span class="sect2"> 45 <a href="simpleprogramlisting.html#create_env_c">Function: create_env()</a> 46 </span> 47 </dt> 48 <dt> 49 <span class="sect2"> 50 <a href="simpleprogramlisting.html#env_init_c">Function: env_init()</a> 51 </span> 52 </dt> 53 <dt> 54 <span class="sect2"> 55 <a href="simpleprogramlisting.html#doloop_c">Function: doloop()</a> 56 </span> 57 </dt> 58 <dt> 59 <span class="sect2"> 60 <a href="simpleprogramlisting.html#printstocks_c"> 61 <span>Function: print_stocks()</span> 62 63 64 </a> 65 </span> 66 </dt> 67 </dl> 68 </div> 69 <p> 70 Our example program is a fairly simple transactional 71 application. At this early stage of its development, the 72 application contains no hint that it must be network-aware 73 so the only command line argument that it takes is one that 74 allows us to specify the environment home directory. 75 (Eventually, we will specify things like host names and 76 ports from the command line). 77 </p> 78 <p> 79 Note that the application performs all writes under the 80 protection of a transaction; however, multiple database 81 operations are not performed per transaction. Consequently, 82 we simplify things a bit by using autocommit for our 83 database writes. 84 </p> 85 <p> 86 Also, this application is single-threaded. It is possible 87 to write a multi-threaded or multi-process application that 88 performs replication. That said, the concepts described in 89 this book are applicable to both single threaded and 90 multi-threaded applications so nothing 91 is gained by multi-threading this application other than 92 distracting complexity. This manual 93 does, however, identify where care must be taken when 94 performing replication with a non-single threaded 95 application. 96 </p> 97 <p> 98 Finally, remember that transaction processing is not described in 99 this manual. Rather, see the 100 <em class="citetitle">Berkeley DB Getting Started with Transaction Processing</em> guide for details on 101 that topic. 102 </p> 103 <div class="sect2" lang="en" xml:lang="en"> 104 <div class="titlepage"> 105 <div> 106 <div> 107 <h3 class="title"><a id="main_c"></a>Function: main()</h3> 108 </div> 109 </div> 110 </div> 111 <p> 112 Our program begins with the usual assortment of 113 include statements. 114 </p> 115 <pre class="programlisting">/* 116 * File: ex_rep_gsg_simple.c 117 */ 118 119#include <stdlib.h> 120#include <string.h> 121#ifndef _WIN32 122#include <unistd.h> 123#endif 124 125#include <db.h> 126 127#ifdef _WIN32 128extern int getopt(int, char * const *, const char *); 129#endif </pre> 130 <p> 131 We then define a few values. One is the size of our cache, 132 which we keep deliberately small for this example, and the 133 other is the name of our database. We also provide a global 134 variable that is the name of our program; this is used for 135 error reporting later on. 136 </p> 137 <pre class="programlisting">#define CACHESIZE (10 * 1024 * 1024) 138#define DATABASE "quote.db" 139 140const char *progname = "ex_rep_gsg_simple"; </pre> 141 <p> 142 Then we perform a couple of forward declarations. The first 143 of these, <code class="function">create_env()</code> and 144 <code class="function">env_init()</code> are used to open 145 and initialize our environment. 146 </p> 147 <p> 148 Next we declare 149 <code class="function">doloop()</code>, which is the function that we use to 150 add data to the database and then display its contents. This is 151 essentially a big <code class="literal">do</code> loop, hence the 152 function's name. 153 </p> 154 <p> 155 Finally, we have <code class="function">print_stocks</code>, which is 156 used to display a database record once it has been retrieved from the 157 database. 158 </p> 159 <pre class="programlisting">int create_env(const char *, DB_ENV **); 160int env_init(DB_ENV *, const char *); 161int doloop (DB_ENV *); 162int print_stocks(DBC *); </pre> 163 <p> 164 Next we need our <code class="function">usage()</code> function, 165 which is fairly trivial at this point: 166 </p> 167 <pre class="programlisting">/* Usage function */ 168static void 169usage() 170{ 171 fprintf(stderr, "usage: %s ", progname); 172 fprintf(stderr, "-h home\n"); 173 exit(EXIT_FAILURE); 174} </pre> 175 <p> 176 That completed, we can jump into our application's 177 <code class="function">main()</code> function. If you are familiar with 178 DB transactional applications, you will not find any 179 surprises here. We begin by declaring and initializing the 180 usual set of variables: 181 </p> 182 <pre class="programlisting">int 183main(int argc, char *argv[]) 184{ 185 extern char *optarg; 186 DB_ENV *dbenv; 187 const char *home; 188 char ch; 189 int ret; 190 191 dbenv = NULL; 192 193 ret = 0; 194 home = NULL; </pre> 195 <p> 196 Now we create and configure our environment handle. 197 We do this with our <code class="function">create_env()</code> function, which we will 198 show a little later in this example. 199 200 </p> 201 <pre class="programlisting"> if ((ret = create_env(progname, &dbenv)) != 0) 202 goto err; </pre> 203 <p> 204 Then we parse the command line arguments: 205 </p> 206 <pre class="programlisting"> while ((ch = getopt(argc, argv, "h:")) != EOF) 207 switch (ch) { 208 case 'h': 209 home = optarg; 210 break; 211 case '?': 212 default: 213 usage(); 214 } 215 216 /* Error check command line. */ 217 if (home == NULL) 218 usage(); </pre> 219 <p> 220 Now we can open our environment. We do this with our 221 <code class="function">env_init()</code> function which we will describe 222 a little later in this chapter. 223 </p> 224 <pre class="programlisting"> if ((ret = env_init(dbenv, home)) != 0) 225 goto err; </pre> 226 <p> 227 Now that we have opened the environment, we can call our 228 <code class="function">doloop()</code> function. This function performs the basic 229 database interaction. Notice that we have not yet opened any databases. In 230 a traditional transactional application we would probably open the 231 databases before calling our our main data processing function. 232 However, the eventual replicated application will want to handle 233 database open and close in the main processing loop, so in a nod to what this 234 application will eventually become we do a slightly unusual thing 235 here. 236 </p> 237 <pre class="programlisting"> if ((ret = doloop(dbenv)) != 0) { 238 dbenv->err(dbenv, ret, "Application failed"); 239 goto err; 240 } </pre> 241 <p> 242 Finally, we provide our application shutdown code. Note, again, 243 that in a traditional transactional application all databases would 244 also be closed here. But, again, due to the way this application 245 will eventually behave, we cause the database close to occur in the 246 <code class="function">doloop()</code> function. 247 </p> 248 <pre class="programlisting">err: if (dbenv != NULL) 249 (void)dbenv->close(dbenv, 0); 250 251 return (ret); 252} </pre> 253 </div> 254 <div class="sect2" lang="en" xml:lang="en"> 255 <div class="titlepage"> 256 <div> 257 <div> 258 <h3 class="title"><a id="create_env_c"></a>Function: create_env()</h3> 259 </div> 260 </div> 261 </div> 262 <p> 263 Having written our <code class="function">main()</code> 264 function, we now implement the first of our utility 265 functions that we use to manage our environments. 266 This function exists only to make our code easier 267 to manage, and all it does is create an environment 268 handle for us. 269 </p> 270 <pre class="programlisting">int 271create_env(const char *progname, DB_ENV **dbenvp) 272{ 273 DB_ENV *dbenv; 274 int ret; 275 276 if ((ret = db_env_create(&dbenv, 0)) != 0) { 277 fprintf(stderr, "can't create env handle: %s\n", 278 db_strerror(ret)); 279 return (ret); 280 } 281 282 dbenv->set_errfile(dbenv, stderr); 283 dbenv->set_errpfx(dbenv, progname); 284 285 *dbenvp = dbenv; 286 return (0); 287} </pre> 288 </div> 289 <div class="sect2" lang="en" xml:lang="en"> 290 <div class="titlepage"> 291 <div> 292 <div> 293 <h3 class="title"><a id="env_init_c"></a>Function: env_init()</h3> 294 </div> 295 </div> 296 </div> 297 <p> 298 Having written the function that initializes an 299 environment handle, we now implement the function 300 that opens the handle. Again, there should be no 301 surprises here for anyone familiar with DB 302 applications. The open flags that we use are those 303 normally used for a transactional application. 304 </p> 305 <pre class="programlisting">int 306env_init(DB_ENV *dbenv, const char *home) 307{ 308 u_int32_t flags; 309 int ret; 310 311 (void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0); 312 (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1); 313 314 flags = DB_CREATE | 315 DB_INIT_LOCK | 316 DB_INIT_LOG | 317 DB_INIT_MPOOL | 318 DB_INIT_TXN | 319 DB_RECOVER; 320 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) 321 dbenv->err(dbenv, ret, "can't open environment"); 322 return (ret); 323} </pre> 324 </div> 325 <div class="sect2" lang="en" xml:lang="en"> 326 <div class="titlepage"> 327 <div> 328 <div> 329 <h3 class="title"><a id="doloop_c"></a>Function: doloop()</h3> 330 </div> 331 </div> 332 </div> 333 <p> 334 Having written our <code class="function">main()</code> 335 function and utility functions, we now implement 336 our application's 337 primary data processing function. This 338 function provides a command prompt at which the 339 user can enter a stock ticker value and a price for 340 that value. This information is then entered to the 341 database. 342 </p> 343 <p> 344 To display the database, simply enter 345 <code class="literal">return</code> at the prompt. 346 </p> 347 <p> 348 To begin, we declare a database pointer, 349 several <code class="classname">DBT</code> variables, and 350 the usual assortment of variables used for buffers 351 and return codes. We also initialize all of this. 352 </p> 353 <pre class="programlisting">#define BUFSIZE 1024 354int 355doloop(DB_ENV *dbenv) 356{ 357 DB *dbp; 358 DBT key, data; 359 char buf[BUFSIZE], *rbuf; 360 int ret; 361 u_int32_t db_flags; 362 363 dbp = NULL; 364 memset(&key, 0, sizeof(key)); 365 memset(&data, 0, sizeof(data)); 366 ret = 0; </pre> 367 <p> 368 Next, we begin the loop and we immediately open our 369 database if it has not already been opened. Notice that 370 we specify autocommit when we open the database. In 371 this case, autocommit is important because we will only 372 ever write to our database using it. There is no need 373 for explicit transaction handles and commit/abort code 374 in this application, because we are not combining 375 multiple database operations together under a single 376 transaction. 377 </p> 378 <p> 379 Autocommit is described in greater detail in the 380 <em class="citetitle">Berkeley DB Getting Started with Transaction Processing</em> guide. 381 </p> 382 <pre class="programlisting"> for (;;) { 383 384 if (dbp == NULL) { 385 if ((ret = db_create(&dbp, dbenv, 0)) != 0) 386 return (ret); 387 388 db_flags = DB_AUTO_COMMIT | DB_CREATE; 389 390 if ((ret = dbp->open(dbp, NULL, DATABASE, 391 NULL, DB_BTREE, db_flags, 0)) != 0) { 392 dbenv->err(dbenv, ret, "DB->open"); 393 goto err; 394 } 395 } </pre> 396 <p> 397 Now we implement our command prompt. This is a simple and not 398 very robust implementation of a command prompt. 399 If the user enters the keywords <code class="literal">exit</code> 400 or <code class="literal">quit</code>, the loop is exited and the 401 application ends. If the user enters nothing and instead simply 402 presses <code class="literal">return</code>, the entire contents of the 403 database is displayed. We use our 404 <code class="function">print_stocks()</code> function to display the 405 database. (That implementation is shown next in this chapter.) 406 </p> 407 <p> 408 Notice that very little error checking is performed on the data 409 entered at this prompt. If the user fails to enter at least one 410 space in the value string, a simple help message is printed and 411 the prompt is returned to the user. That is the only error 412 checking performed here. In a real-world application, 413 at a minimum the application would probably check to ensure 414 that the price was in fact an integer or float value. 415 However, in order to keep this example code as simple as 416 possible, we refrain from implementing a thorough user interface. 417 </p> 418 <pre class="programlisting"> printf("QUOTESERVER > "); 419 fflush(stdout); 420 421 if (fgets(buf, sizeof(buf), stdin) == NULL) 422 break; 423 if (strtok(&buf[0], " \t\n") == NULL) { 424 switch ((ret = print_stocks(dbp))) { 425 case 0: 426 continue; 427 default: 428 dbp->err(dbp, ret, "Error traversing data"); 429 goto err; 430 } 431 } 432 rbuf = strtok(NULL, " \t\n"); 433 if (rbuf == NULL || rbuf[0] == '\0') { 434 if (strncmp(buf, "exit", 4) == 0 || 435 strncmp(buf, "quit", 4) == 0) 436 break; 437 dbenv->errx(dbenv, "Format: TICKER VALUE"); 438 continue; 439 } </pre> 440 <p> 441 Now we assign data to the <code class="classname">DBT</code>s that 442 we will use to write the new information to the database. 443 </p> 444 <pre class="programlisting"> key.data = buf; 445 key.size = (u_int32_t)strlen(buf); 446 447 data.data = rbuf; 448 data.size = (u_int32_t)strlen(rbuf); </pre> 449 <p> 450 Having done that, we can write the new information to the 451 database. Remember that this application uses autocommit, 452 so no explicit transaction management is required. Also, 453 the database is not configured for duplicate records, so 454 the data portion of a record is overwritten if the provided 455 key already exists in the database. However, in this case 456 DB returns <code class="literal">DB_KEYEXIST</code> ��� which 457 we ignore. 458 </p> 459 <pre class="programlisting"> if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) != 0) 460 { 461 dbp->err(dbp, ret, "DB->put"); 462 if (ret != DB_KEYEXIST) 463 goto err; 464 } 465 } </pre> 466 <p> 467 Finally, we close our database before returning from the 468 function. 469 </p> 470 <pre class="programlisting">err: if (dbp != NULL) 471 (void)dbp->close(dbp, DB_NOSYNC); 472 473 return (ret); 474} </pre> 475 </div> 476 <div class="sect2" lang="en" xml:lang="en"> 477 <div class="titlepage"> 478 <div> 479 <div> 480 <h3 class="title"><a id="printstocks_c"></a> 481 <span>Function: print_stocks()</span> 482 483 484 </h3> 485 </div> 486 </div> 487 </div> 488 <p> 489 The <code class="function">print_stocks()</code> 490 491 <span>function</span> 492 493 simply takes a database handle, opens a cursor, and uses 494 it to display all the information it finds in a database. 495 This is trivial cursor operation that should hold 496 no surprises for you. We simply provide it here for 497 the sake of completeness. 498 </p> 499 <p> 500 If you are unfamiliar with basic cursor operations, 501 please see the <em class="citetitle">Getting Started with Berkeley DB</em> 502 guide. 503 </p> 504 <pre class="programlisting">/* Displays all stock quote information in the database. */ 505int 506print_stocks(DB *dbp) 507{ 508 DBC *dbc; 509 DBT key, data; 510#define MAXKEYSIZE 10 511#define MAXDATASIZE 20 512 char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1]; 513 int ret, t_ret; 514 u_int32_t keysize, datasize; 515 516 if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) { 517 dbp->err(dbp, ret, "can't open cursor"); 518 return (ret); 519 } 520 521 memset(&key, 0, sizeof(key)); 522 memset(&data, 0, sizeof(data)); 523 524 printf("\tSymbol\tPrice\n"); 525 printf("\t======\t=====\n"); 526 527 for (ret = dbc->get(dbc, &key, &data, DB_FIRST); 528 ret == 0; 529 ret = dbc->get(dbc, &key, &data, DB_NEXT)) { 530 keysize = key.size > MAXKEYSIZE ? MAXKEYSIZE : key.size; 531 memcpy(keybuf, key.data, keysize); 532 keybuf[keysize] = '\0'; 533 534 datasize = data.size >= MAXDATASIZE ? MAXDATASIZE : data.size; 535 memcpy(databuf, data.data, datasize); 536 databuf[datasize] = '\0'; 537 538 printf("\t%s\t%s\n", keybuf, databuf); 539 } 540 printf("\n"); 541 fflush(stdout); 542 543 if ((t_ret = dbc->close(dbc)) != 0 && ret == 0) 544 ret = t_ret; 545 546 switch (ret) { 547 case 0: 548 case DB_NOTFOUND: 549 return (0); 550 default: 551 return (ret); 552 } 553} </pre> 554 </div> 555 </div> 556 <div class="navfooter"> 557 <hr /> 558 <table width="100%" summary="Navigation footer"> 559 <tr> 560 <td width="40%" align="left"><a accesskey="p" href="txnapp.html">Prev</a>��</td> 561 <td width="20%" align="center"> 562 <a accesskey="u" href="txnapp.html">Up</a> 563 </td> 564 <td width="40%" align="right">��<a accesskey="n" href="repapp.html">Next</a></td> 565 </tr> 566 <tr> 567 <td width="40%" align="left" valign="top">Chapter��2.��Transactional Application��</td> 568 <td width="20%" align="center"> 569 <a accesskey="h" href="index.html">Home</a> 570 </td> 571 <td width="40%" align="right" valign="top">��Chapter��3.��The DB Replication Manager</td> 572 </tr> 573 </table> 574 </div> 575 </body> 576</html> 577