• 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>Adding the Replication Manager to RepMgr</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="repapp.html" title="Chapter��3.��The DB Replication Manager" />
11    <link rel="prev" href="repapp.html" title="Chapter��3.��The DB Replication Manager" />
12    <link rel="next" href="fwrkpermmessage.html" title="Permanent Message Handling" />
13  </head>
14  <body>
15    <div class="navheader">
16      <table width="100%" summary="Navigation header">
17        <tr>
18          <th colspan="3" align="center">Adding the Replication Manager to
19                    
20                    <span>RepMgr</span>
21                    
22            </th>
23        </tr>
24        <tr>
25          <td width="20%" align="left"><a accesskey="p" href="repapp.html">Prev</a>��</td>
26          <th width="60%" align="center">Chapter��3.��The DB Replication Manager</th>
27          <td width="20%" align="right">��<a accesskey="n" href="fwrkpermmessage.html">Next</a></td>
28        </tr>
29      </table>
30      <hr />
31    </div>
32    <div class="sect1" lang="en" xml:lang="en">
33      <div class="titlepage">
34        <div>
35          <div>
36            <h2 class="title" style="clear: both"><a id="repmgr_init_example_c"></a>Adding the Replication Manager to
37                    
38                    <span>RepMgr</span>
39                    
40            </h2>
41          </div>
42        </div>
43      </div>
44      <p>
45                    We now use the methods described above to add partial
46                    support to the 
47                    
48                    <span>RepMgr</span>
49                    
50                    example that we presented in 
51                    <a class="xref" href="txnapp.html" title="Chapter��2.��Transactional Application">Transactional Application</a>.
52                    That is, in this section we will:
53            </p>
54      <div class="itemizedlist">
55        <ul type="disc">
56          <li>
57            <p>
58                                    Enhance our command line options to
59                                    accept information of interest to a
60                                    replicated application.
61                            </p>
62          </li>
63          <li>
64            <p>
65                                    Configure our environment handle to use
66                                    replication and the Replication Manager.
67                            </p>
68          </li>
69          <li>
70            <p>
71                                    Minimally configure the Replication Manager.
72                            </p>
73          </li>
74          <li>
75            <p>
76                                    Start replication.
77                            </p>
78          </li>
79        </ul>
80      </div>
81      <p>
82                Note that when we are done with this section, we will be
83                only partially ready to run the application. Some critical
84                pieces will be missing; specifically, we will not yet be
85                handling the differences between a master and a
86                replica. (We do that in the next chapter).
87            </p>
88      <p>
89                Also, note that in the following code fragments, additions
90                and changes to the code are marked in <strong class="userinput"><code>bold</code></strong>.
91            </p>
92      <p>
93                    To begin, we copy the 
94                    
95                    <span>SimpleTxn</span>
96                    code to a new file called
97                    <code class="literal">RepMgrGSG.cpp</code>.
98
99                    
100
101                    <span>
102                            Having done that, we must make some significant
103                            changes to our 
104                            <code class="classname">RepConfigInfo</code>
105                            class because now we will be using it to
106                            maintain a lot more information.
107                    </span>
108            </p>
109      <p>
110                First, we create a new structure,
111                <code class="literal">RepHostInfoObj</code>, which we use to store
112                host and port information for all "other" servers
113                identified to the application via the
114                <code class="literal">-o</code> command line option. This structure
115                is chain-able, which makes cleaning up at program shutdown
116                time easier.
117            </p>
118      <pre class="programlisting">#include &lt;db_cxx.h&gt;
119#include &lt;iostream&gt;
120
121<strong class="userinput"><code>// Chain-able struct used to store host information.
122typedef struct RepHostInfoObj{
123    char* host;
124    u_int16_t port;
125    RepHostInfoObj* next; // used for chaining multiple "other" hosts.
126} REP_HOST_INFO; </code></strong></pre>
127      <p>
128        Next, we update our <code class="classname">RepConfigInfo</code> class
129        definition to manage a lot more information and a new method.
130</p>
131      <pre class="programlisting">class RepConfigInfo {
132public:
133    RepConfigInfo();
134    virtual ~RepConfigInfo();
135
136    <strong class="userinput"><code>void addOtherHost(char* host, int port);</code></strong>
137public:
138    <strong class="userinput"><code>u_int32_t start_policy;</code></strong>
139    char* home;
140    <strong class="userinput"><code>bool got_listen_address;
141    REP_HOST_INFO this_host;
142    int totalsites;
143    int priority;
144    // used to store a set of optional other hosts.
145    REP_HOST_INFO *other_hosts;</code></strong>
146}; </pre>
147      <p>
148        Then, we update our constructor to initialize our new variables.
149</p>
150      <pre class="programlisting">RepConfigInfo::RepConfigInfo()
151{
152    <strong class="userinput"><code>start_policy = DB_REP_ELECTION;</code></strong>
153    home = "TESTDIR";
154    <strong class="userinput"><code>got_listen_address = false;
155    totalsites = 0;
156    priority = 100;
157    other_hosts = NULL;</code></strong>
158} </pre>
159      <p>
160        Next, we implement our new method, <code class="methodname">RepConfigInfo::addOtherHost</code>,
161        which is used to create <code class="literal">RepHostInfoObj</code> instances and add them to
162        the chain of "other" hosts.
163</p>
164      <pre class="programlisting">RepConfigInfo::addOtherHost(char* host, int port)
165{
166    REP_HOST_INFO *newinfo;
167    newinfo = (REP_HOST_INFO*)malloc(sizeof(REP_HOST_INFO));
168    newinfo-&gt;host = host;
169    newinfo-&gt;port = port;
170    if (other_hosts == NULL) {
171        other_hosts = newinfo;
172        newinfo-&gt;next = NULL;
173    } else {
174        newinfo-&gt;next = other_hosts;
175        other_hosts = newinfo;
176    }
177}</pre>
178      <p>
179        Having done that, we update our class destructor to release the <code class="literal">RepHostInfoObj</code>
180        chain of objects at class destruction time.
181</p>
182      <pre class="programlisting">RepConfigInfo::~RepConfigInfo()
183{
184    <strong class="userinput"><code>// release any other_hosts structs.
185    if (other_hosts != NULL) {
186        REP_HOST_INFO *CurItem = other_hosts;
187        while (CurItem-&gt;next != NULL)
188        {
189            REP_HOST_INFO *TmpItem = CurItem;
190            free(CurItem);
191            CurItem = TmpItem;
192        }
193        free(CurItem);
194    }
195    other_hosts = NULL;</code></strong>
196} </pre>
197      <p>
198        Having completed our update to the
199        <code class="classname">RepConfigInfo</code> 
200         
201        class, we can now start making
202        changes to the main portion of our program. We begin by changing
203        the program's name. 
204</p>
205      <pre class="programlisting">using std::cout;
206using std::cin;
207using std::cerr;
208using std::endl;
209using std::flush;
210                
211#define CACHESIZE   (10 * 1024 * 1024)
212#define DATABASE    "quote.db"
213                
214<strong class="userinput"><code>const char *progname = "RepMgrGSG";</code></strong> </pre>
215      <p>
216        Next we update our usage function. The application will continue to
217        accept the <code class="literal">-h</code> parameter so that we can identify
218        the environment home directory used by this application. However,
219        we also add the 
220</p>
221      <div class="itemizedlist">
222        <ul type="disc">
223          <li>
224            <p>
225                    <code class="literal">-l</code> parameter which allows us to
226                    identify the host and port used by this application to
227                    listen for replication messages.
228                </p>
229          </li>
230          <li>
231            <p>
232                        <code class="literal">-r</code> parameter which allows us to
233                        specify other replicas.
234                </p>
235          </li>
236          <li>
237            <p>
238                        <code class="literal">-n</code> parameter which allows us to
239                        identify the number of sites in this replication
240                        group.
241                </p>
242          </li>
243          <li>
244            <p>
245                    <code class="literal">-p</code> option, which is used to identify
246                    this replica's priority (recall that the priority is
247                    used as a tie breaker for elections)
248                </p>
249          </li>
250        </ul>
251      </div>
252      <pre class="programlisting">class RepMgrGSG
253{
254public:
255    // Constructor.
256    RepMgrGSG();
257    // Initialization method. Creates and opens our environment handle.
258    int init(RepConfigInfo* config);
259    // The doloop is where all the work is performed.
260    int doloop();
261    // terminate() provides our shutdown code.
262    int terminate();
263
264private:
265    // disable copy constructor.
266    RepMgrGSG(const RepMgrGSG &amp;);
267    void operator = (const RepMgrGSG &amp;);
268
269    // internal data members.
270    RepConfigInfo   *app_config;
271    DbEnv           dbenv;
272
273    // private methods.
274    // print_stocks() is used to display the contents of our database.
275    static int print_stocks(Db *dbp);
276};
277
278static void usage()
279{
280    cerr &lt;&lt; "usage: " &lt;&lt; progname &lt;&lt; endl
281         &lt;&lt; "-h home<strong class="userinput"><code>[-r host:port][-l host:port]</code></strong>"
282         <strong class="userinput"><code>&lt;&lt; "[-n nsites][-p priority]" &lt;&lt; endl;</code></strong>
283
284    cerr <strong class="userinput"><code>&lt;&lt; "\t -l host:port (required; l stands for local)" &lt;&lt; endl
285         &lt;&lt; "\t -r host:port (optional; r stands for replica; any "
286         &lt;&lt; "number of these may be specified)" &lt;&lt; endl</code></strong>
287         &lt;&lt; "\t -h home directory" &lt;&lt; endl
288         <strong class="userinput"><code>&lt;&lt; "\t -n nsites (optional; number of sites in replication "
289         &lt;&lt; "group; defaults to 0" &lt;&lt; endl
290         &lt;&lt; "\t  in which case we try to dynamically compute the "
291         &lt;&lt; "number of sites in" &lt;&lt; endl
292         &lt;&lt; "\t  the replication group)" &lt;&lt; endl
293         &lt;&lt; "\t -p priority (optional: defaults to 100)" &lt;&lt; endl;</code></strong>
294
295    exit(EXIT_FAILURE);
296} </pre>
297      <p>
298        Now we can begin working on our <code class="literal">main()</code> function.
299        We begin by adding a couple of variables that we will use to
300        collect TCP/IP host and port information. 
301
302
303        
304</p>
305      <pre class="programlisting">int main(int argc, char **argv)
306{
307    RepConfigInfo config;
308    char ch<strong class="userinput"><code>, *portstr, *tmphost;
309    int tmpport;</code></strong>
310    int ret; </pre>
311      <p>
312        Now we collect our command line arguments. As we do so, we will
313        configure host and port information as required, and we will
314        configure the application's election priority if necessary.
315</p>
316      <pre class="programlisting">    // Extract the command line parameters
317    while ((ch = getopt(argc, argv, "h:<strong class="userinput"><code>l:n:p:r:</code></strong>")) != EOF) {
318        switch (ch) {
319        case 'h':
320            config.home = optarg;
321            break;
322        <strong class="userinput"><code>case 'l':
323            config.this_host.host = strtok(optarg, ":");
324            if ((portstr = strtok(NULL, ":")) == NULL) {
325                cerr &lt;&lt; "Bad host specification." &lt;&lt; endl;
326                usage();
327            }
328            config.this_host.port = (unsigned short)atoi(portstr);
329            config.got_listen_address = true;
330            break;
331        case 'n':
332            config.totalsites = atoi(optarg);
333            break;
334        case 'p':
335            config.priority = atoi(optarg);
336            break;
337        case 'r':
338            tmphost = strtok(optarg, ":");
339            if ((portstr = strtok(NULL, ":")) == NULL) {
340                cerr &lt;&lt; "Bad host specification." &lt;&lt; endl;
341                usage();
342            }
343            tmpport = (unsigned short)atoi(portstr);
344            config.addOtherHost(tmphost, tmpport);
345            break;</code></strong>
346        case '?':
347        default:
348            usage();
349        }
350    }
351
352    // Error check command line.
353    if ((!config.got_listen_address) || config.home == NULL)
354        usage(); </pre>
355      <p>
356        Having done that, the remainder of our <code class="function">main()</code>
357        function is left unchanged:
358</p>
359      <pre class="programlisting">    RepMgrGSG runner;
360    try {
361        if((ret = runner.init(&amp;config)) != 0)
362            goto err;
363        if((ret = runner.doloop()) != 0)
364            goto err;
365    } catch (DbException dbe) {
366        cerr &lt;&lt; "Caught an exception during initialization or"
367            &lt;&lt; " processing: " &lt;&lt; dbe.what() &lt;&lt; endl;
368    }
369err:
370    runner.terminate();
371    return 0;
372}  </pre>
373      <p>
374        Now we need to update our 
375            <code class="methodname">RepMgrGSG::init()</code>
376            
377        method. Our updates are at first related to configuring
378        replication. First, we need to update the method so that we can 
379        identify the local site to the environment handle (that is, the site identified by the 
380<code class="literal">-l</code> command line option):
381</p>
382      <pre class="programlisting">RepMgrGSG::RepMgrGSG() : app_config(0), dbenv(0)
383{
384}
385
386int RepMgrGSG::init(RepConfigInfo *config)
387{
388    int ret = 0;
389
390    app_config = config;
391
392    dbenv.set_errfile(stderr);
393    dbenv.set_errpfx(progname);
394
395    <strong class="userinput"><code>if ((ret = dbenv.repmgr_set_local_site(app_config-&gt;this_host.host,
396        app_config-&gt;this_host.port, 0)) != 0) {
397        cerr &lt;&lt; "Could not set listen address to host:port "
398             &lt;&lt; app_config-&gt;this_host.host &lt;&lt; ":"
399             &lt;&lt; app_config-&gt;this_host.port
400             &lt;&lt; "error: " &lt;&lt; ret &lt;&lt; endl;
401    }</code></strong> </pre>
402      <p>
403    And we also add code to allow us to identify "other" sites to the environment handle (that is,
404the sites that we identify using the <code class="literal">-o</code> command line
405option). To do this, we iterate over each of the "other" sites provided to
406us using the <code class="literal">-o</code> command line option, and we add each one
407individually in turn:     
408</p>
409      <pre class="programlisting">    <strong class="userinput"><code>for ( REP_HOST_INFO *cur = app_config-&gt;other_hosts; cur != NULL;
410        cur = cur-&gt;next) {
411        if ((ret = dbenv.repmgr_add_remote_site(cur-&gt;host, cur-&gt;port,
412                                                NULL, 0, 0)) != 0) {
413                cerr &lt;&lt; "could not add site." &lt;&lt; endl
414        }
415    } </code></strong> </pre>
416      <p>
417    And then we need code to allow us to identify the total number of sites
418    in this replication group, and to set the environment's priority.
419</p>
420      <pre class="programlisting">    <strong class="userinput"><code>if (app_config-&gt;totalsites &gt; 0) {
421        try {
422            if ((ret = dbenv.rep_set_nsites(app_config-&gt;totalsites)) != 0)
423                dbenv.err(ret, "set_nsites");
424        } catch (DbException dbe) {
425            cerr &lt;&lt; "rep_set_nsites call failed. Continuing." &lt;&lt; endl;
426        }
427    } 
428    dbenv.rep_set_priority(app_config-&gt;priority); </code></strong> </pre>
429      <p>
430            
431
432            <span>We can now open our environment. Note that the flags</span>
433
434            
435
436            we use to open the environment are slightly different for a
437            replicated application than they are for a non-replicated
438            application. Namely, replication requires the
439            <span>
440            <code class="literal">DB_INIT_REP</code> flag. 
441            </span>
442
443            
444    </p>
445      <p>
446            Also, because we are using the Replication Manager, we must prepare
447            our environment for threaded usage. For this reason, we also
448            need the <code class="literal">DB_THREAD</code> flag.
449    </p>
450      <pre class="programlisting">    dbenv.set_cachesize(0, CACHESIZE, 0);
451    dbenv.set_flags(DB_TXN_NOSYNC, 1);
452
453    try {
454        dbenv.open(app_config-&gt;home, 
455            DB_CREATE | 
456            DB_INIT_LOCK | 
457            DB_INIT_LOG | 
458            DB_INIT_MPOOL |
459            <strong class="userinput"><code>DB_INIT_REP |</code></strong>
460            DB_INIT_TXN | 
461            DB_RECOVER <strong class="userinput"><code>|
462            DB_THREAD;</code></strong>
463            0);
464    } catch(DbException dbe) {
465        cerr  &lt;&lt; "Caught an exception during DB environment open." &lt;&lt; endl
466              &lt;&lt; "Ensure that the home directory is created prior to "
467              &lt;&lt; "starting the application." &lt;&lt; endl;
468        ret = ENOENT;
469        goto err;
470    }</pre>
471      <p>
472        Finally, we start replication before we exit this method.
473        Immediately after exiting this method, our application will go into
474        the 
475        <code class="methodname">RepMgrGSG::doloop()</code>
476        
477        method, which is where
478       the bulk of our application's work is performed. We update that
479       method in the next chapter. 
480</p>
481      <pre class="programlisting">    if ((ret = dbenv.repmgr_start(3, app_config-&gt;start_policy)) != 0)
482        goto err;
483
484err:
485    return ret;
486} </pre>
487      <p>
488        This completes our replication updates for the moment. We are not as
489        yet ready to actually run this program; there remains a few
490        critical pieces left to add to it. However, the work that we
491        performed in this section represents a solid foundation for the
492        remainder of our replication work.
493    </p>
494    </div>
495    <div class="navfooter">
496      <hr />
497      <table width="100%" summary="Navigation footer">
498        <tr>
499          <td width="40%" align="left"><a accesskey="p" href="repapp.html">Prev</a>��</td>
500          <td width="20%" align="center">
501            <a accesskey="u" href="repapp.html">Up</a>
502          </td>
503          <td width="40%" align="right">��<a accesskey="n" href="fwrkpermmessage.html">Next</a></td>
504        </tr>
505        <tr>
506          <td width="40%" align="left" valign="top">Chapter��3.��The DB Replication Manager��</td>
507          <td width="20%" align="center">
508            <a accesskey="h" href="index.html">Home</a>
509          </td>
510          <td width="40%" align="right" valign="top">��Permanent Message Handling</td>
511        </tr>
512      </table>
513    </div>
514  </body>
515</html>
516