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 &lt;stdio.h&gt;
72#include &lt;stdlib.h&gt;
73#include &lt;string.h&gt;
74#include &lt;pthread.h&gt;
75#include &lt;db.h&gt;
76
77#ifdef _WIN32
78extern int getopt(int, char * const *, const char *);
79#else
80#include &lt;unistd.h&gt;
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 &lt;database_home_directory&gt;]\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(&amp;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-&gt;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-&gt;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(&amp;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(&amp;thread_num_lock, NULL);
276
277    /* Start the writer threads. */
278    for (i = 0; i &lt; NUMWRITERS; i++)
279        (void)pthread_create(&amp;writer_threads[i], NULL, 
280            writer_thread, (void *)dbp);
281
282    /* Join the writers */
283    for (i = 0; i &lt; 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-&gt;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-&gt;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-&gt;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(&amp;thread_num_lock);
361    global_thread_num++;
362    thread_num = global_thread_num;
363    (void)pthread_mutex_unlock(&amp;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 &lt; 50; i++) {
410        retry_count = 0; /* Used for deadlock retries */
411
412retry:
413        /* Begin our transaction. */
414        ret = envp-&gt;txn_begin(envp, NULL, &amp;txn, 0);
415        if (ret != 0) {
416            envp-&gt;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 &lt; 10; j++) {
428            /* Set up our key and values DBTs */
429            memset(&amp;key, 0, sizeof(DBT));
430            key.data = key_strings[j];
431            key.size = (strlen(key_strings[j]) + 1) * sizeof(char);
432
433            memset(&amp;value, 0, sizeof(DBT));
434            payload = rand() + i;
435            value.data = &amp;payload;
436            value.size = sizeof(int);
437
438            /* Perform the database put. */
439            switch (ret = dbp-&gt;put(dbp, txn, &amp;key, &amp;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-&gt;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 &lt; 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-&gt;err(envp, ret, "db put failed");
492                    ret = txn-&gt;abort(txn);
493                    if (ret != 0)
494                        envp-&gt;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-&gt;commit(txn, 0);
527        if (ret != 0) {
528            envp-&gt;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-&gt;stat() or DB-&gt;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-&gt;cursor(dbp, txn, &amp;cursorp, DB_READ_UNCOMMITTED);
635    if (ret != 0) {
636        dbp-&gt;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(&amp;key, 0, sizeof(DBT));
642    memset(&amp;value, 0, sizeof(DBT));
643    do {
644        ret = cursorp-&gt;get(cursorp, &amp;key, &amp;value, DB_NEXT);
645        switch (ret) {
646            case 0:
647                count++;
648                break;
649            case DB_NOTFOUND:
650                break;
651            default:
652                dbp-&gt;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-&gt;close(cursorp);
660        if (ret != 0) {
661            dbp-&gt;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(&amp;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-&gt;set_flags(dbp, extra_flags);
704        if (ret != 0) {
705            dbp-&gt;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-&gt;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-&gt;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