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