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 Framework to 7 simple_txn 8 9 </title> 10 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 11 <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /> 12 <link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" /> 13 <link rel="up" href="repapp.html" title="Chapter��3.��The DB Replication Framework" /> 14 <link rel="previous" href="repapp.html" title="Chapter��3.��The DB Replication Framework" /> 15 <link rel="next" href="fwrkpermmessage.html" title="Permanent Message Handling" /> 16 </head> 17 <body> 18 <div class="navheader"> 19 <table width="100%" summary="Navigation header"> 20 <tr> 21 <th colspan="3" align="center">Adding the Replication Framework to 22 simple_txn 23 24 </th> 25 </tr> 26 <tr> 27 <td width="20%" align="left"><a accesskey="p" href="repapp.html">Prev</a>��</td> 28 <th width="60%" align="center">Chapter��3.��The DB Replication Framework</th> 29 <td width="20%" align="right">��<a accesskey="n" href="fwrkpermmessage.html">Next</a></td> 30 </tr> 31 </table> 32 <hr /> 33 </div> 34 <div class="sect1" lang="en" xml:lang="en"> 35 <div class="titlepage"> 36 <div> 37 <div> 38 <h2 class="title" style="clear: both"><a id="repmgr_init_example_c"></a>Adding the Replication Framework to 39 <span>simple_txn</span> 40 41 </h2> 42 </div> 43 </div> 44 <div></div> 45 </div> 46 <p> 47 We now use the methods described above to add partial 48 support to the 49 <tt class="literal">simple_txn</tt> 50 51 example that we presented in 52 <a href="txnapp.html">Transactional Application</a>. 53 That is, in this section we will: 54 </p> 55 <div class="itemizedlist"> 56 <ul type="disc"> 57 <li> 58 <p> 59 Enhance our command line options to 60 accept information of interest to a 61 replicated application. 62 </p> 63 </li> 64 <li> 65 <p> 66 Configure our environment handle to use 67 replication and the replication framework. 68 </p> 69 </li> 70 <li> 71 <p> 72 Minimally configure the replication framework. 73 </p> 74 </li> 75 <li> 76 <p> 77 Start replication. 78 </p> 79 </li> 80 </ul> 81 </div> 82 <p> 83 Note that when we are done with this section, we will be 84 only partially ready to run the application. Some critical 85 pieces will be missing; specifically, we will not yet be 86 handling the differences between a master and a 87 replica. (We do that in the next chapter). 88 </p> 89 <p> 90 Also, note that in the following code fragments, additions 91 and changes to the code are marked in <b class="userinput"><tt>bold</tt></b>. 92 </p> 93 <p> 94 To begin, we copy the 95 <tt class="literal">simple_txn</tt> 96 97 code to a new file called 98 <tt class="literal">rep_mgr.c</tt>. 99 100 <span> 101 We then make the corresponding change to the program name. 102 </span> 103 104 105 </p> 106 <pre class="programlisting">/* 107 <b class="userinput"><tt>* File: rep_mgr.c</tt></b> 108 */ 109 110#include <stdlib.h> 111#include <string.h> 112#ifndef _WIN32 113#include <unistd.h> 114#endif 115 116#include <db.h> 117 118#ifdef _WIN32 119extern int getopt(int, char * const *, const char *); 120#endif 121 122#define CACHESIZE (10 * 1024 * 1024) 123#define DATABASE "quote.db" 124 125const char *progname = <b class="userinput"><tt>"rep_mgr";</tt></b> 126 127int create_env(const char *, DB_ENV **); 128int env_init(DB_ENV *, const char *); 129int doloop (DB_ENV *); 130int print_stocks(DBC *); </pre> 131 <p> 132 Next we update our usage function. The application will continue to 133 accept the <tt class="literal">-h</tt> parameter so that we can identify 134 the environment home directory used by this application. However, 135 we also add the 136</p> 137 <div class="itemizedlist"> 138 <ul type="disc"> 139 <li> 140 <p> 141 <tt class="literal">-m</tt> parameter which allows us to 142 identify the host and port used by this application to 143 listen for replication messages. 144 </p> 145 </li> 146 <li> 147 <p> 148 <tt class="literal">-o</tt> parameter which allows us to 149 specify other replicas. 150 </p> 151 </li> 152 <li> 153 <p> 154 <tt class="literal">-n</tt> parameter which allows us to 155 identify the number of sites in this replication 156 group. 157 </p> 158 </li> 159 <li> 160 <p> 161 <tt class="literal">-p</tt> option, which is used to identify 162 this replica's priority (recall that the priority is 163 used as a tie breaker for elections) 164 </p> 165 </li> 166 </ul> 167 </div> 168 <pre class="programlisting">/* Usage function */ 169static void 170usage() 171{ 172 fprintf(stderr, "usage: %s ", progname); 173 fprintf(stderr, "[-h home] <b class="userinput"><tt>-m host:port [-o host:port]</tt></b>\n"); 174 <b class="userinput"><tt>fprintf(stderr, "\t\t[-p priority]\n");</tt></b> 175 fprintf(stderr, "where:\n"); 176 fprintf(stderr, "\t-h identifies the environment home directory\n"); 177 <b class="userinput"><tt>fprintf(stderr, "\t-o identifies another site participating in "); 178 fprintf(stderr, "this replication group\n"); 179 fprintf(stderr, "\t-m identifies the host and port used by this "); 180 fprintf(stderr, "site (required).\n"); 181 fprintf(stderr, "\t-n identifies the number of sites in this "); 182 fprintf(stderr, "replication group (required).\n"); 183 fprintf(stderr, "\t-p identifies the election priority used by "); 184 fprintf(stderr, "this replica.\n");</tt></b> 185 exit(EXIT_FAILURE); 186} </pre> 187 <p> 188 Now we can begin working on our <tt class="literal">main()</tt> function. 189 We begin by adding a couple of variables that we will use to 190 collect TCP/IP host and port information. 191 192 193 <span> 194 We also declare a couple 195 of flags that we use to make sure some required information is 196 provided to this application. 197 </span> 198</p> 199 <pre class="programlisting">int 200main(int argc, char *argv[]) 201{ 202 extern char *optarg; 203 DB_ENV *dbenv; 204 const char *home; 205 char ch, <b class="userinput"><tt>*host, *portstr</tt></b>; 206 int ret, <b class="userinput"><tt>local_is_set, totalsites</tt></b>; 207 <b class="userinput"><tt>u_int32_t port</tt></b>; 208 209 dbenv = NULL; 210 211 ret = <b class="userinput"><tt>local_is_set = totalsites = </tt></b>0; 212 home = NULL; </pre> 213 <p> 214 At this time we can create our environment handle and configure it 215 exactly as we did for <tt class="literal">simple_txn</tt>. 216 The only thing that we will do differently here is that we will set a priority, 217 arbitrarily picked to be 100, so that we can be sure the environment has 218 a priority other than 0 (the default value). This ensures that the 219 environment can become a master via an election. 220</p> 221 <pre class="programlisting"> if ((ret = create_env(progname, &dbenv)) != 0) 222 goto err; 223 224 /* Default priority is 100 */ 225 <b class="userinput"><tt>dbenv->rep_set_priority(dbenv, 100);</tt></b> </pre> 226 <p> 227 Now we collect our command line arguments. As we do so, we will 228 configure host and port information as required, and we will 229 configure the application's election priority if necessary. 230</p> 231 <pre class="programlisting"> /* Collect the command line options */ 232 while ((ch = getopt(argc, argv, "h:<b class="userinput"><tt>m:o:p:</tt></b>")) != EOF) 233 switch (ch) { 234 case 'h': 235 home = optarg; 236 break; 237 <b class="userinput"><tt>/* Set the host and port used by this environment */ 238 case 'm': 239 host = strtok(optarg, ":"); 240 if ((portstr = strtok(NULL, ":")) == NULL) { 241 fprintf(stderr, "Bad host specification.\n"); 242 goto err; 243 } 244 port = (unsigned short)atoi(portstr); 245 if (dbenv->repmgr_set_local_site(dbenv, host, port, 0) != 0) { 246 fprintf(stderr, 247 "Could not set local address %s.\n", host); 248 goto err; 249 } 250 local_is_set = 1; 251 break; 252 /* Identify another site in the replication group */ 253 case 'o': 254 host = strtok(optarg, ":"); 255 if ((portstr = strtok(NULL, ":")) == NULL) { 256 fprintf(stderr, "Bad host specification.\n"); 257 goto err; 258 } 259 port = (unsigned short)atoi(portstr); 260 if (dbenv->repmgr_add_remote_site(dbenv, host, port, 261 NULL, 0) != 0) { 262 fprintf(stderr, 263 "Could not add site %s.\n", host); 264 goto err; 265 } 266 break; 267 /* Set the number of sites in this replication group */ 268 case 'n': 269 totalsites = atoi(optarg); 270 if ((ret = dbenv->rep_set_nsites(dbenv, totalsites)) != 0) 271 dbenv->err(dbenv, ret, "set_nsites"); 272 break; 273 /* Set this replica's election priority */ 274 case 'p': 275 dbenv->rep_set_priority(dbenv, atoi(optarg)); 276 break; </tt></b> 277 case '?': 278 default: 279 usage(); 280 } 281 282 /* Error check command line. */ 283 if (home == NULL <b class="userinput"><tt>|| !local_is_set || !totalsites</tt></b>) 284 usage(); </pre> 285 <p> 286 Having done that, we can call <tt class="function">env_init()</tt>, which we use to 287 open our environment handle. Note that this function changes 288 slightly for this update (see below). 289 </p> 290 <pre class="programlisting"> if ((ret = env_init(dbenv, home)) != 0) 291 goto err; </pre> 292 <p> 293 Finally, we start replication before we go into the 294 <tt class="function">doloop()</tt> function (where we perform all our 295 database access). 296</p> 297 <pre class="programlisting"> 298 <b class="userinput"><tt>if ((ret = dbenv->repmgr_start(dbenv, 3, DB_REP_ELECTION)) != 0) 299 goto err; </tt></b> 300 301 if ((ret = doloop(dbenv)) != 0) { 302 dbenv->err(dbenv, ret, "Application failed"); 303 goto err; 304 } 305 306err: if (dbenv != NULL) 307 (void)dbenv->close(dbenv, 0); 308 309 return (ret); 310} </pre> 311 <p> 312 <span>Beyond that, the rest of our application remains the same for 313 now, with the exception of the <tt class="function">env_init()</tt> 314 function, which we use to actually open our environment handle. 315 The flags </span> 316 317 318 319 320 321 we use to open the environment are slightly different for a 322 replicated application than they are for a non-replicated 323 application. Namely, replication requires the 324 <span> 325 <tt class="literal">DB_INIT_REP</tt> flag. 326 </span> 327 328 329 </p> 330 <p> 331 Also, because we are using the replication framework, we must prepare 332 our environment for threaded usage. For this reason, we also 333 need the <tt class="literal">DB_THREAD</tt> flag. 334 </p> 335 <pre class="programlisting"> int 336env_init(DB_ENV *dbenv, const char *home) 337{ 338 u_int32_t flags; 339 int ret; 340 341 (void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0); 342 (void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1); 343 344 flags = DB_CREATE | 345 DB_INIT_LOCK | 346 DB_INIT_LOG | 347 DB_INIT_MPOOL | 348 DB_INIT_TXN | 349 <b class="userinput"><tt>DB_INIT_REP | 350 DB_THREAD |</tt></b> 351 DB_RECOVER; 352 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) 353 dbenv->err(dbenv, ret, "can't open environment"); 354 return (ret); 355}</pre> 356 <p> 357 This completes our replication updates for the moment. We are not as 358 yet ready to actually run this program; there remains a few 359 critical pieces left to add to it. However, the work that we 360 performed in this section represents a solid foundation for the 361 remainder of our replication work. 362 </p> 363 </div> 364 <div class="navfooter"> 365 <hr /> 366 <table width="100%" summary="Navigation footer"> 367 <tr> 368 <td width="40%" align="left"><a accesskey="p" href="repapp.html">Prev</a>��</td> 369 <td width="20%" align="center"> 370 <a accesskey="u" href="repapp.html">Up</a> 371 </td> 372 <td width="40%" align="right">��<a accesskey="n" href="fwrkpermmessage.html">Next</a></td> 373 </tr> 374 <tr> 375 <td width="40%" align="left" valign="top">Chapter��3.��The DB Replication Framework��</td> 376 <td width="20%" align="center"> 377 <a accesskey="h" href="index.html">Home</a> 378 </td> 379 <td width="40%" align="right" valign="top">��Permanent Message Handling</td> 380 </tr> 381 </table> 382 </div> 383 </body> 384</html> 385