Просмотр исходного кода

Some Source Forge Documents did not get moved over: javaExample, zookeeperTutorial, zookeeperInternals

git-svn-id: https://svn.apache.org/repos/asf/hadoop/zookeeper/trunk@703480 13f79535-47bb-0310-9956-ffa450edef68
Patrick D. Hunt 16 лет назад
Родитель
Сommit
03f0f816dc

+ 3 - 0
CHANGES.txt

@@ -20,6 +20,9 @@ Backward compatibile changes:
 
 
   BUGFIXES: 
   BUGFIXES: 
 
 
+  ZOOKEEPER-181. Some Source Forge Documents did not get moved over: 
+  javaExample, zookeeperTutorial, zookeeperInternals (robbie via phunt)
+
   ZOOKEEPER-180. Placeholder sections needed in document for new topics that
   ZOOKEEPER-180. Placeholder sections needed in document for new topics that
   the umbrella jira discusses (robbie via phunt)
   the umbrella jira discusses (robbie via phunt)
 
 

BIN
docs/images/2pc.png


+ 18 - 0
docs/index.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
@@ -189,6 +198,15 @@ The following documents provide concepts and procedures to get you started using
 <li>
 <li>
 <a href="zookeeperAdmin.html">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy Zookeeer</li>
 <a href="zookeeperAdmin.html">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy Zookeeer</li>
       
       
+<li>
+<a href="javaExample.html">ZooKeeper Java Example</a> - A simple Zookeeer Client, written in Java</li>
+      
+<li>
+<a href="zookeeperTutorial.html">Barrier and Queue Tutorial</a> - Simple Implementations of Barriers and Queues</li>
+      
+<li>
+<a href="zookeeperInternals.html">ZooKeeper Internals</a> - Assorted Topics on the Inner Workings of ZooKeeper</li>
+      
 <li>
 <li>
 <a href="api/index.html">API Docs</a> - the technical reference to ZooKeeper APIs</li>
 <a href="api/index.html">API Docs</a> - the technical reference to ZooKeeper APIs</li>
       
       

Разница между файлами не показана из-за своего большого размера
+ 1 - 2
docs/index.pdf


+ 880 - 0
docs/javaExample.html

@@ -0,0 +1,880 @@
+<!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>ZooKeeper Java Example</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="The Hadoop database"></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 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_selected_1.1', 'skin/')" id="menu_selected_1.1Title" class="menutitle" style="background-image: url('skin/images/chapter_open.gif');">Documentation</div>
+<div id="menu_selected_1.1" class="selectedmenuitemgroup" style="display: block;">
+<div class="menuitem">
+<a href="index.html">Welcome</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperOver.html">Zookeeper Overview</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperStarted.html">Getting Started</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperProgrammers.html">Programmer's Guide</a>
+</div>
+<div class="menuitem">
+<a href="recipes.html">Recipes</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperAdmin.html">Administrator's Guide</a>
+</div>
+<div class="menupage">
+<div class="menupagetitle">Java Example</div>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
+<a href="api/index.html">API Docs</a>
+</div>
+<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 class="menuitem">
+<a href="zookeeperOtherInfo.html">Other Info</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="javaExample.pdf"><img alt="PDF -icon" src="skin/images/pdfdoc.gif" class="skin"><br>
+        PDF</a>
+</div>
+<h1>ZooKeeper Java Example</h1>
+<div id="minitoc-area">
+<ul class="minitoc">
+<li>
+<a href="#ch_Introduction">A Simple Watch Client</a>
+<ul class="minitoc">
+<li>
+<a href="#sc_requirements">Requirements</a>
+</li>
+<li>
+<a href="#sc_design">Program Design</a>
+</li>
+</ul>
+</li>
+<li>
+<a href="#sc_executor">The Executor Class</a>
+</li>
+<li>
+<a href="#sc_DataMonitor">The DataMonitor Class</a>
+</li>
+<li>
+<a href="#sc_completeSourceCode">Complete Source Listings</a>
+</li>
+</ul>
+</div>
+  
+
+  
+
+  
+<a name="N10009"></a><a name="ch_Introduction"></a>
+<h2 class="h3">A Simple Watch Client</h2>
+<div class="section">
+<p>To introduce you to the ZooKeeper Java API, we develop here a very simple 
+    watch client. This ZooKeeper client watches a ZooKeeper node for changes 
+    and responds to by starting or stopping a program.</p>
+<a name="N10012"></a><a name="sc_requirements"></a>
+<h3 class="h4">Requirements</h3>
+<p>The client has four requirements:</p>
+<ul>
+<li>
+<p>It takes as parameters:</p>
+    	
+<ul>
+		
+<li>
+<p>the address of the ZooKeeper service</p>
+</li>
+		
+<li> 
+<p> a znode, by name</p>
+</li>
+		
+<li>
+<p> an executable with arguments.</p>
+</li>
+</ul>
+</li>
+	
+<li>
+<p>It fetches the data associated with the znode and starts the executable.</p>
+</li>
+	
+<li>
+<p>If the znode changes, the client refetches the contents and restarts the executable.</p>
+</li>
+	
+<li>
+<p>If the znode disappears, the client kills the executable.</p>
+</li>
+</ul>
+<a name="N1003B"></a><a name="sc_design"></a>
+<h3 class="h4">Program Design</h3>
+<p>Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection, 
+   and the other which monitors data.  In this application, the class called the <strong>Executor</strong> 
+   maintains the ZooKeeper connection, and the class called the  <strong>DataMonitor</strong> monitors the data
+   in the ZooKeeper tree. Also, Executor contains the main thread and contains the execution logic.
+   It is responsible for what little user interaction there is, as well as interaction with the exectuable program you
+   pass in as an argument and which the sample (per the requirements) shuts down and restarts, according to the 
+   state of the znode.</p>
+</div>
+
+   
+<a name="N1004C"></a><a name="sc_executor"></a>
+<h2 class="h3">The Executor Class</h2>
+<div class="section">
+<p>The Executor object is the primary container of the sample application. It contains 
+    both the <strong>ZooKeeper</strong> object, <strong>DataMonitor</strong>, as described above in 
+    <a href="#sc_design">Program Design</a>.  </p>
+<pre class="code">
+// from the Executor class...
+    
+public static void main(String[] args) {
+    if (args.length &lt; 4) {
+        System.err
+                .println("USAGE: Executor hostPort znode filename program [args ...]");
+        System.exit(2);
+    }
+    String hostPort = args[0];
+    String znode = args[1];
+    String filename = args[2];
+    String exec[] = new String[args.length - 3];
+    System.arraycopy(args, 3, exec, 0, exec.length);
+    try {
+        Executor theExectutor = new Executor(hostPort, znode, filename, exec);
+	theExectutor.run();
+    } catch (Exception e) {
+        e.printStackTrace();
+    }
+}
+    
+public Executor(String hostPort, String znode, String filename,
+    String exec[]) throws KeeperException, IOException {
+    this.filename = filename;
+    this.exec = exec;
+    
+    //create a new zookeeper object, passing a self-reference in a the Watcher
+    zk = new ZooKeeper(hostPort, 3000, this);
+    dm = new DataMonitor(zk, znode, null, this);
+}
+   
+public void run() {
+    try {
+        synchronized (this) {
+            while (!dm.dead) {
+                wait();
+            }
+        }
+    } catch (InterruptedException e) {    
+    }
+}
+</pre>
+<p>
+    Recall that the Executor's job is to starts and stop the executable whose name you pass in on the command line. 
+    It does this in response to events fired by the ZooKeeper object. As you can see in the code above, the Executor passes
+    a reference to itself as the Watcher argument in the ZooKeeper constructor. It also passes a reference to itself
+    as DataMonitorListener argument to the DataMonitor constructor. Per the Executor's definition, it implements both these
+    interfaces:
+    </p>
+<pre class="code">
+public class Executor implements Watcher, Runnable, DataMonitorListener {
+...
+    </pre>
+<p>The <strong>Watcher</strong> interface is defined by the ZooKeeper Java API.
+    ZooKeeper uses it to communicate back to its container. It supports only one method, <span class="codefrag command">process()</span>, and ZooKeeper uses 
+    it to communciates generic events that the main thread would be intersted in, such as the state of the ZooKeeper connection or the ZooKeeper session.The Executor 
+    in this example simply forwards those events down to the DataMonitor to decide what to do with them. It does this simply to illustrate
+    the point that, by convention, the Executor or some Executor-like object "owns" the ZooKeeper connection, but it is free to delegate the events to other
+    events to other objects. It also uses this as the default channel on which to fire watch events. (More on this later.)</p>
+<pre class="code">
+public void process(WatcherEvent event) {
+    dm.process(event);
+}
+</pre>
+<p>The <strong>DataMonitorListener</strong> 
+    interface, on the other hand, is not part of the the ZooKeeper API. It is a completely custom interface, 
+    designed for this sample application. The DataMonitor object uses it to communicate back to its container, which
+    is also the the Executor object.The DataMonitorListener interface looks like this:</p>
+<pre class="code">
+public interface DataMonitorListener {
+    /**
+    * The existence status of the node has changed.
+    */
+    void exists(byte data[]);
+
+    /**
+    * The ZooKeeper session is no longer valid.
+    * 
+    * @param rc
+    * the ZooKeeper reason code
+    */
+    void closing(int rc);
+}
+</pre>
+<p>This interface is defined in the DataMonitor class and implemented in the Executor class. 
+    When <span class="codefrag command">Executor.exists()</span> is invoked,
+    the Executor decides whether to start up or shut down per the requirements. Recall that the requires say to kill the executable when the 
+    znode ceases to <em>exist</em>. </p>
+<p>When <span class="codefrag command">Executor.closing()</span>
+    is invoked, the Executor decides whether or not to shut itself down in response to the ZooKeeper connection permanently disappearing.</p>
+<p>As you might have guessed, DataMonitor is the object that invokes 
+    these methods, in response to changes in ZooKeeper's state.</p>
+<p>Here are Executor's implementation of 
+    <span class="codefrag command">DataMonitorListener.exists()</span> and <span class="codefrag command">DataMonitorListener.closing</span>:
+    </p>
+<pre class="code">
+public void exists( byte[] data ) {
+    if (data == null) {
+        if (child != null) {
+            System.out.println("Killing process");
+            child.destroy();
+            try {
+                child.waitFor();
+            } catch (InterruptedException e) {
+            }
+        }
+        child = null;
+    } else {
+        if (child != null) {
+            System.out.println("Stopping child");
+            child.destroy();
+            try {
+               child.waitFor();
+            } catch (InterruptedException e) {
+            e.printStackTrace();
+            }
+        }
+        try {
+            FileOutputStream fos = new FileOutputStream(filename);
+            fos.write(data);
+            fos.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        try {
+            System.out.println("Starting child");
+            child = Runtime.getRuntime().exec(exec);
+            new StreamWriter(child.getInputStream(), System.out);
+            new StreamWriter(child.getErrorStream(), System.err);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
+
+public void closing(int rc) {
+    synchronized (this) {
+        notifyAll();
+    }
+}
+</pre>
+</div>
+
+<a name="N100A0"></a><a name="sc_DataMonitor"></a>
+<h2 class="h3">The DataMonitor Class</h2>
+<div class="section">
+<p>
+The DataMonitor class has the meat of the ZooKeeper logic. It is mostly 
+asynchronous and event driven. DataMonitor kicks things off in the constructor with:</p>
+<pre class="code">
+public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
+        DataMonitorListener listener) {
+    this.zk = zk;
+    this.znode = znode;
+    this.chainedWatcher = chainedWatcher;
+    this.listener = listener;
+    
+    // Get things started by checking if the node exists. We are going
+    // to be completely event driven
+    <strong>zk.exists(znode, true, this, null);</strong>
+}
+</pre>
+<p>The call to <span class="codefrag command">ZooKeeper.exists()</span> checks for the existence of the znode, 
+sets a watch, and passes a reference to itself (<span class="codefrag command">this</span>)
+as the completion callback object. In this sense, it kicks things off, since the
+real processing happens when the watch is triggered.</p>
+<div class="note">
+<div class="label">Note</div>
+<div class="content">
+
+<p>Don't confuse the completion callback with the watch callback. The <span class="codefrag command">ZooKeeper.exists()</span> 
+completion callback, which happens to be the method <span class="codefrag command">StatCallback.processResult()</span> implemented 
+in the DataMonitor object, is invoked when the asynchronous <em>setting of the watch</em> operation 
+(by <span class="codefrag command">ZooKeeper.exists()</span>) completes on the server. </p>
+
+<p>
+The triggering of the watch, on the other hand, sends an event to the <em>Executor</em> object, since
+the Executor registered as the Watcher of the ZooKeeper object.</p>
+
+
+<p>As an aside, you might note that the DataMonitor could also register itself as the Watcher
+for this particular watch event. This is new to ZooKeeper 3.0.0 (the support of multiple Watchers). In this
+example, however, DataMonitor does not register as the Watcher.</p>
+
+</div>
+</div>
+<p>When the <span class="codefrag command">ZooKeeper.exists()</span> operation completes on the server, the ZooKeeper API invokes this completion callback on 
+the client:</p>
+<pre class="code">
+public void processResult(int rc, String path, Object ctx, Stat stat) {
+    boolean exists;
+    switch (rc) {
+    case Code.Ok:
+        exists = true;
+        break;
+    case Code.NoNode:
+        exists = false;
+        break;
+    case Code.SessionExpired:
+    case Code.NoAuth:
+        dead = true;
+        listener.closing(rc);
+        return;
+    default:
+        // Retry errors
+        zk.exists(znode, true, this, null);
+        return;
+    }
+ 
+    byte b[] = null;
+    if (exists) {
+        try {
+            <strong>b = zk.getData(znode, false, null);</strong>
+        } catch (KeeperException e) {
+            // We don't need to worry about recovering now. The watch
+            // callbacks will kick off any exception handling
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            return;
+        }
+    }     
+    if ((b == null &amp;&amp; b != prevData)
+            || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {
+        <strong>listener.exists(b);</strong>
+        prevData = b;
+    }
+}
+</pre>
+<p>
+The code first checks the error codes for znode existence, fatal errors, and 
+recoverable errors. If the file (or znode) exists, it gets the data from the znode, and 
+then invoke the exists() callback of Executor if the state has changed. Note, 
+it doesn't have to do any Exception processing for the getData call because it 
+has watches pending for anything that could cause an error: if the node is deleted 
+before it calls <span class="codefrag command">ZooKeeper.getData()</span>, the watch event set by 
+the <span class="codefrag command">ZooKeeper.exists()</span> triggers a callback; 
+if there is a communication error, a connection watch event fires when 
+the connection comes back up.
+</p>
+<p>Finally, notice how DataMonitor processes watch events: </p>
+<pre class="code">
+public void process(WatcherEvent event) {
+    String path = event.getPath();
+    if (event.getType() == Watcher.Event.EventNone) {
+        // We are are being told that the state of the
+        // connection has changed
+        switch (event.getState()) {
+        case Event.KeeperStateSyncConnected:
+            // Everything is happy. Lets kick things off
+            // again by checking the existence of the znode
+            zk.exists(znode, true, this, null);
+            break;
+        case Event.KeeperStateExpired:
+            // It's all over
+            dead = true;
+            listener.closing(KeeperException.Code.SessionExpired);
+            break;
+        }
+    } else {
+        if (path != null &amp;&amp; path.equals(znode)) {
+            // Something has changed on the node, let's find out
+            zk.exists(znode, true, this, null);
+        }
+   }
+   if (chainedWatcher != null) {
+        chainedWatcher.process(event);
+   }
+}
+</pre>
+<p>
+If the client-side ZooKeeper libraries can reestablish the communication channel to ZooKeeper, DataMonitor simply kicks
+everything off again with the call to <span class="codefrag command">ZooKeeper.exists()</span>. 
+If it gets an event for a znode, it calls <span class="codefrag command">ZooKeeper.exists()</span> to find out what has changed.
+</p>
+</div>
+
+
+<a name="N10104"></a><a name="sc_completeSourceCode"></a>
+<h2 class="h3">Complete Source Listings</h2>
+<div class="section">
+<div class="note example">
+<div class="label">Executor.java</div>
+<div class="content">
+<title>Executor.java</title>
+<pre class="code">
+/**
+ * A simple example program to use DataMonitor to start and
+ * stop executables based on a znode. The program watches the
+ * specified znode and saves the data that corresponds to the
+ * znode in the filesystem. It also starts the specified program
+ * with the specified arguments when the znode exists and kills
+ * the program if the znode goes away.
+ */
+package com.yahoo.zk.executor;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.yahoo.zk.executor.DataMonitor.DataMonitorListener;
+import com.yahoo.zookeeper.KeeperException;
+import com.yahoo.zookeeper.Watcher;
+import com.yahoo.zookeeper.ZooKeeper;
+import com.yahoo.zookeeper.proto.WatcherEvent;
+
+public class Executor implements Watcher, Runnable, DataMonitorListener {
+    String znode;
+
+    DataMonitor dm;
+
+    ZooKeeper zk;
+
+    String filename;
+
+    String exec[];
+
+    Process child;
+
+    public Executor(String hostPort, String znode, String filename,
+            String exec[]) throws KeeperException, IOException {
+        this.filename = filename;
+        this.exec = exec;
+        zk = new ZooKeeper(hostPort, 3000, this);
+        dm = new DataMonitor(zk, znode, null, this);
+    }
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        if (args.length &lt; 4) {
+            System.err
+                    .println("USAGE: Executor hostPort znode filename program [args ...]");
+            System.exit(2);
+        }
+        String hostPort = args[0];
+        String znode = args[1];
+        String filename = args[2];
+        String exec[] = new String[args.length - 3];
+        System.arraycopy(args, 3, exec, 0, exec.length);
+        try {
+            new Executor(hostPort, znode, filename, exec).run();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /***************************************************************************
+     * We do process any events ourselves, we just need to forward them on.
+     * 
+     * @see com.yahoo.zookeeper.Watcher#process(com.yahoo.zookeeper.proto.WatcherEvent)
+     */
+    @Override
+    public void process(WatcherEvent event) {
+        dm.process(event);
+    }
+
+    @Override
+    public void run() {
+        try {
+            synchronized (this) {
+                while (!dm.dead) {
+                    wait();
+                }
+            }
+        } catch (InterruptedException e) {
+        }
+    }
+
+    @Override
+    public void closing(int rc) {
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    static class StreamWriter extends Thread {
+        OutputStream os;
+
+        InputStream is;
+
+        StreamWriter(InputStream is, OutputStream os) {
+            this.is = is;
+            this.os = os;
+            start();
+        }
+
+        public void run() {
+            byte b[] = new byte[80];
+            int rc;
+            try {
+                while ((rc = is.read(b)) &gt; 0) {
+                    os.write(b, 0, rc);
+                }
+            } catch (IOException e) {
+            }
+
+        }
+    }
+
+    @Override
+    public void exists(byte[] data) {
+        if (data == null) {
+            if (child != null) {
+                System.out.println("Killing process");
+                child.destroy();
+                try {
+                    child.waitFor();
+                } catch (InterruptedException e) {
+                }
+            }
+            child = null;
+        } else {
+            if (child != null) {
+                System.out.println("Stopping child");
+                child.destroy();
+                try {
+                    child.waitFor();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            try {
+                FileOutputStream fos = new FileOutputStream(filename);
+                fos.write(data);
+                fos.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            try {
+                System.out.println("Starting child");
+                child = Runtime.getRuntime().exec(exec);
+                new StreamWriter(child.getInputStream(), System.out);
+                new StreamWriter(child.getErrorStream(), System.err);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
+</pre>
+	
+
+</div>
+</div>
+<div class="note example">
+<div class="label">DataMonitor.java</div>
+<div class="content">
+	
+<title>DataMonitor.java</title>
+	
+<pre class="code">
+/**
+ * A simple class that monitors the data and existence of a ZooKeeper
+ * node. It uses asynchronous ZooKeeper APIs.
+ */
+package com.yahoo.zk.executor;
+
+import java.util.Arrays;
+
+import com.yahoo.zookeeper.KeeperException;
+import com.yahoo.zookeeper.Watcher;
+import com.yahoo.zookeeper.ZooKeeper;
+import com.yahoo.zookeeper.AsyncCallback.StatCallback;
+import com.yahoo.zookeeper.KeeperException.Code;
+import com.yahoo.zookeeper.data.Stat;
+import com.yahoo.zookeeper.proto.WatcherEvent;
+
+public class DataMonitor implements Watcher, StatCallback {
+
+    ZooKeeper zk;
+
+    String znode;
+
+    Watcher chainedWatcher;
+
+    boolean dead;
+
+    DataMonitorListener listener;
+
+    byte prevData[];
+
+    public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
+            DataMonitorListener listener) {
+        this.zk = zk;
+        this.znode = znode;
+        this.chainedWatcher = chainedWatcher;
+        this.listener = listener;
+        // Get things started by checking if the node exists. We are going
+        // to be completely event driven
+        zk.exists(znode, true, this, null);
+    }
+
+    /**
+     * Other classes use the DataMonitor by implementing this method
+     */
+    public interface DataMonitorListener {
+        /**
+         * The existence status of the node has changed.
+         */
+        void exists(byte data[]);
+
+        /**
+         * The ZooKeeper session is no longer valid.
+         * 
+         * @param rc
+         *                the ZooKeeper reason code
+         */
+        void closing(int rc);
+    }
+
+    @Override
+    /**
+     * This is a watch event callback. The node we were watching has changed or
+     * something happened to our connection to ZooKeeper.
+     */
+    public void process(WatcherEvent event) {
+        String path = event.getPath();
+        if (event.getType() == Watcher.Event.EventNone) {
+            // We are are being told that the state of the
+            // connection has changed
+            switch (event.getState()) {
+            case Event.KeeperStateSyncConnected:
+                // Everything is happy. Lets kick things off
+                // again by checking the existence of the znode
+                zk.exists(znode, true, this, null);
+                break;
+            case Event.KeeperStateExpired:
+                // It's all over
+                dead = true;
+                listener.closing(KeeperException.Code.SessionExpired);
+                break;
+            }
+        } else {
+            if (path != null &amp;&amp; path.equals(znode)) {
+                // Something has changed on the node, let's find out
+                zk.exists(znode, true, this, null);
+            }
+        }
+        if (chainedWatcher != null) {
+            chainedWatcher.process(event);
+        }
+    }
+
+    @Override
+    public void processResult(int rc, String path, Object ctx, Stat stat) {
+        boolean exists;
+        switch (rc) {
+        case Code.Ok:
+            exists = true;
+            break;
+        case Code.NoNode:
+            exists = false;
+            break;
+        case Code.SessionExpired:
+        case Code.NoAuth:
+            dead = true;
+            listener.closing(rc);
+            return;
+        default:
+            // Retry errors
+            zk.exists(znode, true, this, null);
+            return;
+        }
+
+        byte b[] = null;
+        if (exists) {
+            try {
+                b = zk.getData(znode, false, null);
+            } catch (KeeperException e) {
+                // We don't need to worry about recovering now. The watch
+                // callbacks will kick off any exception handling
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                return;
+            }
+        }
+        if ((b == null &amp;&amp; b != prevData)
+                || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {
+            listener.exists(b);
+            prevData = b;
+        }
+    }
+}
+</pre>
+
+</div>
+</div>
+</div>
+
+
+
+
+<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>

Разница между файлами не показана из-за своего большого размера
+ 96 - 0
docs/javaExample.pdf


+ 27 - 0
docs/linkmap.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
@@ -210,6 +219,24 @@ document.write("Last Published: " + document.lastModified);
 </li>
 </li>
 </ul>
 </ul>
     
     
+<ul>
+<li>
+<a href="javaExample.html">Java Example</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>javaEx</em>
+</li>
+</ul>
+    
+<ul>
+<li>
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>barTutor</em>
+</li>
+</ul>
+    
+<ul>
+<li>
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>internals</em>
+</li>
+</ul>
+    
 <ul>
 <ul>
 <li>
 <li>
 <a href="api/index.html">API Docs</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>api</em>
 <a href="api/index.html">API Docs</a>&nbsp;&nbsp;___________________&nbsp;&nbsp;<em>api</em>

+ 12 - 12
docs/linkmap.pdf

@@ -5,10 +5,10 @@
 /Producer (FOP 0.20.5) >>
 /Producer (FOP 0.20.5) >>
 endobj
 endobj
 5 0 obj
 5 0 obj
-<< /Length 840 /Filter [ /ASCII85Decode /FlateDecode ]
+<< /Length 955 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
  >>
 stream
 stream
-Gatn%;,>q#&BE]".Ju)K^p>'98KJ6J`l&"=84X]Kj<\\ZOi/D_WVH1.'&#=<&1O]G>2NJns6jcrF2tQ[q90(s63Q;ELRPur6X]"aJF"))W:=kbT[,t:kMXt.XYTGY*0DAN1C'8HGfW>,4(@_=F6</$+.qc6aMQG^i&?J,=_.dkl')En/-m@g[$-F"Wbt/-B'-lLMgkFfcl&Bb2`>I))i;k`9H(rM/(YD&l6mN?W]&BS0q1eP4Za]nB+^*>(\W2BfK72ae1;!f#h!"e?U^u;P7'a[n=R1^I6dcY+:0`\+u0S[jZ!`9GQU5d,\V^VKQ3@VWD5@^h)Ac,0'8o(eF1ahTi<E.*<s_,#:&qd"RSrrG#RL=.#-L$)G"[g0rMMmJ`-md:TY_7/7m?RTrTPD4Xmq4b=[mK$5*h[ofhRB/.MQlUgCm/94Lr+l;;JZW/OD_YH"_u.,mV=H5CW0PgfWq^&l!NoVrOL/uqcCD4YZF3r9%V`#tq!-sLjUe#\dn(<mAXW)D1g/XM#V[>R&aeWf\3f-8I>U$R1SN;em]BH8o<LWZ?RRYF7Y[#>dP(Hp\jHWeQEFODb=.jdkG8`tlFB\hIC#;mIA8$A\+gMg(R4<,r6Zc1/oESTJFnMj61UX9/</lXa=<A*[<S%jN*m6GKY%MZ6%iY5pegBcl*m15^KqP%*Wq+$B2+7l1rmc(\dI>PYX[^BlI"Dk:5J-"@2,=iZM,Zo@OhJq#-&NdaCa[-V:k&b.$0c4m7+s4+`P<%%PF/;oQe+[&?K]1c3#_c$3[WWRr74Al$^=>l_'p[f>e!hOu?iJDt/B`@7eZKosf(Qd&;qS#I%k`l_df~>
+Gatn%>u03/'Sc)R.rmSY^p>%C+.))1YYDoh1hgHg9]HnL1_,O5ftX/C:h#&NUp*m7rLobUZ/bTRlt<Yca'jK)J3gW6_=he%K>D;W!bf:r8DCD*5S-CVOKF/-4'+c?h-^c6M4*&m,0IMTX+l1ah%\GQ>Rp-'=__:.H8kU6A7nB""pjtGNZ=$g&4+afA[eCO6dU!ga)85Wq*`SRHHEn'Du%a_aE:L%D2m&^m]eOVPdD`:CXjtXUH!L17iliBJi%a^^W)YTYuh.`D4qOEA@pPk/=3YJ$\b/@n(42pJC1EJ3(>#bYoBuUUE9P-/He?>6O.rKTmlNeEm^u5HXg7#E[k6`_B-r;b2qWb_gnJ)J7A-962Sq8o2>Bp.#PU&j[a3r0updH#)S-$LQm"Q='Q2)kkp"4#Ji>t=U?p^^kjQlT7`0>OsD"uo`Fi?CG!]ZJ9n&[dQF/7X2aO@)S)=02Wbii7#%K6!q\h$Q"'&:=!&u3ShqX`HiaSL!"n55<kZd</"p:uI,bT3nbTqBE?s$ljqq08Bb/fX?].gLI)`PkO5"=P8<UL*XHa]ZKostVBC*H,njebBc/7!2-19"F#lZOc7usF,@1mqSZd4jK^0B[(iJf^]2.kGD.jj_+LdC7Qgb@8I*FD0uGb&F:e`RbElI=V>Was*0,Aa_P)A-%P$rP&a8a81br8Meu4mXe`W>>R&D!$PY8rV5Qd!mL$4#%VONU''kFQ(5a&G3QtG^fH`*'<qYh2g"B'RB*:Q&3AgD8)BR2#RTtVD:%)gJKNuLguMn+8GbQDX'^3$VNMYLd`FSOXhgVpt\;-g$HF'\\%\MR;5!`!U57\^bekM=O&O3qe`<mc2>"L:N0"+<N.38NSeE2L4I:Wb^lkp.^?S86OeL(.2mLL_Sdq[Dlpm)?Eo4?^QM7'@EKKKQ;*ck73SlV.uL%LC"HCXf;;m53>e(]&%OamRf~>
 endstream
 endstream
 endobj
 endobj
 6 0 obj
 6 0 obj
@@ -72,17 +72,17 @@ endobj
 xref
 xref
 0 12
 0 12
 0000000000 65535 f 
 0000000000 65535 f 
-0000001663 00000 n 
-0000001721 00000 n 
-0000001771 00000 n 
+0000001778 00000 n 
+0000001836 00000 n 
+0000001886 00000 n 
 0000000015 00000 n 
 0000000015 00000 n 
 0000000071 00000 n 
 0000000071 00000 n 
-0000001002 00000 n 
-0000001108 00000 n 
-0000001220 00000 n 
-0000001329 00000 n 
-0000001439 00000 n 
-0000001547 00000 n 
+0000001117 00000 n 
+0000001223 00000 n 
+0000001335 00000 n 
+0000001444 00000 n 
+0000001554 00000 n 
+0000001662 00000 n 
 trailer
 trailer
 <<
 <<
 /Size 12
 /Size 12
@@ -90,5 +90,5 @@ trailer
 /Info 4 0 R
 /Info 4 0 R
 >>
 >>
 startxref
 startxref
-1891
+2006
 %%EOF
 %%EOF

+ 9 - 0
docs/recipes.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">

+ 8 - 3
docs/skin/profile.css

@@ -156,8 +156,13 @@ a:hover { color:#6587ff}
       font-family: monospace;
       font-family: monospace;
     }
     }
 
 
-    .code {
-      font-family: "Courier New", Courier, monospace;
-      font-size: 110%;
+    pre.code {
+      margin-left: 0em;
+      padding: 0.5em;
+      background-color: #f0f0f0;
+      font-family: monospace;
     }
     }
+
+
+
   
   

+ 31 - 16
docs/zookeeperAdmin.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <div class="menupagetitle">Administrator's Guide</div>
 <div class="menupagetitle">Administrator's Guide</div>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
@@ -341,7 +350,6 @@ document.write("Last Published: " + document.lastModified);
 <p>Install the ZooKeeper Server Package. It can be downloaded
 <p>Install the ZooKeeper Server Package. It can be downloaded
             from:
             from:
           </p>
           </p>
-
           
           
 <p>
 <p>
             
             
@@ -474,7 +482,7 @@ server.3=zoo3:2888</span>
 <p>The steps to setting up a single server instance are the similar
 <p>The steps to setting up a single server instance are the similar
       to the above, except the configuration file is simpler. You can find the
       to the above, except the configuration file is simpler. You can find the
       complete instructions in the <a href="zookeeperStarted.html#sc_InstallingSingleMode">Installing and
       complete instructions in the <a href="zookeeperStarted.html#sc_InstallingSingleMode">Installing and
-      Running ZooKeeper in SIngle Server Mode</a> section of the <a href="zookeeperStarted.html">ZooKeeper Getting Started
+      Running ZooKeeper in Single Server Mode</a> section of the <a href="zookeeperStarted.html">ZooKeeper Getting Started
       Guide</a>.</p>
       Guide</a>.</p>
 <p>For information on installing the client side libraries, refer to
 <p>For information on installing the client side libraries, refer to
       the <a href="zookeeperProgrammers.html#Bindings">Bindings</a>
       the <a href="zookeeperProgrammers.html#Bindings">Bindings</a>
@@ -615,11 +623,18 @@ server.3=zoo3:2888</span>
 <p></p>
 <p></p>
 <a name="N1018A"></a><a name="sc_logging"></a>
 <a name="N1018A"></a><a name="sc_logging"></a>
 <h3 class="h4">Logging</h3>
 <h3 class="h4">Logging</h3>
-<p></p>
-<a name="N10193"></a><a name="sc_troubleshooting"></a>
+<p>ZooKeeper uses <strong>log4j</strong> version 1.2 as 
+      its logging infrastructure. The  ZooKeeper default <span class="codefrag filename">log4j.properties</span> 
+      file resides in the <span class="codefrag filename">conf</span> directory. Log4j requires that 
+      <span class="codefrag filename">log4j.properties</span> either be in the working directory 
+      (the directory from which ZooKeeper is run) or be accessible from the classpath.</p>
+<p>For more information, see 
+      <a href="http://logging.apache.org/log4j/1.2/manual.html#defaultInit">Log4j Default Initialization Procedure</a> 
+      of the log4j manual.</p>
+<a name="N101AA"></a><a name="sc_troubleshooting"></a>
 <h3 class="h4">Troubleshooting</h3>
 <h3 class="h4">Troubleshooting</h3>
 <p></p>
 <p></p>
-<a name="N1019C"></a><a name="sc_configuration"></a>
+<a name="N101B3"></a><a name="sc_configuration"></a>
 <h3 class="h4">Configuration Parameters</h3>
 <h3 class="h4">Configuration Parameters</h3>
 <p>ZooKeeper's behavior is governed by the ZooKeeper configuration
 <p>ZooKeeper's behavior is governed by the ZooKeeper configuration
       file. This file is designed so that the exact same file can be used by
       file. This file is designed so that the exact same file can be used by
@@ -627,7 +642,7 @@ server.3=zoo3:2888</span>
       layouts are the same. If servers use different configuration files, care
       layouts are the same. If servers use different configuration files, care
       must be taken to ensure that the list of servers in all of the different
       must be taken to ensure that the list of servers in all of the different
       configuration files match.</p>
       configuration files match.</p>
-<a name="N101A5"></a><a name="sc_minimumConfiguration"></a>
+<a name="N101BC"></a><a name="sc_minimumConfiguration"></a>
 <h4>Minimum Configuration</h4>
 <h4>Minimum Configuration</h4>
 <p>Here are the minimum configuration keywords that must be defined
 <p>Here are the minimum configuration keywords that must be defined
         in the configuration file:</p>
         in the configuration file:</p>
@@ -674,7 +689,7 @@ server.3=zoo3:2888</span>
 </dd>
 </dd>
         
         
 </dl>
 </dl>
-<a name="N101CC"></a><a name="sc_advancedConfiguration"></a>
+<a name="N101E3"></a><a name="sc_advancedConfiguration"></a>
 <h4>Advanced Configuration</h4>
 <h4>Advanced Configuration</h4>
 <p>The configuration settings in the section are optional. You can
 <p>The configuration settings in the section are optional. You can
         use them to further fine tune the behaviour of your ZooKeeper servers.
         use them to further fine tune the behaviour of your ZooKeeper servers.
@@ -765,7 +780,7 @@ server.3=zoo3:2888</span>
 </dd>
 </dd>
         
         
 </dl>
 </dl>
-<a name="N1022C"></a><a name="sc_clusterOptions"></a>
+<a name="N10243"></a><a name="sc_clusterOptions"></a>
 <h4>Cluster Options</h4>
 <h4>Cluster Options</h4>
 <p>The options in this section are designed for use in quorums --
 <p>The options in this section are designed for use in quorums --
         that is, when deploying clusters of servers.</p>
         that is, when deploying clusters of servers.</p>
@@ -868,7 +883,7 @@ server.3=zoo3:2888</span>
         
         
 </dl>
 </dl>
 <p></p>
 <p></p>
-<a name="N10298"></a><a name="Unsafe+Options"></a>
+<a name="N102AF"></a><a name="Unsafe+Options"></a>
 <h4>Unsafe Options</h4>
 <h4>Unsafe Options</h4>
 <p>The following options can be useful, but be careful when you use
 <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
         them. The risk of each is explained along with the explanation of what
@@ -913,7 +928,7 @@ server.3=zoo3:2888</span>
 </dd>
 </dd>
         
         
 </dl>
 </dl>
-<a name="N102CA"></a><a name="sc_zkCommands"></a>
+<a name="N102E1"></a><a name="sc_zkCommands"></a>
 <h3 class="h4">ZooKeeper Commands: The Four Letter Words</h3>
 <h3 class="h4">ZooKeeper Commands: The Four Letter Words</h3>
 <p>ZooKeeper responds to a small set of commands. Each command is
 <p>ZooKeeper responds to a small set of commands. Each command is
       composed of four letters. You issue the commands to ZooKeeper via telnet
       composed of four letters. You issue the commands to ZooKeeper via telnet
@@ -962,7 +977,7 @@ server.3=zoo3:2888</span>
 <pre class="code">$ echo ruok | nc 127.0.0.1 5111
 <pre class="code">$ echo ruok | nc 127.0.0.1 5111
 imok
 imok
 </pre>
 </pre>
-<a name="N102FC"></a><a name="sc_dataFileManagement"></a>
+<a name="N10313"></a><a name="sc_dataFileManagement"></a>
 <h3 class="h4">Data File Management</h3>
 <h3 class="h4">Data File Management</h3>
 <p>ZooKeeper stores its data in a data directory and its transaction
 <p>ZooKeeper stores its data in a data directory and its transaction
       log in a transaction log directory. By default these two directories are
       log in a transaction log directory. By default these two directories are
@@ -970,7 +985,7 @@ imok
       transaction log files in a separate directory than the data files.
       transaction log files in a separate directory than the data files.
       Throughput increases and latency decreases when transaction logs reside
       Throughput increases and latency decreases when transaction logs reside
       on a dedicated log devices.</p>
       on a dedicated log devices.</p>
-<a name="N10305"></a><a name="The+Data+Directory"></a>
+<a name="N1031C"></a><a name="The+Data+Directory"></a>
 <h4>The Data Directory</h4>
 <h4>The Data Directory</h4>
 <p>This directory has two files in it:</p>
 <p>This directory has two files in it:</p>
 <ul>
 <ul>
@@ -1016,14 +1031,14 @@ imok
         idempotent nature of its updates. By replaying the transaction log
         idempotent nature of its updates. By replaying the transaction log
         against fuzzy snapshots ZooKeeper gets the state of the system at the
         against fuzzy snapshots ZooKeeper gets the state of the system at the
         end of the log.</p>
         end of the log.</p>
-<a name="N10341"></a><a name="The+Log+Directory"></a>
+<a name="N10358"></a><a name="The+Log+Directory"></a>
 <h4>The Log Directory</h4>
 <h4>The Log Directory</h4>
 <p>The Log Directory contains the ZooKeeper transaction logs.
 <p>The Log Directory contains the ZooKeeper transaction logs.
         Before any update takes place, ZooKeeper ensures that the transaction
         Before any update takes place, ZooKeeper ensures that the transaction
         that represents the update is written to non-volatile storage. A new
         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
         log file is started each time a snapshot is begun. The log file's
         suffix is the first zxid written to that log.</p>
         suffix is the first zxid written to that log.</p>
-<a name="N1034B"></a><a name="File+Management"></a>
+<a name="N10362"></a><a name="File+Management"></a>
 <h4>File Management</h4>
 <h4>File Management</h4>
 <p>The format of snapshot and log files does not change between
 <p>The format of snapshot and log files does not change between
         standalone ZooKeeper servers and different configurations of
         standalone ZooKeeper servers and different configurations of
@@ -1040,7 +1055,7 @@ imok
         needs the latest complete fuzzy snapshot and the log files from the
         needs the latest complete fuzzy snapshot and the log files from the
         start of that snapshot. The PurgeTxnLog utility implements a simple
         start of that snapshot. The PurgeTxnLog utility implements a simple
         retention policy that administrators can use.</p>
         retention policy that administrators can use.</p>
-<a name="N1035C"></a><a name="sc_commonProblems"></a>
+<a name="N10373"></a><a name="sc_commonProblems"></a>
 <h3 class="h4">Things to Avoid</h3>
 <h3 class="h4">Things to Avoid</h3>
 <p>Here are some common problems you can avoid by configuring
 <p>Here are some common problems you can avoid by configuring
       ZooKeeper correctly:</p>
       ZooKeeper correctly:</p>
@@ -1094,7 +1109,7 @@ imok
 </dd>
 </dd>
       
       
 </dl>
 </dl>
-<a name="N10380"></a><a name="sc_bestPractices"></a>
+<a name="N10397"></a><a name="sc_bestPractices"></a>
 <h3 class="h4">Best Practices</h3>
 <h3 class="h4">Best Practices</h3>
 <p>For best results, take note of the following list of good
 <p>For best results, take note of the following list of good
       Zookeeper practices. <em>[tbd...]</em>
       Zookeeper practices. <em>[tbd...]</em>

Разница между файлами не показана из-за своего большого размера
+ 2 - 2
docs/zookeeperAdmin.pdf


+ 729 - 0
docs/zookeeperInternals.html

@@ -0,0 +1,729 @@
+<!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>ZooKeeper Internals</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="The Hadoop database"></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 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_selected_1.1', 'skin/')" id="menu_selected_1.1Title" class="menutitle" style="background-image: url('skin/images/chapter_open.gif');">Documentation</div>
+<div id="menu_selected_1.1" class="selectedmenuitemgroup" style="display: block;">
+<div class="menuitem">
+<a href="index.html">Welcome</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperOver.html">Zookeeper Overview</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperStarted.html">Getting Started</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperProgrammers.html">Programmer's Guide</a>
+</div>
+<div class="menuitem">
+<a href="recipes.html">Recipes</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperAdmin.html">Administrator's Guide</a>
+</div>
+<div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menupage">
+<div class="menupagetitle">ZooKeeper Internals</div>
+</div>
+<div class="menuitem">
+<a href="api/index.html">API Docs</a>
+</div>
+<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 class="menuitem">
+<a href="zookeeperOtherInfo.html">Other Info</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="zookeeperInternals.pdf"><img alt="PDF -icon" src="skin/images/pdfdoc.gif" class="skin"><br>
+        PDF</a>
+</div>
+<h1>ZooKeeper Internals</h1>
+<div id="minitoc-area">
+<ul class="minitoc">
+<li>
+<a href="#ch_Introduction">Introduction</a>
+</li>
+<li>
+<a href="#sc_atomicBroadcast">Atomic Broadcast</a>
+<ul class="minitoc">
+<li>
+<a href="#sc_guaranteesPropertiesDefinitions">Guarantees, Properties, and Definitions</a>
+</li>
+<li>
+<a href="#sc_leaderElection">Leader Activation</a>
+</li>
+<li>
+<a href="#sc_activeMessaging">Active Messaging</a>
+</li>
+<li>
+<a href="#sc_summary">Summary</a>
+</li>
+<li>
+<a href="#sc_comparisons">Comparisons</a>
+</li>
+</ul>
+</li>
+<li>
+<a href="#sc_logging">Logging</a>
+<ul class="minitoc">
+<li>
+<a href="#sc_developerGuidelines">Developer Guidelines</a>
+<ul class="minitoc">
+<li>
+<a href="#sc_rightLevel">Logging at the Right Level</a>
+</li>
+<li>
+<a href="#sc_log4jIdioms">Use of Standard log4j Idioms</a>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+  
+
+  
+
+  
+<a name="N10009"></a><a name="ch_Introduction"></a>
+<h2 class="h3">Introduction</h2>
+<div class="section">
+<p>This document contains information on the inner workings of ZooKeeper. 
+    So far, it discusses these topics:
+    </p>
+<ul>    
+
+<li>
+<p>
+<a href="#sc_atomicBroadcast">Atomic Broadcast</a>
+</p>
+</li>
+
+<li>
+<p>
+<a href="#sc_logging">Logging</a>
+</p>
+</li>
+
+</ul>
+</div>
+
+
+<a name="N10022"></a><a name="sc_atomicBroadcast"></a>
+<h2 class="h3">Atomic Broadcast</h2>
+<div class="section">
+<p>
+At the heart of ZooKeeper is an atomic messaging system that keeps all of the servers in sync.</p>
+<a name="N1002B"></a><a name="sc_guaranteesPropertiesDefinitions"></a>
+<h3 class="h4">Guarantees, Properties, and Definitions</h3>
+<p>
+The specific guarantees provided by the messaging system used by ZooKeeper are the following:</p>
+<dl>
+
+
+<dt>
+<term>
+<em>Reliable delivery</em>
+</term>
+</dt>
+<dd>
+<p>If a message, m, is delivered 
+by one server, it will be eventually delivered by all servers.</p>
+</dd>
+
+
+<dt>
+<term>
+<em>Total order</em>
+</term>
+</dt>
+<dd>
+<p> If a message is 
+delivered before message b by one server, a will be delivered before b by all 
+servers. If a and b are delivered messages, either a will be delivered before b 
+or b will be delivered before a.</p>
+</dd>
+
+
+<dt>
+<term>
+<em>Causal order</em> 
+</term>
+</dt>
+<dd>
+<p>
+If a message b is sent after a message a has been delivered by the sender of b, 
+a must be ordered before b. If a sender sends c after sending b, c must be ordered after b.
+</p>
+</dd>
+
+
+</dl>
+<p>
+The ZooKeeper messaging system also needs to be efficient, reliable, and easy to 
+implement and maintain. We make heavy use of messaging, so we need the system to 
+be able to handle thousands of requests per second. Although we can require at 
+least k+1 correct servers to send new messages, we must be able to recover from 
+correlated failures such as power outages. When we implemented the system we had 
+little time and few engineering resources, so we needed a protocol that is 
+accessible to engineers and is easy to implement. We found that our protocol 
+satisfied all of these goals.
+
+</p>
+<p>
+Our protocol assumes that we can construct point-to-point FIFO channels between 
+the servers. While similar services usually assume message delivery that can 
+lose or reorder messages, our assumption of FIFO channels is very practical 
+given that we use TCP for communication. Specifically we rely on the following property of TCP:</p>
+<dl>
+
+
+<dt>
+<term>
+<em>Ordered delivery</em>
+</term>
+</dt>
+<dd>
+<p>Data is delivered in the same order it is sent and a message m is 
+delivered only after all messages sent before m have been delivered. 
+(The corollary to this is that if message m is lost all messages after m will be lost.)</p>
+</dd>
+
+
+<dt>
+<term>
+<em>No message after close</em>
+</term>
+</dt>
+<dd>
+<p>Once a FIFO channel is closed, no messages will be received from it.</p>
+</dd>
+
+
+</dl>
+<p>
+FLP proved that consensus cannot be achieved in asynchronous distributed systems 
+if failures are possible. To ensure we achieve consensus in the presence of failures 
+we use timeouts. However, we rely on times for liveness not for correctness. So, 
+if timeouts stop working (clocks malfunction for example) the messaging system may 
+hang, but it will not violate its guarantees.</p>
+<p>When describing the ZooKeeper messaging protocol we will talk of packets, 
+proposals, and messages:</p>
+<dl>
+
+<dt>
+<term>
+<em>Packet</em>
+</term>
+</dt>
+<dd>
+<p>a sequence of bytes sent through a FIFO channel</p>
+</dd>
+<dt>
+<term>
+<em>Proposal</em>
+</term>
+</dt>
+<dd>
+<p>a unit of agreement. Proposals are agreed upon by exchanging packets 
+with a quorum of ZooKeeper servers. Most proposals contain messages, however the 
+NEW_LEADER proposal is an example of a proposal that does not correspond to a message.</p>
+</dd>
+<dt>
+<term>
+<em>Message</em>
+</term>
+</dt>
+<dd>
+<p>a sequence of bytes to be atomically broadcast to all ZooKeeper 
+servers. A message put into a proposal and agreed upon before it is delivered.</p>
+</dd>
+
+
+</dl>
+<p>
+As stated above, ZooKeeper guarantees a total order of messages, and it also 
+guarantees a total order of proposals. ZooKeeper exposes the total ordering using
+a ZooKeeper transaction id (<em>zxid</em>). All proposals will be stamped with a zxid when 
+it is proposed and exactly reflects the total ordering. Proposals are sent to all 
+ZooKeeper servers and committed when a quorum of them acknowledge the proposal. 
+If a proposal contains a message, the message will be delivered when the proposal 
+is committed. Acknowledgement means the server has recorded the proposal to persistent storage. 
+Our quorums have the requirement that any pair of quorum must have at least one server 
+in common. We ensure this by requiring that all quorums have size (<em>n/2+1</em>) where 
+n is the number of servers that make up a ZooKeeper service.
+</p>
+<p>
+The zxid has two parts: the epoch and a counter. In our implementation the zxid 
+is a 64-bit number. We use the high order 32-bits for the epoch and the low order 
+32-bits for the counter. Because it has two parts represent the zxid both as a 
+number and as a pair of integers, (<em>epoch, count</em>). The epoch number represents a 
+change in leadership. Each time a new leader comes into power it will have its 
+own epoch number. We have a simple algorithm to assign a unique zxid to a proposal: 
+the leader simply increments the zxid to obtain a unique zxid for each proposal. 
+<em>Leadership activation will ensure that only one leader uses a given epoch, so our 
+simple algorithm guarantees that every proposal will have a unique id.</em>
+
+</p>
+<p>
+ZooKeeper messaging consists of two phases:</p>
+<dl>
+
+<dt>
+<term>
+<em>Leader activation</em>
+</term>
+</dt>
+<dd>
+<p>In this phase a leader establishes the correct state of the system 
+and gets ready to start making proposals.</p>
+</dd>
+
+
+<dt>
+<term>
+<em>Active messaging</em>
+</term>
+</dt>
+<dd>
+<p>In this phase a leader accepts messages to propose and coordinates message delivery.</p>
+</dd>
+
+</dl>
+<p>
+ZooKeeper is a holistic protocol. We do not focus on individual proposals, rather 
+look at the stream of proposals as a whole. Our strict ordering allows us to do this 
+efficiently and greatly simplifies our protocol. Leadership activation embodies 
+this holistic concept. A leader becomes active only when a quorum of followers 
+(The leader counts as a follower as well. You can always vote for yourself ) has synced 
+up with the leader, they have the same state. This state consists of all of the 
+proposals that the leader believes have been committed and the proposal to follow 
+the leader, the NEW_LEADER proposal. (Hopefully you are thinking to 
+yourself, <em>Does the set of proposals that the leader believes has been committed 
+included all the proposals that really have been committed?</em> The answer is <em>yes</em>. 
+Below, we make clear why.)
+</p>
+<a name="N100B9"></a><a name="sc_leaderElection"></a>
+<h3 class="h4">Leader Activation</h3>
+<p>
+Leader activation includes leader election. We currently have two leader election 
+algorithms in ZooKeeper: LeaderElection and FastLeaderElection (AuthFastLeaderElection 
+is a variant of FastLeaderElection). ZooKeeper messaging doesn't care about the 
+exact method of electing a leader has long as the following holds:
+</p>
+<ul>
+
+
+<li>
+<p>The leader has seen the highest zxid of all the followers.</p>
+</li>
+
+<li>
+<p>A quorum of servers have committed to following the leader.</p>
+</li>
+
+
+</ul>
+<p>
+Of these two requirements only the first, the highest zxid amoung the followers 
+needs to hold for correct operation. The second requirement, a quorum of followers, 
+just needs to hold with high probability. We are going to recheck the second requirement, 
+so if a failure happens during or after the leader election and quorum is lost, 
+we will recover by abandoning leader activation and running another election.
+</p>
+<p>
+After leader election a single server will be designated as a leader and start 
+waiting for followers to connect. The rest of the servers will try to connect to 
+the leader. The leader will sync up with followers by sending any proposals they 
+are missing, or if a follower is missing too many proposals, it will send a full 
+snapshot of the state to the follower.
+</p>
+<p>
+There is a corner cases that a follower arrives that has proposals, U, not seen 
+by a leader. Proposals are seen in order, so the proposals of U will have a zxids 
+higher than zxids seen by the leader. The follower must have arrived after the 
+leader election, otherwise the follower would have been elected leader given that 
+it has seen a higher zxid. Since committed proposals must be seen by a quorum of 
+servers, and a quorum of servers that elected the leader did not see U, the proposals 
+of you have not been committed, so they can be discarded. When the follower connects 
+to the leader, the leader will tell the follower to discard U.
+</p>
+<p>
+A new leader establishes a zxid to start using for new proposals by getting the 
+epoch, e, of the highest zxid it has seen and setting the next zxid to use to be 
+(e+1, 0), fter the leader syncs with a follower, it will propose a NEW_LEADER 
+proposal. Once the NEW_LEADER proposal has been committed, the leader will activate 
+and start receiving and issuing proposals.
+</p>
+<p>
+It all sounds complicated but here are the basic rules of operation during leader 
+activation:
+</p>
+<ul>
+
+<li>
+<p>A follower will ACK the NEW_LEADER proposal after it has synced with the leader.</p>
+</li>
+
+<li>
+<p>A follower will only ACK a NEW_LEADER proposal with a given zxid from a single server.</p>
+</li>
+
+<li>
+<p>A new leader will COMMIT the NEW_LEADER proposal when a quorum of followers have ACKed it.</p>
+</li>
+
+<li>
+<p>A follower will commit any state it received from the leader when the NEW_LEADER proposal is COMMIT.</p>
+</li>
+
+<li>
+<p>A new leader will not accept new proposals until the NEW_LEADER proposal has been COMMITED.</p>
+</li>
+
+</ul>
+<p>
+If leader election terminates erroneously, we don't have a problem since the 
+NEW_LEADER proposal will not be committed since the leader will not have quorum. 
+When this happens, the leader and any remaining followers will timeout and go back 
+to leader election.
+</p>
+<a name="N100F7"></a><a name="sc_activeMessaging"></a>
+<h3 class="h4">Active Messaging</h3>
+<p>
+Leader Activation does all the heavy lifting. Once the leader is coronated he can 
+start blasting out proposals. As long as he remains the leader no other leader can 
+emerge since no other leader will be able to get a quorum of followers. If a new 
+leader does emerge, 
+it means that the leader has lost quorum, and the new leader will clean up any 
+mess left over during her leadership activation.
+</p>
+<p>ZooKeeper messaging operates similar to a classic two-phase commit.</p>
+<img alt="" src="images/2pc.png"><p>
+All communication channels are FIFO, so everything is done in order. Specifically 
+the following operating constraints are observed:</p>
+<ul>
+
+
+<li>
+<p>The leader sends proposals to all followers using 
+the same order. Moreover, this order follows the order in which requests have been 
+received. Because we use FIFO channels this means that followers also receive proposals in order.
+</p>
+</li>
+
+
+<li>
+<p>Followers process messages in the order they are received. This 
+means that messages will be ACKed in order and the leader will receive ACKs from 
+followers in order, due to the FIFO channels. It also means that if message $m$ 
+has been written to non-volatile storage, all messages that were proposed before 
+$m$ have been written to non-volatile storage.</p>
+</li>
+
+
+<li>
+<p>The leader will issue a COMMIT to all followers as soon as a 
+quorum of followers have ACKed a message. Since messages are ACKed in order, 
+COMMITs will be sent by the leader as received by the followers in order.</p>
+</li>
+
+
+<li>
+<p>COMMITs are processed in order. Followers deliver a proposals 
+message when that proposal is committed.</p>
+</li>
+
+
+</ul>
+<a name="N1011E"></a><a name="sc_summary"></a>
+<h3 class="h4">Summary</h3>
+<p>So there you go. Why does it work? Specifically, why does is set of proposals 
+believed by a new leader always contain any proposal that has actually been committed? 
+First, all proposals have a unique zxid, so unlike other protocols, we never have 
+to worry about two different values being proposed for the same zxid; followers 
+(a leader is also a follower) see and record proposals in order; proposals are 
+committed in order; there is only one active leader at a time since followers only 
+follow a single leader at a time; a new leader has seen all committed proposals 
+from the previous epoch since it has seen the highest zxid from a quorum of servers; 
+any uncommited proposals from a previous epoch seen by a new leader will be committed 
+by that leader before it becomes active.</p>
+<a name="N10127"></a><a name="sc_comparisons"></a>
+<h3 class="h4">Comparisons</h3>
+<p>
+Isn't this just Multi-Paxos? No, Multi-Paxos requires some way of assuring that 
+there is only a single coordinator. We do not count on such assurances. Instead 
+we use the leader activation to recover from leadership change or old leaders 
+believing they are still active.
+</p>
+<p>
+Isn't this just Paxos? Your active messaging phase looks just like phase 2 of Paxos? 
+Actually, to us active messaging looks just like 2 phase commit without the need to 
+handle aborts. Active messaging is different from both in the sense that it has 
+cross proposal ordering requirements. If we do not maintain strict FIFO ordering of 
+all packets, it all falls apart. Also, our leader activation phase is different from 
+both of them. In particular, our use of epochs allows us to skip blocks of uncommitted
+proposals and to not worry about duplicate proposals for a given zxid.
+</p>
+</div>
+
+
+
+<a name="N10134"></a><a name="sc_logging"></a>
+<h2 class="h3">Logging</h2>
+<div class="section">
+<p>
+ZooKeeper uses 
+<a href="http://logging.apache.org/log4j">log4j</a>
+version 1.2 as its logging infrastructure. For information on configuring log4j for
+ZooKeeper, see the <a href="zookeeperAdmin.html#sc_logging">Logging</a> section 
+of the <a href="zookeeperAdmin.html">ZooKeeper Administrator's Guide.</a>
+
+</p>
+<a name="N10149"></a><a name="sc_developerGuidelines"></a>
+<h3 class="h4">Developer Guidelines</h3>
+<p>Please follow these guidelines when submitting code. Patch reviewers will look for the following:</p>
+<a name="N10151"></a><a name="sc_rightLevel"></a>
+<h4>Logging at the Right Level</h4>
+<p>
+There are <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html#FATAL">6 levels of logging in log4j</a>. 
+It's important to pick the right one. In order of higher to lower severity:</p>
+<ol>
+   
+<li>
+<p> FATAL level designates very severe error events that will presumably lead the application to abort</p>
+</li>
+   
+<li>
+<p>ERROR level designates error events that might still allow the application to continue running.</p>
+</li>
+   
+<li>
+<p>WARN level designates potentially harmful situations.</p>
+</li>
+   
+<li>
+<p>INFO level designates informational messages that highlight the progress of the application at coarse-grained level.</p>
+</li>
+   
+<li>
+<p>EBUG Level designates fine-grained informational events that are most useful to debug an application.</p>
+</li>
+   
+<li>
+<p>TRACE Level designates finer-grained informational events than the DEBUG.</p>
+</li>
+
+</ol>
+<p>
+ZooKeeper is typically run in production such that log messages of INFO level 
+severity and higher (more severe) are output to the log.</p>
+<a name="N1017C"></a><a name="sc_log4jIdioms"></a>
+<h4>Use of Standard log4j Idioms</h4>
+<p>
+<em>Static Message Logging</em>
+</p>
+<pre class="code">
+LOG.debug("process completed successfully!");
+</pre>
+<p>However when creating a message from a number of components (string 
+concatenation), the log call should be wrapped with a "isXEnabled()" call. this 
+eliminates the string concatenation overhead when debug level logging is not enabled.
+</p>
+<pre class="code">
+if (LOG.isDebugEnabled()) {
+    LOG.debug("got " + count + " messages in " + time + " minutes");
+}
+</pre>
+<p>
+<em>Naming</em>
+</p>
+<p>
+Loggers should be named after the class in which they are used. (See the 
+<a href="http://logging.apache.org/log4j/1.2/faq.html#2.4">log4j faq</a> 
+for reasons why this is a good idea.)
+</p>
+<pre class="code">
+public class Foo {
+    private static final Logger LOG = Logger.getLogger(Foo.class);
+    ....
+    public Foo() {
+       LOG.info("constructing Foo");
+</pre>
+<p>
+<em>Exception handling</em>
+</p>
+<pre class="code">
+try {
+  // code
+} catch (XYZException e) {
+  // do this
+  LOG.error("Something bad happened", e);
+  // don't do this (generally)
+  // LOG.error(e);
+  // why? because "don't do" case hides the stack trace
+ 
+  // continue process here as you need... recover or (re)throw
+}
+</pre>
+</div>
+
+
+<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>

Разница между файлами не показана из-за своего большого размера
+ 129 - 0
docs/zookeeperInternals.pdf


+ 9 - 0
docs/zookeeperOtherInfo.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">

+ 9 - 0
docs/zookeeperOver.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">

+ 9 - 0
docs/zookeeperProgrammers.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">

+ 29 - 22
docs/zookeeperStarted.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 <a href="zookeeperAdmin.html">Administrator's Guide</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperTutorial.html">Barrie and Queue Tutorial</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 <a href="api/index.html">API Docs</a>
 </div>
 </div>
 <div class="menuitem">
 <div class="menuitem">
@@ -216,18 +225,17 @@ document.write("Last Published: " + document.lastModified);
 </div>
 </div>
 </div>
 </div>
 <p>Once you have downloaded the ZooKeeper source, cd to the root of
 <p>Once you have downloaded the ZooKeeper source, cd to the root of
-      your ZooKeeper source, and run "ant jar". For example:<span class="codefrag computeroutput">$ cd ~/dev/zookeeper
-
-$ ~/dev/zookeeper/: ant jar</span>
-</p>
+      your ZooKeeper source, and run "ant jar". For example:</p>
+<pre class="code">
+$ cd ~/dev/zookeeper
+$ ~/dev/zookeeper/: ant jar
+</pre>
 <p>This should generate a JAR file called zookeeper.jar. To start
 <p>This should generate a JAR file called zookeeper.jar. To start
-      Zookeeper, compile and run zookeeper.jar. <em>[tbd, some more
-      instruction here. Perhaps a command line? Are these two steps or
-      one?]</em>
-</p>
+      Zookeeper, compile and run zookeeper.jar.</p>
 <p>To start ZooKeeper you need a configuration file. Here is a sample
 <p>To start ZooKeeper you need a configuration file. Here is a sample
       file:</p>
       file:</p>
-<pre class="code">tickTime=2000
+<pre class="code">
+tickTime=2000
 dataDir=/var/zookeeper/ 
 dataDir=/var/zookeeper/ 
 clientPort=2181
 clientPort=2181
 </pre>
 </pre>
@@ -274,9 +282,7 @@ clientPort=2181
 </dl>
 </dl>
 <p>Now that you created the configuration file, you can start
 <p>Now that you created the configuration file, you can start
       ZooKeeper:</p>
       ZooKeeper:</p>
-<p>
-<span class="codefrag computeroutput">java -cp zookeeper-dev.jar:java/lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg</span>
-</p>
+<pre class="code">java -cp zookeeper-dev.jar:java/lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg</pre>
 <p>ZooKeeper logs messages using log4j -- more detail available in
 <p>ZooKeeper logs messages using log4j -- more detail available in
       the <a href="zookeeperProgrammers.html#Logging">Logging</a>
       the <a href="zookeeperProgrammers.html#Logging">Logging</a>
       section of the Programmer's Guide.<em>[tbd:
       section of the Programmer's Guide.<em>[tbd:
@@ -288,7 +294,7 @@ clientPort=2181
       replicated mode, please see <a href="#sc_RunningReplicatedZooKeeper">Running Replicated
       replicated mode, please see <a href="#sc_RunningReplicatedZooKeeper">Running Replicated
       Zookeeper</a>.</p>
       Zookeeper</a>.</p>
 <p></p>
 <p></p>
-<a name="N10076"></a><a name="sc_ConnectingToZooKeeper"></a>
+<a name="N10072"></a><a name="sc_ConnectingToZooKeeper"></a>
 <h3 class="h4">Connecting to ZooKeeper</h3>
 <h3 class="h4">Connecting to ZooKeeper</h3>
 <p>Once ZooKeeper is running, you have several option for connection
 <p>Once ZooKeeper is running, you have several option for connection
       to it:</p>
       to it:</p>
@@ -312,7 +318,7 @@ clientPort=2181
 <p>
 <p>
 <strong>C</strong>: compile cli_mt
 <strong>C</strong>: compile cli_mt
           (multi-threaded) or cli_st (single-threaded) by running
           (multi-threaded) or cli_st (single-threaded) by running
-          <span class="codefrag command">_make cli_mt_</span> or <span class="codefrag command">_make cli_st_</span>
+          <span class="codefrag command">make cli_mt</span> or <span class="codefrag command">make cli_st</span>
           in the c subdirectory in the ZooKeeper sources.</p>
           in the c subdirectory in the ZooKeeper sources.</p>
 
 
           
           
@@ -324,7 +330,7 @@ clientPort=2181
 </li>
 </li>
       
       
 </ul>
 </ul>
-<a name="N100A7"></a><a name="sc_ProgrammingToZooKeeper"></a>
+<a name="N100A3"></a><a name="sc_ProgrammingToZooKeeper"></a>
 <h3 class="h4">Programming to ZooKeeper</h3>
 <h3 class="h4">Programming to ZooKeeper</h3>
 <p>ZooKeeper has a Java bindings and C bindings. They are
 <p>ZooKeeper has a Java bindings and C bindings. They are
       functionally equivalent. The C bindings exist in two variants: single
       functionally equivalent. The C bindings exist in two variants: single
@@ -332,7 +338,7 @@ clientPort=2181
       is done. For more information, see the <a href="zookeeperProgrammers.html#ch_programStructureWithExample.html">Programming
       is done. For more information, see the <a href="zookeeperProgrammers.html#ch_programStructureWithExample.html">Programming
       Examples in the Zookeeper Programmer's Guide</a> for
       Examples in the Zookeeper Programmer's Guide</a> for
       sample code using of the different APIs.</p>
       sample code using of the different APIs.</p>
-<a name="N100B5"></a><a name="sc_RunningReplicatedZooKeeper"></a>
+<a name="N100B1"></a><a name="sc_RunningReplicatedZooKeeper"></a>
 <h3 class="h4">Running Replicated ZooKeeper</h3>
 <h3 class="h4">Running Replicated ZooKeeper</h3>
 <p>Running ZooKeeper in standalone mode is convenient for evaluation,
 <p>Running ZooKeeper in standalone mode is convenient for evaluation,
       some development, and testing. But in production, you should run
       some development, and testing. But in production, you should run
@@ -341,15 +347,16 @@ clientPort=2181
       mode, all servers in the quorum have copies of the same configuration
       mode, all servers in the quorum have copies of the same configuration
       file. The file is similar to the one used in standalone mode, but with a
       file. The file is similar to the one used in standalone mode, but with a
       few differences. Here is an example:</p>
       few differences. Here is an example:</p>
-<p>
-<span class="codefrag computeroutput">tickTime=2000 
+<pre class="code">
+tickTime=2000 
 dataDir=/var/zookeeper/ 
 dataDir=/var/zookeeper/ 
 clientPort=2181 
 clientPort=2181 
 initLimit=5 
 initLimit=5 
 syncLimit=2 
 syncLimit=2 
-server.1=zoo1:2888 server.2=zoo2:2888 
-server.3=zoo3:2888 </span>
-</p>
+server.1=zoo1:2888
+server.2=zoo2:2888 
+server.3=zoo3:2888 
+</pre>
 <p>The new entry, <strong>initLimit</strong> is
 <p>The new entry, <strong>initLimit</strong> is
       timeouts ZooKeeper uses to limit the length of time the Zookeeper
       timeouts ZooKeeper uses to limit the length of time the Zookeeper
       servers in quorum have to connect to a leader. The entry <strong>syncLimit</strong> limits how far out of date a server can
       servers in quorum have to connect to a leader. The entry <strong>syncLimit</strong> limits how far out of date a server can
@@ -377,7 +384,7 @@ server.3=zoo3:2888 </span>
       
       
 </div>
 </div>
 </div>
 </div>
-<a name="N100EC"></a><a name="Other+Optimizations"></a>
+<a name="N100E6"></a><a name="Other+Optimizations"></a>
 <h3 class="h4">Other Optimizations</h3>
 <h3 class="h4">Other Optimizations</h3>
 <p>There are a couple of other configuration parameters that can
 <p>There are a couple of other configuration parameters that can
       greatly increase performance:</p>
       greatly increase performance:</p>

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
docs/zookeeperStarted.pdf


+ 857 - 0
docs/zookeeperTutorial.html

@@ -0,0 +1,857 @@
+<!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>Programming with ZooKeeper - A basic tutorial</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="The Hadoop database"></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 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_selected_1.1', 'skin/')" id="menu_selected_1.1Title" class="menutitle" style="background-image: url('skin/images/chapter_open.gif');">Documentation</div>
+<div id="menu_selected_1.1" class="selectedmenuitemgroup" style="display: block;">
+<div class="menuitem">
+<a href="index.html">Welcome</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperOver.html">Zookeeper Overview</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperStarted.html">Getting Started</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperProgrammers.html">Programmer's Guide</a>
+</div>
+<div class="menuitem">
+<a href="recipes.html">Recipes</a>
+</div>
+<div class="menuitem">
+<a href="zookeeperAdmin.html">Administrator's Guide</a>
+</div>
+<div class="menuitem">
+<a href="javaExample.html">Java Example</a>
+</div>
+<div class="menupage">
+<div class="menupagetitle">Barrie and Queue Tutorial</div>
+</div>
+<div class="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
+<a href="api/index.html">API Docs</a>
+</div>
+<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 class="menuitem">
+<a href="zookeeperOtherInfo.html">Other Info</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="zookeeperTutorial.pdf"><img alt="PDF -icon" src="skin/images/pdfdoc.gif" class="skin"><br>
+        PDF</a>
+</div>
+<h1>Programming with ZooKeeper - A basic tutorial</h1>
+<div id="minitoc-area">
+<ul class="minitoc">
+<li>
+<a href="#ch_Introduction">Introduction</a>
+</li>
+<li>
+<a href="#sc_barriers">Barriers</a>
+</li>
+<li>
+<a href="#sc_producerConsumerQueues">Producer-Consumer Queues</a>
+</li>
+<li>
+<a href="#sc_sourceListing">Complete Source Listing</a>
+</li>
+</ul>
+</div>
+  
+
+  
+
+  
+<a name="N10009"></a><a name="ch_Introduction"></a>
+<h2 class="h3">Introduction</h2>
+<div class="section">
+<p>In this tutorial, we show simple implementations of barriers and 
+    producer-consumer queues using ZooKeeper. We call the respective classes Barrier and Queue. 
+    These examples assume that you have at least one ZooKeeper server running.</p>
+<p>Both primitives use the following common excerpt of code:</p>
+<pre class="code">
+static ZooKeeper zk = null;
+static Integer mutex;
+
+String root;
+
+SyncPrimitive(String address) {
+	if(zk == null){
+	    try {
+		System.out.println("Starting ZK:");
+		zk = new ZooKeeper(address, 3000, this);
+		mutex = new Integer(-1);
+		System.out.println("Finished starting ZK: " + zk);
+	    } catch (KeeperException e) {
+		System.out.println("Keeper exception when starting new session: "
+			+ e.toString());
+		zk = null;
+	    } catch (IOException e) {
+		System.out.println(e.toString());
+		zk = null;
+	    }
+	}
+}
+
+synchronized public void process(WatcherEvent event) {
+	synchronized (mutex) {
+	    mutex.notify();
+	}
+}
+
+</pre>
+<p>Both classes extend SyncPrimitive. In this way, we execute steps that are 
+common to all primitives in the constructor of SyncPrimitive. To keep the examples 
+simple, we create a ZooKeeper object the first time we instantiate either a barrier 
+object or a queue object, and we declare a static variable that is a reference 
+to this object. The subsequent instances of Barrier and Queue check whether a 
+ZooKeeper object exists. Alternatively, we could have the application creating a
+ZooKeeper object and passing it to the constructor of Barrier and Queue.</p>
+<p>
+We use the process() method to process notifications triggered due to watches. 
+In the following discussion, we present code that sets watches. A watch is internal 
+structure that enables ZooKeeper to notify a client of a change to a node. For example, 
+if a client is waiting for other clients to leave a barrier, then it can set a watch and 
+wait for modifications to a particular node, which can indicate that it is the end of the wait. 
+This point becomes clear once we go over the examples.
+</p>
+</div>
+   
+ 
+<a name="N1001F"></a><a name="sc_barriers"></a>
+<h2 class="h3">Barriers</h2>
+<div class="section">
+<p>
+ A barrier is a primitive that enables a group of processes to synchronize the 
+ beginning and the end of a computation. The general idea of this implementation 
+ is to have a barrier node that serves the purpose of being a parent for individual 
+ process nodes. Suppose that we call the barrier node "/b1". Each process "p" then 
+ creates a node "/b1/p". Once enough processes have created their corresponding 
+ nodes, joined processes can start the computation.
+ </p>
+<p>In this example, each process instantiates a Barrier object, and its constructor takes as parameters:</p>
+<ul>
+<li>
+<p>the address of a ZooKeeper server (e.g., "zoo1.foo.com:2181")</p>
+</li>
+
+<li>
+<p>the path of the barrier node on ZooKeeper (e.g., "/b1")</p>
+</li>
+
+<li>
+<p>the size of the group of processes</p>
+</li>
+
+</ul>
+<p>The constructor of Barrier passes the address of the Zookeeper server to the 
+constructor of the parent class. The parent class creates a ZooKeeper instance if 
+one does not exist. The constructor of Barrier then creates a 
+barrier node on ZooKeeper, which is the parent node of all process nodes, and 
+we call root (<strong>Note:</strong> This is not the ZooKeeper root "/").</p>
+<pre class="code">
+ /**
+ * Barrier constructor
+ *
+ * @param address
+ * @param name
+ * @param size
+ */
+Barrier(String address, String name, int size) {
+    super(address);
+    this.root = name;
+    this.size = size;
+
+    // Create barrier node
+    if (zk != null) {
+	try {
+	    Stat s = zk.exists(root, false);
+	    if (s == null) {
+		zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+	    }
+	} catch (KeeperException e) {
+	    System.out.println("Keeper exception when instantiating queue: " + e.toString());
+	} catch (InterruptedException e) {
+	    System.out.println("Interrupted exception");
+	}
+    }
+
+    // My node name
+    try {
+	name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());
+    } catch (UnknownHostException e) {
+	System.out.println(e.toString());
+    }
+
+}
+</pre>
+<p>
+To enter the barrier, a process calls enter(). The process creates a node under 
+the root to represent it, using its host name to form the node name. It then wait 
+until enough processes have entered the barrier. A process does it by checking 
+the number of children the root node has with "getChildren()", and waiting for 
+notifications in the case it does not have enough. To receive a notification when 
+there is a change to the root node, a process has to set a watch, and does it 
+through the call to "getChildren()". In the code, we have that "getChildren()" 
+has two parameters. The first one states the node to read from, and the second is
+a boolean flag that enables the process to set a watch. In the code the flag is true.
+</p>
+<pre class="code">
+ /**
+ * Join barrier
+ *
+ * @return
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+
+boolean enter() throws KeeperException, InterruptedException{
+    zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,
+	    CreateFlags.EPHEMERAL);
+    while (true) {
+	synchronized (mutex) {
+	    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+
+	    if (list.size() &lt; size) {
+		mutex.wait();
+	    } else {
+		return true;
+	    }
+	}
+    }
+}
+</pre>
+<p>
+Note that enter() throws both KeeperException and InterruptedException, so it is 
+the reponsability of the application to catch and handle such exceptions.</p>
+<p>
+Once the computation is finished, a process calls leave() to leave the barrier. 
+First it deletes its corresponding node, and then it gets the children of the root 
+node. If there is at least one child, then it waits for a notification (obs: note 
+that the second parameter of the call to getChildren() is true, meaning that 
+ZooKeeper has to set a watch on the the root node). Upon reception of a notification, 
+it checks once more whether the root node has any child.</p>
+<pre class="code">
+ /**
+ * Wait until all reach barrier
+ *
+ * @return
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+
+boolean leave() throws KeeperException, InterruptedException{
+    zk.delete(root + "/" + name, 0);
+    while (true) {
+	synchronized (mutex) {
+	    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+		if (list.size() &gt; 0) {
+		    mutex.wait();
+		} else {
+		    return true;
+		}
+	    }
+	}
+}
+</pre>
+</div>
+
+<a name="N10051"></a><a name="sc_producerConsumerQueues"></a>
+<h2 class="h3">Producer-Consumer Queues</h2>
+<div class="section">
+<p>
+A producer-consumer queue is a distributed data estructure thata group of processes 
+use to generate and consume items. Producer processes create new elements and add 
+them to the queue. Consumer processes remove elements from the list, and process them. 
+In this implementation, the elements are simple integers. The queue is represented 
+by a root node, and to add an element to the queue, a producer process creates a new node, 
+a child of the root node.
+</p>
+<p>
+The following excerpt of code corresponds to the constructor of the object. As 
+with Barrier objects, it first calls the constructor of the parent class, SyncPrimitive, 
+that creates a ZooKeeper object if one doesn't exist. It then verifies if the root 
+node of the queue exists, and creates if it doesn't.
+</p>
+<pre class="code">
+/**
+ * Constructor of producer-consumer queue
+ *
+ * @param address
+ * @param name
+ */
+Queue(String address, String name) {
+    super(address);
+    this.root = name;
+    // Create ZK node name
+    if (zk != null) {
+	try {
+	    Stat s = zk.exists(root, false);
+	    if (s == null) {
+		zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+	    }
+	} catch (KeeperException e) {
+	    System.out
+		    .println("Keeper exception when instantiating queue: "
+			    + e.toString());
+	} catch (InterruptedException e) {
+	    System.out.println("Interrupted exception");
+	}
+    }
+}
+ </pre>
+<p>
+A producer process calls "produce()" to add an element to the queue, and passes 
+an integer as an argument. To add an element to the queue, the method creates a 
+new node using "create()", and uses the SEQUENCE flag to instruct ZooKeeper to 
+append the value of the sequencer counter associated to the root node. In this way, 
+we impose a total order on the elements of the queue, thus guaranteeing that the 
+oldest element of the queue is the next one consumed.
+</p>
+<pre class="code">
+/**
+ * Add element to the queue.
+ *
+ * @param i
+ * @return
+ */
+
+boolean produce(int i) throws KeeperException, InterruptedException{
+    ByteBuffer b = ByteBuffer.allocate(4);
+    byte[] value;
+
+    // Add child with value i
+    b.putInt(i);
+    value = b.array();
+    zk.create(root + "/element", value, Ids.OPEN_ACL_UNSAFE,
+		CreateFlags.SEQUENCE);
+
+    return true;
+}
+</pre>
+<p>
+To consume an element, a consumer process obtains the children of the root node, 
+reads the node with smallest counter value, and returns the element. Note that 
+if there is a conflict, then one of the two contending processes won't be able to 
+delete the node and the delete operation will throw an exception.</p>
+<p>
+A call to getChildren() returns the list of children in lexicographic order. 
+As lexicographic order does not necessary follow the numerical order of the counter 
+values, we need to decide which element is the smallest. To decide which one has 
+the smallest counter value, we traverse the list, and remove the prefix "element" 
+from each one.</p>
+<pre class="code">
+/**
+ * Remove first element from the queue.
+ *
+ * @return
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+int consume() throws KeeperException, InterruptedException{
+    int retvalue = -1;
+    Stat stat = null;
+
+    // Get the first element available
+    while (true) {
+	synchronized (mutex) {
+	    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+	    if (list.size() == 0) {
+		System.out.println("Going to wait");
+		mutex.wait();
+	    } else {
+		Integer min = new Integer(list.get(0).substring(7));
+		for(String s : list){
+		    Integer tempValue = new Integer(s.substring(7));
+		    if(tempValue &gt; min) min = tempValue;
+		}
+		System.out.println("Temporary value: " + root + "/element" + min);
+		byte[] b = zk.getData(root + "/element" + min, false, stat);
+		zk.delete(root + "/element" + min, 0);
+		ByteBuffer buffer = ByteBuffer.wrap(b);
+		retvalue = buffer.getInt();
+
+		return retvalue;
+	    }
+	}
+    }
+}
+</pre>
+</div>
+
+<a name="N1006F"></a><a name="sc_sourceListing"></a>
+<h2 class="h3">Complete Source Listing</h2>
+<div class="section">
+<div class="note example">
+<div class="label">SyncPrimitive.Java</div>
+<div class="content">
+
+<title>SyncPrimitive.Java</title>
+
+<pre class="code">
+package com.yahoo.SyncPrimitive;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.lang.InterruptedException;
+import java.util.ArrayList;
+import java.util.Random;
+
+import com.yahoo.zookeeper.Watcher;
+import com.yahoo.zookeeper.data.Stat;
+import com.yahoo.zookeeper.proto.WatcherEvent;
+import com.yahoo.zookeeper.KeeperException;
+import com.yahoo.zookeeper.ZooDefs.Ids;
+import com.yahoo.zookeeper.ZooDefs.CreateFlags;
+import com.yahoo.zookeeper.ZooKeeper;
+
+public class SyncPrimitive implements Watcher {
+
+    static ZooKeeper zk = null;
+    static Integer mutex;
+    
+    String root;
+
+    SyncPrimitive(String address) {
+        if(zk == null){
+            try {
+                System.out.println("Starting ZK:");
+                zk = new ZooKeeper(address, 3000, this);
+                mutex = new Integer(-1);
+                System.out.println("Finished starting ZK: " + zk);
+            } catch (KeeperException e) {
+                System.out.println("Keeper exception when starting new session: "
+                        + e.toString());
+                zk = null;
+            } catch (IOException e) {
+                System.out.println(e.toString());
+                zk = null;
+            }
+        }
+        //else mutex = new Integer(-1);
+    }
+
+    synchronized public void process(WatcherEvent event) {
+        synchronized (mutex) {
+            //System.out.println("Process: " + event.getType());
+            mutex.notify();
+        }
+    }
+
+    /**
+     * Barrier
+     */
+    static public class Barrier extends SyncPrimitive {
+        int size;
+        String name;
+
+        /**
+         * Barrier constructor
+         * 
+         * @param address
+         * @param name
+         * @param size
+         */
+        Barrier(String address, String name, int size) {
+            super(address);
+            this.root = name;
+            this.size = size;
+
+            // Create barrier node
+            if (zk != null) {
+                try {
+                    Stat s = zk.exists(root, false);
+                    if (s == null) {
+                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+                    }
+                } catch (KeeperException e) {
+                    System.out
+                            .println("Keeper exception when instantiating queue: "
+                                    + e.toString());
+                } catch (InterruptedException e) {
+                    System.out.println("Interrupted exception");
+                }
+            }
+            
+            // My node name
+            try {
+                name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());
+            } catch (UnknownHostException e) {
+                System.out.println(e.toString());
+            }
+            
+        }
+
+        /**
+         * Join barrier
+         * 
+         * @return
+         * @throws KeeperException
+         * @throws InterruptedException
+         */
+        
+        boolean enter() throws KeeperException, InterruptedException{
+            zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,
+                    CreateFlags.EPHEMERAL);
+            while (true) {
+                synchronized (mutex) {                    
+                    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+       
+                    if (list.size() &lt; size) {
+                        mutex.wait();
+                    } else {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Wait until all reach barrier
+         * 
+         * @return
+         * @throws KeeperException
+         * @throws InterruptedException
+         */
+        
+        boolean leave() throws KeeperException, InterruptedException{
+            zk.delete(root + "/" + name, 0);
+            while (true) {
+                synchronized (mutex) {
+                    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+                        if (list.size() &gt; 0) {
+                            mutex.wait();
+                        } else {
+                            return true;
+                        }
+                    }
+                }
+        }
+    }
+
+    /**
+     * Producer-Consumer queue
+     */
+    static public class Queue extends SyncPrimitive {
+
+        /**
+         * Constructor of producer-consumer queue
+         * 
+         * @param address
+         * @param name
+         */
+        Queue(String address, String name) {
+            super(address);
+            this.root = name;
+            // Create ZK node name
+            if (zk != null) {
+                try {
+                    Stat s = zk.exists(root, false);
+                    if (s == null) {
+                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+                    }
+                } catch (KeeperException e) {
+                    System.out
+                            .println("Keeper exception when instantiating queue: "
+                                    + e.toString());
+                } catch (InterruptedException e) {
+                    System.out.println("Interrupted exception");
+                }
+            }
+        }
+
+        /**
+         * Add element to the queue.
+         * 
+         * @param i
+         * @return
+         */
+        
+        boolean produce(int i) throws KeeperException, InterruptedException{
+            ByteBuffer b = ByteBuffer.allocate(4);
+            byte[] value;
+
+            // Add child with value i
+            b.putInt(i);
+            value = b.array();
+            zk.create(root + "/element", value, Ids.OPEN_ACL_UNSAFE,
+                        CreateFlags.SEQUENCE);
+            
+            return true;
+        }
+
+
+        /**
+         * Remove first element from the queue.
+         * 
+         * @return
+         * @throws KeeperException
+         * @throws InterruptedException
+         */
+        int consume() throws KeeperException, InterruptedException{
+            int retvalue = -1;
+            Stat stat = null;
+            
+            // Get the first element available
+            while (true) {
+                synchronized (mutex) {
+                    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+                    if (list.size() == 0) {
+                        System.out.println("Going to wait");
+                        mutex.wait();
+                    } else {
+                        Integer min = new Integer(list.get(0).substring(7));
+                        for(String s : list){
+                            Integer tempValue = new Integer(s.substring(7));
+                            //System.out.println("Temporary value: " + tempValue);
+                            if(tempValue &lt; min) min = tempValue;
+                        }
+                        System.out.println("Temporary value: " + root + "/element" + min);
+                        byte[] b = zk.getData(root + "/element" + min,
+                                    false, stat);
+                        zk.delete(root + "/element" + min, 0);
+                        ByteBuffer buffer = ByteBuffer.wrap(b);
+                        retvalue = buffer.getInt();
+                        
+                        return retvalue;
+                    }
+                }
+            }           
+        }
+    }
+
+    public static void main(String args[]) {
+        if (args[0].equals("qTest"))
+            queueTest(args);
+        else
+            barrierTest(args);
+
+    }
+
+    public static void queueTest(String args[]) {
+        Queue q = new Queue(args[1], "/app1");
+
+        System.out.println("Input: " + args[1]);
+        int i;
+        Integer max = new Integer(args[2]);
+
+        if (args[3].equals("p")) {
+            System.out.println("Producer");
+            for (i = 0; i &lt; max; i++)
+                try{    
+                    q.produce(10 + i);
+                } catch (KeeperException e){
+                    
+                } catch (InterruptedException e){
+                    
+                }
+        } else {
+            System.out.println("Consumer");
+   
+            for (i = 0; i &lt; max; i++) {
+                try{
+                    int r = q.consume();
+                    System.out.println("Item: " + r);
+                } catch (KeeperException e){
+                    i--;
+                } catch (InterruptedException e){
+                    
+                }
+            }
+        }
+    }
+
+    public static void barrierTest(String args[]) {
+        Barrier b = new Barrier(args[1], "/b1", new Integer(args[2]));
+        try{
+            boolean flag = b.enter();
+            System.out.println("Entered barrier: " + args[2]);
+            if(!flag) System.out.println("Error when entering the barrier");
+        } catch (KeeperException e){
+            
+        } catch (InterruptedException e){
+            
+        }
+
+        // Generate random integer
+        Random rand = new Random();
+        int r = rand.nextInt(100);
+        // Loop for rand iterations
+        for (int i = 0; i &lt; r; i++) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+
+            }
+        }
+        try{
+            b.leave();
+        } catch (KeeperException e){
+            
+        } catch (InterruptedException e){
+            
+        }
+        System.out.println("Left barrier");
+    }
+}</pre>
+</div>
+</div>
+</div>
+
+
+<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>

Разница между файлами не показана из-за своего большого размера
+ 89 - 0
docs/zookeeperTutorial.pdf


+ 3 - 0
src/docs/src/documentation/content/xdocs/index.xml

@@ -38,6 +38,9 @@ The following documents provide concepts and procedures to get you started using
       <li><a href="zookeeperProgrammers.html">Programmer's Guide</a> - an application developer's guide to ZooKeeper</li>
       <li><a href="zookeeperProgrammers.html">Programmer's Guide</a> - an application developer's guide to ZooKeeper</li>
       <li><a href="recipes.html">ZooKeeper Recipes</a> - a set of common, higher level solutions using ZooKeeper</li>
       <li><a href="recipes.html">ZooKeeper Recipes</a> - a set of common, higher level solutions using ZooKeeper</li>
       <li><a href="zookeeperAdmin.html">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy Zookeeer</li>
       <li><a href="zookeeperAdmin.html">Administrator's Guide</a> - a guide for system administrators and anyone else who might deploy Zookeeer</li>
+      <li><a href="javaExample.html">ZooKeeper Java Example</a> - A simple Zookeeer Client, written in Java</li>
+      <li><a href="zookeeperTutorial.html">Barrier and Queue Tutorial</a> - Simple Implementations of Barriers and Queues</li>
+      <li><a href="zookeeperInternals.html">ZooKeeper Internals</a> - Assorted Topics on the Inner Workings of ZooKeeper</li>
       <li><a href="ext:api/index">API Docs</a> - the technical reference to ZooKeeper APIs</li>
       <li><a href="ext:api/index">API Docs</a> - the technical reference to ZooKeeper APIs</li>
       <li><a href="ext:wiki">Wiki</a> - miscellaneous, informal ZooKeeper documentation, in Wiki format</li>
       <li><a href="ext:wiki">Wiki</a> - miscellaneous, informal ZooKeeper documentation, in Wiki format</li>
       <li><a href="ext:faq">FAQ</a> - frequently asked questions</li>    
       <li><a href="ext:faq">FAQ</a> - frequently asked questions</li>    

+ 672 - 0
src/docs/src/documentation/content/xdocs/javaExample.xml

@@ -0,0 +1,672 @@
+<?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="ar_JavaExample">
+  <title>ZooKeeper Java Example</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 article contains sample Java code for a simple watch client.</para>
+
+    </abstract>
+  </articleinfo>
+
+  <section id="ch_Introduction">
+    <title>A Simple Watch Client</title>
+
+    <para>To introduce you to the ZooKeeper Java API, we develop here a very simple 
+    watch client. This ZooKeeper client watches a ZooKeeper node for changes 
+    and responds to by starting or stopping a program.</para>
+    
+    <section id="sc_requirements"><title>Requirements</title>
+    
+    <para>The client has four requirements:</para>
+    
+    <itemizedlist><listitem><para>It takes as parameters:</para>
+    	<itemizedlist>
+		<listitem><para>the address of the ZooKeeper service</para></listitem>
+		<listitem> <para> a znode, by name</para></listitem>
+		<listitem><para> an executable with arguments.</para></listitem></itemizedlist></listitem>
+	<listitem><para>It fetches the data associated with the znode and starts the executable.</para></listitem>
+	<listitem><para>If the znode changes, the client refetches the contents and restarts the executable.</para></listitem>
+	<listitem><para>If the znode disappears, the client kills the executable.</para></listitem></itemizedlist>
+
+   </section>
+   
+   <section id="sc_design">
+   	<title>Program Design</title>
+
+   <para>Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection, 
+   and the other which monitors data.  In this application, the class called the <emphasis role="bold">Executor</emphasis> 
+   maintains the ZooKeeper connection, and the class called the  <emphasis role="bold">DataMonitor</emphasis> monitors the data
+   in the ZooKeeper tree. Also, Executor contains the main thread and contains the execution logic.
+   It is responsible for what little user interaction there is, as well as interaction with the exectuable program you
+   pass in as an argument and which the sample (per the requirements) shuts down and restarts, according to the 
+   state of the znode.</para>
+   
+   </section>
+  
+   </section>
+
+   <section id="sc_executor"><title>The Executor Class</title>
+    <para>The Executor object is the primary container of the sample application. It contains 
+    both the <emphasis role="bold">ZooKeeper</emphasis> object, <emphasis role="bold">DataMonitor</emphasis>, as described above in 
+    <xref linkend="sc_design"/>.  </para>
+    
+    <programlisting>
+// from the Executor class...
+    
+public static void main(String[] args) {
+    if (args.length &lt; 4) {
+        System.err
+                .println("USAGE: Executor hostPort znode filename program [args ...]");
+        System.exit(2);
+    }
+    String hostPort = args[0];
+    String znode = args[1];
+    String filename = args[2];
+    String exec[] = new String[args.length - 3];
+    System.arraycopy(args, 3, exec, 0, exec.length);
+    try {
+        Executor theExectutor = new Executor(hostPort, znode, filename, exec);
+	theExectutor.run();
+    } catch (Exception e) {
+        e.printStackTrace();
+    }
+}
+    
+public Executor(String hostPort, String znode, String filename,
+    String exec[]) throws KeeperException, IOException {
+    this.filename = filename;
+    this.exec = exec;
+    
+    //create a new zookeeper object, passing a self-reference in a the Watcher
+    zk = new ZooKeeper(hostPort, 3000, this);
+    dm = new DataMonitor(zk, znode, null, this);
+}
+   
+public void run() {
+    try {
+        synchronized (this) {
+            while (!dm.dead) {
+                wait();
+            }
+        }
+    } catch (InterruptedException e) {    
+    }
+}
+</programlisting>
+
+
+    <para>
+    Recall that the Executor's job is to starts and stop the executable whose name you pass in on the command line. 
+    It does this in response to events fired by the ZooKeeper object. As you can see in the code above, the Executor passes
+    a reference to itself as the Watcher argument in the ZooKeeper constructor. It also passes a reference to itself
+    as DataMonitorListener argument to the DataMonitor constructor. Per the Executor's definition, it implements both these
+    interfaces:
+    </para>
+    
+    <programlisting>
+public class Executor implements Watcher, Runnable, DataMonitorListener {
+...
+    </programlisting>
+    
+    <para>The <emphasis role="bold">Watcher</emphasis> interface is defined by the ZooKeeper Java API.
+    ZooKeeper uses it to communicate back to its container. It supports only one method, <command>process()</command>, and ZooKeeper uses 
+    it to communciates generic events that the main thread would be intersted in, such as the state of the ZooKeeper connection or the ZooKeeper session.The Executor 
+    in this example simply forwards those events down to the DataMonitor to decide what to do with them. It does this simply to illustrate
+    the point that, by convention, the Executor or some Executor-like object "owns" the ZooKeeper connection, but it is free to delegate the events to other
+    events to other objects. It also uses this as the default channel on which to fire watch events. (More on this later.)</para>
+    
+<programlisting>
+public void process(WatcherEvent event) {
+    dm.process(event);
+}
+</programlisting>
+    
+    <para>The <emphasis role="bold">DataMonitorListener</emphasis> 
+    interface, on the other hand, is not part of the the ZooKeeper API. It is a completely custom interface, 
+    designed for this sample application. The DataMonitor object uses it to communicate back to its container, which
+    is also the the Executor object.The DataMonitorListener interface looks like this:</para>
+    <programlisting>
+public interface DataMonitorListener {
+    /**
+    * The existence status of the node has changed.
+    */
+    void exists(byte data[]);
+
+    /**
+    * The ZooKeeper session is no longer valid.
+    * 
+    * @param rc
+    * the ZooKeeper reason code
+    */
+    void closing(int rc);
+}
+</programlisting>
+    <para>This interface is defined in the DataMonitor class and implemented in the Executor class. 
+    When <command>Executor.exists()</command> is invoked,
+    the Executor decides whether to start up or shut down per the requirements. Recall that the requires say to kill the executable when the 
+    znode ceases to <emphasis>exist</emphasis>. </para>
+    
+    <para>When <command>Executor.closing()</command>
+    is invoked, the Executor decides whether or not to shut itself down in response to the ZooKeeper connection permanently disappearing.</para>
+    
+    <para>As you might have guessed, DataMonitor is the object that invokes 
+    these methods, in response to changes in ZooKeeper's state.</para>
+    
+    <para>Here are Executor's implementation of 
+    <command>DataMonitorListener.exists()</command> and <command>DataMonitorListener.closing</command>:
+    </para>
+    <programlisting>
+public void exists( byte[] data ) {
+    if (data == null) {
+        if (child != null) {
+            System.out.println("Killing process");
+            child.destroy();
+            try {
+                child.waitFor();
+            } catch (InterruptedException e) {
+            }
+        }
+        child = null;
+    } else {
+        if (child != null) {
+            System.out.println("Stopping child");
+            child.destroy();
+            try {
+               child.waitFor();
+            } catch (InterruptedException e) {
+            e.printStackTrace();
+            }
+        }
+        try {
+            FileOutputStream fos = new FileOutputStream(filename);
+            fos.write(data);
+            fos.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        try {
+            System.out.println("Starting child");
+            child = Runtime.getRuntime().exec(exec);
+            new StreamWriter(child.getInputStream(), System.out);
+            new StreamWriter(child.getErrorStream(), System.err);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
+
+public void closing(int rc) {
+    synchronized (this) {
+        notifyAll();
+    }
+}
+</programlisting>
+    
+</section>
+<section id="sc_DataMonitor"><title>The DataMonitor Class</title>
+<para>
+The DataMonitor class has the meat of the ZooKeeper logic. It is mostly 
+asynchronous and event driven. DataMonitor kicks things off in the constructor with:</para>
+<programlisting>
+public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
+        DataMonitorListener listener) {
+    this.zk = zk;
+    this.znode = znode;
+    this.chainedWatcher = chainedWatcher;
+    this.listener = listener;
+    
+    // Get things started by checking if the node exists. We are going
+    // to be completely event driven
+    <emphasis role="bold">zk.exists(znode, true, this, null);</emphasis>
+}
+</programlisting>
+
+<para>The call to <command>ZooKeeper.exists()</command> checks for the existence of the znode, 
+sets a watch, and passes a reference to itself (<command>this</command>)
+as the completion callback object. In this sense, it kicks things off, since the
+real processing happens when the watch is triggered.</para>
+
+<note>
+<para>Don't confuse the completion callback with the watch callback. The <command>ZooKeeper.exists()</command> 
+completion callback, which happens to be the method <command>StatCallback.processResult()</command> implemented 
+in the DataMonitor object, is invoked when the asynchronous <emphasis>setting of the watch</emphasis> operation 
+(by <command>ZooKeeper.exists()</command>) completes on the server. </para>
+<para>
+The triggering of the watch, on the other hand, sends an event to the <emphasis>Executor</emphasis> object, since
+the Executor registered as the Watcher of the ZooKeeper object.</para>
+
+<para>As an aside, you might note that the DataMonitor could also register itself as the Watcher
+for this particular watch event. This is new to ZooKeeper 3.0.0 (the support of multiple Watchers). In this
+example, however, DataMonitor does not register as the Watcher.</para>
+</note>
+
+<para>When the <command>ZooKeeper.exists()</command> operation completes on the server, the ZooKeeper API invokes this completion callback on 
+the client:</para>
+
+<programlisting>
+public void processResult(int rc, String path, Object ctx, Stat stat) {
+    boolean exists;
+    switch (rc) {
+    case Code.Ok:
+        exists = true;
+        break;
+    case Code.NoNode:
+        exists = false;
+        break;
+    case Code.SessionExpired:
+    case Code.NoAuth:
+        dead = true;
+        listener.closing(rc);
+        return;
+    default:
+        // Retry errors
+        zk.exists(znode, true, this, null);
+        return;
+    }
+ 
+    byte b[] = null;
+    if (exists) {
+        try {
+            <emphasis role="bold">b = zk.getData(znode, false, null);</emphasis>
+        } catch (KeeperException e) {
+            // We don't need to worry about recovering now. The watch
+            // callbacks will kick off any exception handling
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            return;
+        }
+    }     
+    if ((b == null &amp;&amp; b != prevData)
+            || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {
+        <emphasis role="bold">listener.exists(b);</emphasis>
+        prevData = b;
+    }
+}
+</programlisting>
+
+<para>
+The code first checks the error codes for znode existence, fatal errors, and 
+recoverable errors. If the file (or znode) exists, it gets the data from the znode, and 
+then invoke the exists() callback of Executor if the state has changed. Note, 
+it doesn't have to do any Exception processing for the getData call because it 
+has watches pending for anything that could cause an error: if the node is deleted 
+before it calls <command>ZooKeeper.getData()</command>, the watch event set by 
+the <command>ZooKeeper.exists()</command> triggers a callback; 
+if there is a communication error, a connection watch event fires when 
+the connection comes back up.
+</para>
+
+<para>Finally, notice how DataMonitor processes watch events: </para>
+<programlisting>
+public void process(WatcherEvent event) {
+    String path = event.getPath();
+    if (event.getType() == Watcher.Event.EventNone) {
+        // We are are being told that the state of the
+        // connection has changed
+        switch (event.getState()) {
+        case Event.KeeperStateSyncConnected:
+            // Everything is happy. Lets kick things off
+            // again by checking the existence of the znode
+            zk.exists(znode, true, this, null);
+            break;
+        case Event.KeeperStateExpired:
+            // It's all over
+            dead = true;
+            listener.closing(KeeperException.Code.SessionExpired);
+            break;
+        }
+    } else {
+        if (path != null &amp;&amp; path.equals(znode)) {
+            // Something has changed on the node, let's find out
+            zk.exists(znode, true, this, null);
+        }
+   }
+   if (chainedWatcher != null) {
+        chainedWatcher.process(event);
+   }
+}
+</programlisting>
+<para>
+If the client-side ZooKeeper libraries can reestablish the communication channel to ZooKeeper, DataMonitor simply kicks
+everything off again with the call to <command>ZooKeeper.exists()</command>. 
+If it gets an event for a znode, it calls <command>ZooKeeper.exists()</command> to find out what has changed.
+</para>
+</section>
+
+<section id="sc_completeSourceCode">
+	<title>Complete Source Listings</title>
+	<example id="eg_Executor_java"><title>Executor.java</title><programlisting>
+/**
+ * A simple example program to use DataMonitor to start and
+ * stop executables based on a znode. The program watches the
+ * specified znode and saves the data that corresponds to the
+ * znode in the filesystem. It also starts the specified program
+ * with the specified arguments when the znode exists and kills
+ * the program if the znode goes away.
+ */
+package com.yahoo.zk.executor;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.yahoo.zk.executor.DataMonitor.DataMonitorListener;
+import com.yahoo.zookeeper.KeeperException;
+import com.yahoo.zookeeper.Watcher;
+import com.yahoo.zookeeper.ZooKeeper;
+import com.yahoo.zookeeper.proto.WatcherEvent;
+
+public class Executor implements Watcher, Runnable, DataMonitorListener {
+    String znode;
+
+    DataMonitor dm;
+
+    ZooKeeper zk;
+
+    String filename;
+
+    String exec[];
+
+    Process child;
+
+    public Executor(String hostPort, String znode, String filename,
+            String exec[]) throws KeeperException, IOException {
+        this.filename = filename;
+        this.exec = exec;
+        zk = new ZooKeeper(hostPort, 3000, this);
+        dm = new DataMonitor(zk, znode, null, this);
+    }
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        if (args.length &lt; 4) {
+            System.err
+                    .println("USAGE: Executor hostPort znode filename program [args ...]");
+            System.exit(2);
+        }
+        String hostPort = args[0];
+        String znode = args[1];
+        String filename = args[2];
+        String exec[] = new String[args.length - 3];
+        System.arraycopy(args, 3, exec, 0, exec.length);
+        try {
+            new Executor(hostPort, znode, filename, exec).run();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /***************************************************************************
+     * We do process any events ourselves, we just need to forward them on.
+     * 
+     * @see com.yahoo.zookeeper.Watcher#process(com.yahoo.zookeeper.proto.WatcherEvent)
+     */
+    @Override
+    public void process(WatcherEvent event) {
+        dm.process(event);
+    }
+
+    @Override
+    public void run() {
+        try {
+            synchronized (this) {
+                while (!dm.dead) {
+                    wait();
+                }
+            }
+        } catch (InterruptedException e) {
+        }
+    }
+
+    @Override
+    public void closing(int rc) {
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    static class StreamWriter extends Thread {
+        OutputStream os;
+
+        InputStream is;
+
+        StreamWriter(InputStream is, OutputStream os) {
+            this.is = is;
+            this.os = os;
+            start();
+        }
+
+        public void run() {
+            byte b[] = new byte[80];
+            int rc;
+            try {
+                while ((rc = is.read(b)) > 0) {
+                    os.write(b, 0, rc);
+                }
+            } catch (IOException e) {
+            }
+
+        }
+    }
+
+    @Override
+    public void exists(byte[] data) {
+        if (data == null) {
+            if (child != null) {
+                System.out.println("Killing process");
+                child.destroy();
+                try {
+                    child.waitFor();
+                } catch (InterruptedException e) {
+                }
+            }
+            child = null;
+        } else {
+            if (child != null) {
+                System.out.println("Stopping child");
+                child.destroy();
+                try {
+                    child.waitFor();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            try {
+                FileOutputStream fos = new FileOutputStream(filename);
+                fos.write(data);
+                fos.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            try {
+                System.out.println("Starting child");
+                child = Runtime.getRuntime().exec(exec);
+                new StreamWriter(child.getInputStream(), System.out);
+                new StreamWriter(child.getErrorStream(), System.err);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
+</programlisting>
+	
+</example>
+
+<example id="eg_DataMonitor_java">
+	<title>DataMonitor.java</title>
+	<programlisting>
+/**
+ * A simple class that monitors the data and existence of a ZooKeeper
+ * node. It uses asynchronous ZooKeeper APIs.
+ */
+package com.yahoo.zk.executor;
+
+import java.util.Arrays;
+
+import com.yahoo.zookeeper.KeeperException;
+import com.yahoo.zookeeper.Watcher;
+import com.yahoo.zookeeper.ZooKeeper;
+import com.yahoo.zookeeper.AsyncCallback.StatCallback;
+import com.yahoo.zookeeper.KeeperException.Code;
+import com.yahoo.zookeeper.data.Stat;
+import com.yahoo.zookeeper.proto.WatcherEvent;
+
+public class DataMonitor implements Watcher, StatCallback {
+
+    ZooKeeper zk;
+
+    String znode;
+
+    Watcher chainedWatcher;
+
+    boolean dead;
+
+    DataMonitorListener listener;
+
+    byte prevData[];
+
+    public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
+            DataMonitorListener listener) {
+        this.zk = zk;
+        this.znode = znode;
+        this.chainedWatcher = chainedWatcher;
+        this.listener = listener;
+        // Get things started by checking if the node exists. We are going
+        // to be completely event driven
+        zk.exists(znode, true, this, null);
+    }
+
+    /**
+     * Other classes use the DataMonitor by implementing this method
+     */
+    public interface DataMonitorListener {
+        /**
+         * The existence status of the node has changed.
+         */
+        void exists(byte data[]);
+
+        /**
+         * The ZooKeeper session is no longer valid.
+         * 
+         * @param rc
+         *                the ZooKeeper reason code
+         */
+        void closing(int rc);
+    }
+
+    @Override
+    /**
+     * This is a watch event callback. The node we were watching has changed or
+     * something happened to our connection to ZooKeeper.
+     */
+    public void process(WatcherEvent event) {
+        String path = event.getPath();
+        if (event.getType() == Watcher.Event.EventNone) {
+            // We are are being told that the state of the
+            // connection has changed
+            switch (event.getState()) {
+            case Event.KeeperStateSyncConnected:
+                // Everything is happy. Lets kick things off
+                // again by checking the existence of the znode
+                zk.exists(znode, true, this, null);
+                break;
+            case Event.KeeperStateExpired:
+                // It's all over
+                dead = true;
+                listener.closing(KeeperException.Code.SessionExpired);
+                break;
+            }
+        } else {
+            if (path != null &amp;&amp; path.equals(znode)) {
+                // Something has changed on the node, let's find out
+                zk.exists(znode, true, this, null);
+            }
+        }
+        if (chainedWatcher != null) {
+            chainedWatcher.process(event);
+        }
+    }
+
+    @Override
+    public void processResult(int rc, String path, Object ctx, Stat stat) {
+        boolean exists;
+        switch (rc) {
+        case Code.Ok:
+            exists = true;
+            break;
+        case Code.NoNode:
+            exists = false;
+            break;
+        case Code.SessionExpired:
+        case Code.NoAuth:
+            dead = true;
+            listener.closing(rc);
+            return;
+        default:
+            // Retry errors
+            zk.exists(znode, true, this, null);
+            return;
+        }
+
+        byte b[] = null;
+        if (exists) {
+            try {
+                b = zk.getData(znode, false, null);
+            } catch (KeeperException e) {
+                // We don't need to worry about recovering now. The watch
+                // callbacks will kick off any exception handling
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                return;
+            }
+        }
+        if ((b == null &amp;&amp; b != prevData)
+                || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {
+            listener.exists(b);
+            prevData = b;
+        }
+    }
+}
+</programlisting>
+</example>
+</section>
+
+
+
+</article>

+ 3 - 0
src/docs/src/documentation/content/xdocs/site.xml

@@ -38,6 +38,9 @@ See http://forrest.apache.org/docs/linking.html for more info.
     <program   label="Programmer's Guide"     href="zookeeperProgrammers.html" />
     <program   label="Programmer's Guide"     href="zookeeperProgrammers.html" />
     <recipes   label="Recipes"		      href="recipes.html" />
     <recipes   label="Recipes"		      href="recipes.html" />
     <admin     label="Administrator's Guide"  href="zookeeperAdmin.html" />
     <admin     label="Administrator's Guide"  href="zookeeperAdmin.html" />
+    <javaEx    label="Java Example"     href="javaExample.html" />
+    <barTutor  label="Barrie and Queue Tutorial" href="zookeeperTutorial.html" />
+    <internals label="ZooKeeper Internals"	href="zookeeperInternals.html" />
     <api       label="API Docs"               href="ext:api/index" />
     <api       label="API Docs"               href="ext:api/index" />
     <wiki      label="Wiki"                   href="ext:wiki" />
     <wiki      label="Wiki"                   href="ext:wiki" />
     <faq       label="FAQ"                    href="ext:faq" />
     <faq       label="FAQ"                    href="ext:faq" />

+ 10 - 2
src/docs/src/documentation/content/xdocs/zookeeperAdmin.xml

@@ -116,7 +116,6 @@
           <para>Install the ZooKeeper Server Package. It can be downloaded
           <para>Install the ZooKeeper Server Package. It can be downloaded
             from:
             from:
           </para>
           </para>
-
           <para>
           <para>
             <ulink url="http://hadoop.apache.org/zookeeper/releases.html">
             <ulink url="http://hadoop.apache.org/zookeeper/releases.html">
               http://hadoop.apache.org/zookeeper/releases.html
               http://hadoop.apache.org/zookeeper/releases.html
@@ -312,7 +311,16 @@ server.3=zoo3:2888</computeroutput></para>
     <section id="sc_logging">
     <section id="sc_logging">
       <title>Logging</title>
       <title>Logging</title>
 
 
-      <para></para>
+      <para>ZooKeeper uses <emphasis role="bold">log4j</emphasis> version 1.2 as 
+      its logging infrastructure. The  ZooKeeper default <filename>log4j.properties</filename> 
+      file resides in the <filename>conf</filename> directory. Log4j requires that 
+      <filename>log4j.properties</filename> either be in the working directory 
+      (the directory from which ZooKeeper is run) or be accessible from the classpath.</para>
+
+      <para>For more information, see 
+      <ulink url="http://logging.apache.org/log4j/1.2/manual.html#defaultInit">Log4j Default Initialization Procedure</ulink> 
+      of the log4j manual.</para>
+      
     </section>
     </section>
 
 
     <section id="sc_troubleshooting">
     <section id="sc_troubleshooting">

+ 447 - 0
src/docs/src/documentation/content/xdocs/zookeeperInternals.xml

@@ -0,0 +1,447 @@
+<?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="ar_ZooKeeperInternals">
+  <title>ZooKeeper Internals</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 article contains topics which discuss the inner workings of
+       ZooKeeper. So far, that's logging and atomic broadcast. </para>
+
+    </abstract>
+  </articleinfo>
+
+  <section id="ch_Introduction">
+    <title>Introduction</title>
+
+    <para>This document contains information on the inner workings of ZooKeeper. 
+    So far, it discusses these topics:
+    </para>
+
+<itemizedlist>    
+<listitem><para><xref linkend="sc_atomicBroadcast"/></para></listitem>
+<listitem><para><xref linkend="sc_logging"/></para></listitem>
+</itemizedlist>
+
+</section>
+
+<section id="sc_atomicBroadcast">
+<title>Atomic Broadcast</title>
+
+<para>
+At the heart of ZooKeeper is an atomic messaging system that keeps all of the servers in sync.</para>
+
+<section id="sc_guaranteesPropertiesDefinitions"><title>Guarantees, Properties, and Definitions</title>
+<para>
+The specific guarantees provided by the messaging system used by ZooKeeper are the following:</para>
+
+<variablelist>
+
+<varlistentry><term><emphasis >Reliable delivery</emphasis></term>
+<listitem><para>If a message, m, is delivered 
+by one server, it will be eventually delivered by all servers.</para></listitem></varlistentry>
+
+<varlistentry><term><emphasis >Total order</emphasis></term>
+<listitem><para> If a message is 
+delivered before message b by one server, a will be delivered before b by all 
+servers. If a and b are delivered messages, either a will be delivered before b 
+or b will be delivered before a.</para></listitem></varlistentry>
+
+<varlistentry><term><emphasis >Causal order</emphasis> </term>
+
+<listitem><para>
+If a message b is sent after a message a has been delivered by the sender of b, 
+a must be ordered before b. If a sender sends c after sending b, c must be ordered after b.
+</para></listitem></varlistentry>
+
+</variablelist>
+
+
+<para>
+The ZooKeeper messaging system also needs to be efficient, reliable, and easy to 
+implement and maintain. We make heavy use of messaging, so we need the system to 
+be able to handle thousands of requests per second. Although we can require at 
+least k+1 correct servers to send new messages, we must be able to recover from 
+correlated failures such as power outages. When we implemented the system we had 
+little time and few engineering resources, so we needed a protocol that is 
+accessible to engineers and is easy to implement. We found that our protocol 
+satisfied all of these goals.
+
+</para>
+
+<para>
+Our protocol assumes that we can construct point-to-point FIFO channels between 
+the servers. While similar services usually assume message delivery that can 
+lose or reorder messages, our assumption of FIFO channels is very practical 
+given that we use TCP for communication. Specifically we rely on the following property of TCP:</para>
+
+<variablelist>
+
+<varlistentry>
+<term><emphasis >Ordered delivery</emphasis></term>
+<listitem><para>Data is delivered in the same order it is sent and a message m is 
+delivered only after all messages sent before m have been delivered. 
+(The corollary to this is that if message m is lost all messages after m will be lost.)</para></listitem></varlistentry>
+
+<varlistentry><term><emphasis >No message after close</emphasis></term>
+<listitem><para>Once a FIFO channel is closed, no messages will be received from it.</para></listitem></varlistentry>
+
+</variablelist>
+
+<para>
+FLP proved that consensus cannot be achieved in asynchronous distributed systems 
+if failures are possible. To ensure we achieve consensus in the presence of failures 
+we use timeouts. However, we rely on times for liveness not for correctness. So, 
+if timeouts stop working (clocks malfunction for example) the messaging system may 
+hang, but it will not violate its guarantees.</para>
+
+<para>When describing the ZooKeeper messaging protocol we will talk of packets, 
+proposals, and messages:</para>
+<variablelist>
+<varlistentry><term><emphasis >Packet</emphasis></term>
+<listitem><para>a sequence of bytes sent through a FIFO channel</para></listitem></varlistentry><varlistentry>
+
+<term><emphasis >Proposal</emphasis></term>
+<listitem><para>a unit of agreement. Proposals are agreed upon by exchanging packets 
+with a quorum of ZooKeeper servers. Most proposals contain messages, however the 
+NEW_LEADER proposal is an example of a proposal that does not correspond to a message.</para></listitem>
+</varlistentry><varlistentry>
+
+<term><emphasis >Message</emphasis></term>
+<listitem><para>a sequence of bytes to be atomically broadcast to all ZooKeeper 
+servers. A message put into a proposal and agreed upon before it is delivered.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>
+As stated above, ZooKeeper guarantees a total order of messages, and it also 
+guarantees a total order of proposals. ZooKeeper exposes the total ordering using
+a ZooKeeper transaction id (<emphasis>zxid</emphasis>). All proposals will be stamped with a zxid when 
+it is proposed and exactly reflects the total ordering. Proposals are sent to all 
+ZooKeeper servers and committed when a quorum of them acknowledge the proposal. 
+If a proposal contains a message, the message will be delivered when the proposal 
+is committed. Acknowledgement means the server has recorded the proposal to persistent storage. 
+Our quorums have the requirement that any pair of quorum must have at least one server 
+in common. We ensure this by requiring that all quorums have size (<emphasis>n/2+1</emphasis>) where 
+n is the number of servers that make up a ZooKeeper service.
+</para>
+
+<para>
+The zxid has two parts: the epoch and a counter. In our implementation the zxid 
+is a 64-bit number. We use the high order 32-bits for the epoch and the low order 
+32-bits for the counter. Because it has two parts represent the zxid both as a 
+number and as a pair of integers, (<emphasis>epoch, count</emphasis>). The epoch number represents a 
+change in leadership. Each time a new leader comes into power it will have its 
+own epoch number. We have a simple algorithm to assign a unique zxid to a proposal: 
+the leader simply increments the zxid to obtain a unique zxid for each proposal. 
+<emphasis>Leadership activation will ensure that only one leader uses a given epoch, so our 
+simple algorithm guarantees that every proposal will have a unique id.</emphasis>
+</para>
+
+<para>
+ZooKeeper messaging consists of two phases:</para>
+
+<variablelist>
+<varlistentry><term><emphasis >Leader activation</emphasis></term>
+<listitem><para>In this phase a leader establishes the correct state of the system 
+and gets ready to start making proposals.</para></listitem>
+</varlistentry>
+
+<varlistentry><term><emphasis >Active messaging</emphasis></term>
+<listitem><para>In this phase a leader accepts messages to propose and coordinates message delivery.</para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+ZooKeeper is a holistic protocol. We do not focus on individual proposals, rather 
+look at the stream of proposals as a whole. Our strict ordering allows us to do this 
+efficiently and greatly simplifies our protocol. Leadership activation embodies 
+this holistic concept. A leader becomes active only when a quorum of followers 
+(The leader counts as a follower as well. You can always vote for yourself ) has synced 
+up with the leader, they have the same state. This state consists of all of the 
+proposals that the leader believes have been committed and the proposal to follow 
+the leader, the NEW_LEADER proposal. (Hopefully you are thinking to 
+yourself, <emphasis>Does the set of proposals that the leader believes has been committed 
+included all the proposals that really have been committed?</emphasis> The answer is <emphasis>yes</emphasis>. 
+Below, we make clear why.)
+</para>
+
+</section>
+
+<section id="sc_leaderElection">
+
+<title>Leader Activation</title>
+<para>
+Leader activation includes leader election. We currently have two leader election 
+algorithms in ZooKeeper: LeaderElection and FastLeaderElection (AuthFastLeaderElection 
+is a variant of FastLeaderElection). ZooKeeper messaging doesn't care about the 
+exact method of electing a leader has long as the following holds:
+</para>
+
+<itemizedlist>
+
+<listitem><para>The leader has seen the highest zxid of all the followers.</para></listitem>
+<listitem><para>A quorum of servers have committed to following the leader.</para></listitem>
+
+</itemizedlist>
+
+<para>
+Of these two requirements only the first, the highest zxid amoung the followers 
+needs to hold for correct operation. The second requirement, a quorum of followers, 
+just needs to hold with high probability. We are going to recheck the second requirement, 
+so if a failure happens during or after the leader election and quorum is lost, 
+we will recover by abandoning leader activation and running another election.
+</para>
+
+<para>
+After leader election a single server will be designated as a leader and start 
+waiting for followers to connect. The rest of the servers will try to connect to 
+the leader. The leader will sync up with followers by sending any proposals they 
+are missing, or if a follower is missing too many proposals, it will send a full 
+snapshot of the state to the follower.
+</para>
+
+<para>
+There is a corner cases that a follower arrives that has proposals, U, not seen 
+by a leader. Proposals are seen in order, so the proposals of U will have a zxids 
+higher than zxids seen by the leader. The follower must have arrived after the 
+leader election, otherwise the follower would have been elected leader given that 
+it has seen a higher zxid. Since committed proposals must be seen by a quorum of 
+servers, and a quorum of servers that elected the leader did not see U, the proposals 
+of you have not been committed, so they can be discarded. When the follower connects 
+to the leader, the leader will tell the follower to discard U.
+</para>
+
+<para>
+A new leader establishes a zxid to start using for new proposals by getting the 
+epoch, e, of the highest zxid it has seen and setting the next zxid to use to be 
+(e+1, 0), fter the leader syncs with a follower, it will propose a NEW_LEADER 
+proposal. Once the NEW_LEADER proposal has been committed, the leader will activate 
+and start receiving and issuing proposals.
+</para>
+
+<para>
+It all sounds complicated but here are the basic rules of operation during leader 
+activation:
+</para>
+
+<itemizedlist>
+<listitem><para>A follower will ACK the NEW_LEADER proposal after it has synced with the leader.</para></listitem>
+<listitem><para>A follower will only ACK a NEW_LEADER proposal with a given zxid from a single server.</para></listitem>
+<listitem><para>A new leader will COMMIT the NEW_LEADER proposal when a quorum of followers have ACKed it.</para></listitem>
+<listitem><para>A follower will commit any state it received from the leader when the NEW_LEADER proposal is COMMIT.</para></listitem>
+<listitem><para>A new leader will not accept new proposals until the NEW_LEADER proposal has been COMMITED.</para></listitem>
+</itemizedlist>
+
+<para>
+If leader election terminates erroneously, we don't have a problem since the 
+NEW_LEADER proposal will not be committed since the leader will not have quorum. 
+When this happens, the leader and any remaining followers will timeout and go back 
+to leader election.
+</para>
+
+</section>
+
+<section id="sc_activeMessaging">
+<title>Active Messaging</title>
+<para>
+Leader Activation does all the heavy lifting. Once the leader is coronated he can 
+start blasting out proposals. As long as he remains the leader no other leader can 
+emerge since no other leader will be able to get a quorum of followers. If a new 
+leader does emerge, 
+it means that the leader has lost quorum, and the new leader will clean up any 
+mess left over during her leadership activation.
+</para>
+
+<para>ZooKeeper messaging operates similar to a classic two-phase commit.</para>
+
+<mediaobject id="fg_2phaseCommit" >
+  <imageobject>
+    <imagedata fileref="images/2pc.png"/>
+  </imageobject>
+</mediaobject>
+
+<para>
+All communication channels are FIFO, so everything is done in order. Specifically 
+the following operating constraints are observed:</para>
+
+<itemizedlist>
+
+<listitem><para>The leader sends proposals to all followers using 
+the same order. Moreover, this order follows the order in which requests have been 
+received. Because we use FIFO channels this means that followers also receive proposals in order.
+</para></listitem>
+
+<listitem><para>Followers process messages in the order they are received. This 
+means that messages will be ACKed in order and the leader will receive ACKs from 
+followers in order, due to the FIFO channels. It also means that if message $m$ 
+has been written to non-volatile storage, all messages that were proposed before 
+$m$ have been written to non-volatile storage.</para></listitem>
+
+<listitem><para>The leader will issue a COMMIT to all followers as soon as a 
+quorum of followers have ACKed a message. Since messages are ACKed in order, 
+COMMITs will be sent by the leader as received by the followers in order.</para></listitem>
+
+<listitem><para>COMMITs are processed in order. Followers deliver a proposals 
+message when that proposal is committed.</para></listitem>
+
+</itemizedlist>
+
+</section>
+
+<section id="sc_summary">
+<title>Summary</title>
+<para>So there you go. Why does it work? Specifically, why does is set of proposals 
+believed by a new leader always contain any proposal that has actually been committed? 
+First, all proposals have a unique zxid, so unlike other protocols, we never have 
+to worry about two different values being proposed for the same zxid; followers 
+(a leader is also a follower) see and record proposals in order; proposals are 
+committed in order; there is only one active leader at a time since followers only 
+follow a single leader at a time; a new leader has seen all committed proposals 
+from the previous epoch since it has seen the highest zxid from a quorum of servers; 
+any uncommited proposals from a previous epoch seen by a new leader will be committed 
+by that leader before it becomes active.</para></section>
+
+<section id="sc_comparisons"><title>Comparisons</title>
+<para>
+Isn't this just Multi-Paxos? No, Multi-Paxos requires some way of assuring that 
+there is only a single coordinator. We do not count on such assurances. Instead 
+we use the leader activation to recover from leadership change or old leaders 
+believing they are still active.
+</para>
+
+<para>
+Isn't this just Paxos? Your active messaging phase looks just like phase 2 of Paxos? 
+Actually, to us active messaging looks just like 2 phase commit without the need to 
+handle aborts. Active messaging is different from both in the sense that it has 
+cross proposal ordering requirements. If we do not maintain strict FIFO ordering of 
+all packets, it all falls apart. Also, our leader activation phase is different from 
+both of them. In particular, our use of epochs allows us to skip blocks of uncommitted
+proposals and to not worry about duplicate proposals for a given zxid.
+</para>
+
+</section>
+
+</section>
+
+
+<section id="sc_logging">
+
+<title>Logging</title>
+
+<para>
+ZooKeeper uses 
+<ulink url="http://logging.apache.org/log4j">log4j</ulink>
+version 1.2 as its logging infrastructure. For information on configuring log4j for
+ZooKeeper, see the <ulink url="zookeeperAdmin.html#sc_logging">Logging</ulink> section 
+of the <ulink url="zookeeperAdmin.html">ZooKeeper Administrator's Guide.</ulink>
+</para>
+
+<section id="sc_developerGuidelines"><title>Developer Guidelines</title>
+
+<para>Please follow these guidelines when submitting code. Patch reviewers will look for the following:</para>
+<section id="sc_rightLevel"><title>Logging at the Right Level</title>
+<para>
+There are <ulink url="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html#FATAL">6 levels of logging in log4j</ulink>. 
+It's important to pick the right one. In order of higher to lower severity:</para>
+<orderedlist>
+   <listitem><para> FATAL level designates very severe error events that will presumably lead the application to abort</para></listitem>
+   <listitem><para>ERROR level designates error events that might still allow the application to continue running.</para></listitem>
+   <listitem><para>WARN level designates potentially harmful situations.</para></listitem>
+   <listitem><para>INFO level designates informational messages that highlight the progress of the application at coarse-grained level.</para></listitem>
+   <listitem><para>EBUG Level designates fine-grained informational events that are most useful to debug an application.</para></listitem>
+   <listitem><para>TRACE Level designates finer-grained informational events than the DEBUG.</para></listitem>
+</orderedlist>
+
+<para>
+ZooKeeper is typically run in production such that log messages of INFO level 
+severity and higher (more severe) are output to the log.</para>
+
+
+</section>
+
+<section id="sc_log4jIdioms"><title>Use of Standard log4j Idioms</title>
+
+<para><emphasis>Static Message Logging</emphasis></para>
+<programlisting>
+LOG.debug("process completed successfully!");
+</programlisting>
+
+<para>However when creating a message from a number of components (string 
+concatenation), the log call should be wrapped with a "isXEnabled()" call. this 
+eliminates the string concatenation overhead when debug level logging is not enabled.
+</para>
+
+<programlisting>
+if (LOG.isDebugEnabled()) {
+    LOG.debug("got " + count + " messages in " + time + " minutes");
+}
+</programlisting>
+
+<para><emphasis>Naming</emphasis></para>
+
+<para>
+Loggers should be named after the class in which they are used. (See the 
+<ulink url="http://logging.apache.org/log4j/1.2/faq.html#2.4">log4j faq</ulink> 
+for reasons why this is a good idea.)
+</para>
+
+<programlisting>
+public class Foo {
+    private static final Logger LOG = Logger.getLogger(Foo.class);
+    ....
+    public Foo() {
+       LOG.info("constructing Foo");
+</programlisting>
+
+<para><emphasis>Exception handling</emphasis></para>
+<programlisting>
+try {
+  // code
+} catch (XYZException e) {
+  // do this
+  LOG.error("Something bad happened", e);
+  // don't do this (generally)
+  // LOG.error(e);
+  // why? because "don't do" case hides the stack trace
+ 
+  // continue process here as you need... recover or (re)throw
+}
+</programlisting>
+</section>
+</section>
+
+</section>
+
+</article>

+ 16 - 12
src/docs/src/documentation/content/xdocs/zookeeperStarted.xml

@@ -71,19 +71,20 @@
       </note>
       </note>
 
 
       <para>Once you have downloaded the ZooKeeper source, cd to the root of
       <para>Once you have downloaded the ZooKeeper source, cd to the root of
-      your ZooKeeper source, and run "ant jar". For example:<computeroutput>$ cd ~/dev/zookeeper
-
-$ ~/dev/zookeeper/: ant jar</computeroutput></para>
+      your ZooKeeper source, and run "ant jar". For example:</para>
+<programlisting>
+$ cd ~/dev/zookeeper
+$ ~/dev/zookeeper/: ant jar
+</programlisting>
 
 
       <para>This should generate a JAR file called zookeeper.jar. To start
       <para>This should generate a JAR file called zookeeper.jar. To start
-      Zookeeper, compile and run zookeeper.jar. <emphasis>[tbd, some more
-      instruction here. Perhaps a command line? Are these two steps or
-      one?]</emphasis></para>
+      Zookeeper, compile and run zookeeper.jar.</para>
 
 
       <para>To start ZooKeeper you need a configuration file. Here is a sample
       <para>To start ZooKeeper you need a configuration file. Here is a sample
       file:</para>
       file:</para>
 
 
-      <programlisting>tickTime=2000
+<programlisting>
+tickTime=2000
 dataDir=/var/zookeeper/ 
 dataDir=/var/zookeeper/ 
 clientPort=2181
 clientPort=2181
 </programlisting>
 </programlisting>
@@ -127,7 +128,7 @@ clientPort=2181
       <para>Now that you created the configuration file, you can start
       <para>Now that you created the configuration file, you can start
       ZooKeeper:</para>
       ZooKeeper:</para>
 
 
-      <para><computeroutput>java -cp zookeeper-dev.jar:java/lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg</computeroutput></para>
+      <programlisting>java -cp zookeeper-dev.jar:java/lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg</programlisting>
 
 
       <para>ZooKeeper logs messages using log4j -- more detail available in
       <para>ZooKeeper logs messages using log4j -- more detail available in
       the <ulink url="zookeeperProgrammers.html#Logging">Logging</ulink>
       the <ulink url="zookeeperProgrammers.html#Logging">Logging</ulink>
@@ -163,7 +164,7 @@ clientPort=2181
         <listitem>
         <listitem>
           <para><emphasis role="bold">C</emphasis>: compile cli_mt
           <para><emphasis role="bold">C</emphasis>: compile cli_mt
           (multi-threaded) or cli_st (single-threaded) by running
           (multi-threaded) or cli_st (single-threaded) by running
-          <command>_make cli_mt_</command> or <command>_make cli_st_</command>
+          <command>make cli_mt</command> or <command>make cli_st</command>
           in the c subdirectory in the ZooKeeper sources.</para>
           in the c subdirectory in the ZooKeeper sources.</para>
 
 
           <para>You can run the program using <emphasis>LD_LIBRARY_PATH=.
           <para>You can run the program using <emphasis>LD_LIBRARY_PATH=.
@@ -197,13 +198,16 @@ clientPort=2181
       file. The file is similar to the one used in standalone mode, but with a
       file. The file is similar to the one used in standalone mode, but with a
       few differences. Here is an example:</para>
       few differences. Here is an example:</para>
 
 
-      <para><computeroutput>tickTime=2000 
+<programlisting>
+tickTime=2000 
 dataDir=/var/zookeeper/ 
 dataDir=/var/zookeeper/ 
 clientPort=2181 
 clientPort=2181 
 initLimit=5 
 initLimit=5 
 syncLimit=2 
 syncLimit=2 
-server.1=zoo1:2888 server.2=zoo2:2888 
-server.3=zoo3:2888 </computeroutput></para>
+server.1=zoo1:2888
+server.2=zoo2:2888 
+server.3=zoo3:2888 
+</programlisting>
 
 
       <para>The new entry, <emphasis role="bold">initLimit</emphasis> is
       <para>The new entry, <emphasis role="bold">initLimit</emphasis> is
       timeouts ZooKeeper uses to limit the length of time the Zookeeper
       timeouts ZooKeeper uses to limit the length of time the Zookeeper

+ 674 - 0
src/docs/src/documentation/content/xdocs/zookeeperTutorial.xml

@@ -0,0 +1,674 @@
+<?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="ar_Tutorial">
+  <title>Programming with ZooKeeper - A basic tutorial</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 article contains sample Java code for simple implementations of barrier
+      and consumers queues..</para>
+
+    </abstract>
+  </articleinfo>
+
+  <section id="ch_Introduction">
+    <title>Introduction</title>
+
+    <para>In this tutorial, we show simple implementations of barriers and 
+    producer-consumer queues using ZooKeeper. We call the respective classes Barrier and Queue. 
+    These examples assume that you have at least one ZooKeeper server running.</para>
+    
+    <para>Both primitives use the following common excerpt of code:</para>
+    
+    <programlisting>
+static ZooKeeper zk = null;
+static Integer mutex;
+
+String root;
+
+SyncPrimitive(String address) {
+	if(zk == null){
+	    try {
+		System.out.println("Starting ZK:");
+		zk = new ZooKeeper(address, 3000, this);
+		mutex = new Integer(-1);
+		System.out.println("Finished starting ZK: " + zk);
+	    } catch (KeeperException e) {
+		System.out.println("Keeper exception when starting new session: "
+			+ e.toString());
+		zk = null;
+	    } catch (IOException e) {
+		System.out.println(e.toString());
+		zk = null;
+	    }
+	}
+}
+
+synchronized public void process(WatcherEvent event) {
+	synchronized (mutex) {
+	    mutex.notify();
+	}
+}
+
+</programlisting>
+
+<para>Both classes extend SyncPrimitive. In this way, we execute steps that are 
+common to all primitives in the constructor of SyncPrimitive. To keep the examples 
+simple, we create a ZooKeeper object the first time we instantiate either a barrier 
+object or a queue object, and we declare a static variable that is a reference 
+to this object. The subsequent instances of Barrier and Queue check whether a 
+ZooKeeper object exists. Alternatively, we could have the application creating a
+ZooKeeper object and passing it to the constructor of Barrier and Queue.</para>
+<para>
+We use the process() method to process notifications triggered due to watches. 
+In the following discussion, we present code that sets watches. A watch is internal 
+structure that enables ZooKeeper to notify a client of a change to a node. For example, 
+if a client is waiting for other clients to leave a barrier, then it can set a watch and 
+wait for modifications to a particular node, which can indicate that it is the end of the wait. 
+This point becomes clear once we go over the examples.
+</para>
+</section>
+   
+ <section id="sc_barriers"><title>Barriers</title>
+ 
+ <para>
+ A barrier is a primitive that enables a group of processes to synchronize the 
+ beginning and the end of a computation. The general idea of this implementation 
+ is to have a barrier node that serves the purpose of being a parent for individual 
+ process nodes. Suppose that we call the barrier node "/b1". Each process "p" then 
+ creates a node "/b1/p". Once enough processes have created their corresponding 
+ nodes, joined processes can start the computation.
+ </para>
+ 
+ <para>In this example, each process instantiates a Barrier object, and its constructor takes as parameters:</para>
+
+ <itemizedlist><listitem><para>the address of a ZooKeeper server (e.g., "zoo1.foo.com:2181")</para></listitem>
+<listitem><para>the path of the barrier node on ZooKeeper (e.g., "/b1")</para></listitem>
+<listitem><para>the size of the group of processes</para></listitem>
+</itemizedlist>
+
+<para>The constructor of Barrier passes the address of the Zookeeper server to the 
+constructor of the parent class. The parent class creates a ZooKeeper instance if 
+one does not exist. The constructor of Barrier then creates a 
+barrier node on ZooKeeper, which is the parent node of all process nodes, and 
+we call root (<emphasis role="bold">Note:</emphasis> This is not the ZooKeeper root "/").</para>
+
+<programlisting>
+ /**
+ * Barrier constructor
+ *
+ * @param address
+ * @param name
+ * @param size
+ */
+Barrier(String address, String name, int size) {
+    super(address);
+    this.root = name;
+    this.size = size;
+
+    // Create barrier node
+    if (zk != null) {
+	try {
+	    Stat s = zk.exists(root, false);
+	    if (s == null) {
+		zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+	    }
+	} catch (KeeperException e) {
+	    System.out.println("Keeper exception when instantiating queue: " + e.toString());
+	} catch (InterruptedException e) {
+	    System.out.println("Interrupted exception");
+	}
+    }
+
+    // My node name
+    try {
+	name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());
+    } catch (UnknownHostException e) {
+	System.out.println(e.toString());
+    }
+
+}
+</programlisting>
+<para>
+To enter the barrier, a process calls enter(). The process creates a node under 
+the root to represent it, using its host name to form the node name. It then wait 
+until enough processes have entered the barrier. A process does it by checking 
+the number of children the root node has with "getChildren()", and waiting for 
+notifications in the case it does not have enough. To receive a notification when 
+there is a change to the root node, a process has to set a watch, and does it 
+through the call to "getChildren()". In the code, we have that "getChildren()" 
+has two parameters. The first one states the node to read from, and the second is
+a boolean flag that enables the process to set a watch. In the code the flag is true.
+</para>
+
+<programlisting>
+ /**
+ * Join barrier
+ *
+ * @return
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+
+boolean enter() throws KeeperException, InterruptedException{
+    zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,
+	    CreateFlags.EPHEMERAL);
+    while (true) {
+	synchronized (mutex) {
+	    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+
+	    if (list.size() &lt; size) {
+		mutex.wait();
+	    } else {
+		return true;
+	    }
+	}
+    }
+}
+</programlisting>
+<para>
+Note that enter() throws both KeeperException and InterruptedException, so it is 
+the reponsability of the application to catch and handle such exceptions.</para>
+
+<para>
+Once the computation is finished, a process calls leave() to leave the barrier. 
+First it deletes its corresponding node, and then it gets the children of the root 
+node. If there is at least one child, then it waits for a notification (obs: note 
+that the second parameter of the call to getChildren() is true, meaning that 
+ZooKeeper has to set a watch on the the root node). Upon reception of a notification, 
+it checks once more whether the root node has any child.</para>
+
+<programlisting>
+ /**
+ * Wait until all reach barrier
+ *
+ * @return
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+
+boolean leave() throws KeeperException, InterruptedException{
+    zk.delete(root + "/" + name, 0);
+    while (true) {
+	synchronized (mutex) {
+	    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+		if (list.size() &gt; 0) {
+		    mutex.wait();
+		} else {
+		    return true;
+		}
+	    }
+	}
+}
+</programlisting>
+</section>
+<section id="sc_producerConsumerQueues"><title>Producer-Consumer Queues</title>
+<para>
+A producer-consumer queue is a distributed data estructure thata group of processes 
+use to generate and consume items. Producer processes create new elements and add 
+them to the queue. Consumer processes remove elements from the list, and process them. 
+In this implementation, the elements are simple integers. The queue is represented 
+by a root node, and to add an element to the queue, a producer process creates a new node, 
+a child of the root node.
+</para>
+
+<para>
+The following excerpt of code corresponds to the constructor of the object. As 
+with Barrier objects, it first calls the constructor of the parent class, SyncPrimitive, 
+that creates a ZooKeeper object if one doesn't exist. It then verifies if the root 
+node of the queue exists, and creates if it doesn't.
+</para>
+<programlisting>
+/**
+ * Constructor of producer-consumer queue
+ *
+ * @param address
+ * @param name
+ */
+Queue(String address, String name) {
+    super(address);
+    this.root = name;
+    // Create ZK node name
+    if (zk != null) {
+	try {
+	    Stat s = zk.exists(root, false);
+	    if (s == null) {
+		zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+	    }
+	} catch (KeeperException e) {
+	    System.out
+		    .println("Keeper exception when instantiating queue: "
+			    + e.toString());
+	} catch (InterruptedException e) {
+	    System.out.println("Interrupted exception");
+	}
+    }
+}
+ </programlisting>
+ 
+<para>
+A producer process calls "produce()" to add an element to the queue, and passes 
+an integer as an argument. To add an element to the queue, the method creates a 
+new node using "create()", and uses the SEQUENCE flag to instruct ZooKeeper to 
+append the value of the sequencer counter associated to the root node. In this way, 
+we impose a total order on the elements of the queue, thus guaranteeing that the 
+oldest element of the queue is the next one consumed.
+</para>
+
+<programlisting>
+/**
+ * Add element to the queue.
+ *
+ * @param i
+ * @return
+ */
+
+boolean produce(int i) throws KeeperException, InterruptedException{
+    ByteBuffer b = ByteBuffer.allocate(4);
+    byte[] value;
+
+    // Add child with value i
+    b.putInt(i);
+    value = b.array();
+    zk.create(root + "/element", value, Ids.OPEN_ACL_UNSAFE,
+		CreateFlags.SEQUENCE);
+
+    return true;
+}
+</programlisting>
+<para>
+To consume an element, a consumer process obtains the children of the root node, 
+reads the node with smallest counter value, and returns the element. Note that 
+if there is a conflict, then one of the two contending processes won't be able to 
+delete the node and the delete operation will throw an exception.</para>
+
+<para>
+A call to getChildren() returns the list of children in lexicographic order. 
+As lexicographic order does not necessary follow the numerical order of the counter 
+values, we need to decide which element is the smallest. To decide which one has 
+the smallest counter value, we traverse the list, and remove the prefix "element" 
+from each one.</para>
+
+<programlisting>
+/**
+ * Remove first element from the queue.
+ *
+ * @return
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+int consume() throws KeeperException, InterruptedException{
+    int retvalue = -1;
+    Stat stat = null;
+
+    // Get the first element available
+    while (true) {
+	synchronized (mutex) {
+	    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+	    if (list.size() == 0) {
+		System.out.println("Going to wait");
+		mutex.wait();
+	    } else {
+		Integer min = new Integer(list.get(0).substring(7));
+		for(String s : list){
+		    Integer tempValue = new Integer(s.substring(7));
+		    if(tempValue &gt; min) min = tempValue;
+		}
+		System.out.println("Temporary value: " + root + "/element" + min);
+		byte[] b = zk.getData(root + "/element" + min, false, stat);
+		zk.delete(root + "/element" + min, 0);
+		ByteBuffer buffer = ByteBuffer.wrap(b);
+		retvalue = buffer.getInt();
+
+		return retvalue;
+	    }
+	}
+    }
+}
+</programlisting>
+ 
+</section>
+<section id="sc_sourceListing"><title>Complete Source Listing</title>
+<example id="eg_SyncPrimitive_java">
+<title>SyncPrimitive.Java</title>
+<programlisting>
+package com.yahoo.SyncPrimitive;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.lang.InterruptedException;
+import java.util.ArrayList;
+import java.util.Random;
+
+import com.yahoo.zookeeper.Watcher;
+import com.yahoo.zookeeper.data.Stat;
+import com.yahoo.zookeeper.proto.WatcherEvent;
+import com.yahoo.zookeeper.KeeperException;
+import com.yahoo.zookeeper.ZooDefs.Ids;
+import com.yahoo.zookeeper.ZooDefs.CreateFlags;
+import com.yahoo.zookeeper.ZooKeeper;
+
+public class SyncPrimitive implements Watcher {
+
+    static ZooKeeper zk = null;
+    static Integer mutex;
+    
+    String root;
+
+    SyncPrimitive(String address) {
+        if(zk == null){
+            try {
+                System.out.println("Starting ZK:");
+                zk = new ZooKeeper(address, 3000, this);
+                mutex = new Integer(-1);
+                System.out.println("Finished starting ZK: " + zk);
+            } catch (KeeperException e) {
+                System.out.println("Keeper exception when starting new session: "
+                        + e.toString());
+                zk = null;
+            } catch (IOException e) {
+                System.out.println(e.toString());
+                zk = null;
+            }
+        }
+        //else mutex = new Integer(-1);
+    }
+
+    synchronized public void process(WatcherEvent event) {
+        synchronized (mutex) {
+            //System.out.println("Process: " + event.getType());
+            mutex.notify();
+        }
+    }
+
+    /**
+     * Barrier
+     */
+    static public class Barrier extends SyncPrimitive {
+        int size;
+        String name;
+
+        /**
+         * Barrier constructor
+         * 
+         * @param address
+         * @param name
+         * @param size
+         */
+        Barrier(String address, String name, int size) {
+            super(address);
+            this.root = name;
+            this.size = size;
+
+            // Create barrier node
+            if (zk != null) {
+                try {
+                    Stat s = zk.exists(root, false);
+                    if (s == null) {
+                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+                    }
+                } catch (KeeperException e) {
+                    System.out
+                            .println("Keeper exception when instantiating queue: "
+                                    + e.toString());
+                } catch (InterruptedException e) {
+                    System.out.println("Interrupted exception");
+                }
+            }
+            
+            // My node name
+            try {
+                name = new String(InetAddress.getLocalHost().getCanonicalHostName().toString());
+            } catch (UnknownHostException e) {
+                System.out.println(e.toString());
+            }
+            
+        }
+
+        /**
+         * Join barrier
+         * 
+         * @return
+         * @throws KeeperException
+         * @throws InterruptedException
+         */
+        
+        boolean enter() throws KeeperException, InterruptedException{
+            zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE,
+                    CreateFlags.EPHEMERAL);
+            while (true) {
+                synchronized (mutex) {                    
+                    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+       
+                    if (list.size() &lt; size) {
+                        mutex.wait();
+                    } else {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Wait until all reach barrier
+         * 
+         * @return
+         * @throws KeeperException
+         * @throws InterruptedException
+         */
+        
+        boolean leave() throws KeeperException, InterruptedException{
+            zk.delete(root + "/" + name, 0);
+            while (true) {
+                synchronized (mutex) {
+                    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+                        if (list.size() > 0) {
+                            mutex.wait();
+                        } else {
+                            return true;
+                        }
+                    }
+                }
+        }
+    }
+
+    /**
+     * Producer-Consumer queue
+     */
+    static public class Queue extends SyncPrimitive {
+
+        /**
+         * Constructor of producer-consumer queue
+         * 
+         * @param address
+         * @param name
+         */
+        Queue(String address, String name) {
+            super(address);
+            this.root = name;
+            // Create ZK node name
+            if (zk != null) {
+                try {
+                    Stat s = zk.exists(root, false);
+                    if (s == null) {
+                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, 0);
+                    }
+                } catch (KeeperException e) {
+                    System.out
+                            .println("Keeper exception when instantiating queue: "
+                                    + e.toString());
+                } catch (InterruptedException e) {
+                    System.out.println("Interrupted exception");
+                }
+            }
+        }
+
+        /**
+         * Add element to the queue.
+         * 
+         * @param i
+         * @return
+         */
+        
+        boolean produce(int i) throws KeeperException, InterruptedException{
+            ByteBuffer b = ByteBuffer.allocate(4);
+            byte[] value;
+
+            // Add child with value i
+            b.putInt(i);
+            value = b.array();
+            zk.create(root + "/element", value, Ids.OPEN_ACL_UNSAFE,
+                        CreateFlags.SEQUENCE);
+            
+            return true;
+        }
+
+
+        /**
+         * Remove first element from the queue.
+         * 
+         * @return
+         * @throws KeeperException
+         * @throws InterruptedException
+         */
+        int consume() throws KeeperException, InterruptedException{
+            int retvalue = -1;
+            Stat stat = null;
+            
+            // Get the first element available
+            while (true) {
+                synchronized (mutex) {
+                    ArrayList&lt;String&gt; list = zk.getChildren(root, true);
+                    if (list.size() == 0) {
+                        System.out.println("Going to wait");
+                        mutex.wait();
+                    } else {
+                        Integer min = new Integer(list.get(0).substring(7));
+                        for(String s : list){
+                            Integer tempValue = new Integer(s.substring(7));
+                            //System.out.println("Temporary value: " + tempValue);
+                            if(tempValue &lt; min) min = tempValue;
+                        }
+                        System.out.println("Temporary value: " + root + "/element" + min);
+                        byte[] b = zk.getData(root + "/element" + min,
+                                    false, stat);
+                        zk.delete(root + "/element" + min, 0);
+                        ByteBuffer buffer = ByteBuffer.wrap(b);
+                        retvalue = buffer.getInt();
+                        
+                        return retvalue;
+                    }
+                }
+            }           
+        }
+    }
+
+    public static void main(String args[]) {
+        if (args[0].equals("qTest"))
+            queueTest(args);
+        else
+            barrierTest(args);
+
+    }
+
+    public static void queueTest(String args[]) {
+        Queue q = new Queue(args[1], "/app1");
+
+        System.out.println("Input: " + args[1]);
+        int i;
+        Integer max = new Integer(args[2]);
+
+        if (args[3].equals("p")) {
+            System.out.println("Producer");
+            for (i = 0; i &lt; max; i++)
+                try{    
+                    q.produce(10 + i);
+                } catch (KeeperException e){
+                    
+                } catch (InterruptedException e){
+                    
+                }
+        } else {
+            System.out.println("Consumer");
+   
+            for (i = 0; i &lt; max; i++) {
+                try{
+                    int r = q.consume();
+                    System.out.println("Item: " + r);
+                } catch (KeeperException e){
+                    i--;
+                } catch (InterruptedException e){
+                    
+                }
+            }
+        }
+    }
+
+    public static void barrierTest(String args[]) {
+        Barrier b = new Barrier(args[1], "/b1", new Integer(args[2]));
+        try{
+            boolean flag = b.enter();
+            System.out.println("Entered barrier: " + args[2]);
+            if(!flag) System.out.println("Error when entering the barrier");
+        } catch (KeeperException e){
+            
+        } catch (InterruptedException e){
+            
+        }
+
+        // Generate random integer
+        Random rand = new Random();
+        int r = rand.nextInt(100);
+        // Loop for rand iterations
+        for (int i = 0; i &lt; r; i++) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+
+            }
+        }
+        try{
+            b.leave();
+        } catch (KeeperException e){
+            
+        } catch (InterruptedException e){
+            
+        }
+        System.out.println("Left barrier");
+    }
+}</programlisting></example>
+</section>
+
+</article>

BIN
src/docs/src/documentation/resources/images/2pc.png


+ 10 - 0
src/docs/src/documentation/skinconf.xml

@@ -142,10 +142,20 @@ which will be used to configure the chosen Forrest skin.
       font-family: monospace;
       font-family: monospace;
     }
     }
 
 
+    pre.code {
+      margin-left: 0em;
+      padding: 0.5em;
+      background-color: #f0f0f0;
+      font-family: monospace;
+    }
+
+<!-- patricks
     .code {
     .code {
       font-family: "Courier New", Courier, monospace;
       font-family: "Courier New", Courier, monospace;
       font-size: 110%;
       font-size: 110%;
     }
     }
+-->
+
   </extra-css>
   </extra-css>
 
 
   <colors>
   <colors>

Некоторые файлы не были показаны из-за большого количества измененных файлов