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>Transaction Example</title> 7 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 8 <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /> 9 <link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" /> 10 <link rel="up" href="wrapup.html" title="Chapter 6. Summary and Examples" /> 11 <link rel="previous" href="wrapup.html" title="Chapter 6. Summary and Examples" /> 12 <link rel="next" href="inmem_txnexample_c.html" title="In-Memory Transaction Example" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Transaction Example</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="wrapup.html">Prev</a> </td> 22 <th width="60%" align="center">Chapter 6. Summary and Examples</th> 23 <td width="20%" align="right"> <a accesskey="n" href="inmem_txnexample_c.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="txnexample_c"></a>Transaction Example</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 The following code provides a fully functional example of a 39 multi-threaded transactional DB application. For improved 40 portability across platforms, this examples uses pthreads to 41 provide threading support. 42 </p> 43 <p> 44 The example opens an environment and database and then creates 5 45 threads, each of which writes 500 records to the database. The keys 46 used for these writes are pre-determined strings, while the data is 47 a random value. This means that the actual data is arbitrary and 48 therefore uninteresting; we picked it only because it requires 49 minimum code to implement and therefore will stay out of the way of 50 the main points of this example. 51 </p> 52 <p> 53 Each thread writes 10 records under a single transaction 54 before committing and writing another 10 (this is repeated 50 55 times). At the end of each transaction, but before committing, each 56 thread calls a function that uses a cursor to read every record in 57 the database. We do this in order to make some points about 58 database reads in a transactional environment. 59 </p> 60 <p> 61 Of course, each writer thread performs deadlock detection as 62 described in this manual. In addition, normal recovery is performed 63 when the environment is opened. 64 </p> 65 <p> 66 We start with our normal <tt class="literal">include</tt> directives: 67 </p> 68 <pre class="programlisting">/* File: txn_guide.c */ 69 70/* We assume an ANSI-compatible compiler */ 71#include <stdio.h> 72#include <stdlib.h> 73#include <string.h> 74#include <pthread.h> 75#include <db.h> 76 77#ifdef _WIN32 78extern int getopt(int, char * const *, const char *); 79#else 80#include <unistd.h> 81#endif </pre> 82 <p> 83 We also need a directive that we use to identify how many threads we 84 want our program to create: 85</p> 86 <pre class="programlisting">/* Run 5 writers threads at a time. */ 87#define NUMWRITERS 5 </pre> 88 <p> 89 Next we declare a couple of global 90 variables (used by our threads), and we provide our forward 91 declarations for the functions used by this example. 92</p> 93 <pre class="programlisting">/* 94 * Printing of pthread_t is implementation-specific, so we 95 * create our own thread IDs for reporting purposes. 96 */ 97int global_thread_num; 98pthread_mutex_t thread_num_lock; 99 100/* Forward declarations */ 101int count_records(DB *, DB_TXN *); 102int open_db(DB **, const char *, const char *, DB_ENV *, u_int32_t); 103int usage(void); 104void *writer_thread(void *); </pre> 105 <p> 106 We now implement our usage function, which identifies our only command line 107 parameter: 108</p> 109 <pre class="programlisting">/* Usage function */ 110int 111usage() 112{ 113 fprintf(stderr, " [-h <database_home_directory>]\n"); 114 return (EXIT_FAILURE); 115} </pre> 116 <p> 117 With that, we have finished up our program's housekeeping, and we can 118 now move on to the main part of our program. As usual, we begin with 119 <tt class="function">main()</tt>. First we declare all our variables, and 120 then we initialize our DB handles. 121</p> 122 <pre class="programlisting">int 123main(int argc, char *argv[]) 124{ 125 /* Initialize our handles */ 126 DB *dbp = NULL; 127 DB_ENV *envp = NULL; 128 129 pthread_t writer_threads[NUMWRITERS]; 130 int ch, i, ret, ret_t; 131 u_int32_t env_flags; 132 char *db_home_dir; 133 /* Application name */ 134 const char *prog_name = "txn_guide"; 135 /* Database file name */ 136 const char *file_name = "mydb.db"; </pre> 137 <p> 138 Now we need to parse our command line. In this case, all we want is to 139 know where our environment directory is. If the <tt class="literal">-h</tt> 140 option is not provided when this example is run, the current working 141 directory is used instead. 142</p> 143 <pre class="programlisting"> /* Parse the command line arguments */ 144#ifdef _WIN32 145 db_home_dir = ".\\"; 146#else 147 db_home_dir = "./"; 148#endif 149 while ((ch = getopt(argc, argv, "h:")) != EOF) 150 switch (ch) { 151 case 'h': 152 db_home_dir = optarg; 153 break; 154 case '?': 155 default: 156 return (usage()); 157 } </pre> 158 <p> 159 Next we create our database handle, and we define our environment open flags. 160 There are a few things to notice here: 161</p> 162 <div class="itemizedlist"> 163 <ul type="disc"> 164 <li> 165 <p> 166 We specify <tt class="literal">DB_RECOVER</tt>, which means that normal 167 recovery is run every time we start the application. This is 168 highly desirable and recommended for most 169 applications. 170 </p> 171 </li> 172 <li> 173 <p> 174 We also specify <tt class="literal">DB_THREAD</tt>, which means our 175 environment handle will be free-threaded. This is very 176 important because we will be sharing the environment handle 177 across threads. 178 </p> 179 </li> 180 </ul> 181 </div> 182 <pre class="programlisting"> /* Create the environment */ 183 ret = db_env_create(&envp, 0); 184 if (ret != 0) { 185 fprintf(stderr, "Error creating environment handle: %s\n", 186 db_strerror(ret)); 187 goto err; 188 } 189 190 env_flags = 191 DB_CREATE | /* Create the environment if it does not exist */ 192 DB_RECOVER | /* Run normal recovery. */ 193 DB_INIT_LOCK | /* Initialize the locking subsystem */ 194 DB_INIT_LOG | /* Initialize the logging subsystem */ 195 DB_INIT_TXN | /* Initialize the transactional subsystem. This 196 * also turns on logging. */ 197 DB_INIT_MPOOL | /* Initialize the memory pool (in-memory cache) */ 198 DB_THREAD; /* Cause the environment to be free-threaded */ </pre> 199 <p> 200 Now we configure how we want deadlock detection performed. In our case, we will cause DB to perform deadlock 201 detection by walking its internal lock tables looking for a block every time a lock is requested. Further, in the 202 event of a deadlock, the thread that holds the youngest lock will receive the deadlock notification. 203 </p> 204 <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> 205 <h3 class="title">Note</h3> 206 <p> 207 You will notice that every database operation checks the 208 operation's status return code, and if an error 209 (non-zero) status is returned, we log the error and then go to 210 a <tt class="literal">err</tt> label in our program. Unlike 211 object-oriented programs such as C++ or Java, we do not have 212 <tt class="literal">try</tt> blocks in C. Therefore, this is the best 213 way for us to implement cascading error handling for this 214 example. 215 </p> 216 </div> 217 <pre class="programlisting"> /* 218 * Indicate that we want db to perform lock detection internally. 219 * Also indicate that the transaction with the fewest number of 220 * write locks will receive the deadlock notification in 221 * the event of a deadlock. 222 */ 223 ret = envp->set_lk_detect(envp, DB_LOCK_MINWRITE); 224 if (ret != 0) { 225 fprintf(stderr, "Error setting lock detect: %s\n", 226 db_strerror(ret)); 227 goto err; 228 } </pre> 229 <p> 230 Now we open our environment. 231</p> 232 <pre class="programlisting"> /* 233 * If we had utility threads (for running checkpoints or 234 * deadlock detection, for example) we would spawn those 235 * here. However, for a simple example such as this, 236 * that is not required. 237 */ 238 239 /* Now actually open the environment */ 240 ret = envp->open(envp, db_home_dir, env_flags, 0); 241 if (ret != 0) { 242 fprintf(stderr, "Error opening environment: %s\n", 243 db_strerror(ret)); 244 goto err; 245 } </pre> 246 <p> 247 Now we call the function that will open our database for us. This is 248 not very interesting, except that you will notice that we are 249 specifying <tt class="literal">DB_DUPSORT</tt>. This is required purely by 250 the data that we are writing to the database, and it is only necessary 251 if you run the application more than once without first deleting the environment. 252</p> 253 <p> 254 Also, we do not provide any error logging here because the 255 <tt class="function">open_db()</tt> function does that for us. 256 (The implementation of <tt class="function">open_db()</tt> is described 257 later in this section.) 258</p> 259 <pre class="programlisting"> /* Open the database */ 260 ret = open_db(&dbp, prog_name, file_name, envp, DB_DUPSORT); 261 if (ret != 0) 262 goto err; </pre> 263 <p> 264 Now we create our threads. In this example we are using pthreads 265 for our threading package. A description of threading (beyond how 266 it impacts DB usage) is beyond the scope of this manual. 267 However, the things that we are doing here should be familiar to 268 anyone who has prior experience with any threading package. We are 269 simply initializing a mutex, creating our threads, and then joining 270 our threads, which causes our program to wait until the joined 271 threads have completed before continuing operations in the main 272 thread. 273 </p> 274 <pre class="programlisting"> /* Initialize a pthread mutex. Used to help provide thread ids. */ 275 (void)pthread_mutex_init(&thread_num_lock, NULL); 276 277 /* Start the writer threads. */ 278 for (i = 0; i < NUMWRITERS; i++) 279 (void)pthread_create(&writer_threads[i], NULL, 280 writer_thread, (void *)dbp); 281 282 /* Join the writers */ 283 for (i = 0; i < NUMWRITERS; i++) 284 (void)pthread_join(writer_threads[i], NULL); </pre> 285 <p> 286 Finally, to wrap up <tt class="function">main()</tt>, we close out our 287 database and environment handle, as is normal for any DB 288 application. Notice that this is where our <tt class="literal">err</tt> 289 label is placed in our application. If any database operation prior 290 to this point in the program returns an error status, the program 291 simply jumps to this point and closes our handles if necessary 292 before exiting the application completely. 293 </p> 294 <pre class="programlisting">err: 295 /* Close our database handle, if it was opened. */ 296 if (dbp != NULL) { 297 ret_t = dbp->close(dbp, 0); 298 if (ret_t != 0) { 299 fprintf(stderr, "%s database close failed: %s\n", 300 file_name, db_strerror(ret_t)); 301 ret = ret_t; 302 } 303 } 304 305 /* Close our environment, if it was opened. */ 306 if (envp != NULL) { 307 ret_t = envp->close(envp, 0); 308 if (ret_t != 0) { 309 fprintf(stderr, "environment close failed: %s\n", 310 db_strerror(ret_t)); 311 ret = ret_t; 312 } 313 } 314 315 /* Final status message and return. */ 316 printf("I'm all done.\n"); 317 return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 318} </pre> 319 <p> 320 Now that we have completed <tt class="function">main()</tt>, we need to 321 implement the function that our writer threads will actually run. This 322 is where the bulk of our transactional code resides. 323</p> 324 <p> 325 We start as usual with variable declarations and initialization. 326</p> 327 <pre class="programlisting">/* 328 * A function that performs a series of writes to a 329 * Berkeley DB database. The information written 330 * to the database is largely nonsensical, but the 331 * mechanisms of transactional commit/abort and 332 * deadlock detection are illustrated here. 333 */ 334void * 335writer_thread(void *args) 336{ 337 DBT key, value; 338 DB_TXN *txn; 339 int i, j, payload, ret, thread_num; 340 int retry_count, max_retries = 20; /* Max retry on a deadlock */ 341 char *key_strings[] = {"key 1", "key 2", "key 3", "key 4", 342 "key 5", "key 6", "key 7", "key 8", 343 "key 9", "key 10"}; 344 345 DB *dbp = (DB *)args; 346 DB_ENV *envp = dbp->get_env(dbp); </pre> 347 <p> 348 Now we want a thread number for reporting purposes. It is possible to 349 use the <tt class="literal">pthread_t</tt> value directly for this purpose, 350 but how that is done unfortunately differs depending 351 on the pthread implementation you are using. So instead we use a 352 mutex-protected global variable to obtain a simple integer for 353 our reporting purposes. 354</p> 355 <p> 356 Note that we are also use this thread id for initializing a random number generator, which we do here. 357 We use this random number generator for data generation. 358</p> 359 <pre class="programlisting"> /* Get the thread number */ 360 (void)pthread_mutex_lock(&thread_num_lock); 361 global_thread_num++; 362 thread_num = global_thread_num; 363 (void)pthread_mutex_unlock(&thread_num_lock); 364 365 /* Initialize the random number generator */ 366 srand((u_int)pthread_self()); </pre> 367 <p> 368 Now we begin the loop that we use to write data to the database. 369 <span> 370 Notice that at the beginning of the top loop, we begin a new 371 transaction. 372 </span> 373 374 375 We will actually use 50 transactions per writer 376 thread, although we will only ever have one active transaction per 377 thread at a time. Within each transaction, we will perform 10 378 database writes. 379 </p> 380 <p> 381 By combining multiple writes together under a single transaction, 382 we increase the likelihood that a deadlock will occur. Normally, 383 you want to reduce the potential for a deadlock and in this case 384 the way to do that is to perform a single write per transaction. 385 To avoid deadlocks, we could be using auto commit to 386 write to our database for this workload. 387 </p> 388 <p> 389 However, we want to show deadlock handling and by performing 390 multiple writes per transaction we can actually observe deadlocks 391 occurring. We also want to underscore the idea that you can 392 combing multiple database operations together in a single atomic 393 unit of work in order to improve the efficiency of your writes. 394 </p> 395 <p> 396 Finally, on an issue of style, you will notice the 397 <tt class="literal">retry</tt> label that we place immediately before our 398 transaction begin code. We use this to loop in the event that a 399 deadlock is detected and the write operation has to be performed. A 400 great many people dislike looping with <tt class="literal">goto</tt> 401 statements, and we certainly could have written this code to avoid 402 it. However, we find that using the 403 <tt class="literal">goto</tt> in this case greatly helps to clarify the 404 code, so we ignore the bias against <tt class="literal">goto</tt> 405 programming in order to clearly support looping in the event of 406 what is really an error condition. 407 </p> 408 <pre class="programlisting"> /* Write 50 times and then quit */ 409 for (i = 0; i < 50; i++) { 410 retry_count = 0; /* Used for deadlock retries */ 411 412retry: 413 /* Begin our transaction. */ 414 ret = envp->txn_begin(envp, NULL, &txn, 0); 415 if (ret != 0) { 416 envp->err(envp, ret, "txn_begin failed"); 417 return ((void *)EXIT_FAILURE); 418 } </pre> 419 <p> 420 Now we begin the inner loop that we use to actually 421 perform the write. Notice that we use a <tt class="literal">case</tt> 422 statement to examine the return code from the database put. 423 This case statement is what we use to determine whether we need 424 to abort (or abort/retry in the case of a deadlock) our current 425 transaction. 426 </p> 427 <pre class="programlisting"> for (j = 0; j < 10; j++) { 428 /* Set up our key and values DBTs */ 429 memset(&key, 0, sizeof(DBT)); 430 key.data = key_strings[j]; 431 key.size = (strlen(key_strings[j]) + 1) * sizeof(char); 432 433 memset(&value, 0, sizeof(DBT)); 434 payload = rand() + i; 435 value.data = &payload; 436 value.size = sizeof(int); 437 438 /* Perform the database put. */ 439 switch (ret = dbp->put(dbp, txn, &key, &value, 0)) { 440 case 0: 441 break; 442 /* 443 * Our database is configured for sorted duplicates, 444 * so there is a potential for a KEYEXIST error return. 445 * If we get one, simply ignore it and continue on. 446 * 447 * Note that you will see KEYEXIST errors only after you 448 * have run this program at least once. 449 */ 450 case DB_KEYEXIST: 451 printf("Got keyexists.\n"); 452 break; 453 /* 454 * Here's where we perform deadlock detection. If 455 * DB_LOCK_DEADLOCK is returned by the put operation, 456 * then this thread has been chosen to break a deadlock. 457 * It must abort its operation, and optionally retry the 458 * put. 459 */ 460 case DB_LOCK_DEADLOCK: 461 /* 462 * First thing we MUST do is abort the 463 * transaction. 464 */ 465 (void)txn->abort(txn); 466 /* 467 * Now we decide if we want to retry the operation. 468 * If we have retried less than max_retries, 469 * increment the retry count and goto retry. 470 */ 471 if (retry_count < max_retries) { 472 printf("Writer %i: Got DB_LOCK_DEADLOCK.\n", 473 thread_num); 474 printf("Writer %i: Retrying write operation.\n", 475 thread_num); 476 retry_count++; 477 goto retry; 478 } 479 /* 480 * Otherwise, just give up. 481 */ 482 printf("Writer %i: ", thread_num); 483 printf("Got DB_LOCK_DEADLOCK and out of retries.\n"); 484 printf("Writer %i: Giving up.\n", thread_num); 485 return ((void *)EXIT_FAILURE); 486 /* 487 * If a generic error occurs, we simply abort the 488 * transaction and exit the thread completely. 489 */ 490 default: 491 envp->err(envp, ret, "db put failed"); 492 ret = txn->abort(txn); 493 if (ret != 0) 494 envp->err(envp, ret, "txn abort failed"); 495 return ((void *)EXIT_FAILURE); 496 } /** End case statement **/ 497 498 } /** End for loop **/ </pre> 499 <p> 500 Having completed the inner database write loop, we could simply 501 commit the transaction and continue on to the next block of 10 502 writes. However, we want to first illustrate a few points about 503 transactional processing so instead we call our 504 <tt class="function">count_records()</tt> 505 506 507 function before calling the transaction 508 commit. 509 <tt class="function">count_records()</tt> 510 511 uses a cursor to read every 512 record in the database and return a count of the number of records 513 that it found. 514 </p> 515 <pre class="programlisting"> /* 516 * print the number of records found in the database. 517 * See count_records() for usage information. 518 */ 519 printf("Thread %i. Record count: %i\n", thread_num, 520 count_records(dbp, NULL)); 521 522 /* 523 * If all goes well, we can commit the transaction and 524 * loop to the next transaction. 525 */ 526 ret = txn->commit(txn, 0); 527 if (ret != 0) { 528 envp->err(envp, ret, "txn commit failed"); 529 return ((void *)EXIT_FAILURE); 530 } 531 } 532 return ((void *)EXIT_SUCCESS); 533} </pre> 534 <p> 535 536 If you look at the 537 <tt class="function">count_records()</tt> 538 539 function prototype at the beginning of this example, you will see that the 540 function's second parameter takes a transaction handle. However, 541 our usage of the function here does not pass a transaction handle 542 through to the function. 543 </p> 544 <p> 545 546 Because 547 <tt class="function">count_records()</tt> 548 549 reads every record in the database, if used incorrectly the thread 550 will self-deadlock. The writer thread has just written 500 records 551 to the database, but because the transaction used for that write 552 has not yet been committed, each of those 500 records are still 553 locked by the thread's transaction. If we then simply run a 554 non-transactional cursor over the database from within the same 555 thread that has locked those 500 records, the cursor will 556 block when it tries to read one of those transactional 557 protected records. The thread immediately stops operation at that 558 point while the cursor waits for the read lock it has 559 requested. Because that read lock will never be released (the thread 560 can never make any forward progress), this represents a 561 self-deadlock for the the thread. 562 </p> 563 <p> 564 There are three ways to prevent this self-deadlock: 565 </p> 566 <div class="orderedlist"> 567 <ol type="1"> 568 <li> 569 <p> 570 We can move the call to 571 <tt class="function">count_records()</tt> 572 573 to a point after the thread's transaction has committed. 574 </p> 575 </li> 576 <li> 577 <p> 578 We can allow 579 <tt class="function">count_records()</tt> 580 581 to operate under the same transaction as all of the writes 582 were performed (this is what the transaction parameter for 583 the function is for). 584 </p> 585 </li> 586 <li> 587 <p> 588 We can reduce our isolation guarantee for the application 589 by allowing uncommitted reads. 590 </p> 591 </li> 592 </ol> 593 </div> 594 <p> 595 For this example, we choose to use option 3 (uncommitted reads) to avoid 596 the deadlock. This means that we have to open our database such 597 that it supports uncommitted reads, and we have to open our cursor handle 598 so that it knows to perform uncommitted reads. 599 </p> 600 <p> 601 Note that in <a href="inmem_txnexample_c.html">In-Memory Transaction Example</a>, 602 we simply perform the cursor operation using the same transaction 603 as is used for the thread's writes. 604 </p> 605 <p> 606 The following is the 607 <tt class="function">count_records()</tt> 608 609 implementation. There is not anything particularly interesting 610 about this function other than specifying uncommitted reads when 611 we open the cursor handle, but we include the function here anyway 612 for the sake of completeness. 613 </p> 614 <pre class="programlisting">/* 615 * This simply counts the number of records contained in the 616 * database and returns the result. 617 * 618 * Note that this function exists only for illustrative purposes. 619 * A more straight-forward way to count the number of records in 620 * a database is to use DB->stat() or DB->stat_print(). 621 */ 622 623int 624count_records(DB *dbp, DB_TXN *txn) 625{ 626 DBT key, value; 627 DBC *cursorp; 628 int count, ret; 629 630 cursorp = NULL; 631 count = 0; 632 633 /* Get the cursor */ 634 ret = dbp->cursor(dbp, txn, &cursorp, DB_READ_UNCOMMITTED); 635 if (ret != 0) { 636 dbp->err(dbp, ret, "count_records: cursor open failed."); 637 goto cursor_err; 638 } 639 640 /* Get the key DBT used for the database read */ 641 memset(&key, 0, sizeof(DBT)); 642 memset(&value, 0, sizeof(DBT)); 643 do { 644 ret = cursorp->get(cursorp, &key, &value, DB_NEXT); 645 switch (ret) { 646 case 0: 647 count++; 648 break; 649 case DB_NOTFOUND: 650 break; 651 default: 652 dbp->err(envp, ret, "Count records unspecified error"); 653 goto cursor_err; 654 } 655 } while (ret == 0); 656 657cursor_err: 658 if (cursorp != NULL) { 659 ret = cursorp->close(cursorp); 660 if (ret != 0) { 661 dbp->err(dbp, ret, 662 "count_records: cursor close failed."); 663 } 664 } 665 666 return (count); 667} </pre> 668 <p> 669 Finally, we provide the implementation of our 670 <tt class="function">open_db()</tt> 671 672 function. This function should hold 673 no surprises for you. Note, however, that we do specify uncommitted reads 674 when we open the database. If we did not do this, then our 675 <tt class="function">count_records()</tt> 676 677 function would cause our 678 thread to self-deadlock because the cursor could not be opened to 679 support uncommitted reads (that flag on the cursor open would, in fact, 680 be silently ignored by DB). 681 </p> 682 <pre class="programlisting">/* Open a Berkeley DB database */ 683int 684open_db(DB **dbpp, const char *progname, const char *file_name, 685 DB_ENV *envp, u_int32_t extra_flags) 686{ 687 int ret; 688 u_int32_t open_flags; 689 DB *dbp; 690 691 /* Initialize the DB handle */ 692 ret = db_create(&dbp, envp, 0); 693 if (ret != 0) { 694 fprintf(stderr, "%s: %s\n", progname, 695 db_strerror(ret)); 696 return (EXIT_FAILURE); 697 } 698 699 /* Point to the memory malloc'd by db_create() */ 700 *dbpp = dbp; 701 702 if (extra_flags != 0) { 703 ret = dbp->set_flags(dbp, extra_flags); 704 if (ret != 0) { 705 dbp->err(dbp, ret, 706 "open_db: Attempt to set extra flags failed."); 707 return (EXIT_FAILURE); 708 } 709 } 710 711 /* Now open the database */ 712 open_flags = DB_CREATE | /* Allow database creation */ 713 DB_READ_UNCOMMITTED | /* Allow uncommitted reads */ 714 DB_AUTO_COMMIT; /* Allow auto commit */ 715 716 ret = dbp->open(dbp, /* Pointer to the database */ 717 NULL, /* Txn pointer */ 718 file_name, /* File name */ 719 NULL, /* Logical db name */ 720 DB_BTREE, /* Database type (using btree) */ 721 open_flags, /* Open flags */ 722 0); /* File mode. Using defaults */ 723 if (ret != 0) { 724 dbp->err(dbp, ret, "Database '%s' open failed", 725 file_name); 726 return (EXIT_FAILURE); 727 } 728 return (EXIT_SUCCESS); 729} </pre> 730 <p> 731 This completes our transactional example. If you would like to 732 experiment with this code, you can find the example in the following 733 location in your DB distribution: 734</p> 735 <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/txn_guide</pre> 736 </div> 737 <div class="navfooter"> 738 <hr /> 739 <table width="100%" summary="Navigation footer"> 740 <tr> 741 <td width="40%" align="left"><a accesskey="p" href="wrapup.html">Prev</a> </td> 742 <td width="20%" align="center"> 743 <a accesskey="u" href="wrapup.html">Up</a> 744 </td> 745 <td width="40%" align="right"> <a accesskey="n" href="inmem_txnexample_c.html">Next</a></td> 746 </tr> 747 <tr> 748 <td width="40%" align="left" valign="top">Chapter 6. Summary and Examples </td> 749 <td width="20%" align="center"> 750 <a accesskey="h" href="index.html">Home</a> 751 </td> 752 <td width="40%" align="right" valign="top"> In-Memory Transaction Example</td> 753 </tr> 754 </table> 755 </div> 756 </body> 757</html> 758