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">
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" />
15 <div xmlns="" class="navheader">
17 <p>Library Version 11.2.5.3</p>
19 <table width="100%" summary="Navigation header">
21 <th colspan="3" align="center">Program Listing</th>
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>
31 <div class="sect1" lang="en" xml:lang="en">
32 <div class="titlepage">
35 <h2 class="title" style="clear: both"><a id="simpleprogramlisting"></a>Program Listing</h2>
43 <a href="simpleprogramlisting.html#repconfiginfo_cxx">
44 <span>Class: RepConfigInfo</span>
51 <a href="simpleprogramlisting.html#repmgr_cxx">Class: excxx_repquote_gsg_simple</a>
56 <a href="simpleprogramlisting.html#usage_cxx">Function: usage()</a>
61 <a href="simpleprogramlisting.html#main_cxx">Function: main()</a>
66 <a href="simpleprogramlisting.html#repmgr_init_cxx">Method: SimpleTxn::init()</a>
71 <a href="simpleprogramlisting.html#doloop_cxx">Method: SimpleTxn::doloop()</a>
76 <a href="simpleprogramlisting.html#printstocks_c">
78 <span>Method: SimpleTxn::print_stocks()</span>
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).
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
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
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
119 <div class="sect2" lang="en" xml:lang="en">
120 <div class="titlepage">
123 <h3 class="title"><a id="repconfiginfo_cxx"></a>
124 <span>Class: RepConfigInfo</span>
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
142 The class that we create is called
143 <code class="classname">RepConfigInfo</code>
145 and its only purpose at this time is to track
146 the location of our environment home directory.
148 <pre class="programlisting">#include <db_cxx.h>
150 class RepConfigInfo {
153 virtual ~RepConfigInfo();
160 RepConfigInfo::RepConfigInfo()
165 RepConfigInfo::~RepConfigInfo()
169 <div class="sect2" lang="en" xml:lang="en">
170 <div class="titlepage">
173 <h3 class="title"><a id="repmgr_cxx"></a>Class: excxx_repquote_gsg_simple</h3>
178 Our transactional example will
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
187 First, we provide some declarations and
188 definitions that are needed later in
191 <pre class="programlisting">#include <iostream>
192 #include <db_cxx.h>
193 #include "RepConfig.h"
202 #define CACHESIZE (10 * 1024 * 1024)
203 #define DATABASE "quote.db"
205 const char *progname = "excxx_reqquote_gsg_simple";
208 #define WIN32_LEAN_AND_MEAN
209 #include <windows.h>
210 #include <direct.h>
213 extern int getopt(int, char * const *, const char *);
217 #include <errno.h>
220 And then we define our <code class="classname">SimpleTxn</code> class:
222 <pre class="programlisting">class 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.
231 // terminate() provides our shutdown code.
235 // disable copy constructor.
236 SimpleTxn(const SimpleTxn &);
237 void operator = (const SimpleTxn &);
239 // internal data members.
240 RepConfigInfo *app_config;
244 // print_stocks() is used to display the contents of our database.
245 static int print_stocks(Db *dbp);
248 Note that we show the implementation of the various
249 <code class="classname">SimpleTxn</code> methods later in this section.
252 <div class="sect2" lang="en" xml:lang="en">
253 <div class="titlepage">
256 <h3 class="title"><a id="usage_cxx"></a>Function: usage()</h3>
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
267 <pre class="programlisting">static void usage()
269 cerr << "usage: " << progname << endl
270 << "-h home" << endl;
275 <div class="sect2" lang="en" xml:lang="en">
276 <div class="titlepage">
279 <h3 class="title"><a id="main_cxx"></a>Function: main()</h3>
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.
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.
298 <pre class="programlisting">int main(int argc, char **argv)
300 RepConfigInfo config;
304 Then we collect our command line information. Again, this is at
305 this point fairly trivial:
307 <pre class="programlisting"> // Extract the command line parameters
308 while ((ch = getopt(argc, argv, "h:")) != EOF) {
311 config.home = optarg;
319 // Error check command line.
320 if (config.home == NULL)
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.
328 <pre class="programlisting"> SimpleTxn runner;
330 if((ret = runner.init(&config)) != 0)
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.
337 <pre class="programlisting"> if((ret = runner.doloop()) != 0)
340 Finally, catch exceptions and terminate the program:
342 <pre class="programlisting"> } catch (DbException dbe) {
343 cerr << "Caught an exception during initialization or"
344 << " processing: " << dbe.what() << endl;
351 <div class="sect2" lang="en" xml:lang="en">
352 <div class="titlepage">
355 <h3 class="title"><a id="repmgr_init_cxx"></a>Method: SimpleTxn::init()</h3>
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.
368 First, we show the class constructor
369 implementation, which is only used to initialize a
372 <pre class="programlisting">SimpleTxn::SimpleTxn() : app_config(0), dbenv(0)
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.
382 <pre class="programlisting">int SimpleTxn::init(RepConfigInfo *config)
388 dbenv.set_errfile(stderr);
389 dbenv.set_errpfx(progname);
392 * We can now open our environment.
394 dbenv.set_cachesize(0, CACHESIZE, 0);
395 dbenv.set_flags(DB_TXN_NOSYNC, 1);
398 dbenv.open(app_config->home,
406 } catch(DbException dbe) {
407 cerr << "Caught an exception during DB environment open." << endl
408 << "Ensure that the home directory is created prior to"
409 << " starting the application." << endl;
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.
423 <pre class="programlisting">int SimpleTxn::terminate()
427 } catch (DbException dbe) {
428 cerr << "error closing environment: " << dbe.what() << endl;
433 <div class="sect2" lang="en" xml:lang="en">
434 <div class="titlepage">
437 <h3 class="title"><a id="doloop_cxx"></a>Method: SimpleTxn::doloop()</h3>
442 Having written our <code class="function">main()</code>
443 function and support utility methods, we now implement
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
452 To display the database, simply enter
453 <code class="literal">return</code> at the prompt.
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.
461 <pre class="programlisting">#define BUFSIZE 1024
462 int SimpleTxn::doloop()
466 char buf[BUFSIZE], *rbuf;
470 memset(&key, 0, sizeof(key));
471 memset(&data, 0, sizeof(data));
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
485 Autocommit is described in greater detail in the
486 <em class="citetitle">Berkeley DB Getting Started with Transaction Processing</em> guide.
488 <pre class="programlisting"> for (;;) {
490 dbp = new Db(&dbenv, 0);
493 dbp->open(NULL, DATABASE, NULL, DB_BTREE,
494 DB_CREATE | DB_AUTO_COMMIT, 0);
495 } catch(DbException dbe) {
496 dbenv.err(ret, "DB->open");
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.)
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.
522 <pre class="programlisting"> cout << "QUOTESERVER" ;
523 cout << "> " << flush;
525 if (fgets(buf, sizeof(buf), stdin) == NULL)
527 if (strtok(&buf[0], " \t\n") == NULL) {
528 switch ((ret = print_stocks(dbp))) {
532 dbp->err(ret, "Error traversing data");
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)
541 dbenv.errx("Format: TICKER VALUE");
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.
548 <pre class="programlisting"> key.set_data(buf);
549 key.set_size((u_int32_t)strlen(buf));
552 data.set_size((u_int32_t)strlen(rbuf)); </pre>
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
563 <pre class="programlisting"> if ((ret = dbp->put(NULL, &key, &data, 0)) != 0)
565 dbp->err(ret, "DB->put");
566 if (ret != DB_KEYEXIST)
571 Finally, we close our database before returning from the
574 <pre class="programlisting">err: if (dbp != NULL) {
575 (void)dbp->close(DB_NOSYNC);
576 cout << "database closed" << endl;
582 <div class="sect2" lang="en" xml:lang="en">
583 <div class="titlepage">
586 <h3 class="title"><a id="printstocks_c"></a>
588 <span>Method: SimpleTxn::print_stocks()</span>
595 The <code class="function">print_stocks()</code>
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.
606 If you are unfamiliar with basic cursor operations,
607 please see the <em class="citetitle">Getting Started with Berkeley DB</em>
610 <pre class="programlisting">int SimpleTxn::print_stocks(Db *dbp)
614 #define MAXKEYSIZE 10
615 #define MAXDATASIZE 20
616 char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1];
618 u_int32_t keysize, datasize;
620 if ((ret = dbp->cursor(NULL, &dbc, 0)) != 0) {
621 dbp->err(ret, "can't open cursor");
625 memset(&key, 0, sizeof(key));
626 memset(&data, 0, sizeof(data));
628 cout << "\tSymbol\tPrice" << endl
629 << "\t======\t=====" << endl;
631 for (ret = dbc->get(&key, &data, DB_FIRST);
633 ret = dbc->get(&key, &data, DB_NEXT)) {
634 keysize = key.get_size() > MAXKEYSIZE ? MAXKEYSIZE :
636 memcpy(keybuf, key.get_data(), keysize);
637 keybuf[keysize] = '\0';
639 datasize = data.get_size() >=
640 MAXDATASIZE ? MAXDATASIZE : data.get_size();
641 memcpy(databuf, data.get_data(), datasize);
642 databuf[datasize] = '\0';
644 cout << "\t" << keybuf << "\t" << databuf << endl;
646 cout << endl << flush;
648 if ((t_ret = dbc->close()) != 0 && ret == 0) {
649 cout << "closed cursor" << endl;
663 <div class="navfooter">
665 <table width="100%" summary="Navigation footer">
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>
671 <td width="40%" align="right"> <a accesskey="n" href="repapp.html">Next</a></td>
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>
678 <td width="40%" align="right" valign="top"> Chapter 3. The DB Replication Manager</td>