2011-09-13 17:44:24 +00:00
|
|
|
|
<?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.73.2" />
|
|
|
|
|
<link rel="start" 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="prev" href="heartbeats.html" title="Managing Heartbeats" />
|
|
|
|
|
<link rel="next" href="processingloop.html" title="Processing Loop" />
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div xmlns="" class="navheader">
|
|
|
|
|
<div class="libver">
|
2012-11-14 21:35:20 +00:00
|
|
|
|
<p>Library Version 11.2.5.3</p>
|
2011-09-13 17:44:24 +00:00
|
|
|
|
</div>
|
|
|
|
|
<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 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 quite 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>
|
|
|
|
|
<p>
|
|
|
|
|
In order to determine whether your code is running
|
|
|
|
|
as a master or a replica, you must write your
|
|
|
|
|
application as an implementation of
|
|
|
|
|
<code class="classname">com.sleepycat.db.EventHandler</code>.
|
|
|
|
|
This class gives you a series of methods within
|
|
|
|
|
which you can detect and respond to various events
|
|
|
|
|
that occur in your DB code. Some, but not all,
|
|
|
|
|
of these methods have to do with elections:
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
Some of the more commonly handled events are
|
|
|
|
|
described below. For a complete list of events, see
|
|
|
|
|
the
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<span>
|
|
|
|
|
<code class="classname">com.sleepycat.db.EventHandler</code>
|
|
|
|
|
javadoc page.
|
|
|
|
|
</span>
|
|
|
|
|
</p>
|
|
|
|
|
<div class="itemizedlist">
|
|
|
|
|
<ul type="disc">
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
<code class="methodname">EventHandler.handlePanicEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
An error has occured in the Berkeley DB library requiring your
|
|
|
|
|
application to shut down and then run recovery.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepClientEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The local environment is now a replica.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepConnectBrokenEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
A previously established connection between
|
|
|
|
|
two sites in the replication group has been
|
|
|
|
|
broken.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepConnectEstablishedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
A connection has been established between
|
|
|
|
|
two sites in the replication group.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepConnectTryFailedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
An attempt was made to establish a connection
|
|
|
|
|
to a known remote site, but the connection
|
|
|
|
|
attempt failed.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepDupmasterEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
A duplicate master has been discovered in the
|
|
|
|
|
replication group.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepElectedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The local site has just won an election and
|
|
|
|
|
is now the master. Your code should now
|
|
|
|
|
reconfigure itself to operation as a master
|
|
|
|
|
site.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepElectionFailedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The local site's attempt to initiate or
|
|
|
|
|
participate in a replication master election
|
|
|
|
|
failed, due to the lack of timely message
|
|
|
|
|
response from a sufficient number of remote
|
|
|
|
|
sites.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
<code class="methodname">EventHandler.handleRepJoinFailureEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The local site could not synchronize with the
|
|
|
|
|
master because an internal initialization was
|
|
|
|
|
required, but internal initialization has
|
|
|
|
|
been turned off
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepLocalSiteRemovedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The local site has been removed from the group.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepNewMasterEvent()</code>
|
|
|
|
|
</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>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepMasterEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The local environment is now a master.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepMasterFailureEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The connection to the remote master replication site has failed.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepPermFailedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The Replication Manager did not receive enough acknowledgements to
|
|
|
|
|
ensure the transaction's durability within the replicationg group.
|
|
|
|
|
The Replication Manager has therefore flushed the transaction to
|
|
|
|
|
the master's local disk for storage.
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
How the Replication Manager knows whether the acknowledgements it
|
|
|
|
|
has received is determined by the ack policy you have set for your
|
|
|
|
|
applicaton. See <a class="xref" href="fwrkpermmessage.html#fmwrkpermpolicy" title="Identifying Permanent Message Policies">Identifying Permanent Message Policies</a>
|
|
|
|
|
for more information.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepSiteAddedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
A new site has joined the replication group.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepSiteRemovedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
An existing site has been removed from the replication group.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleRepStartupDoneEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The replica has completed startup
|
|
|
|
|
synchronization and is now processing
|
|
|
|
|
log records received from the master.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<code class="methodname">EventHandler.handleWriteFailedEvent()</code>
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
A Berkeley DB write to stable storage failed.
|
|
|
|
|
</p>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
<p>
|
|
|
|
|
Note that these events are raised whenever the
|
|
|
|
|
state is established. That is, when the current
|
|
|
|
|
environment becomes a replica, and that includes
|
|
|
|
|
at application startup, the event is raised.
|
|
|
|
|
Also, when an election is held and a replica is elected to be a
|
|
|
|
|
master, then the event occurs.
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
The <code class="classname">EventHandler</code>
|
|
|
|
|
implementation is fairly simple. First you detect
|
|
|
|
|
the event, and then you record the state change
|
|
|
|
|
in some data member maintained in a location that
|
|
|
|
|
is convenient to you.
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
For example:
|
|
|
|
|
</p>
|
|
|
|
|
<pre class="programlisting">
|
|
|
|
|
package db.repquote;
|
|
|
|
|
|
|
|
|
|
// We make our main class an EventHandler implementation
|
|
|
|
|
...
|
|
|
|
|
import com.sleepycat.db.EventHandler;
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
public class MyReplicationClass implements EventHandler
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
// Somewhere we provide a data member that is used to track
|
|
|
|
|
// whether we are a master server. This could be in our main
|
|
|
|
|
// class, or it could be part of a supporting class.
|
|
|
|
|
private boolean isMaster;
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
isMaster = false;
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
// In the code where we open our environment and start replication,
|
|
|
|
|
// we must identify the class that is the event handler. In this
|
|
|
|
|
// example, we are performing this from within the class that
|
|
|
|
|
// implements com.sleepycat.db.EventHandler so we identify
|
|
|
|
|
// "this" class as the event handler
|
|
|
|
|
envConfig.setEventHandler(this); </pre>
|
|
|
|
|
<p>
|
|
|
|
|
That done, we still need to implement the methods required for handling replication events.
|
|
|
|
|
For a simple application like this one, these implementations can be trivial.
|
|
|
|
|
</p>
|
|
|
|
|
<pre class="programlisting"> public void handleRepClientEvent()
|
|
|
|
|
{
|
|
|
|
|
dbenv.setIsMaster(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepConnectBrokenEvent()
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepConnectEstablishedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepConnectTryFailedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepMasterEvent()
|
|
|
|
|
{
|
|
|
|
|
dbenv.setIsMaster(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepNewMasterEvent(int envId)
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleWriteFailedEvent(int errorCode)
|
|
|
|
|
{
|
|
|
|
|
System.err.println("Write to stable storage failed!" +
|
|
|
|
|
"Operating system error code:" + errorCode);
|
|
|
|
|
System.err.println("Continuing....");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepStartupDoneEvent()
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Replication startup is completed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepPermFailedEvent()
|
|
|
|
|
{
|
|
|
|
|
System.out.println("This application failed to receive enough" +
|
|
|
|
|
"acks for a permanent message. The transaction is flushed" +
|
|
|
|
|
"to disk on this master host.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepLocalSiteRemovedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepSiteAddedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepSiteRemovedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Ignored for now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepElectedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Safely ignored for Replication Manager applications.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepElectionFailedEvent()
|
|
|
|
|
{
|
|
|
|
|
// Safely ignored for Replication Manager applications that do
|
|
|
|
|
// not manage their own master selection.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepJoinFailureEvent()
|
|
|
|
|
{
|
|
|
|
|
// Safely ignored since this application did not turn off AUTOINIT.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepMasterFailureEvent()
|
|
|
|
|
{
|
|
|
|
|
// Safely ignored for Replication Manager applications that do
|
|
|
|
|
// not manage their own master selection.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handleRepDupmasterEvent()
|
|
|
|
|
{
|
|
|
|
|
// Safely ignored for Replication Manager applications that do
|
|
|
|
|
// not manage their own master selection.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void handlePanicEvent()
|
|
|
|
|
{
|
|
|
|
|
System.err.println("Panic encountered!");
|
|
|
|
|
System.err.println("Shutting down.");
|
|
|
|
|
System.err.println("You should restart, running recovery.");
|
|
|
|
|
try {
|
|
|
|
|
terminate();
|
|
|
|
|
} catch (DatabaseException dbe) {
|
|
|
|
|
System.err.println("Caught an exception during " +
|
|
|
|
|
"termination in handlePanicEvent: " + dbe.toString());
|
|
|
|
|
}
|
|
|
|
|
System.exit(-1);
|
|
|
|
|
}</pre>
|
|
|
|
|
<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"> </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>
|