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