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