Added: bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStarted.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStarted.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStarted.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStarted.textile Sun May 
15 21:38:37 2016
@@ -0,0 +1,102 @@
+Title:        BookKeeper Getting Started Guide
+Notice: 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":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.
+        .
+
+h1. Abstract
+
+This guide contains detailed information about using BookKeeper for logging. 
It discusses the basic operations BookKeeper supports, and how to create logs 
and perform basic read and write operations on these logs.
+
+h1. Getting Started: Setting up BookKeeper to write logs.
+
+p. This document contains information to get you started quickly with 
BookKeeper. It is aimed primarily at developers willing to try it out, and 
contains simple installation instructions for a simple BookKeeper installation 
and a simple programming example. For further programming detail, please refer 
to the "BookKeeper Tutorial":./bookkeeperTutorial.html.
+
+h1. Pre-requisites
+
+p. See "System Requirements":./bookkeeperConfig.html#bk_sysReqin the Admin 
guide.
+
+h1. Download
+
+p. BookKeeper trunk can be downloaded from subversion. See "Version 
Control":http://bookkeeper.apache.org/svn.html.
+
+h1. LocalBookKeeper
+
+p. BookKeeper provides a utility program to start a standalone ZooKeeper 
ensemble and a number of bookies on a local machine. As this all runs on a 
local machine, throughput will be very low. It should only be used for testing.
+
+p. To start a local bookkeeper ensemble with 5 bookies:
+
+ @bookkeeper-server/bin/bookkeeper localbookie 5@
+
+h1. Setting up bookies
+
+p. If you're bold and you want more than just running things locally, then 
you'll need to run bookies in different servers. You'll need at least three 
bookies to start with. 
+
+p. For each bookie, we need to execute a command like the following: 
+
+ @bookkeeper-server/bin/bookkeeper bookie@
+
+p. This command will use the default directories for storing ledgers and the 
write ahead log, and will look for a zookeeper server on localhost:2181. See 
the "Admin Guide":./bookkeeperConfig.html for more details.
+
+p. To see the default values of these configuration variables, run:
+
+ @bookkeeper-server/bin/bookkeeper help@
+
+h1. Setting up ZooKeeper
+
+p. ZooKeeper stores metadata on behalf of BookKeeper clients and bookies. To 
get a minimal ZooKeeper installation to work with BookKeeper, we can set up one 
server running in standalone mode. Once we have the server running, we need to 
create a few znodes: 
+
+#  @/ledgers @ 
+#  @/ledgers/available @ 
+
+p. We provide a way of bootstrapping it automatically. See the "Admin 
Guide":./bookkeeperConfig.html for a description of how to bootstrap 
automatically, and in particular the shell metaformat command.
+ 
+
+h1. Example
+
+p. In the following excerpt of code, we: 
+
+# Open a bookkeeper client;
+# Create a ledger; 
+# Write to the ledger; 
+# Close the ledger; 
+# Open the same ledger for reading; 
+# Read from the ledger; 
+# Close the ledger again; 
+# Close the bookkeeper client.
+
+<pre><code>
+BookKeeper bkc = new BookKeeper("localhost:2181");
+LedgerHandle lh = bkc.createLedger(ledgerPassword);
+ledgerId = lh.getId();
+ByteBuffer entry = ByteBuffer.allocate(4);
+
+for(int i = 0; i < 10; i++){
+       entry.putInt(i);
+       entry.position(0);
+       entries.add(entry.array());                             
+       lh.addEntry(entry.array());
+}
+lh.close();
+lh = bkc.openLedger(ledgerId, ledgerPassword);         
+                       
+Enumeration<LedgerEntry> ls = lh.readEntries(0, 9);
+int i = 0;
+while(ls.hasMoreElements()){
+       ByteBuffer origbb = ByteBuffer.wrap(
+                               entries.get(i++));
+       Integer origEntry = origbb.getInt();
+       ByteBuffer result = ByteBuffer.wrap(
+                               ls.nextElement().getEntry());
+
+       Integer retrEntry = result.getInt();
+}
+lh.close();
+bkc.close();
+</code></pre>

Added: bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStream.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStream.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStream.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperStream.textile Sun May 
15 21:38:37 2016
@@ -0,0 +1,124 @@
+Title:        Streaming with BookKeeper
+Notice: 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":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.
+        .
+
+h1. Abstract
+
+This guide contains detailed information about using how to stream bytes on 
top of BookKeeper. It essentially motivates and discusses the basic stream 
operations currently supported.
+
+h1. Summary
+
+p. When using the BookKeeper API, an application has to split the data to 
write into entries, each entry being a byte array. This is natural for many 
applications. For example, when using BookKeeper for write-ahead logging, an 
application typically wants to write the modifications corresponding to a 
command or a transaction. Some other applications, however, might not have a 
natural boundary for entries, and may prefer to write and read streams of 
bytes. This is exactly the purpose of the stream API we have implemented on top 
of BookKeeper. 
+
+p. The stream API is implemented in the package @Streaming@ , and it contains 
two main classes: @LedgerOutputStream@ and  @LedgerInputStream@ . The class 
names are indicative of what they do. 
+
+h1. Writing a stream of bytes
+
+p. Class @LedgerOutputStream@ implements two constructors and five public 
methods: 
+
+ @public LedgerOutputStream(LedgerHandle lh) @ 
+
+p. where: 
+
+*  @lh@ is a ledger handle for a previously created and open ledger. 
+
+
+ @public LedgerOutputStream(LedgerHandle lh, int size) @ 
+
+p. where: 
+
+*  @lh@ is a ledger handle for a previously created and open ledger. 
+*  @size@ is the size of the byte buffer to store written bytes before 
flushing. 
+
+
+ _Closing a stream._ This call closes the stream by flushing the write buffer. 
+
+ @public void close() @ 
+
+p. which has no parameters. 
+
+ _Flushing a stream._ This call essentially flushes the write buffer. 
+
+ @public synchronized void flush() @ 
+
+p. which has no parameters. 
+
+ _Writing bytes._ There are three calls for writing bytes to a stream. 
+
+ @public synchronized void write(byte[] b) @ 
+
+p. where: 
+
+*  @b@ is an array of bytes to write. 
+
+
+ @public synchronized void write(byte[] b, int off, int len) @ 
+
+p. where: 
+
+*  @b@ is an array of bytes to write. 
+*  @off@ is a buffer offset. 
+*  @len@ is the length to write. 
+
+
+ @public synchronized void write(int b) @ 
+
+p. where: 
+
+*  @b@ contains a byte to write. The method writes the least significant byte 
of the integer four bytes. 
+
+
+h1. Reading a stream of bytes
+
+p. Class @LedgerOutputStream@ implements two constructors and four public 
methods: 
+
+ @public LedgerInputStream(LedgerHandle lh) throws BKException, 
InterruptedException @ 
+
+p. where: 
+
+*  @lh@ is a ledger handle for a previously created and open ledger. 
+
+
+ @public LedgerInputStream(LedgerHandle lh, int size) throws BKException, 
InterruptedException @ 
+
+p. where: 
+
+*  @lh@ is a ledger handle for a previously created and open ledger. 
+*  @size@ is the size of the byte buffer to store bytes that the application 
will eventually read. 
+
+
+ _Closing._ There is one call to close an input stream, but the call is 
currently empty and the application is responsible for closing the ledger 
handle. 
+
+ @public void close() @ 
+
+p. which has no parameters. 
+
+ _Reading._ There are three calls to read from the stream. 
+
+ @public synchronized int read() throws IOException @ 
+
+p. which has no parameters. 
+
+ @public synchronized int read(byte[] b) throws IOException @ 
+
+p. where: 
+
+*  @b@ is a byte array to write to. 
+
+
+ @public synchronized int read(byte[] b, int off, int len) throws IOException 
@ 
+
+p. where: 
+
+*  @b@ is a byte array to write to. 
+*  @off@ is an offset for byte array @b@ . 
+*  @len@ is the length in bytes to write to @b@ . 
+

Added: bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperTutorial.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperTutorial.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperTutorial.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/bookkeeperTutorial.textile Sun 
May 15 21:38:37 2016
@@ -0,0 +1,552 @@
+Title:     Bookkeeper Client tutorial
+Notice:    Licensed to the Apache Software Foundation (ASF) under one
+           or more contributor license agreements.  See the NOTICE file
+           distributed with this work for additional information
+           regarding copyright ownership.  The ASF licenses this file
+           to you 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.
+
+This tutorial aims to show you how to build a replicated distributed system 
using Bookkeeper as the replicated log. Before we start, you will need to have 
a bookkeeper cluster up and running. You can download the bookkeeper 
distribution at 
"http://bookkeeper.apache.org/releases.html":http://bookkeeper.apache.org/releases.html.
 The binary distribution, bookkeeper-server-4.x.x-bin.tar.gz, will be 
sufficient for the tutorial.
+This tutorial does not cover the setup of a distributed cluster, but you can 
run a local cluster on your machine by running:
+
+<pre>
+$ bookkeeper-server/bin/bookkeeper localbookie 6
+</pre>
+
+This will start up a local zookeeper instance with 6 bookie servers, as 
bookkeeper storage servers are known. Any data written to this cluster will be 
removed when you kill the process.
+
+The code for this tutorial is available at 
"https://github.com/ivankelly/bookkeeper-tutorial/":https://github.com/ivankelly/bookkeeper-tutorial/.
 Each section has a link with points to a tag for the completed code for that 
section.
+
+h1. The base application
+
+"(full code)":https://github.com/ivankelly/bookkeeper-tutorial/tree/basic
+
+We have a dice application. It generates a new number between 1 and 6 every 
second. 
+
+<pre class="prettyprint">
+public class Dice {
+
+    Random r = new Random();
+
+    void playDice() throws InterruptedException {
+        while (true) {
+            Thread.sleep(1000);
+            System.out.println("Value = " + (r.nextInt(6) + 1));
+        }
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+        Dice d = new Dice();
+        d.playDice();
+    }
+}
+</pre>
+
+Our goal is to have multiple instances of this application, possibly running 
on different machine, which each display the exact same sequence of numbers. If 
one the the instances crashes or becomes unable to communicate with the others 
in any way, it should still not diverge from the sequence of numbers. This 
tutorial will show you how to achieve this.
+
+To start, download the base application, compile and run it.
+<pre>
+$ git clone https://github.com/ivankelly/bookkeeper-tutorial.git
+$ mvn package
+$ mvn exec:java -Dexec.mainClass=org.apache.bookkeeper.Dice
+[INFO] Scanning for projects...
+[INFO]                                                                         
+[INFO] ------------------------------------------------------------------------
+[INFO] Building tutorial 1.0-SNAPSHOT
+[INFO] ------------------------------------------------------------------------
+[INFO] 
+[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ tutorial ---
+[WARNING] Warning: killAfter is now deprecated. Do you need it ? Please 
comment on MEXEC-6.
+Value = 4
+Value = 5
+Value = 3
+...
+...
+</pre>
+
+
+h1. Leaders and followers (and a little bit of background)
+
+To achieve this common view in multiple instances of the program, we need each 
instance to agree on what the next number in the sequence will be. For example, 
the instances must agree that 4 is the first number and 2 is the second number 
and 5 is the third number and so on. This is a difficult problem, especially in 
the case that any instance may go away at any time, and messages between the 
instances can be lost or reordered.
+
+Luckily, there are already algorithms to solve this. 
"Paxos":http://en.wikipedia.org/wiki/Paxos_%28computer_science%29 is an 
abstract algorithm to implement this kind of agreement, while 
"Zab":http://zookeeper.apache.org and 
"Raft":http://en.wikipedia.org/wiki/Raft_%28computer_science%29 are more 
practical protocols. "This video":https://www.youtube.com/watch?v=JEpsBg0AO6o 
gives a good overview about how these algorithms usually look. They all have a 
similar core.
+
+It would be possible to run the Paxos to agree on each number in the sequence. 
However, running Paxos each time can be expensive. What Zab and Raft do is that 
they use a Paxos-like algorithm to elect a leader. The leader then decides what 
the sequence of events should be, putting them in a log, which the other 
instances can then follow to maintain the same state as the leader.
+
+Bookkeeper provides the functionality for the second part of the protocol, 
allowing a leader to write events to a log and have multiple followers tailing 
the log. However, bookkeeper does not do leader election. You will need a 
zookeeper or raft instance for that purpose.
+
+h2. Why not just use zookeeper for everything?
+
+There are a number of reasons:
+
+ 1. Zookeeper's log is only exposed through a tree like interface. It can be 
hard to shoehorn your application into this. 
+ 2. A zookeeper ensemble of multiple machines is limited to one log. You may 
want one log per resource, which will become expensive very quickly.
+ 3. Adding extra machines to a zookeeper ensemble does not increase capacity 
nor throughput.
+
+Bookkeeper can be viewed as a means of exposing zookeeper's replicated log to 
applications in a scalable fashion. However, we still use zookeeper to maintain 
consistency guarantees.
+
+**TL;DR You need to elect a leader instance**
+
+h1. Electing a leader
+
+"(full code)":https://github.com/ivankelly/bookkeeper-tutorial/tree/election
+
+We'll use zookeeper to elect a leader. A zookeeper instance will have started 
locally when you started the localbookie application above. To verify it's 
running, run the following command.
+
+<pre>
+$ echo stat | nc localhost 2181
+Zookeeper version: 3.4.6-1569965, built on 02/20/2014 09:09 GMT
+Clients:
+ /127.0.0.1:59343[1](queued=0,recved=40,sent=41)
+ /127.0.0.1:49354[1](queued=0,recved=11,sent=11)
+ /127.0.0.1:49361[0](queued=0,recved=1,sent=0)
+ /127.0.0.1:59344[1](queued=0,recved=38,sent=39)
+ /127.0.0.1:59345[1](queued=0,recved=38,sent=39)
+ /127.0.0.1:59346[1](queued=0,recved=38,sent=39)
+
+Latency min/avg/max: 0/0/23
+Received: 167
+Sent: 170
+Connections: 6
+Outstanding: 0
+Zxid: 0x11
+Mode: standalone
+Node count: 16
+</pre>
+
+To interact with zookeeper, we'll use the 
"Curator":https://curator.apache.org/ client rather than the stock zookeeper 
client. Getting things right with the zookeeper client can be tricky, and 
curator removes a lot of the pointy corners for you. In fact, curator even 
provides a leader election recipe, so we need to do very little work to get 
leader election in our application.
+
+<pre class="prettyprint">
+public class Dice extends LeaderSelectorListenerAdapter implements Closeable {
+
+    final static String ZOOKEEPER_SERVER = "127.0.0.1:2181";
+    final static String ELECTION_PATH = "/dice-elect";
+
+    ...
+
+    Dice() throws InterruptedException {
+        curator = CuratorFrameworkFactory.newClient(ZOOKEEPER_SERVER,
+                2000, 10000, new ExponentialBackoffRetry(1000, 3));
+        curator.start();
+        curator.blockUntilConnected();
+
+        leaderSelector = new LeaderSelector(curator, ELECTION_PATH, this);
+        leaderSelector.autoRequeue();
+        leaderSelector.start();
+    }
+</pre>
+
+In the constructor for Dice, we need to create the curator client. We specify 
four things when creating the client, the location of the zookeeper service, 
the session timeout, the connect timeout and the retry policy.
+
+The session timeout is a zookeeper concept. If the zookeeper server doesn't 
hear anything from the client for this amount of time, any leases which the 
client holds will be timed out. This is important in leader election. For 
leader election, the curator client will take a lease on ELECTION_PATH. The 
first instance to take the lease will become leader and the rest will become 
followers. However, their claim on the lease will remain in the cue. If the 
first instance then goes away, due to a crash etc., its session will timeout. 
Once the session times out, the lease will be released and the next instance in 
the queue will become the leader. The call to <mark>autoRequeue()</mark> will 
make the client queue itself again if it loses the lease for some other reason, 
such as if it was still alive, but it a garbage collection cycle caused it to 
lose its session, and thereby its lease. I've set the lease to be quite low so 
that when we test out leader election, transitions will be quite quic
 k. The optimum length for session timeout depends very much on the use case. 
The other parameters are the connection timeout, i.e. the amount of time it 
will spend trying to connect to a zookeeper server before giving up, and the 
retry policy. The retry policy specifies how the client should respond to 
transient errors, such as connection loss. Operations that fail with transient 
errors can be retried, and this argument specifies how often the retries should 
occur.
+
+Finally, you'll have noticed that Dice now extends 
<mark>LeaderSelectorListenerAdapter</mark> and implements 
<mark>Closeable</mark>. <mark>Closeable</mark> is there to close the resource 
we have initialized in the constructor, the curator client and the 
<mark>leaderSelector</mark>. <mark>LeaderSelectorListenerAdapter</mark> is a 
callback that the <mark>leaderSelector</mark> uses to notify the instance that 
it is now the leader. It is passed as the third argument to the 
<mark>LeaderSelector</mark> constructor.
+
+<pre class="prettyprint">
+    @Override
+    public void takeLeadership(CuratorFramework client)
+            throws Exception {
+        synchronized (this) {
+            leader = true;
+            try {
+                while (true) {
+                    this.wait();
+                }
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                leader = false;
+            }
+        }
+    }
+</pre>
+
+<mark>takeLeadership()</mark> is the callback called by 
<mark>LeaderSelector</mark> when the instance is leader. It should only return 
when the instance wants to give up leadership. In our case, we never do so we 
wait on the current object until we're interrupted. To signal to the rest of 
the program that we are leader we set a volatile boolean called leader to true. 
This is unset after we are interrupted.
+
+<pre class="prettyprint">
+    void playDice() throws InterruptedException {
+        while (true) {
+            while (leader) {
+                Thread.sleep(1000);
+                System.out.println("Value = " + (r.nextInt(6) + 1)
+                                   + ", isLeader = " + leader);
+            }
+        }
+    }
+</pre>
+
+Finally we modify <mark>playDice()</mark> to only generate random numbers when 
it is the leader.
+
+Run two instances of the program in two different terminals. You'll see that 
one becomes leader and prints numbers and the other just sits there.
+
+Now stop the leader using Control-Z. This will pause the process, but it won't 
kill it. You will be dropped back to the shell in that terminal. After a couple 
of seconds, the session timeout, you will see that the other instance has 
become the leader. Zookeeper will guarantee that only one instance is selected 
as leader at any time.
+
+Now go back to the shell that the original leader was on and wake up the 
process using fg. You'll see something like the following:
+
+<pre>
+...
+...
+Value = 4, isLeader = true
+Value = 4, isLeader = true
+^Z
+[1]+  Stopped                 mvn exec:java 
-Dexec.mainClass=org.apache.bookkeeper.Dice
+$ fg
+mvn exec:java -Dexec.mainClass=org.apache.bookkeeper.Dice
+Value = 3, isLeader = true
+Value = 1, isLeader = false
+</pre>
+
+Whats this!?! The other instance is leader, but this instance first of all 
thinks it is leader and generates a number, and then generates a number even 
though it knows it is not leader. In fact this is perfectly natural. The leader 
election happens on zookeeper, but it takes time changes in the leader to be 
propagated to all instances. So a race occurs where an instance thinks it is 
the leader while zookeeper thinks otherwise.
+
+To solve this problem we need to some way to prevent previous leaders from 
continuing to think they are the leader. Sending a message to the previous 
leader isn't an option. Messages may get lost or delayed or the previous leader 
may be temporarily down. Another way is to use a shared log. All updates are 
written to the shared log before being applied. A new leader can tell this log 
to block writes from previous leaders. This is exactly what bookkeeper does!
+
+h1. Writing to the log
+
+"(full code)":https://github.com/ivankelly/bookkeeper-tutorial/tree/storing
+
+Before we get into the business of blocking previous leaders from writing we 
need to first implement the logic for writing to the log.
+
+<pre class="prettyprint">
+    Dice() throws Exception {
+       ...
+
+        ClientConfiguration conf = new ClientConfiguration()
+            .setZkServers(ZOOKEEPER_SERVER).setZkTimeout(30000);
+        bookkeeper = new BookKeeper(conf);
+    }
+
+</pre>
+
+We construct the bookkeeper client in the <mark>Dice</mark> constructor and 
configure the zookeeper server and zookeeper session timeout that it should 
use. The zookeeper session timeout can be quite large for bookkeeper, as it 
doesn't use anything that depends on the session timeout logic. The bookkeeper 
client should also be closed in <mark>Dice#close()</mark>.
+
+<pre class="prettyprint">
+    void lead() throws Exception {
+        LedgerHandle lh = bookkeeper.createLedger(3, 3, 2,
+                BookKeeper.DigestType.MAC, DICE_PASSWD);
+        try {
+            while (leader) {
+                Thread.sleep(1000);
+                int nextInt = r.nextInt(6) + 1;
+                lh.addEntry(Ints.toByteArray(nextInt));
+                System.out.println("Value = " + nextInt
+                                   + ", isLeader = " + leader);
+            }
+        } finally {
+            lh.close();
+        }
+    }
+
+    void playDice() throws Exception {
+        while (true) {
+            if (leader) {
+                lead();
+            }
+        }
+    }
+</pre>
+
+When we become the leader, we create a new ledger. A ledger is the basic unit 
of bookkeeper. It can be thought of as a segment of a larger log. At this 
moment we are only creating a single ledger, but later we will be creating 
multiple ledgers and connecting them together to create a shared log. For now, 
we just want to get data into a ledger.
+
+The ledger is created with a 3-3-2 configuration. These are the ensemble, the 
write quorum and the ack quorum. The ensemble is the number of bookies the data 
in the ledger will be stored on. All entries may not be stored on all bookies 
if the ensemble is larger than the write quorum. The write quorum is the number 
of bookies each entry is written to. The ack quorum is the number of bookies we 
must get a response from before we acknowledge the write to the client. In this 
case, there are 3 bookies, we write to all 3 every time, but we acknowledge to 
the client when we've received a response from 2. If the ensemble is larger 
than the write quorum, then entries will be striped across the bookies.
+
+The digest type and password are used for checksumming. They prevent clients 
from overwriting each others data in a misconfigured system. They're actually 
unnecessary in this example, but the client api requires them.
+
+Once the ledger is created we can write to it. <mark>addEntry()</mark> will 
append an entry onto the end of the ledger. Entries are byte arrays, so we 
convert the randomly generated integer into a byte array, using 
"Guava":https://code.google.com/p/guava-libraries/'s Ints utility, before 
adding it to the ledger.
+
+Once we are finished with a ledger we must close it. This is actually an 
important step and it fixes the content of the ledger. From this point on the 
ledger is immutable. It cannot be reopened for writing and its contents cannot 
be modified.
+
+Of course, we don't save a reference to the ledger anywhere, so once we have 
written it, no one else can ever access it, even to read it. This is what we 
will deal with in the next section.
+
+h1. Making the log available to others
+
+"(full code)":https://github.com/ivankelly/bookkeeper-tutorial/tree/sharing
+
+Previously we have written to a single ledger. However, we have not provided a 
way to share this between instances. What's more, as a ledger is immutable, 
each leader will have to create its own ledger. So ultimately, when the 
application has run for a while, having changed leaders multiple times, we will 
end up with a list of ledgers. This list of ledgers represents the log of the 
application. Any new instance can print the same output as any preexisting 
instance by simply reading this log.
+
+This list of logs needs to be shared among all instances of the application. 
For this we will use zookeeper. 
+
+<pre class="prettyprint">
+public class Dice extends LeaderSelectorListenerAdapter implements Closeable {
+    ...
+
+    final static String DICE_LOG = "/dice-log";
+</pre>
+
+We define the path of the zookeeper znode in which we want to store the log. A 
znode in zookeeper is like a file. You can write and read byte arrays from a 
znode. However, the contents of a znode must be written and read as a whole, so 
it's best to only store small pieces of data there. Each time a znode is 
updated, a new version is assigned. This can be used for check-and-set 
operations, which is important to avoid race conditions in distributed systems.
+
+<pre class="prettyprint">
+    void lead() throws Exception {
+        Stat stat = new Stat();
+        List<Long> ledgers;
+        boolean mustCreate = false;
+        try {
+            byte[] ledgerListBytes = curator.getData()
+                .storingStatIn(stat).forPath(DICE_LOG);
+            ledgers = listFromBytes(ledgerListBytes);
+        } catch (KeeperException.NoNodeException nne) {
+            ledgers = new ArrayList<Long>();
+            mustCreate = true;
+        }
+        for (Long previous : ledgers) {
+            LedgerHandle lh;
+            try {
+                lh = bookkeeper.openLedger(previous,
+                        BookKeeper.DigestType.MAC, DICE_PASSWD);
+            } catch (BKException.BKLedgerRecoveryException e) {
+                return;
+            }
+            Enumeration<LedgerEntry> entries
+                = lh.readEntries(0, lh.getLastAddConfirmed());
+
+            while (entries.hasMoreElements()) {
+                byte[] entryData = entries.nextElement().getEntry();
+                System.out.println("Value = " + Ints.fromByteArray(entryData)
+                                   + ", epoch = " + lh.getId()
+                                   + ", catchup");
+            }
+        }
+</pre>
+
+We read the list of ledgers from DICE_LOG and store the version in stat. As 
the list of ledgers is in byte form, we need to convert into a java list. If 
this is the first time running, there will be no list of ledgers, and therefore 
no znode containing them. In this case a <mark>NoNodeException</mark> will 
occur. We take note of this using <mark>mustCreate</mark>, as it affects how 
will will update the list later.
+
+Once we have the list, we loop through them, opening the ledgers and printing 
their contents. It's important to note that the default open operation in 
bookkeeper is a fencing open. In a fencing open, anyone who is writing to the 
ledger will receive an exception when they try to write again. This is how we 
exclude other leaders.
+
+<pre class="prettyprint">
+    void lead() throws Exception {
+        ...
+
+        LedgerHandle lh = bookkeeper.createLedger(3, 3, 2,
+                BookKeeper.DigestType.MAC, DICE_PASSWD);
+        ledgers.add(lh.getId());
+        byte[] ledgerListBytes = listToBytes(ledgers);
+        if (mustCreate) {
+            try {
+                curator.create().forPath(DICE_LOG, ledgerListBytes);
+            } catch (KeeperException.NodeExistsException nne) {
+                return;
+            }
+        } else {
+            try {
+                curator.setData()
+                    .withVersion(stat.getVersion())
+                    .forPath(DICE_LOG, ledgerListBytes);
+            } catch (KeeperException.BadVersionException bve) {
+                return;
+            }
+        }
+
+        try {
+            while (leader) {
+                Thread.sleep(1000);
+                int nextInt = r.nextInt(6) + 1;
+                lh.addEntry(Ints.toByteArray(nextInt));
+                System.out.println("Value = " + nextInt
+                                   + ", epoch = " + lh.getId()
+                                   + ", leading");
+            }
+            lh.close();
+        } catch (BKException e) {
+            return;
+        }
+    }
+</pre>
+
+Once we have read all the previous ledgers, we create a new one and add it to 
the list. We must make sure this list is updated before writing to the ledger 
to avoid losing data. If <mark>create()</mark> or <mark>setData()</mark> throw 
an exception, it means that someone is trying to update the list concurrently. 
We must examine if we are still leader, and try again if we are. The retry is 
handled by the loop in <mark>playDice()</mark>.
+
+We can then write to the ledger as before. However, now we have to take care 
to handle the <mark>BKException</mark>. If we receive an exception, it may mean 
that someone has fenced the ledger we are writing to. This means that someone 
else has opened it using <mark>openLedger()</mark>, so they must think that 
they are the leader. Like in the case of concurrent modifications to the ledger 
list, we must examine if we are still leader and then try again if so.
+
+Run a couple of instances of this on your machine. You'll see that when the 
leader changes, it will print out the history of what was written by previous 
leaders.
+
+However, we have a bug! When an instance becomes leader, it will print out the 
whole history, even if it has been leader before. So it is necessary to keep 
track of which updates we have seen been changes of leadership.
+
+h1. Tracking the updates
+
+"(full code)":https://github.com/ivankelly/bookkeeper-tutorial/tree/tracking
+
+Tracking the updates is fairly simple. We just need to keep a record of the 
last thing we printed, and skip past it any time we become leader. 
+
+<pre class="prettyprint">
+    EntryId lead(EntryId skipPast) throws Exception {
+        EntryId lastDisplayedEntry = skipPast;
+</pre>
+
+The signature for <mark>lead()</mark> needs to change so that the last 
displayed update is passed between different invocations. <mark>EntryId</mark> 
is a simple data structure, inside which we can store the ledger id and the 
entry id of the last update we have displayed.
+
+<pre class="prettyprint">
+    EntryId lead(EntryId skipPast) throws Exception {
+        ...
+        List<Long> toRead = ledgers;
+        if (skipPast.getLedgerId() != -1) {
+            toRead = ledgers.subList(ledgers.indexOf(skipPast.getLedgerId()),
+                                     ledgers.size());
+        }
+
+        long nextEntry = skipPast.getEntryId() + 1;
+        for (Long previous : toRead) {
+            LedgerHandle lh;
+            try {
+                lh = bookkeeper.openLedger(previous,
+                        BookKeeper.DigestType.MAC, DICE_PASSWD);
+            } catch (BKException.BKLedgerRecoveryException e) {
+                return lastDisplayedEntry;
+            }
+
+            if (nextEntry > lh.getLastAddConfirmed()) {
+                nextEntry = 0;
+                continue;
+            }
+            Enumeration<LedgerEntry> entries
+                = lh.readEntries(nextEntry, lh.getLastAddConfirmed());
+
+            while (entries.hasMoreElements()) {
+                LedgerEntry e = entries.nextElement();
+                byte[] entryData = e.getEntry();
+                System.out.println("Value = " + Ints.fromByteArray(entryData)
+                                   + ", epoch = " + lh.getId()
+                                   + ", catchup");
+                lastDisplayedEntry = new EntryId(lh.getId(), e.getEntryId());
+            }
+        }
+        ...
+</pre>
+
+The algorithm for reading also changes. Instead of iterating through all the 
ledgers in the list we only iterate through any ledger which is greater to or 
equal to the ledger of the last displayed entry. We also skip past the entry id 
of the last displayed entry when calling <mark>readEntries()</mark>. The only 
special case we need to handle is if the last displayed entry is the last entry 
of a ledger. In this case, we set <mark>nextEntry</mark> to zero, and skip to 
the next ledger.
+
+Any time we do read an entry and display it, we update the last displayed 
entry to reflect this.
+
+<pre class="prettyprint">
+    EntryId lead(EntryId skipPast) throws Exception {
+        ...
+
+        try {
+            while (leader) {
+                Thread.sleep(1000);
+                int nextInt = r.nextInt(6) + 1;
+                long entryId = lh.addEntry(Ints.toByteArray(nextInt));
+                System.out.println("Value = " + nextInt
+                                   + ", epoch = " + lh.getId()
+                                   + ", leading");
+                lastDisplayedEntry = new EntryId(lh.getId(), entryId);
+            }
+            lh.close();
+        } catch (BKException e) {
+            // let it fall through to the return
+        }
+        return lastDisplayedEntry;
+    }
+</pre>
+
+Finally, we also update the last displayed entry any time we add a new entry 
to the log. With this change, new leaders will only print numbers which they 
haven't seen before. You can test this for yourself. Run two instances of the 
application. Stop the leader with Control-Z, and once the other instance has 
become leader, resume the first one (<mark>fg</mark>). Then kill the second 
leader. When the first leader becomes leader again, it will only print the 
number which it missed.
+
+h1. Tailing the log
+
+"(full code)":https://github.com/ivankelly/bookkeeper-tutorial/tree/tailing
+
+Of course, it would be nicer if the followers could keep up to date with the 
leader in the background without having to wait to become leaders themselves. 
To do this we need to tail the log. For the most part this is very similar to 
how we read the previous ledgers when we become leader. However, how we open 
the ledgers is different. When we open the ledgers as leader, we need to ensure 
that no other instance can write to the ledgers from that point onwards. 
Therefore, we use a fencing open, which is the default 
<mark>openLedger()</mark> call in Bookkeeper. However, for tailing the log, we 
don't want to stop the leader from writing new updates, so we use a 
non-fenching open, which is the <mark>openLedgerNoRecovery()</mark> call in 
Bookkeeper.
+
+First we must modify <mark>playDice()</mark> to go into a following state when 
we're not the leader.
+<pre class="prettyprint">
+    void playDice() throws Exception {
+        EntryId lastDisplayedEntry = new EntryId(-1, -1);
+        while (true) {
+            if (leader) {
+                lastDisplayedEntry = lead(lastDisplayedEntry);
+            } else {
+                lastDisplayedEntry = follow(lastDisplayedEntry);
+            }
+        }
+    }
+
+    EntryId follow(EntryId skipPast) throws Exception {
+        List<Long> ledgers = null;
+        while (ledgers == null) {
+            try {
+                byte[] ledgerListBytes = curator.getData()
+                    .forPath(DICE_LOG);
+                ledgers = listFromBytes(ledgerListBytes);
+                if (skipPast.getLedgerId() != -1) {
+                    ledgers = 
ledgers.subList(ledgers.indexOf(skipPast.getLedgerId()),
+                                              ledgers.size());
+                }
+            } catch (KeeperException.NoNodeException nne) {
+                Thread.sleep(1000);
+            }
+        }
+</pre>
+
+The first part of following is almost identical to leading. We read the list 
of ledgers from zookeeper and trim the list to only include ledgers which we 
have displayed already. A thing to note here, is that if we go into following 
mode during the first run of the application, and the leader hasn't created the 
list of ledgers in zookeeper yet we will get an exception. If this occurs we 
try again after 1 second.
+
+Once we have the list, we go into the main tailing loop.
+
+<pre class="prettyprint">
+    EntryId follow(EntryId skipPast) throws Exception {
+        ...
+
+        EntryId lastReadEntry = skipPast;
+        while (!leader) {
+            for (long previous : ledgers) {
+                ...
+            }
+            byte[] ledgerListBytes = curator.getData()
+                .forPath(DICE_LOG);
+            ledgers = listFromBytes(ledgerListBytes);
+            ledgers = 
ledgers.subList(ledgers.indexOf(lastReadEntry.getLedgerId())+1,
+                                      ledgers.size());
+        }
+        return lastReadEntry;
+    }
+</pre>
+
+While we are still leader, we loop over all ledgers in the ledgers list, 
printing their content. Once we have finished with the current list of ledgers, 
we check zookeeper to see if any new ledgers have been added to the list. This 
looks like it would run in a tight loop, but that is not the case. Ledger 
reading loop will wait until the last ledger in the list is closed before 
exiting the loop. When the last ledger in the list is closed, it means that the 
leader must have changed, so there must be a new ledger in the list to read.
+
+<pre class="prettyprint">
+            for (long previous : ledgers) {
+                boolean isClosed = false;
+                long nextEntry = 0;
+                while (!isClosed && !leader) {
+                    if (lastReadEntry.getLedgerId() == previous) {
+                        nextEntry = lastReadEntry.getEntryId() + 1;
+                    }
+                    isClosed = bookkeeper.isClosed(previous);
+                    LedgerHandle lh = bookkeeper.openLedgerNoRecovery(previous,
+                            BookKeeper.DigestType.MAC, DICE_PASSWD);
+
+                    if (nextEntry <= lh.getLastAddConfirmed()) {
+                        ... // read all entries from nextEntry to last add 
confirmed
+                    }
+                    if (isClosed) {
+                        break;
+                    }
+                    Thread.sleep(1000);
+                } 
+            }
+</pre>
+
+For each ledger we enter into an inner loop. First we check if the ledger has 
been closed. If so, once we have read all the entries that we can, we need to 
reopen the ledger to check for any new entries. We continue like this until the 
ledger is either closed, or we become leader.
+
+Note that we are using <mark>openLedgerNoRecovery()</mark> here. The value 
returned by last add confirmed will change after each opening if there are new 
entries which can be read. The last add confirmed is a variable maintained by 
the leader. It is the last entry written for which it has received an ACK 
quorum of acknowledgements. In our case, this means that the entry has been 
acknowledged on at least 2 bookies. It also guarantees that each entry before 
it in that ledger has been acknowledged on 2 bookies.
+
+Once we have read all entries, we check isClosed to see if we need to check 
this ledger again. If not, we break out of the loop and move onto the next 
ledger. Otherwise, we wait a second and try again.
+
+h1. Wrap up
+
+Now you have a fully distributed dice application. Not very useful, but it 
should give you some idea of what is required to make an application fault 
tolerant without losing consistency. Play around with the application. Run many 
instances. Kill a few leaders. You will always see the same sequence of number 
printed to the screen. If not, then you have found a bug, please let us know.
+
+h1. What's next?
+
+The dice application we've written is just and example and is pretty useless 
in the real world. But the principles contained therein could be used to 
replicate pretty much any service. Imagine a simple key value store. This could 
be made replicated by adding all create, put and delete operations to a 
replicated log. Multiple logs could be used if you want to shard your store 
across many servers. And there are many possibilities.
+
+However, this tutorial doesn't address some issues that would be important in 
a real implementation. For starters, the log of the dice application will keep 
growing forever, eventually filling up all your disks and grinding you to a 
halt. Avoiding this problem depends on your individual usecase. For example, if 
you have a key value store, you can take a snapshot of the store every so 
often, and then trim the start of the log to remove anything that had been 
applied by the time the snapshot was taken. Trimming simply means removing 
ledgers from the start of the ledger list. For a messaging application, you 
could keep a record of what each subscriber has consumed and then trim the log 
based on that.
+
+Note that the tutorial application only uses synchronous APIs. The bookkeeper 
client does also have asynchronous APIs, which allow for higher throughput when 
writing. However, this means that you have to manage your state more carefully.
+
+<script 
src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js";></script>
\ No newline at end of file

Added: bookkeeper/site/trunk/content/docs/r4.4.0/doc.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/doc.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/doc.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/doc.textile Sun May 15 21:38:37 
2016
@@ -0,0 +1,21 @@
+Notice: 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":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.
+        .
+
+In the documentation directory, you'll find:
+
+* @build.txt@: Building Hedwig, or how to set up Hedwig
+* @user.txt@: User's Guide, or how to program against the Hedwig API and how 
to run it
+* @dev.txt@: Developer's Guide, or Hedwig internals and hacking details
+
+These documents are all written in the 
"Pandoc":http://johnmacfarlane.net/pandoc/ dialect of 
"Markdown":http://daringfireball.net/projects/markdown/. This makes them 
readable as plain text files, but also capable of generating HTML or LaTeX 
documentation.
+
+Documents are wrapped at 80 chars and use 2-space indentation.
+

Added: bookkeeper/site/trunk/content/docs/r4.4.0/index.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/index.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/index.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/index.textile Sun May 15 21:38:37 
2016
@@ -0,0 +1,52 @@
+Title:     BookKeeper Documentation
+Notice:    Licensed to the Apache Software Foundation (ASF) under one
+           or more contributor license agreements.  See the NOTICE file
+           distributed with this work for additional information
+           regarding copyright ownership.  The ASF licenses this file
+           to you 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.
+
+How to start with BookKeeper depends on who you are...
+
+*Developers* who are new to BookKeeper should start with the "BookKeeper 
Tutorial":./bookkeeperTutorial.html. The tutorial shows you how to build a 
basic distributed system using BookKeeper. "Turning ledgers into 
logs":./bookkeeperLedgers2Logs.html gives a briefer description of the 
principles behind the logs used in the tutorial.
+
+Once familiar with the basic concepts, developers can consult the "BookKeeper 
Java API documentation":./apidocs.
+
+*Administrators* will be more interested in the "BookKeeper Admin 
guide":./bookkeeperConfig.html. It describes the steps involved in setting up 
and maintaining a cluster. The available configuration parameters can be found 
"here":./bookieConfigParams.html. An important aspect of BookKeeper is how it 
deals with the failure of storage nodes. This is covered in "Bookie 
Recovery":./bookieRecovery.html.
+
+*Contributor* documentation is less organized, "BookKeeper 
Internals":./bookkeeperInternals.html is a good place to start. From there you 
can check out our 
"wiki":https://cwiki.apache.org/confluence/display/BOOKKEEPER/Index and ask 
questions on our "mailing lists":/lists.html or "IRC":/irc.html.
+
+h3. All documents
+
+* Overview
+** "Getting started":./bookkeeperStarted.html
+** "Overview":./bookkeeperOverview.html
+
+* Developers
+** "BookKeeper Tutorial":./bookkeeperTutorial.html
+** "Turning ledgers into logs":./bookkeeperLedgers2Logs.html
+** "BookKeeper Java API documentation":./apidocs
+** "Programmer's Guide (old)":./bookkeeperProgrammer.html
+** "BookKeeper Configuration Parameters (old)":./bookkeeperConfigParams.html
+
+
+* Administrators
+** "Admin Guide":./bookkeeperConfig.html
+** "BookKeeper JMX":./bookkeeperJMX.html
+** "Bookie Server Configuration Parameters (old)":./bookieConfigParams.html
+** "Bookie Recovery":./bookieRecovery.html
+
+* Contributors
+** "BookKeeper Internals":./bookkeeperInternals.html
+** "BookKeeper Metadata Management":./bookkeeperMetadata.html
+** "Metastore Interface":./metastore.textile

Added: bookkeeper/site/trunk/content/docs/r4.4.0/metastore.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/metastore.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/metastore.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/metastore.textile Sun May 15 
21:38:37 2016
@@ -0,0 +1,47 @@
+Title:        Metastore Interface
+Notice: 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":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.
+        .
+        .
+
+h1. Metastore Interface
+
+Although Apache BookKeeper provides "LedgerManager":./bookkeeperMetadata.html 
for users to plugin different metadata storages for BookKeeper, it is quite 
difficult to implement a correct and efficient manager version based on the 
knowledge. The __MetaStore__ interface extracts the commonality of the metadata 
storage interfaces and is provided for users to focus on adapting the 
underlying storage itself w/o having to worry about the detailed logic for 
BookKeeper.
+
+h2. MetaStore
+
+The __MetaStore__ interface provide users with access to __MetastoreTable__s 
used for BookKeeper metadata management. There are two kinds of table defined 
in a __MetaStore__, __MetastoreTable__ which provides basic 
__PUT__,__GET__,__REMOVE__,__SCAN__ operations and which does not assume any 
ordering requirements from the underlying storage; and 
__MetastoreScannableTable__ which is derived from __MetastoreTable__, but 
*does* assume that data is stored in key order in the underlying storage.
+
+* @getName@: Return the name of the __MetaStore__.
+* @getVersion@: Return current __MetaStore__ plugin version.
+* @init@: Initialize the __MetaStore__ library with the given configuration 
and its version.
+* @close@: Close the __MetaStore__, freeing all resources. i.e. release all 
the open connections and occupied memory etc.
+* @createTable@: Create a table instance to access the data stored in it. A 
table name is given to locate the table. An __MetastoreTable__ object is 
returned.
+* @createScannableTable@: Similar as __createTable__, but returns 
__MetastoreScannableTable__ rather then __MetastoreTable__ object. If the 
underlying table is not an ordered table, __MetastoreException__ should be 
thrown.
+
+h2. MetaStore Table
+
+__MetastoreTable__ is a basic unit in a __MetaStore__, which is used to handle 
different types of metadata, i.e. A __MetastoreTable__ is used to store 
metadata for ledgers, while the other __MetastoreTable__ is used to store 
metadata for topic persistence info. The interface for a __MetastoreTable__ is 
quite simple:
+
+* @get@: Retrieve a entry by a given __key__. __OK__ and its current version 
in metadata storage is returned when succeed. __NoKey__ returned for a 
non-existent key. If __fields__ are specified, return only the specified fields 
for the key.
+* @put@: Put the given __value__ associated with __key__ with given 
__version__. The value is only updated when the given __version__ equals the 
current version in metadata storage. A new __version__ should be returned when 
updated successfully. __NoKey__ is returned for a non-existent key, 
__BadVersion__ is returned when an update is attempted with a __version__ which 
does not match the one in the metadata store.
+* @remove@: Remove the given __value__ associated with __key__. The value is 
only removed when the given __version__ equals its current version in metadata 
storage. __NoKey__ is returned for a non-existent key, __BadVersion__ is 
returned when remove is attempted with a __version__ which does not match.
+* @openCursor@: Open a __cursor__ to iterate over all the entries of a table. 
The returned cursor doesn't need to guarantee any order and transaction.
+
+h2. MetaStore Scannable Table
+
+__MetastoreScannableTable__ is identical to a __MetastoreTable__ except that 
it provides an addition interface to iterate over entries in the table in key 
order.
+
+* @openCursor@: Open a __cursor__ to iterate over all the entries of a table 
between the key range of __firstKey__ and __lastKey__.
+
+h2. How to organize your metadata.
+
+Some metadata in BookKeeper does not need to be stored in the order of the 
ledger id or the topic. You could use kind of hash table to store metadata for 
them. These metadata are topic ownership and topic persistence info. Besides 
that, subscription state and ledger metadata must be stored in key order due to 
the current logic in BookKeeper.

Added: bookkeeper/site/trunk/content/docs/r4.4.0/releaseNotes.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/docs/r4.4.0/releaseNotes.textile?rev=1743979&view=auto
==============================================================================
--- bookkeeper/site/trunk/content/docs/r4.4.0/releaseNotes.textile (added)
+++ bookkeeper/site/trunk/content/docs/r4.4.0/releaseNotes.textile Sun May 15 
21:38:37 2016
@@ -0,0 +1,243 @@
+Title:     BookKeeper Documentation
+Notice:    Licensed to the Apache Software Foundation (ASF) under one
+           or more contributor license agreements.  See the NOTICE file
+           distributed with this work for additional information
+           regarding copyright ownership.  The ASF licenses this file
+           to you 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.
+
+<h1>Release Notes - Bookkeeper - Version 4.4.0</h1>        
+    
+<h2>        Sub-task
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-438'>BOOKKEEPER-438</a>] 
-         Move ledger id generation out of LedgerManager
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-634'>BOOKKEEPER-634</a>] 
-         Provide admin tool to rename bookie identifier in ledger metadata
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-796'>BOOKKEEPER-796</a>] 
-         Make bookkeeper client use reconnectable zookeeper wrapper
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-837'>BOOKKEEPER-837</a>] 
-         UpdateLedgerOp - Replace AbstractFuture with SettableFuture
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-855'>BOOKKEEPER-855</a>] 
-         handle session expire event in bookie
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-867'>BOOKKEEPER-867</a>] 
-         New Client API to allow applications pass-in EntryId.
+</li>
+</ul>
+                            
+<h2>        Bug
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-578'>BOOKKEEPER-578</a>] 
-         LedgerCacheImpl is reserving 1/3 of Heap size but allocates NonHeap 
memory
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-594'>BOOKKEEPER-594</a>] 
-         AutoRecovery shutting down on SyncDisconnected
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-665'>BOOKKEEPER-665</a>] 
-         BK client should not try to read entries from non-available bookies
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-695'>BOOKKEEPER-695</a>] 
-         Some entry logs are not removed from the bookie storage
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-769'>BOOKKEEPER-769</a>] 
-         Remove hedwig from source tree
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-793'>BOOKKEEPER-793</a>] 
-         Move to java 7
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-794'>BOOKKEEPER-794</a>] 
-         BookkeeperProtocol.Response.status is completely ignored
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-795'>BOOKKEEPER-795</a>] 
-         Race condition causes writes to hang if ledger is fenced
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-797'>BOOKKEEPER-797</a>] 
-         IllegalArgumentException when calling 
CodahaleOpStatsLogger#toOpStatsData()
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-799'>BOOKKEEPER-799</a>] 
-         Distribution schedule coverage sets don&#39;t take gaps in response 
lists into account when writequorum &gt; ackquorum
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-800'>BOOKKEEPER-800</a>] 
-         Expose whether a ledger is closed or not
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-801'>BOOKKEEPER-801</a>] 
-         Bookkeeper client tutorial
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-802'>BOOKKEEPER-802</a>] 
-         Bookkeeper protocol documentation
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-803'>BOOKKEEPER-803</a>] 
-         Guide for making a replicated log out of ledgers
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-804'>BOOKKEEPER-804</a>] 
-         Client program is not terminated when using openLedgerNoRecovery
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-805'>BOOKKEEPER-805</a>] 
-         NullPointException in bookie server when using 
twitter-ostrich-provider
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-809'>BOOKKEEPER-809</a>] 
-         Wrong metric on LedgerDeleteOp and LedgerOpenOp
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-813'>BOOKKEEPER-813</a>] 
-         BookieShell doesn&#39;t find index directory 
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-814'>BOOKKEEPER-814</a>] 
-         clean up temp files that generated by test cases.
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-815'>BOOKKEEPER-815</a>] 
-         Ledger fence state is lost when the ledger file is evicted
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-821'>BOOKKEEPER-821</a>] 
-         Failing to write lastId to ledger directories should not fail startup 
of bookies
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-823'>BOOKKEEPER-823</a>] 
-         Clean up temp files created by hedwig tests
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-828'>BOOKKEEPER-828</a>] 
-         Script for updating docs on website from master branch
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-831'>BOOKKEEPER-831</a>] 
-         Outdated links in tutorial
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-833'>BOOKKEEPER-833</a>] 
-         EntryLogId and EntryLogLimit should not be larger than 
Integer.MAX_VALUE
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-834'>BOOKKEEPER-834</a>] 
-         test case error in test class TestDiskChecker
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-835'>BOOKKEEPER-835</a>] 
-         Update copyright for 2015 on all active branches
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-838'>BOOKKEEPER-838</a>] 
-         ForceWriteThread::run() leaks “logFile.close()” when interrupt 
comes
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-839'>BOOKKEEPER-839</a>] 
-         AuditorPeriodicCheckTest timeout
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-840'>BOOKKEEPER-840</a>] 
-         Deadlock on flushLock on compaction
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-848'>BOOKKEEPER-848</a>] 
-         Use volatile for lastAddConfirmed
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-854'>BOOKKEEPER-854</a>] 
-         NPE on InterleavedLedgerStorage.onRotateEntryLog
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-858'>BOOKKEEPER-858</a>] 
-         Fix broken links and typos in bookkeeper documents
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-863'>BOOKKEEPER-863</a>] 
-         Potential resource leak with unclosed LedgerManager in BookieShell
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-883'>BOOKKEEPER-883</a>] 
-         Test timeout in bookkeeper-benchmark
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-890'>BOOKKEEPER-890</a>] 
-         Concurrent modification exception when removing listener in 
Bookkeeper ZK ledger manager
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-891'>BOOKKEEPER-891</a>] 
-         Read entries failure should trigger callback only once
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-893'>BOOKKEEPER-893</a>] 
-         bookie exited with status 0 on journal I/O exception
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-897'>BOOKKEEPER-897</a>] 
-         Fix findbugs warnings and missing apache license header
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-898'>BOOKKEEPER-898</a>] 
-         Underreplication doesn&#39;t get triggered when a read only bookie is 
shut down
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-899'>BOOKKEEPER-899</a>] 
-         Bookie should return to read-write mode once the disk usage drops 
before the threshold
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-900'>BOOKKEEPER-900</a>] 
-         read only bookie runs replicator and does not release the under 
replicated lock after failing
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-902'>BOOKKEEPER-902</a>] 
-         Test failures in EntryLogTest
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-904'>BOOKKEEPER-904</a>] 
-         test BookieInitializationTest.testDuplicateBookieServerStartup fails 
on non-english machines
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-909'>BOOKKEEPER-909</a>] 
-         ZooKeeper of LocalBookkeeper should use the correct tickTime
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-910'>BOOKKEEPER-910</a>] 
-         In LocalBookkeeper, Zookeeper server and client use different host 
addresses
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-911'>BOOKKEEPER-911</a>] 
-         Fix TestReplicationWorker test failures
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-913'>BOOKKEEPER-913</a>] 
-         Fix flakiness in TestBackwardCompat
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-914'>BOOKKEEPER-914</a>] 
-         ReadOnlyBookieTest.testBookieShouldTurnWritableFromReadOnly is 
intermettently failing
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-917'>BOOKKEEPER-917</a>] 
-         LocalBookKeeperTest seems to be silently failing
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-919'>BOOKKEEPER-919</a>] 
-         Auditor is sometimes marking as failed a bookie switching from 
available to read-only mode
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-921'>BOOKKEEPER-921</a>] 
-         Typo in LocalBookkeeper: Use InetAddress.getHostAddress instead of 
InetAddress
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-925'>BOOKKEEPER-925</a>] 
-         Fix FindBugs discovered issues in master
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-926'>BOOKKEEPER-926</a>] 
-         Compacted entries are not properly synced before updating index
+</li>
+</ul>
+        
+<h2>        Documentation
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-870'>BOOKKEEPER-870</a>] 
-         Change the default value for bookie settings.
+</li>
+</ul>
+                
+<h2>        Improvement
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-537'>BOOKKEEPER-537</a>] 
-         Handling session expire event
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-687'>BOOKKEEPER-687</a>] 
-         Use static final Logger for hedwig related modules
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-760'>BOOKKEEPER-760</a>] 
-         Don&#39;t close PCBC proactively if bookies disappeared from 
zookeeper znodes.
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-810'>BOOKKEEPER-810</a>] 
-         Allow to configure TCP connect timeout
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-811'>BOOKKEEPER-811</a>] 
-         Recovery tool doesn&#39;t remove cookie after recovering one bookie
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-820'>BOOKKEEPER-820</a>] 
-         print out fi.isFenced() in BookieShell
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-827'>BOOKKEEPER-827</a>] 
-         change throttle in GarbageCollector to use either &quot;by 
entry&quot; or &quot;by byte&quot;
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-830'>BOOKKEEPER-830</a>] 
-         Documentation has no structure
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-832'>BOOKKEEPER-832</a>] 
-          Allow starting bookie in ReadOnly mode
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-836'>BOOKKEEPER-836</a>] 
-         disable compaction when disk becomes full, otherwise compaction will 
fill up disk quickly
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-841'>BOOKKEEPER-841</a>] 
-         Bookie should calculate ledgers map writing a new entry log file
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-844'>BOOKKEEPER-844</a>] 
-         Add more metrics about latency and bytes characteristics on bookie 
operations 
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-849'>BOOKKEEPER-849</a>] 
-         Collect stats with sub-milliseconds precision
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-850'>BOOKKEEPER-850</a>] 
-         Use nanoseconds to calculate poll timeout when doing group commit
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-851'>BOOKKEEPER-851</a>] 
-         Configurable LedgerStorageImplementation
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-862'>BOOKKEEPER-862</a>] 
-         Add tracing and stats to OrderedSafeExecutor for debugging slow tasks
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-866'>BOOKKEEPER-866</a>] 
-         Fix compile issue when Updating junit to latest release version( 
4.12) in the test of  Bookkeeper-server.
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-877'>BOOKKEEPER-877</a>] 
-         Script for generating patch for reviews
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-880'>BOOKKEEPER-880</a>] 
-         Make LedgerHandle implement AutoCloseable
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-885'>BOOKKEEPER-885</a>] 
-         Script to merge github pull request
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-886'>BOOKKEEPER-886</a>] 
-         Allow to disable ledgers operation throttling
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-888'>BOOKKEEPER-888</a>] 
-         Dispatch individual callbacks from journal in different threads
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-889'>BOOKKEEPER-889</a>] 
-         BookKeeper client should try not to use bookies with errors/timeouts 
when forming a new ensemble
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-894'>BOOKKEEPER-894</a>] 
-         Read ledger entries from the bookie shell
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-895'>BOOKKEEPER-895</a>] 
-         bookies should not retain ledgers which no longer belong to them
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-920'>BOOKKEEPER-920</a>] 
-         Extend bk-merge-pr.py to add more info to Jira ticket when merging
+</li>
+</ul>
+            
+<h2>        New Feature
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-879'>BOOKKEEPER-879</a>] 
-         Record ledger creation time
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-901'>BOOKKEEPER-901</a>] 
-         Add an authentication framework
+</li>
+</ul>
+                                                        
+<h2>        Task
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-789'>BOOKKEEPER-789</a>] 
-         Update README to reflect bookkeeper modules
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-790'>BOOKKEEPER-790</a>] 
-         Add JNA license in NOTICE files
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-868'>BOOKKEEPER-868</a>] 
-         Add ADD_ENTRY quorum timeout
+</li>
+</ul>
+        
+<h2>        Test
+</h2>
+<ul>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-846'>BOOKKEEPER-846</a>] 
-         TestLedgerChecker times out
+</li>
+<li>[<a 
href='https://issues.apache.org/jira/browse/BOOKKEEPER-892'>BOOKKEEPER-892</a>] 
-         Add a sanity test to help identify bookie nodes with problems that 
prevent writes but is still registered in ZK
+</li>
+</ul>
+        
\ No newline at end of file

Modified: bookkeeper/site/trunk/content/releases.textile
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/content/releases.textile?rev=1743979&r1=1743978&r2=1743979&view=diff
==============================================================================
--- bookkeeper/site/trunk/content/releases.textile (original)
+++ bookkeeper/site/trunk/content/releases.textile Sun May 15 21:38:37 2016
@@ -34,6 +34,14 @@ Release notes for Apache BookKeeper rele
 
 h2(#news). News
 
+h3. 16 May, 2016: release 4.4.0 available
+
+This is the fourth release of BookKeeper as an Apache Top Level Project!
+
+This release fixes some issues in both bookie server and bookkeeper client.
+
+See "BookKeeper 4.3.2 Release Notes":./docs/r4.3.2/releaseNotes.html for 
details.
+
 h3. 30 Nov, 2015: release 4.3.2 available
 
 This is the third release of BookKeeper as an Apache Top Level Project!

Modified: bookkeeper/site/trunk/templates/skeleton.html
URL: 
http://svn.apache.org/viewvc/bookkeeper/site/trunk/templates/skeleton.html?rev=1743979&r1=1743978&r2=1743979&view=diff
==============================================================================
--- bookkeeper/site/trunk/templates/skeleton.html (original)
+++ bookkeeper/site/trunk/templates/skeleton.html Sun May 15 21:38:37 2016
@@ -53,9 +53,10 @@
                    <li><a 
href="/docs/master/bookkeeperTutorial.html">Tutorial</a></li>
                    <li><a href="/docs/master/bookkeeperConfig.html">Admin 
guide</a></li>
                </ul><li>
-                <li><a href="/docs/r4.3.2">Release 4.3.2</a></li>
+                <li><a href="/docs/r4.4.0">Release 4.4.0</a></li>
                 <li class="divider"></li>
                 <li>Older releases</li>
+                <li><a href="/docs/r4.3.2">Release 4.3.2</a></li>
                 <li><a href="/docs/r4.3.1">Release 4.3.1</a></li>
                 <li><a href="/docs/r4.3.0">Release 4.3.0</a></li>
                 <li><a href="/docs/r4.2.4">Release 4.2.4</a></li>


Reply via email to