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