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="repconfiginfo_cxx"></a>
76                            <span>Class: RepConfigInfo</span>
77                            
78                    </h3>
79            </div>
80          </div>
81          <div></div>
82        </div>
83        <p>
84                            Before we begin, we present a 
85                            class that we will use to maintain useful
86                            information for us. Under normal circumstances,
87                            this class would not be necessary for a simple
88                            transactional example such as this. However, this code will
89                            grow into a replicated example that needs to
90                            track a lot more information for the
91                            application, and so we lay the groundwork for
92                            it here.
93                    </p>
94        <p>
95                            The class that we create is called
96                            <tt class="classname">RepConfigInfo</tt>
97                            
98                            and its only purpose at this time is to track
99                            the location of our environment home directory.
100                    </p>
101        <pre class="programlisting">#include &lt;db_cxx.h&gt;
102#include &lt;iostream&gt;
103
104class RepConfigInfo {
105public:
106    RepConfigInfo();
107    virtual ~RepConfigInfo();
108
109public:
110    char* home;
111};
112
113
114RepConfigInfo::RepConfigInfo()
115{
116    home = "TESTDIR";
117}
118
119RepConfigInfo::~RepConfigInfo()
120{
121}  </pre>
122      </div>
123      <div class="sect2" lang="en" xml:lang="en">
124        <div class="titlepage">
125          <div>
126            <div>
127              <h3 class="title"><a id="repmgr_cxx"></a>Class: RepMgr</h3>
128            </div>
129          </div>
130          <div></div>
131        </div>
132        <p>
133                            Our transactional example will 
134                            instantiate a class,
135                            <tt class="classname">RepMgr</tt>, that performs
136                            all our work for us. Before we implement our
137                            <tt class="function">main()</tt> function, we show
138                            the <tt class="classname">RepMgr</tt> class
139                            declaration.
140                    </p>
141        <p>
142                            First, we provide some declarations and
143                            definitions that are needed later in
144                            our example:
145                    </p>
146        <pre class="programlisting">using std::cout;
147using std::cin;
148using std::cerr;
149using std::endl;
150using std::flush;
151
152#define CACHESIZE   (10 * 1024 * 1024)
153#define DATABASE    "quote.db"
154
155const char *progname = "SimpleTxn";  </pre>
156        <p>
157        And then we define our <tt class="classname">RepMgr</tt> class:
158</p>
159        <pre class="programlisting">class RepMgr
160{
161public:
162    // Constructor.
163    RepMgr();
164    // Initialization method. Creates and opens our environment handle.
165    int init(RepConfigInfo* config);
166    // The doloop is where all the work is performed.
167    int doloop();
168    // terminate() provides our shutdown code.
169    int terminate();
170
171private:
172    // disable copy constructor.
173    RepMgr(const RepMgr &amp;);
174    void operator = (const RepMgr &amp;);
175
176    // internal data members.
177    RepConfigInfo   *app_config;
178    DbEnv           dbenv;
179
180    // private methods.
181    // print_stocks() is used to display the contents of our database.
182    static int print_stocks(Db *dbp);
183};  </pre>
184        <p>
185            Note that we show the implementation of the various
186            <tt class="classname">RepMgr</tt> methods later in this section.
187    </p>
188      </div>
189      <div class="sect2" lang="en" xml:lang="en">
190        <div class="titlepage">
191          <div>
192            <div>
193              <h3 class="title"><a id="usage_cxx"></a>Function: usage()</h3>
194            </div>
195          </div>
196          <div></div>
197        </div>
198        <p>
199                            Our <tt class="function">usage()</tt> is at this
200                            stage of development trivial because we only
201                            have one command line argument to manage.
202                            Still, we show it here for the sake of
203                            completeness.
204                    </p>
205        <pre class="programlisting">static void usage()
206{
207    cerr &lt;&lt; "usage: " &lt;&lt; progname &lt;&lt; endl
208         &lt;&lt; "-h home" &lt;&lt; endl;
209
210    exit(EXIT_FAILURE);
211}  </pre>
212      </div>
213      <div class="sect2" lang="en" xml:lang="en">
214        <div class="titlepage">
215          <div>
216            <div>
217              <h3 class="title"><a id="main_cxx"></a>Function: main()</h3>
218            </div>
219          </div>
220          <div></div>
221        </div>
222        <p>
223                            Now we provide our <tt class="function">main()</tt>
224                            function. This is a trivial function whose only
225                            job is to collect command line information,
226                            then instantiate a <tt class="classname">RepMgr</tt>
227                            object, run it, then terminate it.
228                    </p>
229        <p>
230                            We begin by declaring some useful variables. Of
231                            these, note that we instantiate our
232                            <tt class="classname">RepConfigInfo</tt>
233                            object here. Recall that this is used to store
234                            information useful to our code. This class becomes more
235                            interesting later in this book.
236                    </p>
237        <pre class="programlisting">int main(int argc, char **argv)
238{
239    RepConfigInfo config;
240    char ch;
241    int ret;  </pre>
242        <p>
243            Then we collect our command line information. Again, this is at
244            this point fairly trivial:
245    </p>
246        <pre class="programlisting">    // Extract the command line parameters
247    while ((ch = getopt(argc, argv, "h:")) != EOF) {
248        switch (ch) {
249        case 'h':
250            config.home = optarg;
251            break;
252        case '?':
253        default:
254            usage();
255        }
256    }
257
258    // Error check command line.
259    if (config.home == NULL)
260        usage();  </pre>
261        <p>
262        Now we instantiate and initialize our <tt class="classname">RepMgr</tt>
263        class, which is what is responsible for doing all our real work.
264        The <tt class="methodname">RepMgr::init()</tt> method creates and
265        opens our environment handle.
266</p>
267        <pre class="programlisting">    RepMgr runner;
268    try {
269        if((ret = runner.init(&amp;config)) != 0)
270            goto err;  </pre>
271        <p>
272            Then we call the <tt class="methodname">RepMgr::doloop()</tt>
273            method, which is where the actual transactional work is
274            performed for this application.
275    </p>
276        <pre class="programlisting">        if((ret = runner.doloop()) != 0)
277            goto err;  </pre>
278        <p>
279                Finally, catch exceptions and terminate the program:
280        </p>
281        <pre class="programlisting">    } catch (DbException dbe) {
282        cerr &lt;&lt; "Caught an exception during initialization or"
283            &lt;&lt; " processing: " &lt;&lt; dbe.what() &lt;&lt; endl;
284    }
285err:
286    runner.terminate();
287    return 0;
288}  </pre>
289      </div>
290      <div class="sect2" lang="en" xml:lang="en">
291        <div class="titlepage">
292          <div>
293            <div>
294              <h3 class="title"><a id="repmgr_init_cxx"></a>Method: RepMgr::init()</h3>
295            </div>
296          </div>
297          <div></div>
298        </div>
299        <p>
300                        The <tt class="methodname">RepMgr::init()</tt>
301                        method is used to create and open our environment handle.
302                        For readers familiar with writing transactional
303                        DB applications, there should be no surprises
304                        here. However, we will be adding to this in later
305                        chapters as we roll replication into this example.
306                </p>
307        <p>
308                        First, we show the class constructor
309                        implementation, which is only used to initialize a
310                        few variables:
311                </p>
312        <pre class="programlisting">RepMgr::RepMgr() : app_config(0), dbenv(0)
313{
314}  </pre>
315        <p>
316        We now provide the <tt class="methodname">init()</tt> method
317        implementation. The only thing of interest here is that we specify
318        <tt class="literal">DB_TXN_NOSYNC</tt> to our environment. This causes
319        our transactional commits to become non-durable, which is something
320        that we are doing only because of the nature of our example.
321</p>
322        <pre class="programlisting">int RepMgr::init(RepConfigInfo *config)
323{
324    int ret = 0;
325
326    app_config = config;
327
328    dbenv.set_errfile(stderr);
329    dbenv.set_errpfx(progname);
330
331    /*
332     * We can now open our environment.
333     */
334    dbenv.set_cachesize(0, CACHESIZE, 0);
335    dbenv.set_flags(DB_TXN_NOSYNC, 1);
336
337    try {
338        dbenv.open(app_config-&gt;home, 
339            DB_CREATE | 
340            DB_RECOVER |
341            DB_INIT_LOCK | 
342            DB_INIT_LOG |
343            DB_INIT_MPOOL | 
344            DB_INIT_TXN, 
345            0);
346    } catch(DbException dbe) {
347        cerr &lt;&lt; "Caught an exception during DB environment open." &lt;&lt; endl
348            &lt;&lt; "Ensure that the home directory is created prior to starting"
349            &lt;&lt; " the application." &lt;&lt; endl;
350        ret = ENOENT;
351        goto err;
352    }
353
354err:
355    return ret;
356}  </pre>
357        <p>
358        Finally, we present the <tt class="methodname">RepMgr::terminate()</tt>
359        method here. All this does is close the environment handle. Again,
360        there should be no surprises here, but we provide the
361        implementation for the sake of completeness anyway.
362</p>
363        <pre class="programlisting">int RepMgr::terminate()
364{
365    try {
366        dbenv.close(0);
367    } catch (DbException dbe) {
368        cerr &lt;&lt; "error closing environment: " &lt;&lt; dbe.what() &lt;&lt; endl;
369    }
370    return 0;
371}  </pre>
372      </div>
373      <div class="sect2" lang="en" xml:lang="en">
374        <div class="titlepage">
375          <div>
376            <div>
377              <h3 class="title"><a id="doloop_cxx"></a>Method: RepMgr::doloop()</h3>
378            </div>
379          </div>
380          <div></div>
381        </div>
382        <p>
383                        Having written our <tt class="function">main()</tt>
384                        function and support utility methods, we now implement 
385                        our application's
386                        primary data processing method. This
387                        method provides a command prompt at which the
388                        user can enter a stock ticker value and a price for
389                        that value. This information is then entered to the
390                        database.
391                    </p>
392        <p>
393                            To display the database, simply enter
394                            <tt class="literal">return</tt> at the prompt.
395                    </p>
396        <p>
397                        To begin, we declare a database pointer,
398                        several <tt class="classname">Dbt</tt> variables, and
399                        the usual assortment of variables used for buffers
400                        and return codes. We also initialize all of this.
401                    </p>
402        <pre class="programlisting">#define BUFSIZE 1024
403int RepMgr::doloop()
404{
405    Db *dbp;
406    Dbt key, data;
407    char buf[BUFSIZE], *rbuf;
408    int ret;
409
410    dbp = NULL;
411    memset(&amp;key, 0, sizeof(key));
412    memset(&amp;data, 0, sizeof(data));
413    ret = 0;  </pre>
414        <p>
415                    Next, we begin the loop and we immediately open our
416                    database if it has not already been opened. Notice that
417                    we specify autocommit when we open the database. In
418                    this case, autocommit is important because we will only
419                    ever write to our database using it. There is no need
420                    for explicit transaction handles and commit/abort code
421                    in this application, because we are not combining
422                    multiple database operations together under a single
423                    transaction.
424                </p>
425        <p>
426                    Autocommit is described in greater detail in the 
427                    <i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide.
428                </p>
429        <pre class="programlisting">    for (;;) {
430        if (dbp == NULL) {
431            dbp = new Db(&amp;dbenv, 0);
432
433            // Set page size small so page allocation is cheap.
434            if ((ret = dbp-&gt;set_pagesize(512)) != 0)
435                goto err;
436
437            try {
438                dbp-&gt;open(NULL, DATABASE, NULL, DB_BTREE,
439                    DB_CREATE | DB_AUTO_COMMIT, 0);
440            } catch(DbException dbe) {
441                dbenv.err(ret, "DB-&gt;open");
442                throw dbe;
443            }
444        }  </pre>
445        <p>
446            Now we implement our command prompt. This is a simple and not
447            very robust implementation of a command prompt.
448            If the user enters the keywords <tt class="literal">exit</tt>
449            or <tt class="literal">quit</tt>, the loop is exited and the
450            application ends. If the user enters nothing and instead simply
451            presses <tt class="literal">return</tt>, the entire contents of the
452            database is displayed. We use our
453            <tt class="function">print_stocks()</tt> method to display the
454            database. (That implementation is shown next in this chapter.)
455        </p>
456        <p>
457           Notice that very little error checking is performed on the data
458           entered at this prompt.  If the user fails to enter at least one 
459            space in the value string, a simple help message is printed and
460            the prompt is returned to the user. That is the only error
461            checking performed here. In a real-world application,
462            at a minimum the application would probably check to ensure
463            that the price was in fact an integer or float value. 
464            However, in order to keep this example code as simple as
465            possible, we refrain from implementing a thorough user interface.
466        </p>
467        <pre class="programlisting">        cout &lt;&lt; "QUOTESERVER" ;
468        cout &lt;&lt; "&gt; " &lt;&lt; flush;
469
470        if (fgets(buf, sizeof(buf), stdin) == NULL)
471            break;
472        if (strtok(&amp;buf[0], " \t\n") == NULL) {
473            switch ((ret = print_stocks(dbp))) {
474            case 0:
475                continue;
476            default:
477                dbp-&gt;err(ret, "Error traversing data");
478                goto err;
479            }
480        }
481        rbuf = strtok(NULL, " \t\n");
482        if (rbuf == NULL || rbuf[0] == '\0') {
483            if (strncmp(buf, "exit", 4) == 0 ||
484                strncmp(buf, "quit", 4) == 0)
485                break;
486            dbenv.errx("Format: TICKER VALUE");
487            continue;
488        }  </pre>
489        <p>
490                Now we assign data to the <tt class="classname">Dbt</tt>s that
491                we will use to write the new information to the database.
492            </p>
493        <pre class="programlisting">        key.set_data(buf);
494        key.set_size((u_int32_t)strlen(buf));
495
496        data.set_data(rbuf);
497        data.set_size((u_int32_t)strlen(rbuf));  </pre>
498        <p>
499                Having done that, we can write the new information to the
500                database. Remember that this application uses autocommit,
501                so no explicit transaction management is required. Also,
502                the database is not configured for duplicate records, so
503                the data portion of a record is overwritten if the provided
504                key already exists in the database. However, in this case
505                DB returns <tt class="literal">DB_KEYEXIST</tt> — which
506                we ignore.
507            </p>
508        <pre class="programlisting">        if ((ret = dbp-&gt;put(NULL, &amp;key, &amp;data, 0)) != 0)
509        {
510            dbp-&gt;err(ret, "DB-&gt;put");
511            if (ret != DB_KEYEXIST)
512                goto err;
513        }
514    }  </pre>
515        <p>
516            Finally, we close our database before returning from the
517            method.
518        </p>
519        <pre class="programlisting">err:    if (dbp != NULL) {
520        (void)dbp-&gt;close(DB_NOSYNC);
521        cout &lt;&lt; "database closed" &lt;&lt; endl;
522        }
523
524    return (ret);
525}  </pre>
526      </div>
527      <div class="sect2" lang="en" xml:lang="en">
528        <div class="titlepage">
529          <div>
530            <div>
531              <h3 class="title"><a id="printstocks_c"></a>
532                            
533                            <span>Method: RepMgr::print_stocks()</span>
534                            
535                    </h3>
536            </div>
537          </div>
538          <div></div>
539        </div>
540        <p>
541                        The <tt class="function">print_stocks()</tt> 
542                          
543                        
544                        <span>method</span>
545                        simply takes a database handle, opens a cursor, and uses 
546                        it to display all the information it finds in a database.
547                        This is trivial cursor operation that should hold
548                        no surprises for you. We simply provide it here for
549                        the sake of completeness.
550                    </p>
551        <p>
552                        If you are unfamiliar with basic cursor operations,
553                        please see the <i class="citetitle">Getting Started with Berkeley DB</i>
554                        guide.
555                    </p>
556        <pre class="programlisting">int RepMgr::print_stocks(Db *dbp)
557{
558    Dbc *dbc;
559    Dbt key, data;
560#define MAXKEYSIZE  10
561#define MAXDATASIZE 20
562    char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1];
563    int ret, t_ret;
564    u_int32_t keysize, datasize;
565
566    if ((ret = dbp-&gt;cursor(NULL, &amp;dbc, 0)) != 0) {
567        dbp-&gt;err(ret, "can't open cursor");
568        return (ret);
569    }
570
571    memset(&amp;key, 0, sizeof(key));
572    memset(&amp;data, 0, sizeof(data));
573
574    cout &lt;&lt; "\tSymbol\tPrice" &lt;&lt; endl
575        &lt;&lt; "\t======\t=====" &lt;&lt; endl;
576
577    for (ret = dbc-&gt;get(&amp;key, &amp;data, DB_FIRST);
578        ret == 0;
579        ret = dbc-&gt;get(&amp;key, &amp;data, DB_NEXT)) {
580        keysize = key.get_size() &gt; MAXKEYSIZE ? MAXKEYSIZE : key.get_size();
581        memcpy(keybuf, key.get_data(), keysize);
582        keybuf[keysize] = '\0';
583
584        datasize = data.get_size() &gt;=
585            MAXDATASIZE ? MAXDATASIZE : data.get_size();
586        memcpy(databuf, data.get_data(), datasize);
587        databuf[datasize] = '\0';
588
589        cout &lt;&lt; "\t" &lt;&lt; keybuf &lt;&lt; "\t" &lt;&lt; databuf &lt;&lt; endl;
590    }
591    cout &lt;&lt; endl &lt;&lt; flush;
592
593    if ((t_ret = dbc-&gt;close()) != 0 &amp;&amp; ret == 0) {
594        cout &lt;&lt; "closed cursor" &lt;&lt; endl;
595        ret = t_ret;
596    }
597
598    switch (ret) {
599    case 0:
600    case DB_NOTFOUND:
601        return (0);
602    default:
603        return (ret);
604    }
605}  </pre>
606      </div>
607    </div>
608    <div class="navfooter">
609      <hr />
610      <table width="100%" summary="Navigation footer">
611        <tr>
612          <td width="40%" align="left"><a accesskey="p" href="txnapp.html">Prev</a> </td>
613          <td width="20%" align="center">
614            <a accesskey="u" href="txnapp.html">Up</a>
615          </td>
616          <td width="40%" align="right"> <a accesskey="n" href="repapp.html">Next</a></td>
617        </tr>
618        <tr>
619          <td width="40%" align="left" valign="top">Chapter 2. Transactional Application </td>
620          <td width="20%" align="center">
621            <a accesskey="h" href="index.html">Home</a>
622          </td>
623          <td width="40%" align="right" valign="top"> Chapter 3. The DB Replication Framework</td>
624        </tr>
625      </table>
626    </div>
627  </body>
628</html>
629