mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
397 lines
15 KiB
HTML
397 lines
15 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Adding the Replication Manager to ex_rep_gsg_simple</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
|
||
<link rel="start" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
|
||
<link rel="up" href="repapp.html" title="Chapter 3. The DB Replication Manager" />
|
||
<link rel="prev" href="rep_init_code.html" title="Starting and Stopping Replication" />
|
||
<link rel="next" href="fwrkpermmessage.html" title="Permanent Message Handling" />
|
||
</head>
|
||
<body>
|
||
<div xmlns="" class="navheader">
|
||
<div class="libver">
|
||
<p>Library Version 11.2.5.3</p>
|
||
</div>
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Adding the Replication Manager to
|
||
<span xmlns="http://www.w3.org/1999/xhtml">ex_rep_gsg_simple</span>
|
||
|
||
|
||
</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="rep_init_code.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 3. The DB Replication Manager</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="fwrkpermmessage.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="repmgr_init_example_c"></a>Adding the Replication Manager to
|
||
<span>ex_rep_gsg_simple</span>
|
||
|
||
|
||
</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
We now use the methods described above to add partial
|
||
support to the
|
||
<span>ex_rep_gsg_simple</span>
|
||
|
||
|
||
example that we presented in
|
||
<a class="xref" href="txnapp.html" title="Chapter 2. Transactional Application">Transactional Application</a>.
|
||
That is, in this section we will:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
Enhance our command line options to accept information
|
||
of interest to a replicated application.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
Configure our environment handle to use replication and
|
||
the Replication Manager.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
Minimally configure the Replication Manager.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
Start replication.
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
Note that when we are done with this section, we will be
|
||
only partially ready to run the application. Some critical
|
||
pieces will be missing; specifically, we will not yet be
|
||
handling the differences between a master and a
|
||
replica. (We do that in the next chapter).
|
||
</p>
|
||
<p>
|
||
Also, note that in the following code fragments, additions
|
||
and changes to the code are marked in <strong class="userinput"><code>bold</code></strong>.
|
||
</p>
|
||
<p>
|
||
To begin, we copy the
|
||
<span>ex_rep_gsg_simple</span>
|
||
|
||
code to a new file called
|
||
<code class="literal">ex_rep_gsg_repmgr.c</code>.
|
||
|
||
<span>
|
||
We then make the corresponding change to the program name.
|
||
</span>
|
||
|
||
|
||
</p>
|
||
<pre class="programlisting">/*
|
||
<strong class="userinput"><code>* File: ex_rep_gsg_repmgr.c</code></strong>
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#ifndef _WIN32
|
||
#include <unistd.h>
|
||
#endif
|
||
|
||
#include <db.h>
|
||
|
||
#ifdef _WIN32
|
||
extern int getopt(int, char * const *, const char *);
|
||
#endif
|
||
|
||
#define CACHESIZE (10 * 1024 * 1024)
|
||
#define DATABASE "quote.db"
|
||
|
||
const char *progname = <strong class="userinput"><code>"ex_rep_gsg_repmgr";</code></strong>
|
||
|
||
int create_env(const char *, DB_ENV **);
|
||
int env_init(DB_ENV *, const char *);
|
||
int doloop (DB_ENV *);
|
||
int print_stocks(DBC *); </pre>
|
||
<p>
|
||
Next we update our usage function. The application will continue to
|
||
accept the <code class="literal">-h</code> parameter so that we can identify
|
||
the environment home directory used by this application. However,
|
||
we also add the:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
<code class="literal">-l</code> parameter which allows us to identify the
|
||
host and port used by this application to listen for
|
||
replication messages. This parameter is required unless the -L
|
||
parameter is specified.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<code class="literal">-L</code> parameter, which allows us to identify
|
||
the local site as the group creator.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<code class="literal">-r</code> parameter which allows us to specify
|
||
other replicas.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<code class="literal">-p</code> option, which is used to identify this
|
||
replica's priority (recall that the priority is used as a tie
|
||
breaker for elections)
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<pre class="programlisting">/* Usage function */
|
||
static void
|
||
usage()
|
||
{
|
||
fprintf(stderr, "usage: %s ", progname);
|
||
fprintf(stderr, "-h home <strong class="userinput"><code>-l|-L host:port</code></strong>\n");
|
||
<strong class="userinput"><code>fprintf(stderr, "\t\t[-r host:port][-p priority]\n");
|
||
fprintf(stderr, "where:\n");
|
||
fprintf(stderr, "\t-h identifies the environment home directory ");
|
||
fprintf(stderr, "(required).\n");
|
||
fprintf(stderr, "\t-l identifies the host and port used by this ");
|
||
fprintf(stderr, "site (required, unless -L is specified).\n");
|
||
fprintf(stderr, "\t-L identifies the host and port used by this ");
|
||
fprintf(stderr, "site, which is the group creator.\n");
|
||
fprintf(stderr, "\t-r identifies another site participating in ");
|
||
fprintf(stderr, "this replication group\n");
|
||
fprintf(stderr, "\t-p identifies the election priority used by ");
|
||
fprintf(stderr, "this replica.\n");</code></strong>
|
||
exit(EXIT_FAILURE);
|
||
} </pre>
|
||
<p>
|
||
Now we can begin working on our <code class="literal">main()</code> function.
|
||
We begin by adding a couple of variables that we will use to
|
||
collect TCP/IP host and port information.
|
||
|
||
|
||
<span>
|
||
We also declare a couple
|
||
of flags that we use to make sure some required information is
|
||
provided to this application.
|
||
</span>
|
||
</p>
|
||
<pre class="programlisting">int
|
||
main(int argc, char *argv[])
|
||
{
|
||
DB_ENV *dbenv;
|
||
<strong class="userinput"><code>DB_SITE *dbsite;</code></strong>
|
||
extern char *optarg;
|
||
const char *home;
|
||
char ch, <strong class="userinput"><code>*host, *portstr</code></strong>;
|
||
int ret, <strong class="userinput"><code>local_is_set, is_group_creator</code></strong>;
|
||
<strong class="userinput"><code>u_int32_t port</code></strong>;
|
||
|
||
dbenv = NULL;
|
||
|
||
ret = <strong class="userinput"><code>local_is_set = is_group_creator = </code></strong>0;
|
||
home = NULL; </pre>
|
||
<p>
|
||
At this time we can create our environment handle and configure it
|
||
exactly as we did for <code class="literal">simple_txn</code>.
|
||
The only thing that we will do differently here is that we will set a priority,
|
||
arbitrarily picked to be 100, so that we can be sure the environment has
|
||
a priority other than 0 (the default value). This ensures that the
|
||
environment can become a master via an election.
|
||
</p>
|
||
<pre class="programlisting"> if ((ret = create_env(progname, &dbenv)) != 0)
|
||
goto err;
|
||
|
||
/* Default priority is 100 */
|
||
<strong class="userinput"><code>dbenv->rep_set_priority(dbenv, 100);</code></strong> </pre>
|
||
<p>
|
||
Now we collect our command line arguments. As we do so, we will
|
||
configure host and port information as required, and we will
|
||
configure the application's election priority if necessary.
|
||
</p>
|
||
<pre class="programlisting"> /* Collect the command line options */
|
||
while ((ch = getopt(argc, argv, "h:<strong class="userinput"><code>l:L:p:r:</code></strong>")) != EOF)
|
||
switch (ch) {
|
||
case 'h':
|
||
home = optarg;
|
||
break;
|
||
<strong class="userinput"><code>/* Set the host and port used by this environment */
|
||
case 'l':
|
||
host = strtok(optarg, ":");
|
||
if ((portstr = strtok(NULL, ":")) == NULL) {
|
||
fprintf(stderr, "Bad host specification.\n");
|
||
goto err;
|
||
}
|
||
port = (unsigned short)atoi(portstr);
|
||
if ((ret = dbenv->repmgr_site(dbenv, host, port, &dbsite
|
||
0)) != 0 ) {
|
||
fprintf(stderr,
|
||
"Could not set local address %s.\n", host);
|
||
goto err;
|
||
}
|
||
dbsite->set_config(dbsite, DB_LOCAL_SITE, 1);
|
||
if (is_group_creator)
|
||
dbsite->set_config(dbsite, DB_GROUP_CREATOR, 1);
|
||
|
||
if ((ret = dbsite->close(dbsite)) != 0) {
|
||
dbenv->(dbenv, ret, "DB_SITE->close");
|
||
goto err;
|
||
}
|
||
local_is_set = 1;
|
||
break;
|
||
/* Set this replica's election priority */
|
||
case 'p':
|
||
dbenv->rep_set_priority(dbenv, atoi(optarg));
|
||
break;
|
||
/* Identify another site in the replication group */
|
||
case 'r':
|
||
host = strtok(optarg, ":");
|
||
if ((portstr = strtok(NULL, ":")) == NULL) {
|
||
fprintf(stderr, "Bad host specification.\n");
|
||
goto err;
|
||
}
|
||
port = (unsigned short)atoi(portstr);
|
||
if ((dbenv->repmgr_site(dbenv, host, port, &dbsite,
|
||
0)) != 0) {
|
||
fprintf(stderr,
|
||
"Could not add site %s.\n", host);
|
||
goto err;
|
||
}
|
||
dbenv->set_config(dbsite, DB_BOOTSTRAP_HELPER, 1);
|
||
if ((dbenv->close(dbsite)) != 0) {
|
||
dbenv->err(dbenv, ret, "DB_SITE->close");
|
||
goto err;
|
||
}
|
||
break;</code></strong>
|
||
case '?':
|
||
default:
|
||
usage();
|
||
}
|
||
|
||
/* Error check command line. */
|
||
if (home == NULL <strong class="userinput"><code>|| !local_is_set</code></strong>)
|
||
usage(); </pre>
|
||
<p>
|
||
Having done that, we can call <code class="function">env_init()</code>,
|
||
which we use to open our environment handle. Note that this
|
||
function changes slightly for this update (see below).
|
||
</p>
|
||
<pre class="programlisting"> if ((ret = env_init(dbenv, home)) != 0)
|
||
goto err; </pre>
|
||
<p>
|
||
Finally, we start replication before we go into the
|
||
<code class="function">doloop()</code> function (where we perform all our
|
||
database access).
|
||
</p>
|
||
<pre class="programlisting">
|
||
<strong class="userinput"><code>if ((ret = dbenv->repmgr_start(dbenv, 3, DB_REP_ELECTION)) != 0)
|
||
goto err; </code></strong>
|
||
|
||
if ((ret = doloop(dbenv)) != 0) {
|
||
dbenv->err(dbenv, ret, "Application failed");
|
||
goto err;
|
||
}
|
||
|
||
err: if (dbenv != NULL)
|
||
(void)dbenv->close(dbenv, 0);
|
||
|
||
return (ret);
|
||
} </pre>
|
||
<p>
|
||
<span>Beyond that, the rest of our application remains the same for
|
||
now, with the exception of the <code class="function">env_init()</code>
|
||
function, which we use to actually open our environment handle.
|
||
The flags </span>
|
||
|
||
|
||
|
||
|
||
|
||
we use to open the environment are slightly different for a
|
||
replicated application than they are for a non-replicated
|
||
application. Namely, replication requires the
|
||
<span>
|
||
<code class="literal">DB_INIT_REP</code> flag.
|
||
</span>
|
||
|
||
|
||
</p>
|
||
<p>
|
||
Also, because we are using the Replication Manager, we must prepare
|
||
our environment for threaded usage. For this reason, we also
|
||
need the <code class="literal">DB_THREAD</code> flag.
|
||
</p>
|
||
<pre class="programlisting">int
|
||
env_init(DB_ENV *dbenv, const char *home)
|
||
{
|
||
u_int32_t flags;
|
||
int ret;
|
||
|
||
(void)dbenv->set_cachesize(dbenv, 0, CACHESIZE, 0);
|
||
(void)dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1);
|
||
|
||
flags = DB_CREATE |
|
||
DB_INIT_LOCK |
|
||
DB_INIT_LOG |
|
||
DB_INIT_MPOOL |
|
||
<strong class="userinput"><code>DB_INIT_REP |</code></strong>
|
||
DB_INIT_TXN |
|
||
DB_RECOVER <strong class="userinput"><code>|
|
||
DB_THREAD;</code></strong>
|
||
if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0)
|
||
dbenv->err(dbenv, ret, "can't open environment");
|
||
return (ret);
|
||
}</pre>
|
||
<p>
|
||
This completes our replication updates for the moment. We are not as
|
||
yet ready to actually run this program; there remains a few
|
||
critical pieces left to add to it. However, the work that we
|
||
performed in this section represents a solid foundation for the
|
||
remainder of our replication work.
|
||
</p>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="rep_init_code.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="repapp.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="fwrkpermmessage.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">
|
||
Starting and Stopping Replication
|
||
</td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Permanent Message Handling</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|