You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by ma...@apache.org on 2009/08/11 23:26:19 UTC

svn commit: r803305 - in /hadoop/zookeeper/branches/branch-3.2: ./ docs/ src/docs/src/documentation/content/xdocs/ src/java/main/org/apache/zookeeper/server/quorum/ src/java/main/org/apache/zookeeper/server/quorum/flexible/ src/java/test/org/apache/zoo...

Author: mahadev
Date: Tue Aug 11 21:26:12 2009
New Revision: 803305

URL: http://svn.apache.org/viewvc?rev=803305&view=rev
Log:
ZOOKEEPER-498. Unending Leader Elections : WAN configuration (flavio via mahadev)

Added:
    hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.html
    hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.pdf
    hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperHierarchicalQuorums.xml
Modified:
    hadoop/zookeeper/branches/branch-3.2/CHANGES.txt
    hadoop/zookeeper/branches/branch-3.2/docs/index.html
    hadoop/zookeeper/branches/branch-3.2/docs/index.pdf
    hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.html
    hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.pdf
    hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/index.xml
    hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
    hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/FastLeaderElection.java
    hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/QuorumCnxManager.java
    hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumHierarchical.java
    hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/FLEZeroWeightTest.java
    hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java

Modified: hadoop/zookeeper/branches/branch-3.2/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/CHANGES.txt?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/CHANGES.txt (original)
+++ hadoop/zookeeper/branches/branch-3.2/CHANGES.txt Tue Aug 11 21:26:12 2009
@@ -58,6 +58,9 @@
 
   ZOOKEEPER-477. zkCleanup.sh is flaky (fernando via mahadev)
 
+  ZOOKEEPER-498. Unending Leader Elections : WAN configuration (flavio via
+  mahadev) 
+
 IMPROVEMENTS:
 
 NEW FEATURES:

Modified: hadoop/zookeeper/branches/branch-3.2/docs/index.html
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/docs/index.html?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/docs/index.html (original)
+++ hadoop/zookeeper/branches/branch-3.2/docs/index.html Tue Aug 11 21:26:12 2009
@@ -284,6 +284,10 @@
 <li>
 <a href="zookeeperJMX.html">JMX</a> - how to enable JMX in ZooKeeper</li>
       
+<li>
+<a href="zookeeperHierarchicalQuorums.html">Hierarchical quorums</a>
+</li>
+      
 </ul>
       
 </li>

Modified: hadoop/zookeeper/branches/branch-3.2/docs/index.pdf
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/docs/index.pdf?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
Binary files - no diff available.

Modified: hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.html
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.html?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.html (original)
+++ hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.html Tue Aug 11 21:26:12 2009
@@ -1150,6 +1150,9 @@
               The left-hand side of the assignment is a colon-separated list of server
               identifiers. Note that groups must be disjoint and the union of all groups
               must be the ZooKeeper ensemble. </p>
+<p> You will find an example <a href="zookeeperHierarchicalQuorums.html">here</a>
+              
+</p>
 </dd>
 
           
@@ -1165,11 +1168,14 @@
               the weight of server is 1. If the configuration defines groups, but not
               weights, then a value of 1 will be assigned to all servers.  
               </p>
+<p> You will find an example <a href="zookeeperHierarchicalQuorums.html">here</a>
+              
+</p>
 </dd>
         
 </dl>
 <p></p>
-<a name="N10383"></a><a name="sc_authOptions"></a>
+<a name="N1038F"></a><a name="sc_authOptions"></a>
 <h4>Authentication &amp; Authorization Options</h4>
 <p>The options in this section allow control over
         authentication/authorization performed by the service.</p>
@@ -1203,7 +1209,7 @@
 </dd>
         
 </dl>
-<a name="N103A6"></a><a name="Unsafe+Options"></a>
+<a name="N103B2"></a><a name="Unsafe+Options"></a>
 <h4>Unsafe Options</h4>
 <p>The following options can be useful, but be careful when you use
         them. The risk of each is explained along with the explanation of what
@@ -1248,7 +1254,7 @@
 </dd>
         
 </dl>
-<a name="N103D8"></a><a name="sc_zkCommands"></a>
+<a name="N103E4"></a><a name="sc_zkCommands"></a>
 <h3 class="h4">ZooKeeper Commands: The Four Letter Words</h3>
 <p>ZooKeeper responds to a small set of commands. Each command is
       composed of four letters. You issue the commands to ZooKeeper via telnet
@@ -1312,7 +1318,7 @@
 <pre class="code">$ echo ruok | nc 127.0.0.1 5111
 imok
 </pre>
-<a name="N10418"></a><a name="sc_dataFileManagement"></a>
+<a name="N10424"></a><a name="sc_dataFileManagement"></a>
 <h3 class="h4">Data File Management</h3>
 <p>ZooKeeper stores its data in a data directory and its transaction
       log in a transaction log directory. By default these two directories are
@@ -1320,7 +1326,7 @@
       transaction log files in a separate directory than the data files.
       Throughput increases and latency decreases when transaction logs reside
       on a dedicated log devices.</p>
-<a name="N10421"></a><a name="The+Data+Directory"></a>
+<a name="N1042D"></a><a name="The+Data+Directory"></a>
 <h4>The Data Directory</h4>
 <p>This directory has two files in it:</p>
 <ul>
@@ -1366,14 +1372,14 @@
         idempotent nature of its updates. By replaying the transaction log
         against fuzzy snapshots ZooKeeper gets the state of the system at the
         end of the log.</p>
-<a name="N1045D"></a><a name="The+Log+Directory"></a>
+<a name="N10469"></a><a name="The+Log+Directory"></a>
 <h4>The Log Directory</h4>
 <p>The Log Directory contains the ZooKeeper transaction logs.
         Before any update takes place, ZooKeeper ensures that the transaction
         that represents the update is written to non-volatile storage. A new
         log file is started each time a snapshot is begun. The log file's
         suffix is the first zxid written to that log.</p>
-<a name="N10467"></a><a name="sc_filemanagement"></a>
+<a name="N10473"></a><a name="sc_filemanagement"></a>
 <h4>File Management</h4>
 <p>The format of snapshot and log files does not change between
         standalone ZooKeeper servers and different configurations of
@@ -1393,7 +1399,7 @@
         this document for more details on setting a retention policy
         and maintenance of ZooKeeper storage.
         </p>
-<a name="N1047C"></a><a name="sc_commonProblems"></a>
+<a name="N10488"></a><a name="sc_commonProblems"></a>
 <h3 class="h4">Things to Avoid</h3>
 <p>Here are some common problems you can avoid by configuring
       ZooKeeper correctly:</p>
@@ -1447,7 +1453,7 @@
 </dd>
       
 </dl>
-<a name="N104A0"></a><a name="sc_bestPractices"></a>
+<a name="N104AC"></a><a name="sc_bestPractices"></a>
 <h3 class="h4">Best Practices</h3>
 <p>For best results, take note of the following list of good
       Zookeeper practices:</p>

Modified: hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.pdf
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/docs/zookeeperAdmin.pdf?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
Binary files - no diff available.

Added: hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.html
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.html?rev=803305&view=auto
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.html (added)
+++ hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.html Tue Aug 11 21:26:12 2009
@@ -0,0 +1,272 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta content="Apache Forrest" name="Generator">
+<meta name="Forrest-version" content="0.8">
+<meta name="Forrest-skin-name" content="pelt">
+<title>Introduction to hierarchical quorums</title>
+<link type="text/css" href="skin/basic.css" rel="stylesheet">
+<link media="screen" type="text/css" href="skin/screen.css" rel="stylesheet">
+<link media="print" type="text/css" href="skin/print.css" rel="stylesheet">
+<link type="text/css" href="skin/profile.css" rel="stylesheet">
+<script src="skin/getBlank.js" language="javascript" type="text/javascript"></script><script src="skin/getMenu.js" language="javascript" type="text/javascript"></script><script src="skin/fontsize.js" language="javascript" type="text/javascript"></script>
+<link rel="shortcut icon" href="images/favicon.ico">
+</head>
+<body onload="init()">
+<script type="text/javascript">ndeSetTextSize();</script>
+<div id="top">
+<!--+
+    |breadtrail
+    +-->
+<div class="breadtrail">
+<a href="http://www.apache.org/">Apache</a> &gt; <a href="http://hadoop.apache.org/">Hadoop</a> &gt; <a href="http://hadoop.apache.org/zookeeper/">ZooKeeper</a><script src="skin/breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+</div>
+<!--+
+    |header
+    +-->
+<div class="header">
+<!--+
+    |start group logo
+    +-->
+<div class="grouplogo">
+<a href="http://hadoop.apache.org/"><img class="logoImage" alt="Hadoop" src="images/hadoop-logo.jpg" title="Apache Hadoop"></a>
+</div>
+<!--+
+    |end group logo
+    +-->
+<!--+
+    |start Project Logo
+    +-->
+<div class="projectlogo">
+<a href="http://hadoop.apache.org/zookeeper/"><img class="logoImage" alt="ZooKeeper" src="images/zookeeper_small.gif" title="ZooKeeper: distributed coordination"></a>
+</div>
+<!--+
+    |end Project Logo
+    +-->
+<!--+
+    |start Search
+    +-->
+<div class="searchbox">
+<form action="http://www.google.com/search" method="get" class="roundtopsmall">
+<input value="hadoop.apache.org" name="sitesearch" type="hidden"><input onFocus="getBlank (this, 'Search the site with google');" size="25" name="q" id="query" type="text" value="Search the site with google">&nbsp; 
+                    <input name="Search" value="Search" type="submit">
+</form>
+</div>
+<!--+
+    |end search
+    +-->
+<!--+
+    |start Tabs
+    +-->
+<ul id="tabs">
+<li>
+<a class="unselected" href="http://hadoop.apache.org/zookeeper/">Project</a>
+</li>
+<li>
+<a class="unselected" href="http://wiki.apache.org/hadoop/ZooKeeper">Wiki</a>
+</li>
+<li class="current">
+<a class="selected" href="index.html">ZooKeeper 3.2 Documentation</a>
+</li>
+</ul>
+<!--+
+    |end Tabs
+    +-->
+</div>
+</div>
+<div id="main">
+<div id="publishedStrip">
+<!--+
+    |start Subtabs
+    +-->
+<div id="level2tabs"></div>
+<!--+
+    |end Endtabs
+    +-->
+<script type="text/javascript"><!--
+document.write("Last Published: " + document.lastModified);
+//  --></script>
+</div>
+<!--+
+    |breadtrail
+    +-->
+<div class="breadtrail">
+
+             &nbsp;
+           </div>
+<!--+
+    |start Menu, mainarea
+    +-->
+<!--+
+    |start Menu
+    +-->
+<div id="menu">
+<div onclick="SwitchMenu('menu_1.1', 'skin/')" id="menu_1.1Title" class="menutitle">Overview</div>
+<div id="menu_1.1" class="menuitemgroup">
+<div class="menuitem">
+<a href="index.html">Welcome</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperOver.html">Overview</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperStarted.html">Getting Started</a>
+</div>
+<div class="menuitem">
+<a href="releasenotes.html">Release Notes</a>
+</div>
+</div>
+<div onclick="SwitchMenu('menu_1.2', 'skin/')" id="menu_1.2Title" class="menutitle">Developer</div>
+<div id="menu_1.2" class="menuitemgroup">
+<div class="menuitem">
+<a href="api/index.html">API Docs</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperProgrammers.html">Programmer's Guide</a>
+</div>
+<div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrier and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="recipes.html">Recipes</a>
+</div>
+</div>
+<div onclick="SwitchMenu('menu_1.3', 'skin/')" id="menu_1.3Title" class="menutitle">BookKeeper</div>
+<div id="menu_1.3" class="menuitemgroup">
+<div class="menuitem">
+<a href="bookkeeperStarted.html">Getting started</a>
+</div>
+<div class="menuitem">
+<a href="bookkeeperOverview.html">Overview</a>
+</div>
+<div class="menuitem">
+<a href="bookkeeperConfig.html">Setup guide</a>
+</div>
+<div class="menuitem">
+<a href="bookkeeperProgrammer.html">Programmer's guide</a>
+</div>
+</div>
+<div onclick="SwitchMenu('menu_1.4', 'skin/')" id="menu_1.4Title" class="menutitle">Admin &amp; Ops</div>
+<div id="menu_1.4" class="menuitemgroup">
+<div class="menuitem">
+<a href="zookeeperAdmin.html">Administrator's Guide</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperQuotas.html">Quota Guide</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperJMX.html">JMX</a>
+</div>
+</div>
+<div onclick="SwitchMenu('menu_1.5', 'skin/')" id="menu_1.5Title" class="menutitle">Contributor</div>
+<div id="menu_1.5" class="menuitemgroup">
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+</div>
+<div onclick="SwitchMenu('menu_1.6', 'skin/')" id="menu_1.6Title" class="menutitle">Miscellaneous</div>
+<div id="menu_1.6" class="menuitemgroup">
+<div class="menuitem">
+<a href="http://wiki.apache.org/hadoop/ZooKeeper">Wiki</a>
+</div>
+<div class="menuitem">
+<a href="http://wiki.apache.org/hadoop/ZooKeeper/FAQ">FAQ</a>
+</div>
+<div class="menuitem">
+<a href="http://hadoop.apache.org/zookeeper/mailing_lists.html">Mailing Lists</a>
+</div>
+</div>
+<div id="credit"></div>
+<div id="roundbottom">
+<img style="display: none" class="corner" height="15" width="15" alt="" src="skin/images/rc-b-l-15-1body-2menu-3menu.png"></div>
+<!--+
+  |alternative credits
+  +-->
+<div id="credit2"></div>
+</div>
+<!--+
+    |end Menu
+    +-->
+<!--+
+    |start content
+    +-->
+<div id="content">
+<div title="Portable Document Format" class="pdflink">
+<a class="dida" href="zookeeperHierarchicalQuorums.pdf"><img alt="PDF -icon" src="skin/images/pdfdoc.gif" class="skin"><br>
+        PDF</a>
+</div>
+<h1>Introduction to hierarchical quorums</h1>
+  
+
+  
+
+    
+<p>
+    This document gives an example of how to use hierarchical quorums. The basic idea is
+    very simple. First, we split servers into groups, and add a line for each group listing
+    the servers that form this group. Next we have to assign a weight to each server.  
+    </p>
+    
+    
+<p>
+    The following example shows how to configure a system with three groups of three servers
+    each, and we assign a weight of 1 to each server:
+    </p>
+    
+    
+<pre class="code">
+    group.1=1:2:3
+    group.2=4:5:6
+    group.3=7:8:9
+   
+    weight.1=1
+    weight.2=1
+    weight.3=1
+    weight.4=1
+    weight.5=1
+    weight.6=1
+    weight.7=1
+    weight.8=1
+    weight.9=1
+ 	</pre>
+
+	
+<p>    
+    When running the system, we are able to form a quorum once we have a majority of votes from
+    a majority of non-zero-weight groups. Groups that have zero weight are discarded and not
+    considered when forming quorums. Looking at the example, we are able to form a quorum once
+    we have votes from at least two servers from each of two different groups.
+    </p> 
+ 
+<p align="right">
+<font size="-2"></font>
+</p>
+</div>
+<!--+
+    |end content
+    +-->
+<div class="clearboth">&nbsp;</div>
+</div>
+<div id="footer">
+<!--+
+    |start bottomstrip
+    +-->
+<div class="lastmodified">
+<script type="text/javascript"><!--
+document.write("Last Published: " + document.lastModified);
+//  --></script>
+</div>
+<div class="copyright">
+        Copyright &copy;
+         2008 <a href="http://www.apache.org/licenses/">The Apache Software Foundation.</a>
+</div>
+<!--+
+    |end bottomstrip
+    +-->
+</div>
+</body>
+</html>

Added: hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.pdf
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.pdf?rev=803305&view=auto
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.pdf (added)
+++ hadoop/zookeeper/branches/branch-3.2/docs/zookeeperHierarchicalQuorums.pdf Tue Aug 11 21:26:12 2009
@@ -0,0 +1,94 @@
+%PDF-1.3
+%ª«¬­
+4 0 obj
+<< /Type /Info
+/Producer (FOP 0.20.5) >>
+endobj
+5 0 obj
+<< /Length 1156 /Filter [ /ASCII85Decode /FlateDecode ]
+ >>
+stream
+Gatm;d>jt['Re;/pi0?gEG]2>7%/mKeQK;[.^b8cLUI^%R,F:gX::AarVDr_iL2Kr[]8m0Y&j+*3PI]/q/Fu7ob\jl0gUS07u"3V8'l6G&TJnMZ=,<C"@l%@%O^o'h03^KFP.J$dd9,<cU@%0GF`'3CF)\mMHUa?Z]'@u[HUK\*VojY^;$Pi`iNLH3/MSe9rX^jDWhp7(4pUY\]@88TiQ?X(D":9Q+H0TZL*s?UO&4+OLNE>r1'D)NEc[0[63(;Z32E"n[Z-eNA^$AFCL5rO[BRaHHN?>Q;Ei%#8())ZS]!*^&SbcC_jgdJHX'eW/U-#0C]4A[c^*\ENCuL#KWiI8G-Y<J%"g>H6ihh(bC`-C-fj3)k_F^e>qimHaZl?&Z?1.].Gl_#G[[1EccH\H.bu46E'<04j`Rdq7-m6<p.da>R\0NlIZ;P\4CbD]C9UM%O3hNU;jMJVb="9\i,P^G^@''BBtEl&Deu&6FW4@p-o7CfGE:6T]/C_2:U,H\IoY<KL]b\I:GcmRc%_R4c$LGK5d1V`Ep>[d=8l!qe<1i*d40GD^J_N(_J<4,hVT<g^$7/Lphg2q'4UQ'V.Oe,"DL!i1;u*bE.kMC%p*E_r/lZU;SuT8dEQ%$,qM8UGcTkdg*Hsqe2he"HP!,'+`A0pcdO^@5rIk90@Ik+SP%`$c<k"/=k^ob/7u2=D-cdq,k(Z,n.hNO,Z'%;9#g_5*g+q;he6=A)f/B?oVA19=D(-K@(DmZ%\/^bZ<NI/M)r:?ZF8,fZamD;1[d'r;9_kE%4Q=[Vr\BorN'gO5)OIVe3g[IEr(pE,:Hj'Xi](BCZKJ9QA5Te4+R6iM6=P3uR[SLi=?YH;m@hfD#""X`!UB8>GY*AhmO2BI"[$*pC'YTA)'[[SM1+Qc^)S.4+>lK,;8!b;+t>9XiP[6Ke!lh)>b4jPn_1Y^9])]Y;VfT_2Y5"OcnaC$J7hF$0[4$g4*;iW!(n;t\qoqIK^V2DVb
 'nHCK;eW%_D`pYB`F+glaWiFi$[@o&P*QVO>YOj7Upsr%CG!=t*8MrF>G&&?+VbB)E>Aj9oNcF3o.#XU&N:MClcS&l__snNB4,`>90ga;7RP#mrnFbK)"7\%Ul7UODO!B^sDp*P')hGh@%J\+cc##`tYF:c-qVSQ%#.F~>
+endstream
+endobj
+6 0 obj
+<< /Type /Page
+/Parent 1 0 R
+/MediaBox [ 0 0 612 792 ]
+/Resources 3 0 R
+/Contents 5 0 R
+>>
+endobj
+7 0 obj
+<< /Type /Font
+/Subtype /Type1
+/Name /F3
+/BaseFont /Helvetica-Bold
+/Encoding /WinAnsiEncoding >>
+endobj
+8 0 obj
+<< /Type /Font
+/Subtype /Type1
+/Name /F5
+/BaseFont /Times-Roman
+/Encoding /WinAnsiEncoding >>
+endobj
+9 0 obj
+<< /Type /Font
+/Subtype /Type1
+/Name /F1
+/BaseFont /Helvetica
+/Encoding /WinAnsiEncoding >>
+endobj
+10 0 obj
+<< /Type /Font
+/Subtype /Type1
+/Name /F9
+/BaseFont /Courier
+/Encoding /WinAnsiEncoding >>
+endobj
+11 0 obj
+<< /Type /Font
+/Subtype /Type1
+/Name /F2
+/BaseFont /Helvetica-Oblique
+/Encoding /WinAnsiEncoding >>
+endobj
+1 0 obj
+<< /Type /Pages
+/Count 1
+/Kids [6 0 R ] >>
+endobj
+2 0 obj
+<< /Type /Catalog
+/Pages 1 0 R
+ >>
+endobj
+3 0 obj
+<< 
+/Font << /F3 7 0 R /F5 8 0 R /F1 9 0 R /F9 10 0 R /F2 11 0 R >> 
+/ProcSet [ /PDF /ImageC /Text ] >> 
+endobj
+xref
+0 12
+0000000000 65535 f 
+0000001975 00000 n 
+0000002033 00000 n 
+0000002083 00000 n 
+0000000015 00000 n 
+0000000071 00000 n 
+0000001319 00000 n 
+0000001425 00000 n 
+0000001537 00000 n 
+0000001646 00000 n 
+0000001753 00000 n 
+0000001859 00000 n 
+trailer
+<<
+/Size 12
+/Root 2 0 R
+/Info 4 0 R
+>>
+startxref
+2203
+%%EOF

Modified: hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/index.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/index.xml?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/index.xml (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/index.xml Tue Aug 11 21:26:12 2009
@@ -63,6 +63,7 @@
       <li><a href="zookeeperAdmin.html">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy ZooKeeper</li>
       <li><a href="zookeeperQuotas.html">Quota Guide</a> - a guide for system administrators on Quotas in ZooKeeper. </li>
       <li><a href="zookeeperJMX.html">JMX</a> - how to enable JMX in ZooKeeper</li>
+      <li><a href="zookeeperHierarchicalQuorums.html">Hierarchical quorums</a></li>
       </ul>
       </li>
       

Modified: hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml Tue Aug 11 21:26:12 2009
@@ -800,6 +800,9 @@
               The left-hand side of the assignment is a colon-separated list of server
               identifiers. Note that groups must be disjoint and the union of all groups
               must be the ZooKeeper ensemble. </para>
+              
+              <para> You will find an example <ulink url="zookeeperHierarchicalQuorums.html">here</ulink>
+              </para>
             </listitem>
           </varlistentry>
 
@@ -816,6 +819,9 @@
               the weight of server is 1. If the configuration defines groups, but not
               weights, then a value of 1 will be assigned to all servers.  
               </para>
+              
+              <para> You will find an example <ulink url="zookeeperHierarchicalQuorums.html">here</ulink>
+              </para>
             </listitem>
           </varlistentry>
         </variablelist>

Added: hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperHierarchicalQuorums.xml
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperHierarchicalQuorums.xml?rev=803305&view=auto
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperHierarchicalQuorums.xml (added)
+++ hadoop/zookeeper/branches/branch-3.2/src/docs/src/documentation/content/xdocs/zookeeperHierarchicalQuorums.xml Tue Aug 11 21:26:12 2009
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2002-2004 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V1.0//EN"
+"http://www.oasis-open.org/docbook/xml/simple/1.0/sdocbook.dtd">
+<article id="zk_HierarchicalQuorums">
+  <title>Introduction to hierarchical quorums</title>
+
+  <articleinfo>
+    <legalnotice>
+      <para>Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License. You may
+      obtain a copy of the License at <ulink
+      url="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</ulink>.</para>
+
+      <para>Unless required by applicable law or agreed to in writing,
+      software distributed under the License is distributed on an "AS IS"
+      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied. See the License for the specific language governing permissions
+      and limitations under the License.</para>
+    </legalnotice>
+
+    <abstract>
+      <para>This document contains information about hierarchical quorums.</para>
+    </abstract>
+  </articleinfo>
+
+    <para>
+    This document gives an example of how to use hierarchical quorums. The basic idea is
+    very simple. First, we split servers into groups, and add a line for each group listing
+    the servers that form this group. Next we have to assign a weight to each server.  
+    </para>
+    
+    <para>
+    The following example shows how to configure a system with three groups of three servers
+    each, and we assign a weight of 1 to each server:
+    </para>
+    
+    <programlisting>
+    group.1=1:2:3
+    group.2=4:5:6
+    group.3=7:8:9
+   
+    weight.1=1
+    weight.2=1
+    weight.3=1
+    weight.4=1
+    weight.5=1
+    weight.6=1
+    weight.7=1
+    weight.8=1
+    weight.9=1
+ 	</programlisting>
+
+	<para>    
+    When running the system, we are able to form a quorum once we have a majority of votes from
+    a majority of non-zero-weight groups. Groups that have zero weight are discarded and not
+    considered when forming quorums. Looking at the example, we are able to form a quorum once
+    we have votes from at least two servers from each of two different groups.
+    </para> 
+ </article>
\ No newline at end of file

Modified: hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/FastLeaderElection.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/FastLeaderElection.java?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/FastLeaderElection.java (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/FastLeaderElection.java Tue Aug 11 21:26:12 2009
@@ -172,20 +172,22 @@
          */
         
         class WorkerReceiver implements Runnable {
-
+            volatile boolean stop;
         	QuorumCnxManager manager;
 
             WorkerReceiver(QuorumCnxManager manager) {
+                this.stop = false;
                 this.manager = manager;
             }
 
             public void run() {
                 
             	Message response;
-            	while (true) {
+            	while (!stop) {
                     // Sleeps on receive
             		try{
-            			response = manager.recvQueue.take();
+            			response = manager.recvQueue.poll(3000, TimeUnit.MILLISECONDS);
+            			if(response == null) continue;
             			
             			// Receive new message
             			LOG.debug("Receive new message.");
@@ -266,6 +268,7 @@
             					e.toString());
             		}
             	}
+                LOG.info("WorkerReceiver is down");
             }
         }
 
@@ -276,23 +279,26 @@
          */
         
         class WorkerSender implements Runnable {
-        	
+        	volatile boolean stop;
             QuorumCnxManager manager;
 
             WorkerSender(QuorumCnxManager manager){ 
+                this.stop = false;
                 this.manager = manager;
             }
             
             public void run() {
-                while (true) {
+                while (!stop) {
                     try {
-                        ToSend m = sendqueue.take();
+                        ToSend m = sendqueue.poll(3000, TimeUnit.MILLISECONDS);
+                        if(m == null) continue;
+                        
                         process(m);
                     } catch (InterruptedException e) {
                         break;
                     }
-
                 }
+                LOG.info("WorkerSender is down");
             }
 
             /**
@@ -326,6 +332,10 @@
             return (sendqueue.isEmpty() || recvqueue.isEmpty());
         }
 
+        
+        WorkerSender ws;
+        WorkerReceiver wr;
+        
         /**
          * Constructor of class Messenger.
          * 
@@ -333,20 +343,33 @@
          */
         Messenger(QuorumCnxManager manager) {
 
-            Thread t = new Thread(new WorkerSender(manager),
+            this.ws = new WorkerSender(manager);
+            
+            Thread t = new Thread(this.ws,
             		"WorkerSender Thread");
             t.setDaemon(true);
             t.start();
 
-            t = new Thread(new WorkerReceiver(manager),
+            this.wr = new WorkerReceiver(manager);
+        
+            t = new Thread(this.wr,
                     				"WorkerReceiver Thread");
             t.setDaemon(true);
             t.start();
         }
+        
+        /**
+         * Stops instances of WorkerSender and WorkerReceiver
+         */
+        void halt(){
+            this.ws.stop = true;
+            this.wr.stop = true;
+        }
 
     }
 
-    QuorumPeer self;
+    QuorumPeer self;    
+    Messenger messenger;
     volatile long logicalclock; /* Election instance */
     long proposedLeader;
     long proposedZxid;
@@ -369,7 +392,8 @@
      * @param manager   Connection manager
      */
     public FastLeaderElection(QuorumPeer self, QuorumCnxManager manager){
-    	this.manager = manager;
+    	this.stop = false;
+        this.manager = manager;
     	starter(self, manager);
     }
     
@@ -390,7 +414,7 @@
 
         sendqueue = new LinkedBlockingQueue<ToSend>();
         recvqueue = new LinkedBlockingQueue<Notification>();
-        new Messenger(manager);
+        this.messenger = new Messenger(manager);
     }
 
     private void leaveInstance() {
@@ -401,9 +425,14 @@
     	return manager;
     }
     
+    volatile boolean stop;
     public void shutdown(){
+        stop = true;
         LOG.debug("Shutting down connection manager");
         manager.halt();
+        LOG.debug("Shutting down messenger");
+        messenger.halt();
+        LOG.debug("FLE is down");
     }
 
     
@@ -434,6 +463,10 @@
      */
     private boolean totalOrderPredicate(long newId, long newZxid, long curId, long curZxid) {
         LOG.debug("id: " + newId + ", proposed id: " + curId + ", zxid: " + newZxid + ", proposed zxid: " + curZxid);
+        if(self.getQuorumVerifier().getWeight(newId) == 0){
+            return false;
+        }
+        
         if ((newZxid > curZxid)
                 || ((newZxid == curZxid) && (newId > curId)))
             return true;
@@ -550,7 +583,8 @@
              * Loop in which we exchange notifications until we find a leader
              */
     
-            while (self.getPeerState() == ServerState.LOOKING) {
+            while ((self.getPeerState() == ServerState.LOOKING) &&
+                    (!stop)){
                 /*
                  * Remove next notification from queue, times out after 2 times
                  * the termination time
@@ -606,14 +640,12 @@
                         }
                     
                         LOG.info("Adding vote");
-                        /*
-                         * Skip zero-weight servers
-                         */
-                        if(self.getQuorumVerifier().getWeight(n.sid) != 0) 
-                            recvset.put(n.sid, new Vote(n.leader, n.zxid, n.epoch));
+
+                        recvset.put(n.sid, new Vote(n.leader, n.zxid, n.epoch));
     
                         //If have received from all nodes, then terminate
-                        if (self.quorumPeers.size() == recvset.size()) {
+                        if ((self.quorumPeers.size() == recvset.size()) &&
+                                (self.getQuorumVerifier().getWeight(proposedLeader) != 0)){
                             self.setPeerState((proposedLeader == self.getId()) ? 
                                     ServerState.LEADING: ServerState.FOLLOWING);
                             leaveInstance();

Modified: hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/QuorumCnxManager.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/QuorumCnxManager.java?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/QuorumCnxManager.java (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/QuorumCnxManager.java Tue Aug 11 21:26:12 2009
@@ -338,7 +338,7 @@
                         e);
             }
         } else {
-            LOG.error("There is a connection for server " + sid);
+            LOG.debug("There is a connection for server " + sid);
         }
     }
     

Modified: hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumHierarchical.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumHierarchical.java?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumHierarchical.java (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/java/main/org/apache/zookeeper/server/quorum/flexible/QuorumHierarchical.java Tue Aug 11 21:26:12 2009
@@ -121,8 +121,8 @@
         this.serverGroup = serverGroup;
         this.groupWeight = new HashMap<Long, Long>();
         
-        computeGroupWeight();
         this.numGroups = numGroups;
+        computeGroupWeight();   
     }
     
     
@@ -219,7 +219,11 @@
          * Do not consider groups with weight zero
          */
         for(long weight: groupWeight.values()){
-            if(weight == 0) numGroups--;
+            LOG.debug("Group weight: " + weight);
+            if(weight == ((long) 0)){
+                numGroups--;
+                LOG.debug("One zero-weight group: " + 1 + ", " + numGroups);
+            }
         }
     }
     
@@ -233,7 +237,7 @@
          * Adds up weights per group
          */
         if(set.size() == 0) return false;
-        else LOG.info("Set size: " + set.size());
+        else LOG.debug("Set size: " + set.size());
         
         for(long sid : set){
             Long gid = serverGroup.get(sid);
@@ -250,17 +254,18 @@
          */
         int majGroupCounter = 0;
         for(long gid : expansion.keySet()) {
-            LOG.info("gid: " + expansion.get(gid));
+            LOG.debug("Group info: " + expansion.get(gid) + ", " + gid + ", " + groupWeight.get(gid));
             if(expansion.get(gid) > (groupWeight.get(gid) / 2) )
                 majGroupCounter++;
         }
         
+        LOG.debug("Majority group counter: " + majGroupCounter + ", " + numGroups); 
         if((majGroupCounter > (numGroups / 2))){
-            LOG.info("Positive set size: " + set.size());
+            LOG.debug("Positive set size: " + set.size());
             return true;
         }
         else {
-            LOG.info("Negative set size: " + set.size());
+            LOG.debug("Negative set size: " + set.size());
             return false;
         }
     }

Modified: hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/FLEZeroWeightTest.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/FLEZeroWeightTest.java?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/FLEZeroWeightTest.java (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/FLEZeroWeightTest.java Tue Aug 11 21:26:12 2009
@@ -105,7 +105,7 @@
     class LEThread extends Thread {
         int i;
         QuorumPeer peer;
-        //int peerRound = 1;
+        boolean fail;
 
         LEThread(QuorumPeer peer, int i) {
             this.i = i;
@@ -116,6 +116,7 @@
         public void run() {
             try {
                 Vote v = null;
+                fail = false;
                 while(true){
 
                     //while(true) {
@@ -137,7 +138,7 @@
                     votes[i] = v;
 
                     if((peer.getPeerState() == ServerState.LEADING) &&
-                            (peer.getId() > 2)) fail("Elected zero-weight server");
+                            (peer.getId() > 2)) fail = true;
                     
                     if((peer.getPeerState() == ServerState.FOLLOWING) ||
                             (peer.getPeerState() == ServerState.LEADING)) break;
@@ -150,10 +151,10 @@
     }
 
     @Test
-    public void testHierarchicalQuorum() throws Exception {
+    public void testZeroWeightQuorum() throws Exception {
         FastLeaderElection le[] = new FastLeaderElection[count];
 
-        LOG.info("TestHierarchicalQuorum: " + getName()+ ", " + count);
+        LOG.info("TestZeroWeightQuorum: " + getName()+ ", " + count);
         for(int i = 0; i < count; i++) {
             peers.put(Long.valueOf(i),
                     new QuorumServer(i,
@@ -177,6 +178,9 @@
             threads.get(i).join(15000);
             if (threads.get(i).isAlive()) {
                 fail("Threads didn't join");
+            } else {
+                if(threads.get(i).fail)
+                    fail("Elected zero-weight server");
             }
         }
     }

Modified: hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java
URL: http://svn.apache.org/viewvc/hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java?rev=803305&r1=803304&r2=803305&view=diff
==============================================================================
--- hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java (original)
+++ hadoop/zookeeper/branches/branch-3.2/src/java/test/org/apache/zookeeper/test/HierarchicalQuorumTest.java Tue Aug 11 21:26:12 2009
@@ -1,5 +1,4 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
+/* Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
  * regarding copyright ownership.  The ASF licenses this file
@@ -17,168 +16,259 @@
  */
 
 package org.apache.zookeeper.test;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.Properties;
-import java.util.Random;
-
-import junit.framework.TestCase;
+import java.util.Set;
 
 import org.apache.log4j.Logger;
+import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.server.quorum.FastLeaderElection;
 import org.apache.zookeeper.server.quorum.QuorumPeer;
-import org.apache.zookeeper.server.quorum.Vote;
 import org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer;
-import org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;
 import org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class HierarchicalQuorumTest extends TestCase {
-    private static final Logger LOG = Logger.getLogger(HierarchicalQuorumTest.class);
-
-    Properties qp;
+/**
+ * Comprehensive test of hierarchical quorums, assuming servers with zero weight.
+ * This test uses ClientTest to verify that the ensemble works after a leader is 
+ * elected.
+ * 
+ * This implementation is based on QuorumBase, the main difference being that it 
+ * uses hierarchical quorums and FLE.
+ */
 
-    int count;
-    int baseport;
-    int baseLEport;
-    HashMap<Long,QuorumServer> peers;
-    ArrayList<LEThread> threads;
-    File tmpdir[];
-    int port[];
-    Object finalObj;
-
-    volatile Vote votes[];
-    volatile boolean leaderDies;
-    volatile long leader = -1;
-    Random rand = new Random();
+public class HierarchicalQuorumTest extends ClientBase {
+    private static final Logger LOG = Logger.getLogger(QuorumBase.class);
 
+    File s1dir, s2dir, s3dir, s4dir, s5dir;
+    QuorumPeer s1, s2, s3, s4, s5;
+    private int port1;
+    private int port2;
+    private int port3;
+    private int port4;
+    private int port5;
+
+    private int leport1;
+    private int leport2;
+    private int leport3;
+    private int leport4;
+    private int leport5;
 
-    @Before
+    Properties qp;
+    private final ClientTest ct = new ClientTest();
+    
     @Override
     protected void setUp() throws Exception {
-        count = 9;
-        baseport= 33003;
-        baseLEport = 43003;
-
-        peers = new HashMap<Long,QuorumServer>(count);
-        threads = new ArrayList<LEThread>(count);
-        votes = new Vote[count];
-        tmpdir = new File[count];
-        port = new int[count];
-        finalObj = new Object();
-
-        String config = "group.1=0:1:2\n" +
-        "group.2=3:4:5\n" +
-        "group.3=6:7:8\n\n" +
-        "weight.0=1\n" +
+        LOG.info("STARTING " + getName());
+        int baseport = 12333;
+        int baseLEport = 14333;
+        
+        setupTestEnv();
+
+        JMXEnv.setUp();
+
+        //setUpAll();
+
+        port1 = baseport;
+        port2 = baseport + 1;
+        port3 = baseport + 2;
+        port4 = baseport + 3;
+        port5 = baseport + 4;
+        leport1 = baseLEport;
+        leport2 = baseLEport + 1;
+        leport3 = baseLEport + 2;
+        leport4 = baseLEport + 3;
+        leport5 = baseLEport + 4;
+
+        hostPort = "127.0.0.1:" + port1 
+            + ",127.0.0.1:" + port2 
+            + ",127.0.0.1:" + port3 
+            + ",127.0.0.1:" + port4 
+            + ",127.0.0.1:" + port5;
+        LOG.info("Ports are: " + hostPort);
+
+        s1dir = ClientBase.createTmpDir();
+        s2dir = ClientBase.createTmpDir();
+        s3dir = ClientBase.createTmpDir();
+        s4dir = ClientBase.createTmpDir();
+        s5dir = ClientBase.createTmpDir();
+
+        String config = "group.1=1:2:3\n" +
+        "group.2=4:5\n" +
         "weight.1=1\n" +
         "weight.2=1\n" +
         "weight.3=1\n" +
-        "weight.4=1\n" +
-        "weight.5=1\n" +
-        "weight.6=1\n" +
-        "weight.7=1\n" +
-        "weight.8=1";
+        "weight.4=0\n" +
+        "weight.5=0\n";
 
         ByteArrayInputStream is = new ByteArrayInputStream(config.getBytes());
         this.qp = new Properties();
+        
         qp.load(is);
+        startServers();
+
+        ct.hostPort = hostPort;
+        //ct.setUpAll();
+        
+        LOG.info("Setup finished");
+    }
+    
+    
+    void startServers() throws Exception {
+        int tickTime = 2000;
+        int initLimit = 3;
+        int syncLimit = 3;
+        HashMap<Long,QuorumServer> peers = new HashMap<Long,QuorumServer>();
+        peers.put(Long.valueOf(1), new QuorumServer(1, 
+                new InetSocketAddress("127.0.0.1", port1 + 1000),
+                new InetSocketAddress("127.0.0.1", leport1 + 1000)));
+        peers.put(Long.valueOf(2), new QuorumServer(2, 
+                new InetSocketAddress("127.0.0.1", port2 + 1000),
+                new InetSocketAddress("127.0.0.1", leport2 + 1000)));
+        peers.put(Long.valueOf(3), new QuorumServer(3, 
+                new InetSocketAddress("127.0.0.1", port3 + 1000),
+                new InetSocketAddress("127.0.0.1", leport3 + 1000)));
+        peers.put(Long.valueOf(4), new QuorumServer(4,
+                new InetSocketAddress("127.0.0.1", port4 + 1000),
+                new InetSocketAddress("127.0.0.1", leport4 + 1000)));
+        peers.put(Long.valueOf(5), new QuorumServer(5,
+                new InetSocketAddress("127.0.0.1", port5 + 1000),
+                new InetSocketAddress("127.0.0.1", leport5 + 1000)));
+
+        LOG.info("creating QuorumPeer 1 port " + port1);
+        QuorumHierarchical hq1 = new QuorumHierarchical(qp); 
+        s1 = new QuorumPeer(peers, s1dir, s1dir, port1, 3, 1, tickTime, initLimit, syncLimit, hq1);
+        assertEquals(port1, s1.getClientPort());
+        
+        LOG.info("creating QuorumPeer 2 port " + port2);
+        QuorumHierarchical hq2 = new QuorumHierarchical(qp); 
+        s2 = new QuorumPeer(peers, s2dir, s2dir, port2, 3, 2, tickTime, initLimit, syncLimit, hq2);
+        assertEquals(port2, s2.getClientPort());
+        
+        LOG.info("creating QuorumPeer 3 port " + port3);
+        QuorumHierarchical hq3 = new QuorumHierarchical(qp); 
+        s3 = new QuorumPeer(peers, s3dir, s3dir, port3, 3, 3, tickTime, initLimit, syncLimit, hq3);
+        assertEquals(port3, s3.getClientPort());
+        
+        LOG.info("creating QuorumPeer 4 port " + port4);
+        QuorumHierarchical hq4 = new QuorumHierarchical(qp); 
+        s4 = new QuorumPeer(peers, s4dir, s4dir, port4, 3, 4, tickTime, initLimit, syncLimit, hq4);
+        assertEquals(port4, s4.getClientPort());
+        
+        LOG.info("creating QuorumPeer 5 port " + port5);
+        QuorumHierarchical hq5 = new QuorumHierarchical(qp); 
+        s5 = new QuorumPeer(peers, s5dir, s5dir, port5, 3, 5, tickTime, initLimit, syncLimit, hq5);
+        assertEquals(port5, s5.getClientPort());
+        LOG.info("start QuorumPeer 1");
+        s1.start();
+        LOG.info("start QuorumPeer 2");
+        s2.start();
+        LOG.info("start QuorumPeer 3");
+        s3.start();
+        LOG.info("start QuorumPeer 4");
+        s4.start();
+        LOG.info("start QuorumPeer 5");
+        s5.start();
+        LOG.info("started QuorumPeer 5");
+
+        LOG.info ("Closing ports " + hostPort);
+        for (String hp : hostPort.split(",")) {
+            assertTrue("waiting for server up",
+                       ClientBase.waitForServerUp(hp,
+                                    CONNECTION_TIMEOUT));
+            LOG.info(hp + " is accepting client connections");
+        }
 
-        LOG.info("SetUp " + getName());
+        // interesting to see what's there...
+        JMXEnv.dump();
+        // make sure we have these 5 servers listed
+        Set<String> ensureNames = new LinkedHashSet<String>();
+        for (int i = 1; i <= 5; i++) {
+            ensureNames.add("InMemoryDataTree");
+        }
+        for (int i = 1; i <= 5; i++) {
+            ensureNames.add("name0=ReplicatedServer_id" + i
+                 + ",name1=replica." + i + ",name2=");
+        }
+        for (int i = 1; i <= 5; i++) {
+            for (int j = 1; j <= 5; j++) {
+                ensureNames.add("name0=ReplicatedServer_id" + i
+                     + ",name1=replica." + j);
+            }
+        }
+        for (int i = 1; i <= 5; i++) {
+            ensureNames.add("name0=ReplicatedServer_id" + i);
+        }
+        JMXEnv.ensureAll(ensureNames.toArray(new String[ensureNames.size()]));
     }
 
+    @After
+    @Override
     protected void tearDown() throws Exception {
-        for(int i = 0; i < threads.size(); i++) {
-            threads.get(i).peer.shutdown();
-            ((FastLeaderElection) threads.get(i).peer.getElectionAlg()).shutdown();
+        LOG.info("TearDown started");
+        //ct.tearDownAll();
+
+        LOG.info("Shutting down server 1");
+        shutdown(s1);
+        LOG.info("Shutting down server 2");
+        shutdown(s2);
+        LOG.info("Shutting down server 3");
+        shutdown(s3);
+        LOG.info("Shutting down server 4");
+        shutdown(s4);
+        LOG.info("Shutting down server 5");
+        shutdown(s5);
+        
+        for (String hp : hostPort.split(",")) {
+            assertTrue("waiting for server down",
+                       ClientBase.waitForServerDown(hp,
+                                           ClientBase.CONNECTION_TIMEOUT));
+            LOG.info(hp + " is no longer accepting client connections");
         }
+
+        JMXEnv.tearDown();
+
         LOG.info("FINISHED " + getName());
     }
 
-    class LEThread extends Thread {
-        int i;
-        QuorumPeer peer;
-        //int peerRound = 1;
-
-        LEThread(QuorumPeer peer, int i) {
-            this.i = i;
-            this.peer = peer;
-            LOG.info("Constructor: " + getName());
-        }
-
-        public void run() {
-            try {
-                Vote v = null;
-                while(true){
-
-                    //while(true) {
-                    peer.setPeerState(ServerState.LOOKING);
-                    LOG.info("Going to call leader election.");
-                    v = peer.getElectionAlg().lookForLeader();
-                    if(v == null){
-                        LOG.info("Thread " + i + " got a null vote");
-                        return;
-                    }
-
-                    /*
-                     * A real zookeeper would take care of setting the current vote. Here
-                     * we do it manually.
-                     */
-                    peer.setCurrentVote(v);
-
-                    LOG.info("Finished election: " + i + ", " + v.id);
-                    votes[i] = v;
-
-                    if((peer.getPeerState() == ServerState.FOLLOWING) ||
-                            (peer.getPeerState() == ServerState.LEADING)) break;
-                }
-                LOG.debug("Thread " + i + " votes " + v);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
+    protected void shutdown(QuorumPeer qp) {
+        try {
+            ((FastLeaderElection) qp.getElectionAlg()).shutdown();
+            LOG.info("Done with leader election");
+            qp.shutdown();
+            LOG.info("Done with quorum peer");
+            qp.join(30000);
+            if (qp.isAlive()) {
+                fail("QP failed to shutdown in 30 seconds");
             }
+        } catch (InterruptedException e) {
+            LOG.debug("QP interrupted", e);
         }
     }
 
-    @Test
-    public void testHierarchicalQuorum() throws Exception {
-        runTest(0);
+    protected ZooKeeper createClient()
+        throws IOException, InterruptedException
+    {
+        return createClient(hostPort);
     }
-    
-    @Test
-    public void testHierarchicalQuorumPartial() throws Exception {
-        runTest(3);
+
+    protected ZooKeeper createClient(String hp)
+        throws IOException, InterruptedException
+    {
+        CountdownWatcher watcher = new CountdownWatcher();
+        return createClient(watcher, hp);
     }
-    
-    private void runTest(int delta) throws Exception {
-        FastLeaderElection le[] = new FastLeaderElection[count];
 
-        LOG.info("TestHierarchicalQuorum: " + getName()+ ", " + count);
-        for(int i = 0; i < count; i++) {
-            peers.put(Long.valueOf(i), new QuorumServer(i, new InetSocketAddress(baseport+i),
-                    new InetSocketAddress(baseLEport+i)));
-            tmpdir[i] = ClientBase.createTmpDir();
-            port[i] = baseport+i;
-        }
-
-        for(int i = 0; i < (le.length - delta); i++) {
-            QuorumHierarchical hq = new QuorumHierarchical(qp);
-            QuorumPeer peer = new QuorumPeer(peers, tmpdir[i], tmpdir[i], port[i], 3, i, 2, 2, 2, hq);
-            peer.startLeaderElection();
-            LEThread thread = new LEThread(peer, i);
-            thread.start();
-            threads.add(thread);
-        }
-        LOG.info("Started threads " + getName());
-
-        for(int i = 0; i < threads.size(); i++) {
-            threads.get(i).join(15000);
-            if (threads.get(i).isAlive()) {
-                fail("Threads didn't join");
-            }
-        }
+    @Test
+    public void testHierarchicalQuorum() throws Throwable {
+        ct.testHammerBasic();
     }
 }
\ No newline at end of file