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