Import BSDDB 4.7.25 (as of svn r89086)

This commit is contained in:
Zachary Ware
2017-09-04 13:40:25 -05:00
parent 4b29e0458f
commit 8f590873d0
4781 changed files with 2241032 additions and 6 deletions

Binary file not shown.

View File

@@ -0,0 +1,191 @@
<?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>Chapter 5. Additional Features</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="previous" href="exampledoloop.html" title="Example Processing Loop" />
<link rel="next" href="manageblock.html" title="Managing Blocking Operations" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Chapter 5. Additional Features</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="exampledoloop.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="manageblock.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="chapter" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a id="addfeatures"></a>Chapter 5. Additional Features</h2>
</div>
</div>
<div></div>
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="sect1">
<a href="addfeatures.html#delayedsync">Delayed Synchronization</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="manageblock.html">Managing Blocking Operations</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="noautoinit.html">Stop Auto-Initialization</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="c2ctransfer.html">Client to Client Transfer</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="c2ctransfer.html#fmwrkpeerserver">Identifying Peers</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="bulk.html">Bulk Transfers</a>
</span>
</dt>
</dl>
</div>
<p>
Beyond the basic functionality that we have discussed so far in
this book, there are several replication features that you
should understand. These are all optional to use, but provide
useful functionality under the right circumstances.
</p>
<p>
These additional features are:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
<a href="addfeatures.html#delayedsync">Delayed Synchronization</a>
</p>
</li>
<li>
<p>
<a href="manageblock.html">Managing Blocking Operations</a>
</p>
</li>
<li>
<p>
<a href="noautoinit.html">Stop Auto-Initialization</a>
</p>
</li>
<li>
<p>
<a href="c2ctransfer.html">Client to Client Transfer</a>
</p>
</li>
<li>
<p>
<a href="bulk.html">Bulk Transfers</a>
</p>
</li>
</ol>
</div>
<div class="sect1" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="delayedsync"></a>Delayed Synchronization</h2>
</div>
</div>
<div></div>
</div>
<p>
When a replication group has a new master, all replicas must
synchronize with that master. This means they must ensure
that the contents of their local database(s) are identical
to that contained by the new master.
</p>
<p>
This synchronization process can result in quite a lot of
network activity. It can also put a large strain on the
master server, especially if is part of a large
replication group or if there is somehow a large difference between
the master's database(s) and the contents of its replicas.
</p>
<p>
It is therefore possible to delay synchronization for any
replica that discovers it has a new master. You would do
this so as to give the master time to synchronize other
replicas before proceeding with the delayed replicas.
</p>
<p>
To delay synchronization of a replica environment, you
specify
<span>
<tt class="literal">DB_REP_CONF_DELAYCLIENT</tt> to
<tt class="methodname">DbEnv::rep_set_config()</tt>
and then specify <tt class="literal">1</tt> to the <tt class="literal">onoff</tt>
parameter. (Specify <tt class="literal">0</tt> to turn the feature off.)
</span>
</p>
<p>
If you use delayed synchronization, then you must manually
synchronize the replica at some future time. Until you do this, the replica is out of
sync with the master, and it will ignore all database changes forwarded to it from
the master.
</p>
<p>
You synchronize a delayed replica by calling
<tt class="methodname">DbEnv::rep_sync()</tt>
on the replica that has been delayed.
</p>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="exampledoloop.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="index.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="manageblock.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Example Processing Loop </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Managing Blocking Operations</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,225 @@
<?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>The Replication APIs</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="introduction.html" title="Chapter 1. Introduction" />
<link rel="previous" href="repadvantage.html" title="Replication Benefits" />
<link rel="next" href="elections.html" title="Holding Elections" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">The Replication APIs</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="repadvantage.html">Prev</a> </td>
<th width="60%" align="center">Chapter 1. Introduction</th>
<td width="20%" align="right"> <a accesskey="n" href="elections.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="apioverview"></a>The Replication APIs</h2>
</div>
</div>
<div></div>
</div>
<p>
There are two ways that you can choose to implement
replication in your transactional application. The first,
and preferred, mechanism is to use the pre-packaged
replication framework that comes with the
DB distribution. This framework should be sufficient
for most customers.
</p>
<p>
If for some reason the Replication Framework
does not meet your application's technical requirements,
you will have to use the replication APIs available
through the Berkeley DB library to write your own custom
replication framework.
</p>
<p>
Both of these approaches are described in slightly greater
detail in this section. The bulk of the chapters later in
this book are dedicated to these two replication
implementation mechanisms.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repframeworkoverview"></a>Replication Framework Overview</h3>
</div>
</div>
<div></div>
</div>
<p>
DB's pre-packaged replication framework exists
as a layer on top of the DB library. The replication framework is a
multi-threaded implementation that allows you to easily add
replication to your existing transactional application.
<span>
You access and manage the replication framework using methods that are
available off the
<tt class="classname">DbEnv</tt>
class.
</span>
</p>
<p>
The replication framework:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Provides a multi-threaded communications layer
using pthreads (on Unix-style systems and
similar derivatives such as Mac OS X), or
Windows threads on Microsoft Windows systems.
</p>
</li>
<li>
<p>
Uses TCP/IP sockets. Network traffic is
handled via threads that handle inbound and
outbound messages. However, each
process uses a single socket
that is shared using <tt class="function">select()</tt>.
</p>
<p>
Note that for this reason, the replication framework is
limited to a maximum of 60 replicas (on
Windows) and approximately 1000 replicas (on
Unix and related systems), depending on how
your system is configured.
</p>
</li>
<li>
<p>
Requires a single process for the master replica.
</p>
</li>
<li>
<p>
Requires that only one instance of the
environment handle be used.
</p>
</li>
<li>
<p>
Upon application startup, a master can be
selected either manually or via elections.
After startup time, however, during the course of
normal operations it is possible for the
replication group to need to locate a new master (due
to network or other hardware related problems,
for example) and in this scenario elections are
always used to select the new master.
</p>
</li>
</ul>
</div>
<p>
If your application has technical requirements that do
not conform to the implementation provided by the
replication framework, you must write a custom
replication framework using the DB replication APIs
directly. See the next section for introductory
details.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repapioverview"></a>Replication API Overview</h3>
</div>
</div>
<div></div>
</div>
<p>
The replication API is a series of Berkeley DB library
classes and methods that you can use to build your own
replication infrastructure. You should use the
replication API only if the replication framework does not meet your
application's technical requirements.
</p>
<p>
To make use of the replication API, you must write your
own networking code. This frees you from the technical
constraints imposed by the replication framework. For example, by
writing your own framework, you can:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Use a threading package other than
pthreads (Unix) or Windows threads
(Microsoft Windows). This might be interesting
to you if you are using a platform
whose preferred threading package
is something other than (for
example) pthreads, such as is the case for
Sun Microsystem's Solaris operating systems.
</p>
</li>
<li>
<p>
Implement your own sockets. The
replication framework uses TCP/IP sockets. While
this should be acceptable for the
majority of applications, sometimes
UDP or even raw sockets might be
desired.
</p>
</li>
<li>
<p>
Write a multi-process master
replica.
</p>
</li>
</ul>
</div>
<p>
For information on writing a replicated application
using the Berkeley DB replication APIs, see the
<i class="citetitle">Berkeley DB Programmer's Reference Guide</i>.
</p>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="repadvantage.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="introduction.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="elections.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Replication Benefits </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Holding Elections</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,139 @@
<?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>Bulk Transfers</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="addfeatures.html" title="Chapter 5. Additional Features" />
<link rel="previous" href="c2ctransfer.html" title="Client to Client Transfer" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Bulk Transfers</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="c2ctransfer.html">Prev</a> </td>
<th width="60%" align="center">Chapter 5. Additional Features</th>
<td width="20%" align="right"> </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="bulk"></a>Bulk Transfers</h2>
</div>
</div>
<div></div>
</div>
<p>
By default, messages are sent from the master to replicas as they are generated.
This can degrade replication performance because the various participating
environments must handle a fair amount of network I/O activity.
</p>
<p>
You can alleviate this problem by configuring your master environment for bulk
transfers. Bulk transfers simply cause replication messages to accumulate in a
buffer until a triggering event occurs. When this event occurs, the entire
contents of the buffer is sent to the replica, thereby eliminating excessive
network I/O.
</p>
<p>
Note that if you are using replica to replica transfers, then you might want any
replica that can service replication requests to also be configured for bulk
transfers.
</p>
<p>
The events that result in a bulk transfer of replication messages to a replica
will differ depending on if the transmitting environment is a master or a
replica.
</p>
<p>
If the servicing environment is a master environment, then bulk a bulk transfer
occurs when:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Bulk transfers are configured for the master environment, and
</p>
</li>
<li>
<p>
the message buffer is full or
</p>
</li>
<li>
<p>
a permanent record (for example, a transaction commit or a
checkpoint record) is placed in the buffer for the replica.
</p>
</li>
</ol>
</div>
<p>
If the servicing environment is a replica environment (that is, replica to replica
transfers are in use), then a bulk transfer occurs when:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Bulk transfers are configured for the transmitting replica, and
</p>
</li>
<li>
<p>
the message buffer is full or
</p>
</li>
<li>
<p>
the replica servicing the request is able to completely satisfy
the request with the contents of the message buffer.
</p>
</li>
</ol>
</div>
<p>
To configure bulk transfers, specify
<span>
<tt class="literal">DB_REP_CONF_BULK</tt> to
<tt class="methodname">DbEnv::rep_set_config()</tt>
and then specify <tt class="literal">1</tt> to the <tt class="literal">onoff</tt>
parameter. (Specify <tt class="literal">0</tt> to turn the feature off.)
</span>
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="c2ctransfer.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="addfeatures.html">Up</a>
</td>
<td width="40%" align="right"> </td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Client to Client Transfer </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> </td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,131 @@
<?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>Client to Client Transfer</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="addfeatures.html" title="Chapter 5. Additional Features" />
<link rel="previous" href="noautoinit.html" title="Stop Auto-Initialization" />
<link rel="next" href="bulk.html" title="Bulk Transfers" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Client to Client Transfer</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="noautoinit.html">Prev</a> </td>
<th width="60%" align="center">Chapter 5. Additional Features</th>
<td width="20%" align="right"> <a accesskey="n" href="bulk.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="c2ctransfer"></a>Client to Client Transfer</h2>
</div>
</div>
<div></div>
</div>
<p>
It is possible to use a replica instead of a master to synchronize another
replica. This serves to take the request load off a master that might otherwise
occur if multiple replicas attempted to synchronize with the master at the same
time.
</p>
<p>
For best results, use this feature combined with the delayed synchronization
feature (see <a href="addfeatures.html#delayedsync">Delayed Synchronization</a>).
</p>
<p>
For example, suppose your replication group consists of four environments. Upon
application startup, all three replicas will immediately attempt to synchronize
with the master. But at the same time, the master itself might be busy with a heavy
database write load.
</p>
<p>
To solve this problem, delay synchronization for two of the three replicas. Allow
the third replica to synchronize as normal with the master. Then, start
synchronization for each of the delayed replicas (since this is a manual process,
you can do them one at a time if that best suits your application).
Assuming you have configured replica to replica synchronization correctly, the
delayed replicas will synchronize using the up-to-date replica, rather than using
the master.
</p>
<p>
When you are using the replication framework, you configure replica to replica synchronization by
declaring one environment to be a peer of another environment. If an
environment is a peer, then
it can be used for synchronization purposes.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="fmwrkpeerserver"></a>Identifying Peers</h3>
</div>
</div>
<div></div>
</div>
<p>
You can designate one replica to be a peer of
another, and then use this special
status for permanent message acknowledgments,
and for replica-to-replica synchronization.
You might want to do this if you have
machines that you know are on fast, reliable
network connections and so you are willing to
accept the overhead of waiting for
acknowledgments from those specific machines.
</p>
<p>
An environment is currently allowed to have only one
peer.
</p>
<p>
Note that peers are not required to be a
bi-directional. That is, just because machine A
declares machine B to be a peer, that does not mean
machine B must also declare machine A to be a peer.
</p>
<p>
You declare a peer for the current environment
when you add that environment to the list of known
sites. You do this by
<span>specifying the
<tt class="literal">DB_REPMGR_PEER</tt> flag to
<span><tt class="methodname">DbEnv::repmgr_add_remote_site()</tt>.</span>
</span>
</p>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="noautoinit.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="addfeatures.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="bulk.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Stop Auto-Initialization </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Bulk Transfers</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,227 @@
<?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>Holding Elections</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="introduction.html" title="Chapter 1. Introduction" />
<link rel="previous" href="apioverview.html" title="The Replication APIs" />
<link rel="next" href="permmessages.html" title="Permanent Message Handling" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Holding Elections</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="apioverview.html">Prev</a> </td>
<th width="60%" align="center">Chapter 1. Introduction</th>
<td width="20%" align="right"> <a accesskey="n" href="permmessages.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="elections"></a>Holding Elections</h2>
</div>
</div>
<div></div>
</div>
<p>
Finding a master environment is one of the fundamental activities that
every replication replica must perform. Upon startup, the
underlying DB replication code will attempt to
locate a master. If a master cannot be found, then the
environment should initiate an election.
</p>
<p>
How elections are held depends upon the API that you use to
implement replication. For example, if you are using the
replication framework elections are held transparently without any
input from your application's code. In this case,
DB will determine which environment is the master and which
are replicas.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="influencingelections"></a>Influencing Elections</h3>
</div>
</div>
<div></div>
</div>
<p>
If you want to control the election process, you can declare
a specific environment to be the master. Note that for the replication framework,
it is only possible to do this at application startup.
Should the master become unavailable during run-time for any
reason, an election is held. The environment that receives
the most number of votes, wins the election and becomes the
master. A machine receives a vote because it has the most
number of log records.
</p>
<p>
Because ties are possible when elections are held,
it is possible to influence which environment will win
the election. How you do this depends on which API you
are using. In particular, if you are writing a custom replication
layer, then there are a great many ways to manually influence
elections.
</p>
<p>
One such mechanism is priorities. When votes are
cast during an election, both the number of log records
contained in the environment <span class="emphasis"><em>and</em></span>
the environment's priority are considered. So given two
environments with the same number of log records, votes
are cast for the environment with the higher priority.
</p>
<p>
Therefore, if you have a machine that you prefer to
become a master in the event of an election, assign it
a high priority. Assuming that the election is held at
a time when the preferred machine has up-to-date log
records, that machine will win the election.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="winningelections"></a>Winning Elections</h3>
</div>
</div>
<div></div>
</div>
<p>
To win an election:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
There cannot currently be a
master environment.
</p>
</li>
<li>
<p>
The environment must have the most
recent log records. Part of
holding the election is
determining which environments have
the most recent log records.
This process happens
automatically; your code does
not need to involve itself in
this process.
</p>
</li>
<li>
<p>
The environment must receive the most
number of votes from the
replication environments that are
participating in the election.
</p>
</li>
</ol>
</div>
<p>
If you are using the replication framework, then in the event of a
tie vote the environment with the highest priority wins
the election. If two or more environments receive the same
number of votes and have the same priority, then
the underlying replication code picks one of the
environments to
be the winner. Which winner will be picked by the
replication code is unpredictable from the
perspective of your application code.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="switchingmasters"></a>Switching Masters</h3>
</div>
</div>
<div></div>
</div>
<p>
To switch masters:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Start up the environment that you want
to be master as normal. At this
time it is a replica. Make
sure this environment has a higher
priority than all the other
environments.
</p>
</li>
<li>
<p>
Allow the new environment to run for a
time as a replica. This allows
it to obtain the most recent
copies of the log files.
</p>
</li>
<li>
<p>
Shut down the current master.
This should force an election.
Because the new environment has the
highest priority, it will win
the election, provided it has
had enough time to obtain all
the log records.
</p>
</li>
<li>
<p>
Optionally restart the old
master environment. Because there is
currently a master environment, an
election will not be held and
the old master will now run as
a replica environment.
</p>
</li>
</ol>
</div>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="apioverview.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="introduction.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="permmessages.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">The Replication APIs </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>

View File

@@ -0,0 +1,152 @@
<?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>Managing Election Times</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
<link rel="previous" href="fwrkpermmessage.html" title="Permanent Message Handling" />
<link rel="next" href="fmwrkconnectretry.html" title="Managing Connection Retries" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Managing Election Times</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="fwrkpermmessage.html">Prev</a> </td>
<th width="60%" align="center">Chapter 3. The DB Replication Framework</th>
<td width="20%" align="right"> <a accesskey="n" href="fmwrkconnectretry.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="electiontimes"></a>Managing Election Times</h2>
</div>
</div>
<div></div>
</div>
<p>
Where it comes to elections, there are two timeout
values with which you should be concerned: election
timeouts and election retries.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="electiontimeout"></a>Managing Election Timeouts</h3>
</div>
</div>
<div></div>
</div>
<p>
When a environment calls for an election, it will wait
some amount of time for the other replicas in the
replication group to respond. The amount of time
that the environment will wait before declaring the
election completed is the <span class="emphasis"><em>election timeout</em></span>.
</p>
<p>
If the environment hears from all other known replicas before
the election timeout occurs, the election is considered
a success and a master is elected.
</p>
<p>
If only a subset of replicas respond, then the success
or failure of the election is determined by (1)
how many replicas have responded and (2) the
election policy that is in place at the time.
For example, usually it only takes a simple
majority of replicas to elect a master. If
there are enough votes for a given environment to
meet that standard, then the master has been
elected and the election is considered a
success.
</p>
<p>
However, upon application startup you can
require that all known replicas must participate in the
election. Or, it is possible that not enough
votes are cast to select a master even with a
simple majority. If either of these conditions
occur when the election timeout value is
reached, the election is considered a failure
and a master is not elected. At this point,
your replication group is operating without a
master, which means that, essentially,
your replicated application has been placed in
read-only mode.
</p>
<p>
Note, however, that the replication framework will attempt a
new election after a given amount of time has
passed. See the next section for details.
</p>
<p>
You set the election timeout value using
<span><tt class="methodname">DbEnv::rep_set_timeout()</tt>.</span>
To do so, specify the
<tt class="literal">DB_REP_ELECTION_TIMEOUT</tt>
flag to the <tt class="literal">which</tt> parameter and then a
timeout value in microseconds to the
<tt class="literal">timeout</tt> parameter.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="electretrytime"></a>Managing Election Retry Times</h3>
</div>
</div>
<div></div>
</div>
<p>
In the event that a election fails (see the
previous section), an election will not be
attempted again until the election retry
timeout value has expired.
</p>
<p>
You set the retry timeout value using
<span><tt class="methodname">DbEnv::rep_set_timeout()</tt>.</span>
To do so, specify the
<tt class="literal">DB_REP_ELECTION_RETRY</tt>
flag to the <tt class="literal">which</tt> parameter and then a
retry value in microseconds to the
<tt class="literal">timeout</tt> parameter.
</p>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="fwrkpermmessage.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="fmwrkconnectretry.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Permanent Message Handling </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Managing Connection Retries</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,541 @@
<?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>Example Processing Loop</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="fwrkmasterreplica.html" title="Chapter 4. Replica versus Master Processes" />
<link rel="previous" href="processingloop.html" title="Processing Loop" />
<link rel="next" href="addfeatures.html" title="Chapter 5. Additional Features" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Example Processing Loop</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="processingloop.html">Prev</a> </td>
<th width="60%" align="center">Chapter 4. Replica versus Master Processes</th>
<td width="20%" align="right"> <a accesskey="n" href="addfeatures.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="exampledoloop"></a>Example Processing Loop</h2>
</div>
</div>
<div></div>
</div>
<p>
In this section we take the example
processing loop that we presented in the
previous section and we flesh it out to
provide a more complete example. We do this
by updating the
<tt class="function">doloop()</tt>
function that our original transaction
application used
<span>(see <a href="simpleprogramlisting.html#doloop_cxx">Method: RepMgr::doloop()</a>)</span>
to fully support our replicated application.
</p>
<p>
In the following example code, code that we
add to the original example is presented in
<b class="userinput"><tt>bold</tt></b>.
</p>
<p>
To begin, we include a new header file into
our application so that we can check for the
<tt class="literal">ENOENT</tt> return value later
in our processing loop. We also define our
<tt class="literal">APP_DATA</tt>
structure, and we define a
<tt class="literal">sleeptime</tt> value.
<span>
Finally, we update <tt class="classname">RepMgr</tt>
to have a new method for our event notification
callback, and to add a new data member for our
<tt class="literal">APP_DATA</tt> data member.
</span>
</p>
<pre class="programlisting">#include &lt;db_cxx.h&gt;
#include &lt;iostream&gt;
<b class="userinput"><tt>#include &lt;errno.h&gt;</tt></b>
...
// Skipping all the RepHostInfoObj and RepConfigInfo code, which does not
// change.
...
using std::cout;
using std::cin;
using std::cerr;
using std::endl;
using std::flush;
#define CACHESIZE (10 * 1024 * 1024)
#define DATABASE "quote.db"
<b class="userinput"><tt>#define SLEEPTIME 3</tt></b>
const char *progname = "RepMgr";
<b class="userinput"><tt>// Struct used to store information in Db app_private field.
typedef struct {
int is_master;
} APP_DATA;</tt></b>
class RepMgr
{
public:
// Constructor.
RepMgr();
// Initialization method. Creates and opens our environment handle.
int init(RepConfigInfo* config);
// The doloop is where all the work is performed.
int doloop();
// terminate() provides our shutdown code.
int terminate();
<b class="userinput"><tt>// event notification callback
static void
event_callback(DbEnv * dbenv, u_int32_t which, void *info);</tt></b>
private:
// disable copy constructor.
RepMgr(const RepMgr &amp;);
void operator = (const RepMgr &amp;);
// internal data members.
<b class="userinput"><tt>APP_DATA app_data;</tt></b>
RepConfigInfo *app_config;
DbEnv dbenv;
// private methods.
// print_stocks() is used to display the contents of our database.
static int print_stocks(Db *dbp);
}; </pre>
<p>
That done, we can skip the
<span><tt class="methodname">main()</tt> method, because it does not change.</span>
Instead, we skip down to our
<span><tt class="classname">RepMgr</tt> constructor where we initialize our
<tt class="literal">APP_DATA is_master</tt> data member:</span>
</p>
<pre class="programlisting">
RepMgr::RepMgr() : app_config(0), dbenv(0)
{
<b class="userinput"><tt>app_data.is_master = 0; // assume I start out as client</tt></b>
}
</pre>
<p>
That done, we must also
update <tt class="methodname">RepMgr::init()</tt> to do a couple
of things. First, we need to register our event callback with
the environment handle. We also need to make our
<tt class="literal">APP_DATA</tt> data member available through our
environment handle's <tt class="methodname">app_private</tt>
field. This is a fairly trivial update, and it happens at the
top of the method (we skip the rest of the method's listing
since it does not change):
</p>
<pre class="programlisting">int RepMgr::init(RepConfigInfo *config)
{
int ret = 0;
app_config = config;
dbenv.set_errfile(stderr);
dbenv.set_errpfx(progname);
<b class="userinput"><tt>dbenv.set_app_private(&amp;app_data);
dbenv.set_event_notify(event_callback);</tt></b>
... </pre>
<p>
That done, we need to implement our
<tt class="function">event_callback()</tt> callback. Note that what we use
here is no different from the callback that we described in
the previous section. However, for the sake of completeness we
provide the implementation here again.
</p>
<pre class="programlisting">
<b class="userinput">
<tt>/*
* A callback used to determine whether the local environment is a replica
* or a master. This is called by the replication framework
* when the local replication environment changes state.
*/
void RepMgr::event_callback(DbEnv *dbenv, u_int32_t which, void *info)
{
APP_DATA *app = dbenv-&gt;get_app_private();
info = NULL; /* Currently unused. */
switch (which) {
case DB_EVENT_REP_MASTER:
app-&gt;is_master = 1;
break;
case DB_EVENT_REP_CLIENT:
app-&gt;is_master = 0;
break;
case DB_EVENT_REP_STARTUPDONE: /* fallthrough */
case DB_EVENT_REP_NEWMASTER:
/* Ignore. */
break;
default:
dbenv-&gt;errx(dbenv, "ignoring event %d", which);
}
}</tt>
</b>
</pre>
<p>
That done, we need to update our
<tt class="function">doloop()</tt>
<span>method.</span>
</p>
<p>
We begin by updating our database handle open flags to
determine which flags to use, depending on whether the
application is running as a master.
</p>
<pre class="programlisting">#define BUFSIZE 1024
int RepMgr::doloop()
{
Db *dbp;
Dbt key, data;
char buf[BUFSIZE], *rbuf;
int ret;
dbp = NULL;
memset(&amp;key, 0, sizeof(key));
memset(&amp;data, 0, sizeof(data));
ret = 0;
for (;;) {
if (dbp == NULL) {
dbp = new Db(&amp;dbenv, 0);
// Set page size small so page allocation is cheap.
if ((ret = dbp-&gt;set_pagesize(512)) != 0)
goto err;
try {
dbp-&gt;open(NULL, DATABASE, NULL, DB_BTREE,
<b class="userinput"><tt>app_data.is_master ? DB_CREATE | DB_AUTO_COMMIT :
DB_AUTO_COMMIT</tt></b>, 0); </pre>
<p>
When we open the database, we modify our error handling to
account for the case where the database does not yet exist. This can
happen if our code is running as a replica and the replication framework has not
yet had a chance to create the databases for us. Recall that replicas never
write to their own databases directly, and so they cannot
create databases on their own.
</p>
<p>
If we detect that the database does not yet exist, we simply
close the database handle, sleep for a short period of time
and then continue processing. This gives the replication framework a chance to
create the database so that our replica can continue
operations.
</p>
<pre class="programlisting"> } catch(DbException dbe) {
<b class="userinput"><tt>/* It is expected that this condition will be triggered
* when client sites start up.
* It can take a while for the master site to be found
* and synced, and no DB will be available until then.
*/
if (dbe.get_errno() == ENOENT) {
cout &lt;&lt; "No stock db available yet - retrying." &lt;&lt; endl;
try {
dbp-&gt;close(0);
} catch (DbException dbe2) {
cout &lt;&lt; "Unexpected error closing after failed"
&lt;&lt; " open, message: " &lt;&lt; dbe2.what() &lt;&lt; endl;
dbp = NULL;
goto err;
}
dbp = NULL;
sleep(SLEEPTIME);
continue;
} else {</tt></b>
dbenv.err(ret, "DB-&gt;open");
throw dbe;
<b class="userinput"><tt>}</tt></b>
}
} </pre>
<p>
Next we modify our prompt, so that if the local process is running
as a replica, we can tell from the shell that the prompt is for a
read-only process.
</p>
<pre class="programlisting"> <b class="userinput"><tt>cout &lt;&lt; "QUOTESERVER" ;
if (!app_data.is_master)
cout &lt;&lt; "(read-only)";
cout &lt;&lt; "&gt; " &lt;&lt; flush; </tt></b></pre>
<p>
When we collect data from the prompt, there is a case that says
if no data is entered then show the entire stocks database.
This display is performed by our
<tt class="function">print_stocks()</tt>
<span>method</span>
(which has not
required a modification since we first introduced it in
<a href="simpleprogramlisting.html#printstocks_c">
<span>Method: RepMgr::print_stocks()</span>
</a>).
</p>
<p>
When we call
<span><tt class="function">print_stocks()</tt>, </span>
we check for a dead replication handle. Dead
replication handles happen whenever a replication election
results in a previously committed transaction becoming
invalid. This is an error scenario caused by a new master having a
slightly older version of the data than the original
master and so all replicas must modify their database(s) to
reflect that of the new master. In this situation, some
number of previously committed transactions may have to be
unrolled. From the replica's perspective, the database
handles should all be closed and then opened again.
</p>
<pre class="programlisting">
if (fgets(buf, sizeof(buf), stdin) == NULL)
break;
if (strtok(&amp;buf[0], " \t\n") == NULL) {
switch ((ret = print_stocks(dbp))) {
case 0:
continue;
<b class="userinput"><tt>case DB_REP_HANDLE_DEAD:
(void)dbp-&gt;close(DB_NOSYNC);
cout &lt;&lt; "closing db handle due to rep handle dead" &lt;&lt; endl;
dbp = NULL;
continue;</tt></b>
default:
dbp-&gt;err(ret, "Error traversing data");
goto err;
}
}
rbuf = strtok(NULL, " \t\n");
if (rbuf == NULL || rbuf[0] == '\0') {
if (strncmp(buf, "exit", 4) == 0 ||
strncmp(buf, "quit", 4) == 0)
break;
dbenv.errx("Format: TICKER VALUE");
continue;
} </pre>
<p>
That done, we need to add a little error checking to our
command prompt to make sure the user is not attempting to
modify the database at a replica. Remember, replicas must never
modify their local databases on their own. This guards against
that happening due to user input at the prompt.
</p>
<pre class="programlisting"> <b class="userinput"><tt>if (!app_data.is_master) {
dbenv-&gt;errx(dbenv, "Can't update at client");
continue;
}</tt></b>
key.set_data(buf);
key.set_size((u_int32_t)strlen(buf));
data.set_data(rbuf);
data.set_size((u_int32_t)strlen(rbuf));
if ((ret = dbp-&gt;put(NULL, &amp;key, &amp;data, 0)) != 0)
{
dbp-&gt;err(ret, "DB-&gt;put");
if (ret != DB_KEYEXIST)
goto err;
}
}
err: if (dbp != NULL)
(void)dbp-&gt;close(dbp, DB_NOSYNC);
return (ret);
} </pre>
<p>
With that completed, we are all done updating our application
for replication.
The only remaining
<span>method, <tt class="function">print_stocks()</tt>,</span>
is unmodified from when we
originally introduced it. For details on that function, see
<a href="simpleprogramlisting.html#printstocks_c">
<span>Method: RepMgr::print_stocks()</span>
</a>.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="runningit"></a>Running It</h3>
</div>
</div>
<div></div>
</div>
<p>
To run our replicated application, we need to make
sure each participating environment has its own unique
home directory. We can do this by running
each site on a separate networked machine, but that
is not strictly necessary; multiple instances of this
code can run on the same machine provided the
environment home restriction is observed.
</p>
<p>
To run a process, make sure the environment home
exists and then start the process using the
<tt class="literal">-h</tt> option to specify that
directory. You must also use the <tt class="literal">-m</tt>
option to identify the local host and port that this
process will use to listen for replication messages, and
the <tt class="literal">-o</tt> option to identify the other
processes in the replication group. Finally, use the
<tt class="literal">-p</tt> option to specify a priority.
The process that you designate to have the highest priority will become
the master.
</p>
<pre class="programlisting">&gt; mkdir env1
&gt; ./RepMgr -h env1 -n 2 -m localhost:8080 -o localhost:8081 -p 10
No stock database yet available.
No stock database yet available. </pre>
<p>
Now, start another process. This time, change the environment
home to something else, use the <tt class="literal">-m</tt> to at
least change the port number the process is listening on, and
use the <tt class="literal">-o</tt> option to identify the host and
port of the other replication process:
</p>
<pre class="programlisting">&gt; mkdir env2
&gt; ./RepMgr -h env2 -n 2 -m localhost:8081 -o localhost:8080 -p 20</pre>
<p>
After a short pause, the second process should display the master
prompt:
</p>
<pre class="programlisting">
QUOTESERVER &gt; </pre>
<p>
And the first process should
display the read-only prompt:
</p>
<pre class="programlisting">
QUOTESERVER (read-only)&gt; </pre>
<p>
Now go to the master process and give it a couple of stocks and stock
prices:
</p>
<pre class="programlisting">QUOTESERVER&gt; FAKECO 9.87
QUOTESERVER&gt; NOINC .23
QUOTESERVER&gt; </pre>
<p>
Then, go to the replica and hit <b class="userinput"><tt>return</tt></b> at the prompt to
see the new values:
</p>
<pre class="programlisting">QUOTESERVER (read-only)&gt;
Symbol Price
====== =====
FAKECO 9.87
NOINC .23
QUOTESERVER (read-only)&gt; </pre>
<p>
Doing the same at the master results in the same thing:
</p>
<pre class="programlisting">QUOTESERVER&gt;
Symbol Price
====== =====
FAKECO 9.87
NOINC .23
QUOTESERVER&gt; </pre>
<p>
You can change a stock by simply entering the stock value and
new price at the master's prompt:
</p>
<pre class="programlisting">QUOTESERVER&gt; FAKECO 10.01
QUOTESERVER&gt; </pre>
<p>
Then, go to either the master or the replica to see the updated
database:
</p>
<pre class="programlisting">QUOTESERVER&gt;
Symbol Price
====== =====
FAKECO 10.01
NOINC .23
QUOTESERVER&gt; </pre>
<p>
And on the replica:
</p>
<pre class="programlisting">QUOTESERVER (read-only)&gt;
Symbol Price
====== =====
FAKECO 10.01
NOINC .23
QUOTESERVER (read-only)&gt; </pre>
<p>
Finally, to quit the applications, simply type
<tt class="literal">quit</tt> at both prompts:
</p>
<pre class="programlisting">QUOTESERVER (read-only)&gt; quit
&gt; </pre>
<p>
And on the master as well:
</p>
<pre class="programlisting">QUOTESERVER&gt; quit
&gt; </pre>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="processingloop.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="fwrkmasterreplica.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="addfeatures.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Processing Loop </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Chapter 5. Additional Features</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,76 @@
<?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>Managing Connection Retries</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
<link rel="previous" href="electiontimes.html" title="Managing Election Times" />
<link rel="next" href="heartbeats.html" title="Managing Heartbeats" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Managing Connection Retries</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="electiontimes.html">Prev</a> </td>
<th width="60%" align="center">Chapter 3. The DB Replication Framework</th>
<td width="20%" align="right"> <a accesskey="n" href="heartbeats.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="fmwrkconnectretry"></a>Managing Connection Retries</h2>
</div>
</div>
<div></div>
</div>
<p>
In the event that a communication failure occurs between
two environments in a replication group, the replication framework will wait a set
amount of time before attempting to re-establish the
connection. You can configure this wait value using
<span>
<span><tt class="methodname">DbEnv::rep_set_timeout()</tt>.</span>
To do so, specify the
<tt class="literal">DB_REP_CONNECTION_RETRY</tt>
flag to the <tt class="literal">which</tt> parameter and then a
retry value in microseconds to the
<tt class="literal">timeout</tt> parameter.
</span>
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="electiontimes.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="heartbeats.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Managing Election Times </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Managing Heartbeats</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,297 @@
<?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>Chapter 4. Replica versus Master Processes</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="previous" href="heartbeats.html" title="Managing Heartbeats" />
<link rel="next" href="processingloop.html" title="Processing Loop" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Chapter 4. Replica versus Master Processes</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="heartbeats.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="processingloop.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="chapter" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a id="fwrkmasterreplica"></a>Chapter 4. Replica versus Master Processes</h2>
</div>
</div>
<div></div>
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="sect1">
<a href="fwrkmasterreplica.html#determinestate">Determining State</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="processingloop.html">Processing Loop</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="exampledoloop.html">Example Processing Loop</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="exampledoloop.html#runningit">Running It</a>
</span>
</dt>
</dl>
</dd>
</dl>
</div>
<p>
Every environment participating in a replicated application
must know whether it is a <span class="emphasis"><em>master</em></span> or
<span class="emphasis"><em>replica</em></span>. The reason for this is
because, simply, the master can modify the database while
replicas cannot. As a result, not only will you open
databases differently depended on whether the environment is
running as a master, but the environment will frequently
behave quit a bit differently depending on whether it
thinks it is operating as the read/write interface for
your database.
</p>
<p>
Moreover, an environment must also be capable of
gracefully switching between master and replica states.
This means that the environment must be able to detect when
it has switched states.
</p>
<p>
Not surprisingly, a large part of your application's code
will be tied up in knowing which state a given
environment is in and then in the logic of how to behave depending on
its state.
</p>
<p>
This chapter shows you how to determine your environment's
state, and it then shows you some sample code on how
an application might behave depending on whether it is a
master or a replica in a replicated application.
</p>
<div class="sect1" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="determinestate"></a>Determining State</h2>
</div>
</div>
<div></div>
</div>
<p>
In order to determine whether your code is
running as a master or a replica, you implement a
callback whose function it is to respond to
events that happen within the DB library.
</p>
<p>
Note that this callback is usable for events beyond
those required for replication purposes. In this
section, however, we only discuss the
replication-specific events.
</p>
<p>
The callback is required to determine
which event has been passed to it, and then take
action depending on the event. For replication,
the events that we care about are:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
<tt class="literal">DB_EVENT_REP_MASTER</tt>
</p>
<p>
The local environment is now a master.
</p>
</li>
<li>
<p>
<tt class="literal">DB_EVENT_REP_CLIENT</tt>
</p>
<p>
The local environment is now a replica.
</p>
</li>
<li>
<p>
<tt class="literal">DB_EVENT_REP_STARTUPDONE</tt>
</p>
<p>
The replica has completed startup
synchronization and is now
processing log records received
from the master.
</p>
</li>
<li>
<p>
<tt class="literal">DB_EVENT_REP_NEWMASTER</tt>
</p>
<p>
An election was held and a new
environment was made a master. However,
the current environment <span class="emphasis"><em>is
not</em></span> the master. This
event exists so that you can
cause your code to take some
unique action in the event that the
replication groups switches masters.
</p>
</li>
</ul>
</div>
<p>
Note that these events are raised whenever the
state is established. That is, when the current
environment becomes a client, and that includes
at application startup, the event is raised.
Also, when an election is held and a client is elected to be a
master, then the event occurs.
</p>
<p>
The implementation of this callback is fairly
simple. First you pass a structure to the
environment handle that you can use to record the
environment's state, and then you implement a switch
statement within the callback that you use to
record the current state, depending on the
arriving event.
</p>
<p>
For example:
</p>
<pre class="programlisting">#include &lt;db_cxx.h&gt;
/* Forward declaration */
void *event_callback(DbEnv *, u_int32_t, void *);
...
/* The structure we use to track our environment's state */
typedef struct {
int is_master;
} APP_DATA;
...
/*
* Inside our main() function, we declare an APP_DATA variable.
*/
APP_DATA my_app_data;
my_app_data.is_master = 0; /* Assume we start as a replica */
...
/*
* Now we open our environment handle and set the APP_DATA structure
* to it's app_private member.
*/
DbEnv *dbenv = new DbEnv(0);
dbenv-&gt;set_app_private(&amp;my_app_data);
/* Having done that, register the callback with the
* Berkeley DB library
*/
dbenv-&gt;set_event_notify(event_callback); </pre>
<p>
That done, we still need to implement the callback itself. This
implementation can be fairly trivial.
</p>
<pre class="programlisting">/*
* A callback used to determine whether the local environment is a replica
* or a master. This is called by the replication framework
* when the local environment changes state.
*/
void *
event_callback(DbEnv *dbenv, u_int32_t which, void *info)
{
APP_DATA *app = dbenv-&gt;get_app_private();
info = NULL; /* Currently unused. */
switch (which) {
case DB_EVENT_REP_MASTER:
app-&gt;is_master = 1;
break;
case DB_EVENT_REP_CLIENT:
app-&gt;is_master = 0;
break;
case DB_EVENT_REP_STARTUPDONE: /* fallthrough */
case DB_EVENT_REP_NEWMASTER:
/* Ignore. */
break;
default:
dbenv-&gt;errx(dbenv, "ignoring event %d", which);
}
} </pre>
<p>
Notice how we access the
<tt class="literal">APP_DATA</tt> information using the environment
handle's <tt class="literal">app_private</tt> data member. We also ignore
the <tt class="literal">DB_EVENT_REP_NEWMASTER</tt> and
<tt class="literal">DB_EVENT_REP_STARTUPDONE</tt> cases since these are not
relevant for simple replicated applications.
</p>
<p>
Of course, this only gives us the current state of the environment. We
still need the code that determines what to do when the environment
changes state and how to behave depending on the state (described
in the next section).
</p>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="heartbeats.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="index.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="processingloop.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Managing Heartbeats </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Processing Loop</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,372 @@
<?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>Permanent Message Handling</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
<link rel="previous" href="repmgr_init_example_c.html" title="Adding the Replication Framework to&#10; &#10; SimpleTxn&#10; " />
<link rel="next" href="electiontimes.html" title="Managing Election Times" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Permanent Message Handling</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="repmgr_init_example_c.html">Prev</a> </td>
<th width="60%" align="center">Chapter 3. The DB Replication Framework</th>
<td width="20%" align="right"> <a accesskey="n" href="electiontimes.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="fwrkpermmessage"></a>Permanent Message Handling</h2>
</div>
</div>
<div></div>
</div>
<p>
As described in <a href="permmessages.html">Permanent Message Handling</a>,
messages are marked permanent if they contain database
modifications that should be committed at the replica.
DB's replication code decides if it must flush its
transaction logs to disk depending on whether it receives
sufficient permanent message acknowledgments from the
participating replica. More importantly, the thread
performing the transaction commit blocks
until it either receives enough acknowledgments, or the
acknowledgment timeout expires.
</p>
<p>
The replication framework is fully capable of managing permanent messages
for you if your application requires it (most do).
Almost all of the details of this are handled by the
replication framework for you. However, you do have to set some policies
that tell the replication framework how to handle permanent messages.
</p>
<p>
There are two things that you have to do:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Determine how many acknowledgments
must be received by the master.
</p>
</li>
<li>
<p>
Identify the amount of time that
replicas have to send their
acknowledgments.
</p>
</li>
</ul>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="fmwrkpermpolicy"></a>Identifying Permanent Message Policies</h3>
</div>
</div>
<div></div>
</div>
<p>
You identify permanent message policies using the
Note that you can set permanent message
policies at any time during the life of the
application.
</p>
<p>
The following permanent message policies are available when you use
the replication framework:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
<tt class="literal">DB_REPMGR_ACKS_NONE</tt>
</p>
<p>
No permanent message acknowledgments are required. If
this policy is selected, permanent message handling is
essentially "turned off." That is, the master will
never wait for replica acknowledgments. In this case,
transaction log data is either flushed or not strictly
depending on the type of commit that is being performed
(synchronous or asynchronous).
</p>
</li>
<li>
<p>
<tt class="literal">DB_REPMGR_ACKS_ONE</tt>
</p>
<p>
At least one replica must acknowledge the permanent
message within the timeout period.
</p>
</li>
<li>
<p>
<tt class="literal">DB_REPMGR_ACKS_ONE_PEER</tt>
</p>
<p>
At least one electable peer must acknowledge the permanent
message within the timeout period.
Note that an
<span class="emphasis"><em>electable peer</em></span> is simply another
environment that can be elected to be a master (that
is, it has a priority greater than 0). Do not confuse
this with the concept of a peer as used for client to
client transfers. See
<a href="c2ctransfer.html">Client to Client Transfer</a>
for more information on client to client transfers.
</p>
</li>
<li>
<p>
<tt class="literal">DB_REPMGR_ACKS_ALL</tt>
</p>
<p>
All environments must acknowledge the message within
the timeout period. This
policy should be selected only if your replication
group has a small number of replicas, and those replicas
are on extremely reliable networks and servers.
</p>
<p>
When this flag is used, the actual number of
environments that must respond is
determined by the value set for
<span><tt class="methodname">DbEnv::rep_set_nsites()</tt>.</span>
</p>
</li>
<li>
<p>
<tt class="literal">DB_REPMGR_ACKS_ALL_PEERS</tt>
</p>
<p>
All electable peers must acknowledge the message within the
timeout period. This
policy should be selected only if your replication
group is small, and its various environments
are on extremely reliable networks and servers.
</p>
<p>
Note that an
<span class="emphasis"><em>electable peer</em></span> is simply another
environment that can be elected to be a master (that
is, it has a priority greater than 0). Do not confuse
this with the concept of a peer as used for client to
client transfers. See
<a href="c2ctransfer.html">Client to Client Transfer</a>
for more information on client to client transfers.
</p>
</li>
<li>
<p>
<tt class="literal">DB_REPMGR_ACKS_QUORUM</tt>
</p>
<p>
A quorum of electable peers must acknowledge the message within the timeout period.
A quorum is reached when acknowledgments are received from the minimum number
of environments needed to ensure that the record remains durable
if an election is held. That is, the master wants to hear from enough
electable replicas that they have committed the record so that if an election
is held, the master knows the record will exist even if a new master is selected.
</p>
<p>
Note that an
<span class="emphasis"><em>electable peer</em></span> is simply another
environment that can be elected to be a master (that
is, it has a priority greater than 0). Do not confuse
this with the concept of a peer as used for client to
client transfers. See
<a href="c2ctransfer.html">Client to Client Transfer</a>
for more information on client to client transfers.
</p>
</li>
</ul>
</div>
<p>
By default, a quorum of sites must must acknowledge a permanent
message in order for it considered to have been successfully
transmitted. The actual number of environments that must respond is
calculated using the value set with
<span><tt class="methodname">DbEnv::rep_set_nsites()</tt>.</span>
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="fmwrkpermtimeout"></a>Setting the Permanent Message Timeout</h3>
</div>
</div>
<div></div>
</div>
<p>
The permanent message timeout represents the
maximum amount of time the committing thread
will block waiting for message
acknowledgments. If sufficient
acknowledgments arrive before this timeout has
expired, the thread continues operations as
normal. However, if this timeout expires, the
committing thread flushes its transaction log
buffer before continuing with normal
operations.
</p>
<p>
You set the timeout value using the
<tt class="methodname">DbEnv::rep_set_timeout()</tt>
method. When you do this, you provide the
<tt class="literal">DB_REP_ACK_TIMEOUT</tt> flag to
the <tt class="literal">which</tt> parameter, and the
timeout value in microseconds to the
<tt class="literal">timeout</tt> parameter.
</p>
<p>
For example:
</p>
<pre class="programlisting"> dbenv-&gt;rep_set_timeout(DB_REP_ACK_TIMEOUT, 100); </pre>
<p>
This timeout value can be set at anytime during the
life of the application.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="perm2fmwrkexample"></a>Adding a Permanent Message Policy to
<span>RepMgr</span>
</h3>
</div>
</div>
<div></div>
</div>
<p>
For illustration purposes, we will now update
<tt class="literal">RepMgr</tt>
such that it requires only one acknowledgment from
a replica on transactional commits. Also, we will give
this acknowledgment a 500 microsecond timeout
value. This means that our application's main
thread will block for up to 500 microseconds waiting
for an acknowledgment. If it does not receive at
least one acknowledgment in that amount of time,
DB will flush the transaction logs to disk
before continuing on.
</p>
<p>
This is a very simple update. We can perform the
entire thing in
<tt class="methodname">RepMgr::init()</tt>
immediately after we set the application's priority
and before we open our environment handle.
</p>
<pre class="programlisting">int RepMgr::init(RepConfigInfo *config)
{
int ret = 0;
app_config = config;
dbenv.set_errfile(stderr);
dbenv.set_errpfx(progname);
if ((ret = dbenv.repmgr_set_local_site(app_config-&gt;this_host.host,
app_config-&gt;this_host.port, 0)) != 0) {
cerr &lt;&lt; "Could not set listen address to host:port "
&lt;&lt; app_config-&gt;this_host.host &lt;&lt; ":"
&lt;&lt; app_config-&gt;this_host.port
&lt;&lt; "error: " &lt;&lt; ret &lt;&lt; endl;
}
for ( REP_HOST_INFO *cur = app_config-&gt;other_hosts; cur != NULL;
cur = cur-&gt;next) {
if ((ret = dbenv.repmgr_add_remote_site(cur-&gt;host, cur-&gt;port,
NULL, 0)) != 0) {
cerr &lt;&lt; "could not add site." &lt;&lt; endl
}
}
if (app_config-&gt;totalsites &gt; 0) {
try {
if ((ret = dbenv.rep_set_nsites(app_config-&gt;totalsites)) != 0)
dbenv.err(ret, "set_nsites");
} catch (DbException dbe) {
cerr &lt;&lt; "rep_set_nsites call failed. Continuing." &lt;&lt; endl;
}
}
dbenv.rep_set_priority(app_config-&gt;priority);
<b class="userinput"><tt>/* Permanent messages require at least one ack */
dbenv.repmgr_set_ack_policy(DB_REPMGR_ACKS_ONE);
/* Give 500 microseconds to receive the ack */
dbenv.rep_set_timeout(DB_REP_ACK_TIMEOUT, 500);</tt></b>
dbenv.set_cachesize(0, CACHESIZE, 0);
dbenv.set_flags(DB_TXN_NOSYNC, 1);
... </pre>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="repmgr_init_example_c.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="electiontimes.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Adding the Replication Framework to
SimpleTxn
 </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Managing Election Times</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,41 @@
body { width: 45em;
margin-left: 3em;
font-family: Arial, Helvetica, sans-serif;
font-size: 11pt;
}
h2.title { margin-left: -1em;
font-family: Verdana, serif;
font-size: 16pt;
}
h3.title { font-family: Verdana, serif;
font-size: 14pt;
}
pre.programlisting {
font-family: monospace;
background-color: #eae8e9;
}
div.navheader { font-size: 9pt;
width: 60em;
margin-left: -2em;
}
div.navheader table tr td { font-size: 9pt; }
div.navfooter { font-size: 9pt;
width: 60em;
margin-left: -2em;
}
div.navfooter table tr td { font-size: 9pt; }
span.emphasis { font-style: italic; font-size: 9pt;}
div.appendix div.informaltable { font-size: 9pt; }
div.appendix div.informaltable td { vertical-align: top; }
div.appendix div.informaltable p { margin-top: .25em; }
div.appendix div.informaltable p { margin-bottom: .25em; }

View File

@@ -0,0 +1,103 @@
<?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>Managing Heartbeats</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
<link rel="previous" href="fmwrkconnectretry.html" title="Managing Connection Retries" />
<link rel="next" href="fwrkmasterreplica.html" title="Chapter 4. Replica versus Master Processes" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Managing Heartbeats</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="fmwrkconnectretry.html">Prev</a> </td>
<th width="60%" align="center">Chapter 3. The DB Replication Framework</th>
<td width="20%" align="right"> <a accesskey="n" href="fwrkmasterreplica.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="heartbeats"></a>Managing Heartbeats</h2>
</div>
</div>
<div></div>
</div>
<p>
If your replicated application experiences few updates,
it is possible for the replication group to lose a
master without noticing it. This is because normally a
replicated application only knows that a master has
gone missing when update activity causes messages to be
passed between the master and clients.
</p>
<p>
To guard against this, you can configure a heartbeat.
The heartbeat must be configured for both the master
and each of the clients.
</p>
<p>
On the master, you configure the application to send a
heartbeat on a defined interval when it is otherwise
idle. Do this by using the
<span>
<tt class="literal">DB_REP_HEARTBEAT_SEND</tt> flag
with the
<tt class="methodname">DbEnv::rep_set_timeout()</tt>
method.
</span>
You must also provide the method a value representing the frequency of
the heartbeat. Note that the heartbeat is sent only if the
system is idle.
</p>
<p>
On the client, you configure the application to listen
for a heartbeat. The time that you configure here is
the amount of time the client will wait for some
message from the master (either the heartbeat or some
other message) before concluding that the connection is
lost. You do this using the
<span>
<tt class="literal">DB_REP_HEARTBEAT_MONITOR</tt> flag
with the
<tt class="methodname">DbEnv::rep_set_timeout()</tt>
method and a timeout value in microseconds.
</span>
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="fmwrkconnectretry.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="fwrkmasterreplica.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Managing Connection Retries </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Chapter 4. Replica versus Master Processes</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,465 @@
<?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>Getting Started with Replicated Berkeley DB Applications</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="next" href="preface.html" title="Preface" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Getting Started with Replicated Berkeley DB Applications</th>
</tr>
<tr>
<td width="20%" align="left"> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="preface.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="book" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h1 class="title"><a id="id613728"></a>Getting Started with Replicated Berkeley DB Applications</h1>
</div>
<div>
<div class="legalnotice">
<p class="legalnotice-title">
<b>Legal Notice</b>
</p>
<p>
This documentation is distributed under an open source license.
You may review the terms of this license at:
<a href="http://www.oracle.com/technology/software/products/berkeley-db/htdocs/oslicense.html" target="_top">http://www.oracle.com/technology/software/products/berkeley-db/htdocs/oslicense.html</a>
</p>
<p>
Oracle, Berkeley DB,
and
Sleepycat are trademarks or registered trademarks of
Oracle. All rights to these marks are reserved.
No third-party use is permitted without the
express prior written consent of Oracle.
</p>
<p>
To obtain a copy of this document's original source code, please
submit a request to the Oracle Technology Network forum at:
<a href="http://forums.oracle.com/forums/forum.jspa?forumID=271" target="_top">http://forums.oracle.com/forums/forum.jspa?forumID=271</a>
</p>
</div>
</div>
<div>
<p class="pubdate">4/25/2008</p>
</div>
</div>
<div></div>
<hr />
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="preface">
<a href="preface.html">Preface</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect1">
<a href="preface.html#conventions">Conventions Used in this Book</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="preface.html#moreinfo">For More Information</a>
</span>
</dt>
</dl>
</dd>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="introduction.html">1. Introduction</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect1">
<a href="introduction.html#overview">Overview</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="introduction.html#repenvirons">Replication Environments</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="introduction.html#repdbs">Replication Databases</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="introduction.html#commlayer">Communications Layer</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="introduction.html#masterselect">Selecting a Master</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="repadvantage.html">Replication Benefits</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="apioverview.html">The Replication APIs</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="apioverview.html#repframeworkoverview">Replication Framework Overview</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="apioverview.html#repapioverview">Replication API Overview</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="elections.html">Holding Elections</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="elections.html#influencingelections">Influencing Elections</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="elections.html#winningelections">Winning Elections</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="elections.html#switchingmasters">Switching Masters</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="permmessages.html">Permanent Message Handling</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="permmessages.html#permmessagenot">When Not to Manage
Permanent Messages</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="permmessages.html#permmanage">Managing Permanent Messages</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="permmessages.html#permimplement">Implementing Permanent
Message Handling</a>
</span>
</dt>
</dl>
</dd>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="txnapp.html">2. Transactional Application</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect1">
<a href="txnapp.html#appoverview">Application Overview</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="simpleprogramlisting.html">Program Listing</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#repconfiginfo_cxx">
Class: RepConfigInfo
</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#repmgr_cxx">Class: RepMgr</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#usage_cxx">Function: usage()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#main_cxx">Function: main()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#repmgr_init_cxx">Method: RepMgr::init()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#doloop_cxx">Method: RepMgr::doloop()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#printstocks_c">
Method: RepMgr::print_stocks()
</a>
</span>
</dt>
</dl>
</dd>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="repapp.html">3. The DB Replication Framework</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect1">
<a href="repapp.html#rep_init_code">
Starting and Stopping Replication
</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="repapp.html#election_flags">Managing Election Policies</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="repapp.html#thread_count">Selecting the Number of Threads</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="repmgr_init_example_c.html">Adding the Replication Framework to
SimpleTxn
</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="fwrkpermmessage.html">Permanent Message Handling</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="fwrkpermmessage.html#fmwrkpermpolicy">Identifying Permanent Message Policies</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="fwrkpermmessage.html#fmwrkpermtimeout">Setting the Permanent Message Timeout</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="fwrkpermmessage.html#perm2fmwrkexample">Adding a Permanent Message Policy to
RepMgr
</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="electiontimes.html">Managing Election Times</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="electiontimes.html#electiontimeout">Managing Election Timeouts</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="electiontimes.html#electretrytime">Managing Election Retry Times</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="fmwrkconnectretry.html">Managing Connection Retries</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="heartbeats.html">Managing Heartbeats</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="fwrkmasterreplica.html">4. Replica versus Master Processes</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect1">
<a href="fwrkmasterreplica.html#determinestate">Determining State</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="processingloop.html">Processing Loop</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="exampledoloop.html">Example Processing Loop</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="exampledoloop.html#runningit">Running It</a>
</span>
</dt>
</dl>
</dd>
</dl>
</dd>
<dt>
<span class="chapter">
<a href="addfeatures.html">5. Additional Features</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect1">
<a href="addfeatures.html#delayedsync">Delayed Synchronization</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="manageblock.html">Managing Blocking Operations</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="noautoinit.html">Stop Auto-Initialization</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="c2ctransfer.html">Client to Client Transfer</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="c2ctransfer.html#fmwrkpeerserver">Identifying Peers</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="bulk.html">Bulk Transfers</a>
</span>
</dt>
</dl>
</dd>
</dl>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"> </td>
<td width="20%" align="center"> </td>
<td width="40%" align="right"> <a accesskey="n" href="preface.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top"> </td>
<td width="20%" align="center"> </td>
<td width="40%" align="right" valign="top"> Preface</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,395 @@
<?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>Chapter 1. Introduction</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="previous" href="preface.html" title="Preface" />
<link rel="next" href="repadvantage.html" title="Replication Benefits" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Chapter 1. Introduction</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="preface.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="repadvantage.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="chapter" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a id="introduction"></a>Chapter 1. Introduction</h2>
</div>
</div>
<div></div>
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="sect1">
<a href="introduction.html#overview">Overview</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="introduction.html#repenvirons">Replication Environments</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="introduction.html#repdbs">Replication Databases</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="introduction.html#commlayer">Communications Layer</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="introduction.html#masterselect">Selecting a Master</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="repadvantage.html">Replication Benefits</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="apioverview.html">The Replication APIs</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="apioverview.html#repframeworkoverview">Replication Framework Overview</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="apioverview.html#repapioverview">Replication API Overview</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="elections.html">Holding Elections</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="elections.html#influencingelections">Influencing Elections</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="elections.html#winningelections">Winning Elections</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="elections.html#switchingmasters">Switching Masters</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="permmessages.html">Permanent Message Handling</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="permmessages.html#permmessagenot">When Not to Manage
Permanent Messages</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="permmessages.html#permmanage">Managing Permanent Messages</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="permmessages.html#permimplement">Implementing Permanent
Message Handling</a>
</span>
</dt>
</dl>
</dd>
</dl>
</div>
<p>
This book provides a thorough introduction and discussion on
replication as used with Berkeley DB (DB). It begins by offering a
general overview to replication and the benefits it provides. It also
describes the APIs that you use to implement replication, and it
describes architecturally the things that you need to do to your
application code in order to use the replication APIs. Finally, it
discusses the differences in backup and restore strategies that you
might pursue when using replication, especially where it comes to log
file removal.
</p>
<p>
You should understand the concepts from the
<span>
<i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i>
</span>
guide before reading this book.
</p>
<div class="sect1" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="overview"></a>Overview</h2>
</div>
</div>
<div></div>
</div>
<p>
The DB replication APIs allow you to distribute your database
write operations (performed on a read-write master) to one or
more read-only <span class="emphasis"><em>replicas</em></span>.
For this reason, DB's replication implementation is said to be a
<span class="emphasis"><em>single master, multiple replica</em></span> replication strategy.
</p>
<p>
Note that your database write operations can occur only on the
master; any attempt to write to a replica results in an error
being
<span>raised by</span>
the DB API used to perform the write.
</p>
<p>
A single replication master and all of its replicas are referred
to as a <span class="emphasis"><em>replication group</em></span>. While all
members of the replication group can reside on the same
machine, usually each replication participant is placed on a
separate physical machine somewhere on the network.
</p>
<p>
Note that all replication applications must first be
transactional applications. The data that the master transmits
its replicas are log records that are generated as records are
updated. Upon transactional commit, the master transmits a
transaction record which tells the replicas to commit the
records they previously received from the master. In order for
all of this to work, your replicated application must also be a
transactional application. For this reason, it is
recommended that you write and debug your DB application as
a stand-alone transactional application before introducing the
replication layer to your code.
</p>
<p>
Finally, be aware that all machines participating in the
replication group must share identical
<span class="emphasis"><em>endianess</em></span>. Endianess is the byte-order
strategy used by the computing platform to store multibyte
numbers. Berkeley DB is sensitive to byte order and so your
replication infrastructure must be consistent in this area.
We expect to remove this requirement in some future
release of the product.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repenvirons"></a>Replication Environments</h3>
</div>
</div>
<div></div>
</div>
<p>
The most important requirement for a replication
participant is that it must use a unique Berkeley DB database
environment independent of all other replication
participants. So while multiple replication participants
can reside on the same physical machine, no two such participants
can share the same environment home directory.
</p>
<p>
For this reason, technically replication occurs between
unique <span class="emphasis"><em>database environments</em></span>. So in the strictest sense,
a replication group consists of a <span class="emphasis"><em>master
environment</em></span> and
one or more <span class="emphasis"><em>replica environments</em></span>. However, the reality
is that for production code, each such environment will
usually be located on its own unique machine. Consequently,
this manual sometimes talks about <span class="emphasis"><em>replication sites</em></span>, meaning the
unique combination of environment home directory, host and port that a specific
replication application is using.
</p>
<p>
There is no DB-specified limit to the number of
environments which can participate in a replication group.
The only limitation here is one of resources —
network bandwidth, for example.
</p>
<p>
(Note, however, that the replication framework does place a limit on the
number of environments you can use. See
<a href="apioverview.html#repframeworkoverview">Replication Framework Overview</a>
for details.)
</p>
<p>
Also, DB's replication implementation requires all
participating environments to be assigned IDs that are
locally unique to the given environment. Depending on the
replication APIs that you choose to use, you may or may not
need to manage this particular detail.
</p>
<p>
For detailed information on database environments, see
the <i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i>
guide. For more information on environment IDs, see
the <i class="citetitle">Berkeley DB Programmer's Reference Guide</i>.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repdbs"></a>Replication Databases</h3>
</div>
</div>
<div></div>
</div>
<p>
DB's databases are managed and used in exactly the same way
as if you were writing a non-replicated application, with
a couple of caveats. First, the databases maintained in a replicated environment
must reside either in the <tt class="literal">ENV_HOME</tt>
directory, or in the directory identified by the
<tt class="methodname">DbEnv::set_data_dir()</tt>
method. Unlike non-replication applications, you cannot place your
databases in a subdirectory below these locations. You should
also not use full path names for your databases or
environments as these are likely to break as to replicated
to other machines.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="commlayer"></a>Communications Layer</h3>
</div>
</div>
<div></div>
</div>
<p>
In order to transmit database writes to the replication
replicas, DB requires a communications layer.
DB is agnostic as to what this layer should
look like. The only requirement is that it
be capable of passing two opaque data objects and an
environment ID from the master to its replicas without
corruption.
</p>
<p>
Because replicas are usually placed on different machines on
the network, the communications layer is usually some kind
of a network-aware implementation. Beyond that, its
implementation details are largely up to you. It could use
TCP/IP sockets, for example, or it could use
raw sockets if they perform better for your particular
application.
</p>
<p>
Note that you may not have to write your own communications
layer. DB provides a replication framework that
includes a fully-functional TCP/IP-based communications layer.
See <a href="apioverview.html">The Replication APIs</a>
for more information.
</p>
<p>
See the <i class="citetitle">Berkeley DB Programmer's Reference Guide</i>
for a description of how to
write your own custom replication communications layer.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="masterselect"></a>Selecting a Master</h3>
</div>
</div>
<div></div>
</div>
<p>
Every replication group is allowed one and only one
master environment. Almost always, masters are selected by
holding an <span class="emphasis"><em>election</em></span>. All such
elections are performed by the underlying Berkeley DB
replication code so you have to do very little to
implement them.
</p>
<p>
When holding an election, replicas "vote" on who should
be the master. Among replicas participating in the
election, the one with the most up-to-date set of log
records will win the election. Note that it's possible
for there to be a tie. When this occurs, priorities are
used to select the master. See
<a href="elections.html">Holding Elections</a>
for details.
</p>
<p>
For more information on holding and managing elections,
see <a href="elections.html">Holding Elections</a>.
</p>
</div>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="preface.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="index.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="repadvantage.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Preface </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Replication Benefits</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,88 @@
<?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>Managing Blocking Operations</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="addfeatures.html" title="Chapter 5. Additional Features" />
<link rel="previous" href="addfeatures.html" title="Chapter 5. Additional Features" />
<link rel="next" href="noautoinit.html" title="Stop Auto-Initialization" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Managing Blocking Operations</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="addfeatures.html">Prev</a> </td>
<th width="60%" align="center">Chapter 5. Additional Features</th>
<td width="20%" align="right"> <a accesskey="n" href="noautoinit.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="manageblock"></a>Managing Blocking Operations</h2>
</div>
</div>
<div></div>
</div>
<p>
When a replica is in the process of synchronizing with its master, all DB
operations are blocked until such a time as the synchronization is completed.
For replicas with a heavy read load, these blocked operations may represent an
unacceptable loss in throughput.
</p>
<p>
You can configure DB so that it will not block when synchronization is in
process. Instead, the DB operation will fail,
<span>
immediately returning a <tt class="literal">DB_REP_LOCKOUT</tt> error.
</span>
When this happens, it is up to your application to your application to determine
what action to take (that is, logging the event, making an appropriate user
response, retrying the operation, and so forth).
</p>
<p>
To turn off blocking on synchronization, specify
<span>
<tt class="literal">DB_REP_CONF_NOWAIT</tt> to
<tt class="methodname">DbEnv::rep_set_config()</tt>
and then specify <tt class="literal">1</tt> to the <tt class="literal">onoff</tt>
parameter. (Specify <tt class="literal">0</tt> to turn the feature off.)
</span>
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="addfeatures.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="addfeatures.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="noautoinit.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Chapter 5. Additional Features </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Stop Auto-Initialization</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,88 @@
<?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>Stop Auto-Initialization</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="addfeatures.html" title="Chapter 5. Additional Features" />
<link rel="previous" href="manageblock.html" title="Managing Blocking Operations" />
<link rel="next" href="c2ctransfer.html" title="Client to Client Transfer" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Stop Auto-Initialization</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="manageblock.html">Prev</a> </td>
<th width="60%" align="center">Chapter 5. Additional Features</th>
<td width="20%" align="right"> <a accesskey="n" href="c2ctransfer.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="noautoinit"></a>Stop Auto-Initialization</h2>
</div>
</div>
<div></div>
</div>
<p>
As stated in the previous section, when a replication replica is synchronizing
with its master, it will block all DB operations until the synchronization
is completed. You can turn off this behavior (see <a href="manageblock.html">Managing Blocking Operations</a>), but for replicas that have been out of touch
from their master for a very long time, this may not be enough.
</p>
<p>
If a replica has been out of touch from its master long enough, it may find that
it is not possible to perform synchronization. When this happens, by default the
master and replica internally decided to completely re-initialize the replica.
This re-initialization involves discarding the replica's current database(s) and
transferring new ones to it from the master. Depending on the size of the master's
databases, this can take a long time, during which time the replica will be
complete non-responsive when it comes to performing database operations.
</p>
<p>
It is possible that there is a time of the day when it is better to perform a replica
re-initialization. Or, you simply might want to decide to bring the replica up to
speed by restoring it's databases using a hot-backup taken from the master. Either
way, you can decide to prevent automatic-initialization of your replica. To do this
specify
<span>
<tt class="literal">DB_REP_CONF_NOAUTOINIT</tt> to
<tt class="methodname">DbEnv::rep_set_config()</tt>
and then specify <tt class="literal">1</tt> to the <tt class="literal">onoff</tt>
parameter. (Specify <tt class="literal">0</tt> to turn the feature off.)
</span>
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="manageblock.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="addfeatures.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="c2ctransfer.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Managing Blocking Operations </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Client to Client Transfer</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,390 @@
<?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>Permanent Message Handling</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="introduction.html" title="Chapter 1. Introduction" />
<link rel="previous" href="elections.html" title="Holding Elections" />
<link rel="next" href="txnapp.html" title="Chapter 2. Transactional Application" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Permanent Message Handling</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="elections.html">Prev</a> </td>
<th width="60%" align="center">Chapter 1. Introduction</th>
<td width="20%" align="right"> <a accesskey="n" href="txnapp.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="permmessages"></a>Permanent Message Handling</h2>
</div>
</div>
<div></div>
</div>
<p>
Messages received by a replica may be marked with an
special flag that indicates the message is permanent.
Custom replicated applications will receive notification of
this flag via the <tt class="literal">DB_REP_ISPERM</tt> return value
from the
<tt class="methodname">DbEnv::rep_process_message()</tt>
method.
There is no hard requirement that a replication application look for, or
respond to, this return code. However, because robust replicated
applications typically do manage permanent messages, we introduce
the concept here.
</p>
<p>
A message is marked as being permanent if the message
affects transactional integrity. For example,
transaction commit messages are an example of a message
that is marked permanent. What the application does
about the permanent message is driven by the durability
guarantees required by the application.
</p>
<p>
For example, consider what the replication framework does when it
has permanent message handling turned on and a
transactional commit record is sent to the replicas.
First, the replicas must transactional-commit the data
modifications identified by the message. And then, upon
a successful commit, the replication framework sends the master a
message acknowledgment.
</p>
<p>
For the master (again, using the replication framework), things are a little more complicated than
simple message acknowledgment. Usually in a replicated
application, the master commits transactions
asynchronously; that is, the commit operation does not
block waiting for log data to be flushed to disk before
returning. So when a master is managing permanent
messages, it typically blocks the committing thread
immediately before <tt class="methodname">commit()</tt>
returns. The thread then waits for acknowledgments from
its replicas. If it receives enough acknowledgments, it
continues to operate as normal.
</p>
<p>
If the master does not
receive message acknowledgments — or, more likely, it does not receive
<span class="emphasis"><em>enough</em></span> acknowledgments — the
committing thread flushes its log data to disk and then
continues operations as normal. The master application can
do this because replicas that fail to handle a message, for
whatever reason, will eventually catch up to the master. So
by flushing the transaction logs to disk, the master is
ensuring that the data modifications have made it to
stable storage in one location (its own hard drive).
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="permmessagenot"></a>When Not to Manage
Permanent Messages</h3>
</div>
</div>
<div></div>
</div>
<p>
There are two reasons why you might
choose to not implement permanent messages.
In part, these go to why you are using
replication in the first place.
</p>
<p>
One class of applications uses replication so that
the application can improve transaction
through-put. Essentially, the application chooses a
reduced transactional durability guarantee so as to
avoid the overhead forced by the disk I/O required
to flush transaction logs to disk. However, the
application can then regain that durability
guarantee to a certain degree by replicating the
commit to some number of replicas.
</p>
<p>
Using replication to improve an application's
transactional commit guarantee is called
<span class="emphasis"><em>replicating to the network.</em></span>
</p>
<p>
In extreme cases where performance is of critical
importance to the application, the master might
choose to both use asynchronous commits
<span class="emphasis"><em>and</em></span> decide not to wait for
message acknowledgments. In this case the master
is simply broadcasting its commit activities to its
replicas without waiting for any sort of a reply. An
application like this might also choose to use
something other than TCP/IP for its network
communications since that protocol involves a fair
amount of packet acknowledgment all on its own. Of
course, this sort of an application should also be
very sure about the reliability of both its network and
the machines that are hosting its replicas.
</p>
<p>
At the other end of the extreme, there is a
class of applications that use replication
purely to improve read performance. This sort
of application might choose to use synchronous
commits on the master because write
performance there is not of critical
performance. In any case, this kind of an
application might not care to know whether its
replicas have received and successfully handled
permanent messages because the primary storage
location is assumed to be on the master, not
the replicas.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="permmanage"></a>Managing Permanent Messages</h3>
</div>
</div>
<div></div>
</div>
<p>
With the exception of a rare breed of
replicated applications, most masters need some
view as to whether commits are occurring on
replicas as expected. At a minimum, this is because
masters will not flush their log buffers unless
they have reason to expect that permanent
messages have not been committed on the
replicas.
</p>
<p>
That said, it is important to remember that
managing permanent messages involves a fair amount
of network traffic. The messages must be sent to
the replicas and the replicas must then acknowledge
the message. This represents a performance overhead
that can be worsened by congested networks or
outright outages.
</p>
<p>
Therefore, when managing permanent messages, you
must first decide on how many of your replicas must
send acknowledgments before your master decides
that all is well and it can continue normal
operations. When making this decision, you could
decide that <span class="emphasis"><em>all</em></span> replicas must
send acknowledgments. But unless you have only one
or two replicas, or you are replicating over a very
fast and reliable network, this policy could prove
very harmful to your application's performance.
</p>
<p>
Therefore, a common strategy is to wait for an
acknowledgment from a simple majority of replicas.
This ensures that commit activity has occurred on
enough machines that you can be reliably certain
that data writes are preserved across your network.
</p>
<p>
Remember that replicas that do not acknowledge a
permanent message are not necessarily unable to
perform the commit; it might be that network
problems have simply resulted in a delay at the
replica. In any case, the underlying DB
replication code is written such that a replica that
falls behind the master will eventually take action
to catch up.
</p>
<p>
Depending on your application, it may be
possible for you to code your permanent message
handling such that acknowledgment must come
from only one or two replicas. This is a
particularly attractive strategy if you are
closely managing which machines are eligible to
become masters. Assuming that you have one or
two machines designated to be a master in the
event that the current master goes down, you
may only want to receive acknowledgments from
those specific machines.
</p>
<p>
Finally, beyond simple message acknowledgment, you
also need to implement an acknowledgment timeout
for your application. This timeout value is simply
meant to ensure that your master does not hang
indefinitely waiting for responses that will never
come because a machine or router is down.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="permimplement"></a>Implementing Permanent
Message Handling</h3>
</div>
</div>
<div></div>
</div>
<p>
How you implement permanent message handling
depends on which API you are using to implement
replication. If you are using the replication framework, then
permanent message handling is configured using
policies that you specify to the framework. In
this case, you can configure your application
to:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Ignore permanent messages (the master
does not wait for acknowledgments).
</p>
</li>
<li>
<p>
Require acknowledgments from a
quorum. A quorum is reached when
acknowledgments are received from the
minimum number of electable
replicas needed to ensure that
the record remains durable if
an election is held.
</p>
<p>
The goal here is to be
absolutely sure the record is
durable. The master wants to
hear from enough electable
replicas that they have
committed the record so that if
an election is held, the master
knows the record will exist even
if a new master is selected.
</p>
<p>
This is the default policy.
</p>
</li>
<li>
<p>
Require an acknowledgment from at least one replica.
</p>
</li>
<li>
<p>
Require acknowledgments from
all replicas.
</p>
</li>
<li>
<p>
Require an acknowledgment from a
peer. (The replication framework allows you to
designate one environment as a peer of
another).
</p>
</li>
<li>
<p>
Require acknowledgments from
all peers.
</p>
</li>
</ul>
</div>
<p>
Note that the replication framework simply flushes its transaction
logs and moves on if a permanent message is not
sufficiently acknowledged.
</p>
<p>
For details on permanent message handling with the
replication framework, see <a href="fwrkpermmessage.html">Permanent Message Handling</a>.
</p>
<p>
If these policies are not sufficient for your
needs, or if you want your application to take more
corrective action than simply flushing log buffers
in the event of an unsuccessful commit, then you
must use write a custom replication implementation.
</p>
<p>
For custom replication implementation, messages are
sent from the master to its replica using a
<tt class="function">send()</tt> callback that you
implement. Note, however, that DB's replication
code automatically sets the permanent
flag for you where appropriate.
</p>
<p>
If the <tt class="function">send()</tt> callback returns with a
non-zero status, DB flushes the transaction log
buffers for you. Therefore, you must cause your
<tt class="function">send()</tt> callback to block waiting
for acknowledgments from your replicas.
As a part of implementing the
<tt class="function">send()</tt> callback, you implement
your permanent message handling policies. This
means that you identify how many replicas must
acknowledge the message before the callback can
return <tt class="literal">0</tt>. You must also
implement the acknowledgment timeout, if any.
</p>
<p>
Further, message acknowledgments are sent from the
replicas to the master using a communications
channel that you implement (the replication code
does not provide a channel for acknowledgments).
So implementing permanent messages means that when
you write your replication communications channel,
you must also write it in such a way as to also
handle permanent message acknowledgments.
</p>
<p>
For more information on implementing permanent
message handling using a custom replication layer,
see the <i class="citetitle">Berkeley DB Programmer's Reference Guide</i>.
</p>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="elections.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="introduction.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="txnapp.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Holding Elections </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Chapter 2. Transactional Application</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,216 @@
<?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>Preface</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="previous" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="next" href="introduction.html" title="Chapter 1. Introduction" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Preface</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="introduction.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="preface" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a id="preface"></a>Preface</h2>
</div>
</div>
<div></div>
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="sect1">
<a href="preface.html#conventions">Conventions Used in this Book</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="preface.html#moreinfo">For More Information</a>
</span>
</dt>
</dl>
</dd>
</dl>
</div>
<p>
This document describes how to write replicated Berkeley DB applications.
The APIs used to implement replication in your application
are described here. This book describes the concepts surrounding replication, the scenarios under which you
might choose to use it, and the architectural requirements that a replication application has over a
transactional application.
</p>
<p>
This book is aimed at the software engineer responsible for writing a
replicated DB application.
</p>
<p>
This book assumes that you have already read and understood the
concepts contained in the
<span><i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide.</span>
</p>
<div class="sect1" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="conventions"></a>Conventions Used in this Book</h2>
</div>
</div>
<div></div>
</div>
<p>
The following typographical conventions are used within in this manual:
</p>
<p>
Class names are represented in <tt class="classname">monospaced font</tt>, as are <tt class="methodname">method
names</tt>. For example:
<span>"<tt class="methodname">DbEnv::open()</tt> is a
<tt class="classname">DbEnv</tt> class method."</span>
</p>
<p>
Variable or non-literal text is presented in <span class="emphasis"><em>italics</em></span>. For example: "Go to your
<span class="emphasis"><em>DB_INSTALL</em></span> directory."
</p>
<p>
Program examples are displayed in a <tt class="classname">monospaced font</tt> on a shaded background.
For example:
</p>
<pre class="programlisting">typedef struct vendor {
char name[MAXFIELD]; // Vendor name
char street[MAXFIELD]; // Street name and number
char city[MAXFIELD]; // City
char state[3]; // Two-digit US state code
char zipcode[6]; // US zipcode
char phone_number[13]; // Vendor phone number
} VENDOR; </pre>
<p>
In some situations, programming examples are updated from one chapter to the next. When
this occurs, the new code is presented in <b class="userinput"><tt>monospaced bold</tt></b> font. For example:
</p>
<pre class="programlisting">typedef struct vendor {
char name[MAXFIELD]; // Vendor name
char street[MAXFIELD]; // Street name and number
char city[MAXFIELD]; // City
char state[3]; // Two-digit US state code
char zipcode[6]; // US zipcode
char phone_number[13]; // Vendor phone number
<b class="userinput"><tt>char sales_rep[MAXFIELD]; // Name of sales representative
char sales_rep_phone[MAXFIELD]; // Sales rep's phone number </tt></b>
} VENDOR; </pre>
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
<h3 class="title">Note</h3>
<p>
Finally, notes of special interest are represented using a note block such
as this.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="moreinfo"></a>For More Information</h3>
</div>
</div>
<div></div>
</div>
<p>
Beyond this manual, you may also find the following sources of information useful when building a
transactional DB application:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/gsg_txn/CXX/index.html" target="_top">
Getting Started with Transaction Processing for C++
</a>
</p>
</li>
<li>
<p>
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/gsg/CXX/index.html" target="_top">
Getting Started with Berkeley DB for C++
</a>
</p>
</li>
<li>
<p>
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/ref/toc.html" target="_top">
Berkeley DB Programmer's Reference Guide
</a>
</p>
</li>
<li>
<p>
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/api_cxx/frame.html" target="_top">
Berkeley DB C++ API
</a>
</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="index.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="introduction.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Getting Started with Replicated Berkeley DB Applications </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Chapter 1. Introduction</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,259 @@
<?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>Processing Loop</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="fwrkmasterreplica.html" title="Chapter 4. Replica versus Master Processes" />
<link rel="previous" href="fwrkmasterreplica.html" title="Chapter 4. Replica versus Master Processes" />
<link rel="next" href="exampledoloop.html" title="Example Processing Loop" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Processing Loop</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="fwrkmasterreplica.html">Prev</a> </td>
<th width="60%" align="center">Chapter 4. Replica versus Master Processes</th>
<td width="20%" align="right"> <a accesskey="n" href="exampledoloop.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="processingloop"></a>Processing Loop</h2>
</div>
</div>
<div></div>
</div>
<p>
Typically the central part of any replication application
is some sort of a continuous loop that constantly
checks the state of the environment (whether it is a
replica or a master), opens and/or closes the
databases as is necessary, and performs other useful
work. A loop such as this one must of necessity
take special care to know whether it is operating
on a master or a replica environment because all of its
activities are dependent upon that state.
</p>
<p>
The flow of activities through the loop will
generally be as follows:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Check whether the environment has
changed state. If it has, you
might want to reopen your
database handles, especially if
you opened your replica's
database handles as read-only.
In this case, you might need to
reopen them as read-write.
However, if you always open your
database handles as read-write,
then it is not automatically necessary to
reopen the databases due to a
state change. Instead, you
could check for a
<span>
<tt class="literal">DB_REP_HANDLE_DEAD</tt>
return code
</span>
when you use your
database handle(s). If you see
this, then you need to reopen
your database handle(s).
</p>
</li>
<li>
<p>
If the databases are closed,
create new database handles,
configure the handle as is
appropriate, and then open the
databases. Note that handle
configuration will be different,
depending on whether the handle
is opened as a replica or a
master. At a minimum, the master
should be opened with database
creation privileges, whereas the
replica does not need to be. You
must also open the master such
that its databases are
read-write. You
<span class="emphasis"><em>can</em></span> open
replicas with read-only
databases, so long as you are
prepared to closed and the reopen
the handle in the event the
client becomes a master.
</p>
<p>
Also, note that if the local
environment
is a replica, then it is possible
that databases do not currently
exist. In this case, the database
open attempts will fail. Your
code will have to take this
corner case into account
(described below).
</p>
</li>
<li>
<p>
Once the databases are opened,
check to see if the local
environment is a
master. If it is, do whatever it is
a master should do for your
application.
</p>
<p>
Remember that the code for your
master should include some way
for you to tell the master
to exit gracefully.
</p>
</li>
<li>
<p>
If the local environment is not a
master, then do whatever it is
your replica environments should do.
Again, like the code for your
master environments, you should provide
a way for your replicas to exit
the processing loop gracefully.
</p>
</li>
</ol>
</div>
<p>
The following code fragment illustrates
these points (note that we fill out this
fragment with a working example
next in this chapter):
</p>
<pre class="programlisting">/* loop to manage replication activities */
Db *dbp;
int ret;
APP_DATA *app_data;
u_int32_t flags;
dbp = NULL;
ret = 0;
/*
* Remember that for this to work, an APP_DATA struct would have first
* had to been set to the environment handle's app_private data
* member. (dbenv is presumable declared and opened in another part of
* the code.)
*/
app_data = dbenv-&gt;get_app_private();
/*
* Infinite loop. We exit depending on how the master and replica code
* is written.
*/
for (;;) {
/* If dbp is not opened, we need to open it. */
if (dbp == NULL) {
/*
* Create the handle and then configure it. Before you open
* it, you have to decide what open flags to use:
*/
flags = DB_AUTO_COMMIT;
if (app_data-&gt;is_master)
flags |= DB_CREATE
/*
* Now you can open your database handle, passing to it the
* flags selected above.
*
* One thing to watch out for is a case where the databases
* you are trying to open do not yet exist. This can happen
* for replicas where the databases are being opened
* read-only. If this happens, ENOENT is returned by the
* open() call.
*/
try {
dbp-&gt;open(NULL, DATABASE, NULL, DB_BTREE,
app_data-&gt;is_master ? DB_CREATE | DB_AUTO_COMMIT :
DB_AUTO_COMMIT, 0);
} catch(DbException dbe) {
if (dbe.get_errno() == ENOENT) {
cout &lt;&lt; "No stock db available yet - retrying." &lt;&lt; endl;
try {
dbp-&gt;close(0);
} catch (DbException dbe2) {
cout &lt;&lt; "Unexpected error closing after failed" &lt;&lt;
" open, message: " &lt;&lt; dbe2.what() &lt;&lt; endl;
dbp = NULL;
goto err;
}
dbp = NULL;
sleep(SLEEPTIME);
continue;
} else {
dbenv.err(ret, "DB-&gt;open");
throw dbe;
}
}
}
/*
* Now that the databases have been opened, continue with general
* processing, depending on whether we are a master or a replica.
*/
if (app_data-&gt;is_master) {
/*
* Do master stuff here. Don't forget to include a way to
* gracefully exit the loop. */
*/
} else {
/*
* Do replica stuff here. As is the case with the master
* code, be sure to include a way to gracefully exit the
* loop.
*/
}
} </pre>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="fwrkmasterreplica.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="fwrkmasterreplica.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="exampledoloop.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Chapter 4. Replica versus Master Processes </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Example Processing Loop</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,184 @@
<?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>Replication Benefits</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="introduction.html" title="Chapter 1. Introduction" />
<link rel="previous" href="introduction.html" title="Chapter 1. Introduction" />
<link rel="next" href="apioverview.html" title="The Replication APIs" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Replication Benefits</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="introduction.html">Prev</a> </td>
<th width="60%" align="center">Chapter 1. Introduction</th>
<td width="20%" align="right"> <a accesskey="n" href="apioverview.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="repadvantage"></a>Replication Benefits</h2>
</div>
</div>
<div></div>
</div>
<p>
Replication offers your application a number of benefits that
can be a tremendous help. Primarily replication's benefits
revolve around performance, but there is also a benefit in
terms of data durability guarantees.
</p>
<p>
Briefly, the reasons why you might choose to implement
replication in your DB application are:
</p>
<div class="itemizedlist">
<div class="itemizedlist">
<ul type="circle">
<li>
<p>
Improved application reliability.
</p>
<p>
By spreading your data across multiple
machines, you can ensure that your
application's data continues to be
available even in the event of a
hardware failure on any given machine in
the replication group.
</p>
</li>
</ul>
</div>
<ul type="disc">
<li>
<p>
Improve read performance.
</p>
<p>
By using replication you can spread data reads across
multiple machines on your network. Doing so allows you
to vastly improve your application's read performance.
This strategy might be particularly interesting for
applications that have readers on remote network nodes;
you can push your data to the network's edges thereby
improving application data read responsiveness.
</p>
<p>
Additionally, depending on how you partition your
data across your replicas, any given replica may
only need to cache part of your data, decreasing
cache misses and reducing I/O on the client.
</p>
</li>
<li>
<p>
Improve transactional commit performance
</p>
<p>
In order to commit a transaction and achieve a
transactional durability guarantee, the commit must be
made <span class="emphasis"><em>durable</em></span>. That is, the commit
must be written to disk (usually, but not always,
synchronously) before the application's thread of
control can continue operations.
</p>
<p>
Replication allows you to avoid this disk I/O and still
maintain a degree of durability by <span class="emphasis"><em>committing
to the network</em></span>. In other words, you relax
your transactional durability guarantees on the master,
but by virtue of replicating the data across the
network you gain some additional durability guarantees
above what is provided locally.
</p>
<p>
Usually this strategy is implemented using some form of
an asynchronous transactional commit on the master. In
this way your data writes will eventually be written to
disk, but your application will not have to wait for
the disk I/O to complete before continuing with its
next operation.
</p>
<p>
Note that it is possible to cause DB's replication
implementation to wait to hear from one or
more replica's as to whether they have successfully
saved the write before continuing. However, in this
case you might be trading performance for a even
higher durability guarantee (see below).
</p>
</li>
<li>
<p>
Improve data durability guarantee.
</p>
<p>
In a traditional transactional application, you commit your
transactions such that data modifications are saved to
disk. Beyond this, the durability of your data is
dependent upon the backup strategy that you choose to
implement for your site.
</p>
<p>
Replication allows you to increase this durability
guarantee by ensuring that data modifications are
written to multiple machines. This means that multiple
disks, disk controllers, power supplies, and CPUs are
used to ensure that your data modification makes it to
stable storage. In other words, replication allows you
to minimize the problem of a single point of failure
by using more hardware to guarantee your data writes.
</p>
<p>
If you are using replication for this reason, then you
probably will want to configure your application such
that it waits to hear about a successful commit from
one or more replicas before continuing with the next
operation. This will obviously impact your
application's write performance to some degree
— with the performance penalty being largely dependent
upon the speed and stability of the network connecting
your replication group.
</p>
<p>
For more information, see <a href="fwrkpermmessage.html">Permanent Message Handling</a>.
</p>
</li>
</ul>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="introduction.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="introduction.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="apioverview.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Chapter 1. Introduction </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> The Replication APIs</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,703 @@
<?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>Chapter 3. The DB Replication Framework</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="previous" href="simpleprogramlisting.html" title="Program Listing" />
<link rel="next" href="repmgr_init_example_c.html" title="Adding the Replication Framework to&#10; &#10; SimpleTxn&#10; " />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Chapter 3. The DB Replication Framework</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="simpleprogramlisting.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="repmgr_init_example_c.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="chapter" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a id="repapp"></a>Chapter 3. The DB Replication Framework</h2>
</div>
</div>
<div></div>
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="sect1">
<a href="repapp.html#rep_init_code">
Starting and Stopping Replication
</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="repapp.html#election_flags">Managing Election Policies</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="repapp.html#thread_count">Selecting the Number of Threads</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="repmgr_init_example_c.html">Adding the Replication Framework to
SimpleTxn
</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="fwrkpermmessage.html">Permanent Message Handling</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="fwrkpermmessage.html#fmwrkpermpolicy">Identifying Permanent Message Policies</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="fwrkpermmessage.html#fmwrkpermtimeout">Setting the Permanent Message Timeout</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="fwrkpermmessage.html#perm2fmwrkexample">Adding a Permanent Message Policy to
RepMgr
</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="electiontimes.html">Managing Election Times</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="electiontimes.html#electiontimeout">Managing Election Timeouts</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="electiontimes.html#electretrytime">Managing Election Retry Times</a>
</span>
</dt>
</dl>
</dd>
<dt>
<span class="sect1">
<a href="fmwrkconnectretry.html">Managing Connection Retries</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="heartbeats.html">Managing Heartbeats</a>
</span>
</dt>
</dl>
</div>
<p>
The easiest way to add replication to your transactional
application is to use the replication framework. The replication framework provides a comprehensive
communications layer that enables replication. For a brief listing
of the replication framework's feature set, see
<a href="apioverview.html#repframeworkoverview">Replication Framework Overview</a>.
</p>
<p>
To use the replication framework, you make use of special methods off the
<span><tt class="classname">DbEnv</tt> class.</span>
That is:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Create an environment handle as normal.
</p>
</li>
<li>
<p>
Configure your environment handle as
needed (e.g. set the error file and
error prefix values, if desired).
</p>
</li>
<li>
<p>
Use the replication framework replication methods to
configure the replication framework. Using these
methods causes DB to know that you
are using the replication framework.
</p>
<p>
Configuring the replication framework
entails setting its replication
priority, setting the TCP/IP address
that this replication environment will use for
incoming replication messages, identify
TCP/IP addresses of other replication
environments, setting the number of
replication environments in the
replication group, and so forth. These actions are
discussed throughout the remainder of
this chapter.
</p>
</li>
<li>
<p>
Open your environment handle. When you
do this, be sure to specify
<span><tt class="literal">DB_INIT_REP</tt> and
<tt class="literal">DB_THREAD</tt> to your
open flags. (This is in addition to the
flags that you normally use for a
single-threaded transactional
application). The first of these causes
replication to be initialized for the
application. The second causes your
environment handle to be free-threaded
(thread safe). Both flags are required
for replication framework usage.
</span>
</p>
</li>
<li>
<p>
Start replication by calling
<span><tt class="methodname">DbEnv::repmgr_start()</tt>.</span>
</p>
</li>
<li>
<p>
Open your databases as needed. Masters
must open their databases for read
and write activity. Replicas can open
their databases for read-only activity, but
doing so means they must re-open the
databases if the replica ever becomes a
master. Either way, replicas should never attempt to
write to the database(s) directly.
</p>
</li>
</ol>
</div>
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
<h3 class="title">Note</h3>
<p>
The replication framework allows you to only use one
environment handle per process.
</p>
</div>
<p>
When you are ready to shut down your application:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Close your databases
</p>
</li>
<li>
<p>
Close your environment. This causes
replication to stop as well.
</p>
</li>
</ol>
</div>
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
<h3 class="title">Note</h3>
<p>
Before you can use the replication framework, you may have to
enable it in your DB library. This is
<span class="emphasis"><em>not</em></span> a requirement for
Microsoft Windows systems, or Unix systems that
use pthread mutexes by default. Other systems,
notably BSD and BSD-derived systems (such as
Mac OS X), must enable the replication framework when you
configure the DB build.
</p>
<p>
You do this by <span class="emphasis"><em>not</em></span>
disabling replication and by configuring the
library with POSIX threads support. In other
words, replication must be turned on in the
build (it is by default), and POSIX thread
support must be enabled if it is not already by
default. To do this, use the
<tt class="literal">--enable-pthread_api</tt> switch
on the configure script.
</p>
<p>
For example:
</p>
<pre class="programlisting">../dist/configure --enable-pthread-api</pre>
</div>
<div class="sect1" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="rep_init_code"></a>
Starting and Stopping Replication
</h2>
</div>
</div>
<div></div>
</div>
<p>
As described above, you introduce replication to an
application by starting with a transactional
application, performing some basic replication
configuration, and then starting replication using
<span><tt class="methodname">DbEnv::repmgr_start()</tt>.</span>
</p>
<p>
You stop replication by closing your environment
cleanly, as is normal for an DB application.
</p>
<p>
For example, the following code fragment initializes, then
stops and starts replication. Note that other replication
activities are omitted for brevity.
</p>
<pre class="programlisting">#include &lt;db_cxx.h&gt;
/* Use a 10mb cache */
#define CACHESIZE (10 * 1024 * 1024)
...
DbEnv *dbenv; /* Environment handle. */
const char *progname; /* Program name. */
const char *envHome; /* Environment home directory. */
const char *listen_host; /* A TCP/IP hostname. */
const char *other_host; /* A TCP/IP hostname. */
u_int16 listen_port; /* A TCP/IP port. */
u_int16 other_port; /* A TCP/IP port. */
/* Initialize variables */
dbenv = NULL;
progname = "example_replication";
envHome = "ENVIRONMENT_HOME";
listen_host = "mymachine.sleepycat.com";
listen_port = 5001;
other_host = "anothermachine.sleepycat.com";
other_port = 4555;
try {
/* Create the environment handle */
dbenv = new DbEnv(0);
/*
* Configure the environment handle. Here we configure
* asynchronous transactional commits for performance reasons.
*/
dbenv-&gt;set_errfile(stderr);
dbenv-&gt;set_errpfx(progname);
(void)dbenv-&gt;set_cachesize(0, CACHESIZE, 0);
(void)dbenv-&gt;set_flags(DB_TXN_NOSYNC, 1);
/*
* Configure the local address. This is the local hostname and
* port that this replication participant will use to receive
* incoming replication messages. Note that this can be performed
* only once for the application. It is required.
*/
dbenv-&gt;repmgr_set_local_site(listen_host, listen_port, 0);
/*
* Set this application's priority. This is used for elections.
*
* Set this number to a positive integer, or 0 if you do not want
* this site to be able to become a master.
*/
dbenv-&gt;rep_set_priority(100);
/*
* Add a site to the list of replication environments known to
* this application.
*/
dbenv-&gt;repmgr_add_remote_site(dbenv, other_host, other_port,
NULL, 0);
/*
* Identify the number of sites in the replication group. This is
* necessary so that elections and permanent message handling can
* be performed correctly.
*/
dbenv-&gt;repmgr_set_nsites(dbenv, 2);
/* Open the environment handle. Note that we add DB_THREAD and
* DB_INIT_REP to the list of flags. These are required.
*/
dbenv-&gt;open(home, DB_CREATE | DB_RECOVER |
DB_INIT_LOCK | DB_INIT_LOG |
DB_INIT_MPOOL | DB_INIT_TXN |
DB_THREAD | DB_INIT_REP,
0);
/* Start the replication framework such that it uses 3 threads. */
dbenv-&gt;repmgr_start(3, DB_REP_ELECTION);
/* Sleep to give ourselves time to find a master */
sleep(5);
/*
**********************************************************
*** All other application code goes here, including *****
*** database opens *****
**********************************************************
*/
} catch (DbException &amp;de) {
/* Error handling goes here */
}
/* Close out the application here.
try {
/*
* Make sure all your database handles are closed
* (omitted from this example).
*/
/* Close the environment */
if (dbenv != NULL)
(void)dbenv-&gt;close(dbenv, 0);
} catch (DbException &amp;de) {
/* Error handling goes here */
}
/* All done */ </pre>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="election_flags"></a>Managing Election Policies</h3>
</div>
</div>
<div></div>
</div>
<p>
Before continuing, it is worth taking a look at the
<span>
startup election flags accepted by
<span><tt class="methodname">DbEnv::repgmr_start()</tt>.</span>
These flags control how your replication application will
behave when it first starts up.
</span>
</p>
<p>
In the previous example, we specified
<tt class="literal">DB_REP_ELECTION</tt>
when we started replication. This causes the
application to try to find a master upon startup. If it
cannot, it calls for an election. In the event an
election is held, the environment receiving the most number of
votes will become the master.
</p>
<p>
There's some important points to make here:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
This
<span>flag</span>
only requires that other
environments in the replication group
participate in the vote. There is no
requirement that
<span class="emphasis"><em>all</em></span> such
environments participate. In other
words, if an environment
starts up, it can call for an
election, and select a master, even
if all other environment have not yet
joined the replication group.
</p>
</li>
<li>
<p>
It only requires a simple majority of
participating environments to elect a master. The number of
environments used to calculate the simple
majority is based on the value set for
<span><tt class="methodname">DbEnv::rep_set_nsites()</tt>.</span>
This is always true of elections held using the replication framework.
</p>
</li>
<li>
<p>
As always, the environment participating in the election with the most
up-to-date log files is selected as
master. If an environment with better log files
has not yet joined the replication
group, it may not become the master.
</p>
</li>
</ul>
</div>
<p>
Any one of these points may be enough to cause a
less-than-optimum environment to be selected as master.
Therefore, to give you a better degree of control over
which environment becomes a master at application startup,
the replication framework offers the following start-up
<span>flags:</span>
</p>
<div class="informaltable">
<table border="1" width="80%">
<colgroup>
<col />
<col />
</colgroup>
<thead>
<tr>
<th>Flag</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<tt class="literal">DB_REP_MASTER</tt>
</td>
<td>
<p>
The application starts up and declares itself to be a master
without calling for an election. It is an error for more
than one environment to start up using this flag, or for
an environment
to use this flag when a master already exists.
</p>
<p>
Note that no replication group should
<span class="emphasis"><em>ever</em></span> operate with more than
one master.
</p>
<p>
In the event that a environment attempts to become a
master when a master already exists, the
replication code will resolve the problem by
holding an election. Note, however, that there
is always a possibility of data loss in the face
of duplicate masters, because once a master is
selected, the environment that loses the election will
have to roll back any transactions committed
until it is in sync with the "real" master.
</p>
</td>
</tr>
<tr>
<td>
<tt class="literal">DB_REP_CLIENT</tt>
</td>
<td>
<p>
The application starts up and declares
itself to be a replica without calling for
an election. Note that the application
can still become a master if a subsequent
application starts up, calls for an
election, and this application is elected
master.
</p>
</td>
</tr>
<tr>
<td>
<tt class="literal">DB_REP_ELECTION</tt>
</td>
<td>
<p>
As described above, the application starts up,
looks for a master, and if one is not found calls
for an election.
</p>
</td>
</tr>
<tr>
<td>
<tt class="literal">DB_REP_FULL_ELECTION</tt>
</td>
<td>
<p>
Identical to
<tt class="literal">DB_REP_ELECTION</tt>
except that the election requires all
known members of the replication group to
participate. If a given environment has not yet
started but it is included in the
replication group count (using
<span><tt class="methodname">DbEnv::rep_set_nsites()</tt>)</span>
then a master can not be elected.
</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="thread_count"></a>Selecting the Number of Threads</h3>
</div>
</div>
<div></div>
</div>
<p>
Under the hood, the replication framework is threaded and you can
control the number of threads used to process messages received from
other replicas. The threads that the replication framework uses are:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Incoming message thread. This thread
receives messages from the site's
socket and passes those messages to
message processing threads (see below)
for handling.
</p>
</li>
<li>
<p>
Outgoing message thread. Outgoing
are performed in whatever thread
performed a write to the database(s).
That is, the thread that called, for
example,
<tt class="methodname">Db::put()</tt>
is the thread that writes replication messages
about that fact to the socket.
</p>
<p>
Note that if this write activity would
cause the thread to be blocked due to
some condition on the socket, the replication framework
will hand the outgoing message to the
incoming message thread, and it will
then write the message to the socket.
This prevents your database write
threads from blocking due to abnormal
network I/O conditions.
</p>
</li>
<li>
<p>
Message processing threads are
responsible for parsing and then
responding to incoming replication
messages. Typically, a response will
include write activity to your
database(s), so these threads can be
busy performing disk I/O.
</p>
</li>
</ul>
</div>
<p>
Of these threads, the only ones that you have any
configuration control over are the message processing
threads. In this case, you can determine how many
of these threads you want to run.
</p>
<p>
It is always a bit of an art to decide on a thread count,
but the short answer is you probably do not need more
than three threads here, and it is likely that one will
suffice. That said, the best thing to do is set your
thread count to a fairly low number and then increase
it if it appears that your application will benefit
from the additional threads.
</p>
</div>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="simpleprogramlisting.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="index.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="repmgr_init_example_c.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Program Listing </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Adding the Replication Framework to
SimpleTxn
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,520 @@
<?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 Framework to
SimpleTxn
</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
<link rel="previous" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
<link rel="next" href="fwrkpermmessage.html" title="Permanent Message Handling" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Adding the Replication Framework to
SimpleTxn
</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="repapp.html">Prev</a> </td>
<th width="60%" align="center">Chapter 3. The DB Replication Framework</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 Framework to
<span>SimpleTxn</span>
</h2>
</div>
</div>
<div></div>
</div>
<p>
We now use the methods described above to add partial
support to the
<tt class="literal">SimpleTxn</tt>
example that we presented in
<a href="txnapp.html">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 framework.
</p>
</li>
<li>
<p>
Minimally configure the replication framework.
</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 <b class="userinput"><tt>bold</tt></b>.
</p>
<p>
To begin, we copy the
<tt class="literal">SimpleTxn</tt>
code to a new file called
<tt class="literal">RepMgr.cpp</tt>.
<span>
Having done that, we must make some significant
changes to our
<tt class="classname">RepConfigInfo</tt>
class because now we will be using it to
maintain a lot more information.
</span>
</p>
<p>
First, we create a new structure,
<tt class="literal">RepHostInfoObj</tt>, which we use to store
host and port information for all "other" servers
identified to the application via the
<tt class="literal">-o</tt> command line option. This structure
is chain-able, which makes cleaning up at program shutdown
time easier.
</p>
<pre class="programlisting">#include &lt;db_cxx.h&gt;
#include &lt;iostream&gt;
<b class="userinput"><tt>// Chain-able struct used to store host information.
typedef struct RepHostInfoObj{
char* host;
int port;
RepHostInfoObj* next; // used for chaining multiple "other" hosts.
} REP_HOST_INFO; </tt></b></pre>
<p>
Next, we update our <tt class="classname">RepConfigInfo</tt> class
definition to manage a lot more information and a new method.
</p>
<pre class="programlisting">class RepConfigInfo {
public:
RepConfigInfo();
virtual ~RepConfigInfo();
<b class="userinput"><tt>void addOtherHost(char* host, int port);</tt></b>
public:
<b class="userinput"><tt>u_int32_t start_policy;</tt></b>
char* home;
<b class="userinput"><tt>bool got_listen_address;
REP_HOST_INFO this_host;
int totalsites;
int priority;
// used to store a set of optional other hosts.
REP_HOST_INFO *other_hosts;</tt></b>
}; </pre>
<p>
Then, we update our constructor to initialize our new variables.
</p>
<pre class="programlisting">RepConfigInfo::RepConfigInfo()
{
<b class="userinput"><tt>start_policy = DB_REP_ELECTION;</tt></b>
home = "TESTDIR";
<b class="userinput"><tt>got_listen_address = false;
totalsites = 0;
priority = 100;
other_hosts = NULL;</tt></b>
} </pre>
<p>
Next, we implement our new method, <tt class="methodname">RepConfigInfo::addOtherHost</tt>,
which is used to create <tt class="literal">RepHostInfoObj</tt> instances and add them to
the chain of "other" hosts.
</p>
<pre class="programlisting">
<b class="userinput">
<tt>RepConfigInfo::addOtherHost(char* host, int port)
{
REP_HOST_INFO *newinfo;
newinfo = (REP_HOST_INFO*)malloc(sizeof(REP_HOST_INFO));
newinfo-&gt;host = host;
newinfo-&gt;port = port;
if (other_hosts == NULL) {
other_hosts = newinfo;
newinfo-&gt;next = NULL;
} else {
newinfo-&gt;next = other_hosts;
other_hosts = newinfo;
}
} </tt>
</b>
</pre>
<p>
Having done that, we update our class destructor to release the <tt class="literal">RepHostInfoObj</tt>
chain of objects at class destruction time.
</p>
<pre class="programlisting">RepConfigInfo::~RepConfigInfo()
{
<b class="userinput"><tt>// release any other_hosts structs.
if (other_hosts != NULL) {
REP_HOST_INFO *CurItem = other_hosts;
while (CurItem-&gt;next != NULL)
{
REP_HOST_INFO *TmpItem = CurItem;
free(CurItem);
CurItem = TmpItem;
}
free(CurItem);
}
other_hosts = NULL;</tt></b>
} </pre>
<p>
Having completed our update to the
<tt class="classname">RepConfigInfo</tt>
class, we can now start making
changes to the main portion of our program. We begin by changing
the program's name.
</p>
<pre class="programlisting">using std::cout;
using std::cin;
using std::cerr;
using std::endl;
using std::flush;
#define CACHESIZE (10 * 1024 * 1024)
#define DATABASE "quote.db"
<b class="userinput"><tt>const char *progname = "RepMgr";</tt></b> </pre>
<p>
Next we update our usage function. The application will continue to
accept the <tt class="literal">-h</tt> 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>
<tt class="literal">-m</tt> parameter which allows us to
identify the host and port used by this application to
listen for replication messages.
</p>
</li>
<li>
<p>
<tt class="literal">-o</tt> parameter which allows us to
specify other replicas.
</p>
</li>
<li>
<p>
<tt class="literal">-n</tt> parameter which allows us to
identify the number of sites in this replication
group.
</p>
</li>
<li>
<p>
<tt class="literal">-p</tt> 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">class RepMgr
{
public:
// Constructor.
RepMgr();
// Initialization method. Creates and opens our environment handle.
int init(RepConfigInfo* config);
// The doloop is where all the work is performed.
int doloop();
// terminate() provides our shutdown code.
int terminate();
private:
// disable copy constructor.
RepMgr(const RepMgr &amp;);
void operator = (const RepMgr &amp;);
// internal data members.
RepConfigInfo *app_config;
DbEnv dbenv;
// private methods.
// print_stocks() is used to display the contents of our database.
static int print_stocks(Db *dbp);
};
static void usage()
{
cerr &lt;&lt; "usage: " &lt;&lt; progname &lt;&lt; endl
&lt;&lt; "[-h home]<b class="userinput"><tt>[-o host:port][-m host:port]</tt></b>"
<b class="userinput"><tt>&lt;&lt; "[-n nsites][-p priority]" &lt;&lt; endl;</tt></b>
cerr <b class="userinput"><tt>&lt;&lt; "\t -m host:port (required; m stands for me)" &lt;&lt; endl
&lt;&lt; "\t -o host:port (optional; o stands for other; any "
&lt;&lt; "number of these may be specified)" &lt;&lt; endl</tt></b>
&lt;&lt; "\t -h home directory" &lt;&lt; endl
<b class="userinput"><tt>&lt;&lt; "\t -n nsites (optional; number of sites in replication "
&lt;&lt; "group; defaults to 0" &lt;&lt; endl
&lt;&lt; "\t in which case we try to dynamically compute the "
&lt;&lt; "number of sites in" &lt;&lt; endl
&lt;&lt; "\t the replication group)" &lt;&lt; endl
&lt;&lt; "\t -p priority (optional: defaults to 100)" &lt;&lt; endl;</tt></b>
exit(EXIT_FAILURE);
} </pre>
<p>
Now we can begin working on our <tt class="literal">main()</tt> function.
We begin by adding a couple of variables that we will use to
collect TCP/IP host and port information.
</p>
<pre class="programlisting">int main(int argc, char **argv)
{
RepConfigInfo config;
char ch<b class="userinput"><tt>, *portstr, *tmphost;
int tmpport;</tt></b>
int ret; </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"> // Extract the command line parameters
while ((ch = getopt(argc, argv, "h:<b class="userinput"><tt>m:n:o:p:</tt></b>")) != EOF) {
switch (ch) {
case 'h':
config.home = optarg;
break;
<b class="userinput"><tt>case 'm':
config.this_host.host = strtok(optarg, ":");
if ((portstr = strtok(NULL, ":")) == NULL) {
cerr &lt;&lt; "Bad host specification." &lt;&lt; endl;
usage();
}
config.this_host.port = (unsigned short)atoi(portstr);
config.got_listen_address = true;
break;
case 'n':
config.totalsites = atoi(optarg);
break;
case 'o':
tmphost = strtok(optarg, ":");
if ((portstr = strtok(NULL, ":")) == NULL) {
cerr &lt;&lt; "Bad host specification." &lt;&lt; endl;
usage();
}
tmpport = (unsigned short)atoi(portstr);
config.addOtherHost(tmphost, tmpport);
break;
case 'p':
config.priority = atoi(optarg);
break;</tt></b>
case '?':
default:
usage();
}
}
// Error check command line.
if ((!config.got_listen_address) || config.home == NULL)
usage(); </pre>
<p>
Having done that, the remainder of our <tt class="function">main()</tt>
function is left unchanged:
</p>
<pre class="programlisting"> RepMgr runner;
try {
if((ret = runner.init(&amp;config)) != 0)
goto err;
if((ret = runner.doloop()) != 0)
goto err;
} catch (DbException dbe) {
cerr &lt;&lt; "Caught an exception during initialization or"
&lt;&lt; " processing: " &lt;&lt; dbe.what() &lt;&lt; endl;
}
err:
runner.terminate();
return 0;
} </pre>
<p>
Now we need to update our
<tt class="methodname">RepMgr::init()</tt>
method. Our updates are at first related to configuring
replication. First, we need to update the method so that we can
identify the local site to the environment handle (that is, the site identified by the
<tt class="literal">-m</tt> command line option):
</p>
<pre class="programlisting">RepMgr::RepMgr() : app_config(0), dbenv(0)
{
}
int RepMgr::init(RepConfigInfo *config)
{
int ret = 0;
app_config = config;
dbenv.set_errfile(stderr);
dbenv.set_errpfx(progname);
<b class="userinput"><tt>if ((ret = dbenv.repmgr_set_local_site(app_config-&gt;this_host.host,
app_config-&gt;this_host.port, 0)) != 0) {
cerr &lt;&lt; "Could not set listen address to host:port "
&lt;&lt; app_config-&gt;this_host.host &lt;&lt; ":"
&lt;&lt; app_config-&gt;this_host.port
&lt;&lt; "error: " &lt;&lt; ret &lt;&lt; endl;
}</tt></b> </pre>
<p>
And we also add code to allow us to identify "other" sites to the environment handle (that is,
the sites that we identify using the <tt class="literal">-o</tt> command line
option). To do this, we iterate over each of the "other" sites provided to
us using the <tt class="literal">-o</tt> command line option, and we add each one
individually in turn:
</p>
<pre class="programlisting"> <b class="userinput"><tt>for ( REP_HOST_INFO *cur = app_config-&gt;other_hosts; cur != NULL;
cur = cur-&gt;next) {
if ((ret = dbenv.repmgr_add_remote_site(cur-&gt;host, cur-&gt;port,
NULL, 0)) != 0) {
cerr &lt;&lt; "could not add site." &lt;&lt; endl
}
} </tt></b> </pre>
<p>
And then we need code to allow us to identify the total number of sites
in this replication group, and to set the environment's priority.
</p>
<pre class="programlisting"> <b class="userinput"><tt>if (app_config-&gt;totalsites &gt; 0) {
try {
if ((ret = dbenv.rep_set_nsites(app_config-&gt;totalsites)) != 0)
dbenv.err(ret, "set_nsites");
} catch (DbException dbe) {
cerr &lt;&lt; "rep_set_nsites call failed. Continuing." &lt;&lt; endl;
}
}
dbenv.rep_set_priority(app_config-&gt;priority); </tt></b> </pre>
<p>
<span>We can now open our environment. Note that 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>
<tt class="literal">DB_INIT_REP</tt> flag.
</span>
</p>
<p>
Also, because we are using the replication framework, we must prepare
our environment for threaded usage. For this reason, we also
need the <tt class="literal">DB_THREAD</tt> flag.
</p>
<pre class="programlisting"> dbenv.set_cachesize(0, CACHESIZE, 0);
dbenv.set_flags(DB_TXN_NOSYNC, 1);
try {
dbenv.open(app_config-&gt;home,
DB_CREATE |
DB_RECOVER |
<b class="userinput"><tt>DB_THREAD |
DB_INIT_REP |</tt></b>
DB_INIT_LOCK |
DB_INIT_LOG |
DB_INIT_MPOOL |
DB_INIT_TXN,
0);
} catch(DbException dbe) {
cerr &lt;&lt; "Caught an exception during DB environment open." &lt;&lt; endl
&lt;&lt; "Ensure that the home directory is created prior to starting"
&lt;&lt; " the application." &lt;&lt; endl;
ret = ENOENT;
goto err;
}</pre>
<p>
Finally, we start replication before we exit this method.
Immediately after exiting this method, our application will go into
the
<tt class="methodname">RepMgr::doloop()</tt>
method, which is where
the bulk of our application's work is performed. We update that
method in the next chapter.
</p>
<pre class="programlisting"> if ((ret = dbenv.repmgr_start(3, app_config-&gt;start_policy)) != 0)
goto err;
err:
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="repapp.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">Chapter 3. The DB Replication Framework </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>

View File

@@ -0,0 +1,628 @@
<?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>Program Listing</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="txnapp.html" title="Chapter 2. Transactional Application" />
<link rel="previous" href="txnapp.html" title="Chapter 2. Transactional Application" />
<link rel="next" href="repapp.html" title="Chapter 3. The DB Replication Framework" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Program Listing</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="txnapp.html">Prev</a> </td>
<th width="60%" align="center">Chapter 2. Transactional Application</th>
<td width="20%" align="right"> <a accesskey="n" href="repapp.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="simpleprogramlisting"></a>Program Listing</h2>
</div>
</div>
<div></div>
</div>
<p>
Our example program is a fairly simple transactional
application. At this early stage of its development, the
application contains no hint that it must be network-aware
so the only command line argument that it takes is one that
allows us to specify the environment home directory.
(Eventually, we will specify things like host names and
ports from the command line).
</p>
<p>
Note that the application performs all writes under the
protection of a transaction; however, multiple database
operations are not performed per transaction. Consequently,
we simplify things a bit by using autocommit for our
database writes.
</p>
<p>
Also, this application is single-threaded. It is possible
to write a multi-threaded or multi-process application that
performs replication. That said, the concepts described in
this book are applicable to both single threaded and
multi-threaded applications so nothing
is gained by multi-threading this application other than
distracting complexity. This manual
does, however, identify where care must be taken when
performing replication with a non-single threaded
application.
</p>
<p>
Finally, remember that transaction processing is not described in
this manual. Rather, see the
<i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide for details on
that topic.
</p>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repconfiginfo_cxx"></a>
<span>Class: RepConfigInfo</span>
</h3>
</div>
</div>
<div></div>
</div>
<p>
Before we begin, we present a
class that we will use to maintain useful
information for us. Under normal circumstances,
this class would not be necessary for a simple
transactional example such as this. However, this code will
grow into a replicated example that needs to
track a lot more information for the
application, and so we lay the groundwork for
it here.
</p>
<p>
The class that we create is called
<tt class="classname">RepConfigInfo</tt>
and its only purpose at this time is to track
the location of our environment home directory.
</p>
<pre class="programlisting">#include &lt;db_cxx.h&gt;
#include &lt;iostream&gt;
class RepConfigInfo {
public:
RepConfigInfo();
virtual ~RepConfigInfo();
public:
char* home;
};
RepConfigInfo::RepConfigInfo()
{
home = "TESTDIR";
}
RepConfigInfo::~RepConfigInfo()
{
} </pre>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repmgr_cxx"></a>Class: RepMgr</h3>
</div>
</div>
<div></div>
</div>
<p>
Our transactional example will
instantiate a class,
<tt class="classname">RepMgr</tt>, that performs
all our work for us. Before we implement our
<tt class="function">main()</tt> function, we show
the <tt class="classname">RepMgr</tt> class
declaration.
</p>
<p>
First, we provide some declarations and
definitions that are needed later in
our example:
</p>
<pre class="programlisting">using std::cout;
using std::cin;
using std::cerr;
using std::endl;
using std::flush;
#define CACHESIZE (10 * 1024 * 1024)
#define DATABASE "quote.db"
const char *progname = "SimpleTxn"; </pre>
<p>
And then we define our <tt class="classname">RepMgr</tt> class:
</p>
<pre class="programlisting">class RepMgr
{
public:
// Constructor.
RepMgr();
// Initialization method. Creates and opens our environment handle.
int init(RepConfigInfo* config);
// The doloop is where all the work is performed.
int doloop();
// terminate() provides our shutdown code.
int terminate();
private:
// disable copy constructor.
RepMgr(const RepMgr &amp;);
void operator = (const RepMgr &amp;);
// internal data members.
RepConfigInfo *app_config;
DbEnv dbenv;
// private methods.
// print_stocks() is used to display the contents of our database.
static int print_stocks(Db *dbp);
}; </pre>
<p>
Note that we show the implementation of the various
<tt class="classname">RepMgr</tt> methods later in this section.
</p>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="usage_cxx"></a>Function: usage()</h3>
</div>
</div>
<div></div>
</div>
<p>
Our <tt class="function">usage()</tt> is at this
stage of development trivial because we only
have one command line argument to manage.
Still, we show it here for the sake of
completeness.
</p>
<pre class="programlisting">static void usage()
{
cerr &lt;&lt; "usage: " &lt;&lt; progname &lt;&lt; endl
&lt;&lt; "-h home" &lt;&lt; endl;
exit(EXIT_FAILURE);
} </pre>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="main_cxx"></a>Function: main()</h3>
</div>
</div>
<div></div>
</div>
<p>
Now we provide our <tt class="function">main()</tt>
function. This is a trivial function whose only
job is to collect command line information,
then instantiate a <tt class="classname">RepMgr</tt>
object, run it, then terminate it.
</p>
<p>
We begin by declaring some useful variables. Of
these, note that we instantiate our
<tt class="classname">RepConfigInfo</tt>
object here. Recall that this is used to store
information useful to our code. This class becomes more
interesting later in this book.
</p>
<pre class="programlisting">int main(int argc, char **argv)
{
RepConfigInfo config;
char ch;
int ret; </pre>
<p>
Then we collect our command line information. Again, this is at
this point fairly trivial:
</p>
<pre class="programlisting"> // Extract the command line parameters
while ((ch = getopt(argc, argv, "h:")) != EOF) {
switch (ch) {
case 'h':
config.home = optarg;
break;
case '?':
default:
usage();
}
}
// Error check command line.
if (config.home == NULL)
usage(); </pre>
<p>
Now we instantiate and initialize our <tt class="classname">RepMgr</tt>
class, which is what is responsible for doing all our real work.
The <tt class="methodname">RepMgr::init()</tt> method creates and
opens our environment handle.
</p>
<pre class="programlisting"> RepMgr runner;
try {
if((ret = runner.init(&amp;config)) != 0)
goto err; </pre>
<p>
Then we call the <tt class="methodname">RepMgr::doloop()</tt>
method, which is where the actual transactional work is
performed for this application.
</p>
<pre class="programlisting"> if((ret = runner.doloop()) != 0)
goto err; </pre>
<p>
Finally, catch exceptions and terminate the program:
</p>
<pre class="programlisting"> } catch (DbException dbe) {
cerr &lt;&lt; "Caught an exception during initialization or"
&lt;&lt; " processing: " &lt;&lt; dbe.what() &lt;&lt; endl;
}
err:
runner.terminate();
return 0;
} </pre>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="repmgr_init_cxx"></a>Method: RepMgr::init()</h3>
</div>
</div>
<div></div>
</div>
<p>
The <tt class="methodname">RepMgr::init()</tt>
method is used to create and open our environment handle.
For readers familiar with writing transactional
DB applications, there should be no surprises
here. However, we will be adding to this in later
chapters as we roll replication into this example.
</p>
<p>
First, we show the class constructor
implementation, which is only used to initialize a
few variables:
</p>
<pre class="programlisting">RepMgr::RepMgr() : app_config(0), dbenv(0)
{
} </pre>
<p>
We now provide the <tt class="methodname">init()</tt> method
implementation. The only thing of interest here is that we specify
<tt class="literal">DB_TXN_NOSYNC</tt> to our environment. This causes
our transactional commits to become non-durable, which is something
that we are doing only because of the nature of our example.
</p>
<pre class="programlisting">int RepMgr::init(RepConfigInfo *config)
{
int ret = 0;
app_config = config;
dbenv.set_errfile(stderr);
dbenv.set_errpfx(progname);
/*
* We can now open our environment.
*/
dbenv.set_cachesize(0, CACHESIZE, 0);
dbenv.set_flags(DB_TXN_NOSYNC, 1);
try {
dbenv.open(app_config-&gt;home,
DB_CREATE |
DB_RECOVER |
DB_INIT_LOCK |
DB_INIT_LOG |
DB_INIT_MPOOL |
DB_INIT_TXN,
0);
} catch(DbException dbe) {
cerr &lt;&lt; "Caught an exception during DB environment open." &lt;&lt; endl
&lt;&lt; "Ensure that the home directory is created prior to starting"
&lt;&lt; " the application." &lt;&lt; endl;
ret = ENOENT;
goto err;
}
err:
return ret;
} </pre>
<p>
Finally, we present the <tt class="methodname">RepMgr::terminate()</tt>
method here. All this does is close the environment handle. Again,
there should be no surprises here, but we provide the
implementation for the sake of completeness anyway.
</p>
<pre class="programlisting">int RepMgr::terminate()
{
try {
dbenv.close(0);
} catch (DbException dbe) {
cerr &lt;&lt; "error closing environment: " &lt;&lt; dbe.what() &lt;&lt; endl;
}
return 0;
} </pre>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="doloop_cxx"></a>Method: RepMgr::doloop()</h3>
</div>
</div>
<div></div>
</div>
<p>
Having written our <tt class="function">main()</tt>
function and support utility methods, we now implement
our application's
primary data processing method. This
method provides a command prompt at which the
user can enter a stock ticker value and a price for
that value. This information is then entered to the
database.
</p>
<p>
To display the database, simply enter
<tt class="literal">return</tt> at the prompt.
</p>
<p>
To begin, we declare a database pointer,
several <tt class="classname">Dbt</tt> variables, and
the usual assortment of variables used for buffers
and return codes. We also initialize all of this.
</p>
<pre class="programlisting">#define BUFSIZE 1024
int RepMgr::doloop()
{
Db *dbp;
Dbt key, data;
char buf[BUFSIZE], *rbuf;
int ret;
dbp = NULL;
memset(&amp;key, 0, sizeof(key));
memset(&amp;data, 0, sizeof(data));
ret = 0; </pre>
<p>
Next, we begin the loop and we immediately open our
database if it has not already been opened. Notice that
we specify autocommit when we open the database. In
this case, autocommit is important because we will only
ever write to our database using it. There is no need
for explicit transaction handles and commit/abort code
in this application, because we are not combining
multiple database operations together under a single
transaction.
</p>
<p>
Autocommit is described in greater detail in the
<i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide.
</p>
<pre class="programlisting"> for (;;) {
if (dbp == NULL) {
dbp = new Db(&amp;dbenv, 0);
// Set page size small so page allocation is cheap.
if ((ret = dbp-&gt;set_pagesize(512)) != 0)
goto err;
try {
dbp-&gt;open(NULL, DATABASE, NULL, DB_BTREE,
DB_CREATE | DB_AUTO_COMMIT, 0);
} catch(DbException dbe) {
dbenv.err(ret, "DB-&gt;open");
throw dbe;
}
} </pre>
<p>
Now we implement our command prompt. This is a simple and not
very robust implementation of a command prompt.
If the user enters the keywords <tt class="literal">exit</tt>
or <tt class="literal">quit</tt>, the loop is exited and the
application ends. If the user enters nothing and instead simply
presses <tt class="literal">return</tt>, the entire contents of the
database is displayed. We use our
<tt class="function">print_stocks()</tt> method to display the
database. (That implementation is shown next in this chapter.)
</p>
<p>
Notice that very little error checking is performed on the data
entered at this prompt. If the user fails to enter at least one
space in the value string, a simple help message is printed and
the prompt is returned to the user. That is the only error
checking performed here. In a real-world application,
at a minimum the application would probably check to ensure
that the price was in fact an integer or float value.
However, in order to keep this example code as simple as
possible, we refrain from implementing a thorough user interface.
</p>
<pre class="programlisting"> cout &lt;&lt; "QUOTESERVER" ;
cout &lt;&lt; "&gt; " &lt;&lt; flush;
if (fgets(buf, sizeof(buf), stdin) == NULL)
break;
if (strtok(&amp;buf[0], " \t\n") == NULL) {
switch ((ret = print_stocks(dbp))) {
case 0:
continue;
default:
dbp-&gt;err(ret, "Error traversing data");
goto err;
}
}
rbuf = strtok(NULL, " \t\n");
if (rbuf == NULL || rbuf[0] == '\0') {
if (strncmp(buf, "exit", 4) == 0 ||
strncmp(buf, "quit", 4) == 0)
break;
dbenv.errx("Format: TICKER VALUE");
continue;
} </pre>
<p>
Now we assign data to the <tt class="classname">Dbt</tt>s that
we will use to write the new information to the database.
</p>
<pre class="programlisting"> key.set_data(buf);
key.set_size((u_int32_t)strlen(buf));
data.set_data(rbuf);
data.set_size((u_int32_t)strlen(rbuf)); </pre>
<p>
Having done that, we can write the new information to the
database. Remember that this application uses autocommit,
so no explicit transaction management is required. Also,
the database is not configured for duplicate records, so
the data portion of a record is overwritten if the provided
key already exists in the database. However, in this case
DB returns <tt class="literal">DB_KEYEXIST</tt> — which
we ignore.
</p>
<pre class="programlisting"> if ((ret = dbp-&gt;put(NULL, &amp;key, &amp;data, 0)) != 0)
{
dbp-&gt;err(ret, "DB-&gt;put");
if (ret != DB_KEYEXIST)
goto err;
}
} </pre>
<p>
Finally, we close our database before returning from the
method.
</p>
<pre class="programlisting">err: if (dbp != NULL) {
(void)dbp-&gt;close(DB_NOSYNC);
cout &lt;&lt; "database closed" &lt;&lt; endl;
}
return (ret);
} </pre>
</div>
<div class="sect2" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="printstocks_c"></a>
<span>Method: RepMgr::print_stocks()</span>
</h3>
</div>
</div>
<div></div>
</div>
<p>
The <tt class="function">print_stocks()</tt>
<span>method</span>
simply takes a database handle, opens a cursor, and uses
it to display all the information it finds in a database.
This is trivial cursor operation that should hold
no surprises for you. We simply provide it here for
the sake of completeness.
</p>
<p>
If you are unfamiliar with basic cursor operations,
please see the <i class="citetitle">Getting Started with Berkeley DB</i>
guide.
</p>
<pre class="programlisting">int RepMgr::print_stocks(Db *dbp)
{
Dbc *dbc;
Dbt key, data;
#define MAXKEYSIZE 10
#define MAXDATASIZE 20
char keybuf[MAXKEYSIZE + 1], databuf[MAXDATASIZE + 1];
int ret, t_ret;
u_int32_t keysize, datasize;
if ((ret = dbp-&gt;cursor(NULL, &amp;dbc, 0)) != 0) {
dbp-&gt;err(ret, "can't open cursor");
return (ret);
}
memset(&amp;key, 0, sizeof(key));
memset(&amp;data, 0, sizeof(data));
cout &lt;&lt; "\tSymbol\tPrice" &lt;&lt; endl
&lt;&lt; "\t======\t=====" &lt;&lt; endl;
for (ret = dbc-&gt;get(&amp;key, &amp;data, DB_FIRST);
ret == 0;
ret = dbc-&gt;get(&amp;key, &amp;data, DB_NEXT)) {
keysize = key.get_size() &gt; MAXKEYSIZE ? MAXKEYSIZE : key.get_size();
memcpy(keybuf, key.get_data(), keysize);
keybuf[keysize] = '\0';
datasize = data.get_size() &gt;=
MAXDATASIZE ? MAXDATASIZE : data.get_size();
memcpy(databuf, data.get_data(), datasize);
databuf[datasize] = '\0';
cout &lt;&lt; "\t" &lt;&lt; keybuf &lt;&lt; "\t" &lt;&lt; databuf &lt;&lt; endl;
}
cout &lt;&lt; endl &lt;&lt; flush;
if ((t_ret = dbc-&gt;close()) != 0 &amp;&amp; ret == 0) {
cout &lt;&lt; "closed cursor" &lt;&lt; endl;
ret = t_ret;
}
switch (ret) {
case 0:
case DB_NOTFOUND:
return (0);
default:
return (ret);
}
} </pre>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="txnapp.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="txnapp.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="repapp.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Chapter 2. Transactional Application </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Chapter 3. The DB Replication Framework</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -0,0 +1,187 @@
<?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>Chapter 2. Transactional Application</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
<link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="up" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
<link rel="previous" href="permmessages.html" title="Permanent Message Handling" />
<link rel="next" href="simpleprogramlisting.html" title="Program Listing" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Chapter 2. Transactional Application</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="permmessages.html">Prev</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="simpleprogramlisting.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="chapter" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a id="txnapp"></a>Chapter 2. Transactional Application</h2>
</div>
</div>
<div></div>
</div>
<div class="toc">
<p>
<b>Table of Contents</b>
</p>
<dl>
<dt>
<span class="sect1">
<a href="txnapp.html#appoverview">Application Overview</a>
</span>
</dt>
<dt>
<span class="sect1">
<a href="simpleprogramlisting.html">Program Listing</a>
</span>
</dt>
<dd>
<dl>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#repconfiginfo_cxx">
Class: RepConfigInfo
</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#repmgr_cxx">Class: RepMgr</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#usage_cxx">Function: usage()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#main_cxx">Function: main()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#repmgr_init_cxx">Method: RepMgr::init()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#doloop_cxx">Method: RepMgr::doloop()</a>
</span>
</dt>
<dt>
<span class="sect2">
<a href="simpleprogramlisting.html#printstocks_c">
Method: RepMgr::print_stocks()
</a>
</span>
</dt>
</dl>
</dd>
</dl>
</div>
<p>
In this chapter, we build a simple transaction-protected DB
application. Throughout the remainder of this book, we will add
replication to this example. We do this to underscore the concepts
that we are presenting in this book; the first being that you
should start with a working transactional program and then add
replication to it.
</p>
<p>
Note that this book assumes you already know how to write a
transaction-protected DB application, so we will not be
covering those concepts in this book. To learn how to write a
transaction-protected application, see the
<i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide.
</p>
<div class="sect1" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="appoverview"></a>Application Overview</h2>
</div>
</div>
<div></div>
</div>
<p>
Our application maintains a stock market quotes database.
This database contains records whose key is the stock
market symbol and whose data is the stock's price.
</p>
<p>
The application operates by presenting you with a command
line prompt. You then enter the stock symbol and its value,
separated by a space. The application takes this
information, writes it to the database.
</p>
<p>
To see the contents of the database, simply press
<tt class="literal">return</tt> at the command prompt.
</p>
<p>
To quit the application, type 'quit' or 'exit' at the
command prompt.
</p>
<p>
For example, the following illustrates the application's
usage. In it, we use entirely fictitious stock market
symbols and price values.
</p>
<pre class="programlisting">&gt; ./SimpleTxn -h env_home_dir
QUOTESERVER&gt; stock1 88
QUOTESERVER&gt; stock2 .08
QUOTESERVER&gt;
Symbol Price
====== =====
stock1 88
QUOTESERVER&gt; stock1 88.9
QUOTESERVER&gt;
Symbol Price
====== =====
stock1 88.9
stock2 .08
QUOTESERVER&gt; quit
&gt;</pre>
</div>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="permmessages.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="index.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="simpleprogramlisting.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Permanent Message Handling </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Program Listing</td>
</tr>
</table>
</div>
</body>
</html>