Prechádzať zdrojové kódy

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 rokov pred
rodič
commit
03f0f816dc

+ 3 - 0
CHANGES.txt

@@ -20,6 +20,9 @@ Backward compatibile changes:
 
   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
   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>
 </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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <div class="menuitem">
@@ -189,6 +198,15 @@ The following documents provide concepts and procedures to get you started using
 <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="api/index.html">API Docs</a> - the technical reference to ZooKeeper APIs</li>
       

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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>
 </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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <div class="menuitem">
@@ -210,6 +219,24 @@ document.write("Last Published: " + document.lastModified);
 </li>
 </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>
 <li>
 <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) >>
 endobj
 5 0 obj
-<< /Length 840 /Filter [ /ASCII85Decode /FlateDecode ]
+<< /Length 955 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 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
 endobj
 6 0 obj
@@ -72,17 +72,17 @@ endobj
 xref
 0 12
 0000000000 65535 f 
-0000001663 00000 n 
-0000001721 00000 n 
-0000001771 00000 n 
+0000001778 00000 n 
+0000001836 00000 n 
+0000001886 00000 n 
 0000000015 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
 <<
 /Size 12
@@ -90,5 +90,5 @@ trailer
 /Info 4 0 R
 >>
 startxref
-1891
+2006
 %%EOF

+ 9 - 0
docs/recipes.html

@@ -123,6 +123,15 @@ document.write("Last Published: " + document.lastModified);
 <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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <div class="menuitem">

+ 8 - 3
docs/skin/profile.css

@@ -156,8 +156,13 @@ a:hover { color:#6587ff}
       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>
 <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>
 </div>
 <div class="menuitem">
@@ -341,7 +350,6 @@ document.write("Last Published: " + document.lastModified);
 <p>Install the ZooKeeper Server Package. It can be downloaded
             from:
           </p>
-
           
 <p>
             
@@ -474,7 +482,7 @@ server.3=zoo3:2888</span>
 <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
       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>
 <p>For information on installing the client side libraries, refer to
       the <a href="zookeeperProgrammers.html#Bindings">Bindings</a>
@@ -615,11 +623,18 @@ server.3=zoo3:2888</span>
 <p></p>
 <a name="N1018A"></a><a name="sc_logging"></a>
 <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>
 <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>
 <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
@@ -627,7 +642,7 @@ server.3=zoo3:2888</span>
       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
       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>
 <p>Here are the minimum configuration keywords that must be defined
         in the configuration file:</p>
@@ -674,7 +689,7 @@ server.3=zoo3:2888</span>
 </dd>
         
 </dl>
-<a name="N101CC"></a><a name="sc_advancedConfiguration"></a>
+<a name="N101E3"></a><a name="sc_advancedConfiguration"></a>
 <h4>Advanced Configuration</h4>
 <p>The configuration settings in the section are optional. You can
         use them to further fine tune the behaviour of your ZooKeeper servers.
@@ -765,7 +780,7 @@ server.3=zoo3:2888</span>
 </dd>
         
 </dl>
-<a name="N1022C"></a><a name="sc_clusterOptions"></a>
+<a name="N10243"></a><a name="sc_clusterOptions"></a>
 <h4>Cluster Options</h4>
 <p>The options in this section are designed for use in quorums --
         that is, when deploying clusters of servers.</p>
@@ -868,7 +883,7 @@ server.3=zoo3:2888</span>
         
 </dl>
 <p></p>
-<a name="N10298"></a><a name="Unsafe+Options"></a>
+<a name="N102AF"></a><a name="Unsafe+Options"></a>
 <h4>Unsafe Options</h4>
 <p>The following options can be useful, but be careful when you use
         them. The risk of each is explained along with the explanation of what
@@ -913,7 +928,7 @@ server.3=zoo3:2888</span>
 </dd>
         
 </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>
 <p>ZooKeeper responds to a small set of commands. Each command is
       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
 imok
 </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>
 <p>ZooKeeper stores its data in a data directory and its transaction
       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.
       Throughput increases and latency decreases when transaction logs reside
       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>
 <p>This directory has two files in it:</p>
 <ul>
@@ -1016,14 +1031,14 @@ imok
         idempotent nature of its updates. By replaying the transaction log
         against fuzzy snapshots ZooKeeper gets the state of the system at the
         end of the log.</p>
-<a name="N10341"></a><a name="The+Log+Directory"></a>
+<a name="N10358"></a><a name="The+Log+Directory"></a>
 <h4>The Log Directory</h4>
 <p>The Log Directory contains the ZooKeeper transaction logs.
         Before any update takes place, ZooKeeper ensures that the transaction
         that represents the update is written to non-volatile storage. A new
         log file is started each time a snapshot is begun. The log file's
         suffix is the first zxid written to that log.</p>
-<a name="N1034B"></a><a name="File+Management"></a>
+<a name="N10362"></a><a name="File+Management"></a>
 <h4>File Management</h4>
 <p>The format of snapshot and log files does not change between
         standalone ZooKeeper servers and different configurations of
@@ -1040,7 +1055,7 @@ imok
         needs the latest complete fuzzy snapshot and the log files from the
         start of that snapshot. The PurgeTxnLog utility implements a simple
         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>
 <p>Here are some common problems you can avoid by configuring
       ZooKeeper correctly:</p>
@@ -1094,7 +1109,7 @@ imok
 </dd>
       
 </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>
 <p>For best results, take note of the following list of good
       Zookeeper practices. <em>[tbd...]</em>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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>
 </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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <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>
 </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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <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>
 </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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <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>
 </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="menuitem">
+<a href="zookeeperInternals.html">ZooKeeper Internals</a>
+</div>
+<div class="menuitem">
 <a href="api/index.html">API Docs</a>
 </div>
 <div class="menuitem">
@@ -216,18 +225,17 @@ document.write("Last Published: " + document.lastModified);
 </div>
 </div>
 <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
-      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
       file:</p>
-<pre class="code">tickTime=2000
+<pre class="code">
+tickTime=2000
 dataDir=/var/zookeeper/ 
 clientPort=2181
 </pre>
@@ -274,9 +282,7 @@ clientPort=2181
 </dl>
 <p>Now that you created the configuration file, you can start
       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
       the <a href="zookeeperProgrammers.html#Logging">Logging</a>
       section of the Programmer's Guide.<em>[tbd:
@@ -288,7 +294,7 @@ clientPort=2181
       replicated mode, please see <a href="#sc_RunningReplicatedZooKeeper">Running Replicated
       Zookeeper</a>.</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>
 <p>Once ZooKeeper is running, you have several option for connection
       to it:</p>
@@ -312,7 +318,7 @@ clientPort=2181
 <p>
 <strong>C</strong>: compile cli_mt
           (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>
 
           
@@ -324,7 +330,7 @@ clientPort=2181
 </li>
       
 </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>
 <p>ZooKeeper has a Java bindings and C bindings. They are
       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
       Examples in the Zookeeper Programmer's Guide</a> for
       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>
 <p>Running ZooKeeper in standalone mode is convenient for evaluation,
       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
       file. The file is similar to the one used in standalone mode, but with a
       few differences. Here is an example:</p>
-<p>
-<span class="codefrag computeroutput">tickTime=2000 
+<pre class="code">
+tickTime=2000 
 dataDir=/var/zookeeper/ 
 clientPort=2181 
 initLimit=5 
 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
       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
@@ -377,7 +384,7 @@ server.3=zoo3:2888 </span>
       
 </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>
 <p>There are a couple of other configuration parameters that can
       greatly increase performance:</p>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 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="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="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:wiki">Wiki</a> - miscellaneous, informal ZooKeeper documentation, in Wiki format</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" />
     <recipes   label="Recipes"		      href="recipes.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" />
     <wiki      label="Wiki"                   href="ext:wiki" />
     <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
             from:
           </para>
-
           <para>
             <ulink url="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">
       <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 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>
 
       <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
-      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
       file:</para>
 
-      <programlisting>tickTime=2000
+<programlisting>
+tickTime=2000
 dataDir=/var/zookeeper/ 
 clientPort=2181
 </programlisting>
@@ -127,7 +128,7 @@ clientPort=2181
       <para>Now that you created the configuration file, you can start
       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
       the <ulink url="zookeeperProgrammers.html#Logging">Logging</ulink>
@@ -163,7 +164,7 @@ clientPort=2181
         <listitem>
           <para><emphasis role="bold">C</emphasis>: compile cli_mt
           (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>
 
           <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
       few differences. Here is an example:</para>
 
-      <para><computeroutput>tickTime=2000 
+<programlisting>
+tickTime=2000 
 dataDir=/var/zookeeper/ 
 clientPort=2181 
 initLimit=5 
 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
       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;
     }
 
+    pre.code {
+      margin-left: 0em;
+      padding: 0.5em;
+      background-color: #f0f0f0;
+      font-family: monospace;
+    }
+
+<!-- patricks
     .code {
       font-family: "Courier New", Courier, monospace;
       font-size: 110%;
     }
+-->
+
   </extra-css>
 
   <colors>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov