mirror of
https://github.com/berkeleydb/je.git
synced 2024-11-15 01:46:24 +00:00
276 lines
13 KiB
HTML
276 lines
13 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Managing Write Requests at a Replica</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 Berkeley DB, Java Edition High Availability Applications" />
|
||
<link rel="up" href="progoverview.html" title="Chapter 2. Replication API First Steps" />
|
||
<link rel="prev" href="repenvironmentopen.html" title="Opening a Replicated Environment" />
|
||
<link rel="next" href="secondary.html" title="Secondary Nodes" />
|
||
</head>
|
||
<body>
|
||
<div xmlns="" class="navheader">
|
||
<div class="libver">
|
||
<p>Library Version 12.2.7.5</p>
|
||
</div>
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Managing Write Requests at a Replica</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="repenvironmentopen.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 2. Replication API First Steps</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="secondary.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="replicawrites"></a>Managing Write Requests at a Replica</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="toc">
|
||
<dl>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="replicawrites.html#using-statechangelistener">Using the StateChangeListener</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="replicawrites.html#repwriteexception">Catching ReplicaWriteException</a>
|
||
</span>
|
||
</dt>
|
||
</dl>
|
||
</div>
|
||
<p>
|
||
For a replicated JE application, read requests can be
|
||
serviced by any electable or secondary node in the replication group, but
|
||
write requests can only be serviced by the Master node. For
|
||
this reason, your application must be prepared to deal with the
|
||
difference in operating behavior between read-only Replicas and
|
||
read-write Masters.
|
||
</p>
|
||
<p>
|
||
It is possible to be quite sophisticated in terms of tracking
|
||
which node is the Master and so which node can service write
|
||
requests. You can even route write requests to the Master node
|
||
by writing a special router process. For an example of an
|
||
application that does this, see <a class="ulink" href="../examples/je/rep/quote/RouterDrivenStockQuotes.html" target="_top">RouterDrivenStockQuotes</a> and
|
||
<a class="ulink" href="../examples/je/rep/quote/HARouter.html" target="_top">HARouter</a>, both of which are available in your JE
|
||
distribution in the
|
||
<code class="literal"><JE HOME>/examples/je/rep/quote</code>
|
||
directory.
|
||
</p>
|
||
<p>
|
||
However, for our purposes here, we simply want to
|
||
make sure our Replica nodes can gracefully handle a situation
|
||
where they receive a write request. The write request should be
|
||
rejected by the node, with some notification being returned to
|
||
the requester that the write activity is rejected. While not
|
||
the most robust solution, this is the simplest thing your
|
||
JE replicated application can do if it receives a write
|
||
request at a Replica node.
|
||
</p>
|
||
<p>
|
||
There are two ways to determine whether a write request can be
|
||
handled at the local node:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
Use a monitor node to implement request routing.
|
||
Monitor nodes are described in <a class="xref" href="monitors.html" title="Chapter 5. Writing Monitor Nodes">Writing Monitor Nodes</a>.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
Use the <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeListener.html" target="_top">StateChangeListener</a> to detect when the local
|
||
node becomes a Master. Otherwise, forward the write
|
||
request to the Master node instead of attempting to
|
||
service it locally.
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
Either way, any code that attempts database writes for an HA
|
||
application should always be prepared to handle a
|
||
<a class="ulink" href="../java/com/sleepycat/je/rep/ReplicaWriteException.html" target="_top">ReplicaWriteException</a>.
|
||
</p>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="using-statechangelistener"></a>Using the StateChangeListener</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
You use the <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeListener.html" target="_top">StateChangeListener</a> interface to implement a
|
||
class that is capable of notifying your node when it has
|
||
changed state. In this way, you can track whether a node
|
||
is in the Master, Replica or Unknown state, and so know
|
||
whether the node is capable of handling write requests.
|
||
</p>
|
||
<p>
|
||
To do this, you must implement <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeListener.html#stateChange(com.sleepycat.je.rep.StateChangeEvent)" target="_top">StateChangeListener.stateChange()</a>,
|
||
which receives a <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeEvent.html" target="_top">StateChangeEvent</a> object whenever it is
|
||
called.
|
||
</p>
|
||
<p>
|
||
If the node is not in the Master state, then the node
|
||
can either reject write requests outright or, more
|
||
usefully, forward write requests to the Master. For an
|
||
example of an HA application that forwards write requests
|
||
and uses the <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeListener.html" target="_top">StateChangeListener</a>, see the
|
||
<a class="ulink" href="../examples/je/rep/quote/UpdateForwardingStockQuotes.html" target="_top">UpdateForwardingStockQuotes</a> example.
|
||
</p>
|
||
<p>
|
||
Alternatively, you can write a router based on an HA
|
||
<a class="ulink" href="../java/com/sleepycat/je/rep/monitor/Monitor.html" target="_top">Monitor</a>. See <a class="xref" href="monitors.html" title="Chapter 5. Writing Monitor Nodes">Writing Monitor Nodes</a>
|
||
for more information.
|
||
</p>
|
||
<p>
|
||
Briefly, you can implement
|
||
<a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeListener.html" target="_top">StateChangeListener</a> as follows. Notice that this partial
|
||
implementation relies on <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeEvent.html#getState()" target="_top">StateChangeEvent.getState()</a> to
|
||
determine the state that the node has just transitioned to.
|
||
It then uses <a class="ulink" href="../java/com/sleepycat/je/rep/StateChangeEvent.html#getMasterNodeName()" target="_top">StateChangeEvent.getMasterNodeName()</a> to
|
||
determine where write requests should be forwarded to in
|
||
the event that the new state is not
|
||
<code class="literal">MASTER</code>.
|
||
</p>
|
||
<pre class="programlisting">private class Listener implements StateChangeListener {
|
||
|
||
private String currentMaster = null;
|
||
|
||
public void stateChange(StateChangeEvent se)
|
||
throws RuntimeException {
|
||
|
||
switch (stateChangeEvent.getState()) {
|
||
|
||
case MASTER:
|
||
// Do whatever your code needs you to do when the
|
||
// current node is the MASTER. For example,
|
||
// set a flag to indicate that the local node
|
||
// is in the MASTER state. Here, we just fall
|
||
// through and do the same thing as if we
|
||
// transitioned to the REPLICA state.
|
||
case REPLICA:
|
||
// Again, do whatever your code needs done when
|
||
// a node is in the REPLICA state. At a minimum,
|
||
// you should probably capture which node is the
|
||
// current Master.
|
||
currentMaster = se.getMasterNodeName();
|
||
break;
|
||
|
||
// We get here if we have transitioned to the UNKNOWN
|
||
// state.
|
||
default:
|
||
currentmasterName = null;
|
||
break;
|
||
}
|
||
}
|
||
|
||
public String getCurrentMasterName() {
|
||
return currentMaster;
|
||
}
|
||
} </pre>
|
||
<p>
|
||
In order to make use of the new listener, the application
|
||
must call <a class="ulink" href="../java/com/sleepycat/je/rep/ReplicatedEnvironment.html#setStateChangeListener(com.sleepycat.je.rep.StateChangeListener)" target="_top">ReplicatedEnvironment.setStateChangeListener()</a>.
|
||
Note that this method can be called at any time after the
|
||
<a class="ulink" href="../java/com/sleepycat/je/rep/ReplicatedEnvironment.html" target="_top">ReplicatedEnvironment</a> handle has been created. Also, the
|
||
listener is set per environment, not per handle. So if you
|
||
set different listeners for different
|
||
<a class="ulink" href="../java/com/sleepycat/je/rep/ReplicatedEnvironment.html" target="_top">ReplicatedEnvironment</a> handles, the last listener
|
||
configured is used environment-wide.
|
||
</p>
|
||
<pre class="programlisting"> EnvironmentConfig envConfig = new EnvironmentConfig();
|
||
envConfig.setAllowCreate(true);
|
||
envConfig.setTransactional(true);
|
||
|
||
// Identify the node
|
||
ReplicationConfig repConfig = new ReplicationConfig();
|
||
repConfig.setGroupName("PlanetaryRepGroup");
|
||
repConfig.setNodeName("Saturn");
|
||
repConfig.setNodeHostPort("saturn.example.com:5001");
|
||
|
||
// Use the node at mars.example.com:5002 as a helper to find
|
||
// the rest of the group.
|
||
repConfig.setHelperHosts("mars.example.com:5002");
|
||
|
||
ReplicatedEnvironment repEnv =
|
||
new ReplicatedEnvironment(home, repConfig, envConfig);
|
||
StateChangeListener listener = new Listener();
|
||
repEnv.setStateChangeListener(listener); </pre>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="repwriteexception"></a>Catching ReplicaWriteException</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
If you perform a Database write operation on a node that is not in the
|
||
Master state, a <a class="ulink" href="../java/com/sleepycat/je/rep/ReplicaWriteException.html" target="_top">ReplicaWriteException</a> is thrown when you attempt to commit the
|
||
transaction. Therefore, whenever performing database write
|
||
operations in an HA application, you should catch and
|
||
handle <a class="ulink" href="../java/com/sleepycat/je/rep/ReplicaWriteException.html" target="_top">ReplicaWriteException</a>.
|
||
</p>
|
||
<p>
|
||
For example:
|
||
</p>
|
||
<pre class="programlisting">Transaction txn = null;
|
||
try {
|
||
txn = env.beginTransaction(null, null);
|
||
/*
|
||
* Perform your write operations under the protection
|
||
* of the transaction handle here.
|
||
*/
|
||
txn.commit();
|
||
} catch (ReplicaWriteException replicaWrite) {
|
||
/*
|
||
* Perform whatever reporting (logging) activies you want
|
||
* to do in order to acknowledge that the write operation(s)
|
||
* failed. Then abort the transaction.
|
||
*/
|
||
|
||
if (txn != null) {
|
||
txn.abort();
|
||
}
|
||
} </pre>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="repenvironmentopen.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="progoverview.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="secondary.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Opening a Replicated Environment </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Secondary Nodes</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|