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