This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 2915f55  ISSUE #553: Documentation for new fluent API
2915f55 is described below

commit 2915f55c9714fcfb88ad443f5d957b786736ecbd
Author: Sijie Guo <[email protected]>
AuthorDate: Fri Nov 24 12:28:55 2017 -0800

    ISSUE #553: Documentation for new fluent API
    
    Descriptions of the changes in this PR:
    
    - Add documentation for the new fluent API: create/open/delete, 
append/write/read, createadv
    
    Author: Sijie Guo <[email protected]>
    
    Reviewers: Enrico Olivelli <[email protected]>, Jia Zhai <None>
    
    This closes #764 from sijie/api_documentation, closes #553
---
 site/docs/4.6.0/api/ledger-api.md      | 274 +++++++++++++++++++++++++++++++++
 site/docs/latest/api/ledger-adv-api.md |  29 ++++
 2 files changed, 303 insertions(+)

diff --git a/site/docs/4.6.0/api/ledger-api.md 
b/site/docs/4.6.0/api/ledger-api.md
index 8aa42ce..acde8d6 100644
--- a/site/docs/4.6.0/api/ledger-api.md
+++ b/site/docs/4.6.0/api/ledger-api.md
@@ -471,3 +471,277 @@ mvn exec:java -Dexec.mainClass=org.apache.bookkeeper.Dice
 Value = 3, isLeader = true
 Value = 1, isLeader = false
 ```
+
+## New API
+
+Since 4.6 BookKeeper provides a new client API which leverages Java8 
[CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
 facility.
+[WriteHandle](../javadoc/org/apache/bookkeeper/client/api/WriteHandle), 
[WriteAdvHandle](../javadoc/org/apache/bookkeeper/client/api/WriteAdvHandle), 
[ReadHandle](../javadoc/org/apache/bookkeeper/client/api/ReadHandle) are 
introduced for replacing the generic 
[LedgerHandle](../javadoc/org/apache/bookkeeper/client/LedgerHandle).
+
+> All the new API now is available in `org.apache.bookkeeper.client.api`. You 
should only use interfaces defined in this package.
+
+*Beware* that this API in 4.6 is still experimental API and can be subject to 
changes in next minor releases.
+
+### Create a new client
+
+In order to create a new 
[`BookKeeper`](../javadoc/org/apache/bookkeeper/client/api/BookKeeper) client 
object, you need to construct a 
[`ClientConfiguration`](../javadoc/org/apache/bookkeeper/conf/ClientConfiguration)
 object and set a [connection string](#connection-string) first, and then use 
[`BookKeeperBuilder`](../javadoc/org/apache/bookkeeper/client/api/BookKeeperBuilder)
 to build the client.
+
+Here is an example building the bookkeeper client.
+
+```java
+// construct a client configuration instance
+ClientConfiguration conf = new ClientConfiguration();
+conf.setZkServers(zkConnectionString);
+conf.setZkLedgersRootPath("/path/to/ledgers/root");
+
+// build the bookkeeper client
+BookKeeper bk = BookKeeper.newBuilder(conf)
+    .statsLogger(...)
+    ...
+    .build();
+
+```
+
+### Create ledgers
+
+the easiest way to create a {% pop ledger %} using the java client is via the 
[`createbuilder`](../javadoc/org/apache/bookkeeper/client/api/createbuilder). 
you must specify at least
+a [`digesttype`](../javadoc/org/apache/bookkeeper/client/api/digesttype) and a 
password.
+
+here's an example:
+
+```java
+BookKeeper bk = ...;
+
+byte[] password = "some-password".getBytes();
+
+WriteHandle wh = bk.newCreateLedgerOp()
+    .withDigestType(DigestType.CRC32)
+    .withPassword(password)
+    .withEnsembleSize(3)
+    .withWriteQuorumSize(3)
+    .withAckQuorumSize(2)
+    .execute()          // execute the creation op
+    .get();             // wait for the execution to complete
+```
+
+A [`WriteHandle`](../javadoc/org/apache/bookkeeper/client/api/WriteHandle) is 
returned for applications to write and read entries to and from the ledger.
+
+### Append entries to ledgers
+
+The [`WriteHandle`](../javadoc/org/apache/bookkeeper/client/api/WriteHandle) 
can be used for applications to append entries to the ledgers.
+
+```java
+WriteHandle wh = ...;
+
+CompletableFuture<Long> addFuture = wh.append("Some entry data".getBytes());
+
+// option 1: you can wait for add to complete synchronously
+try {
+    long entryId = FutureUtils.result(addFuture.get());
+} catch (BKException bke) {
+    // error handling
+}
+
+// option 2: you can process the result and exception asynchronously
+addFuture
+    .thenApply(entryId -> {
+        // process the result
+    })
+    .exceptionally(cause -> {
+        // handle the exception
+    })
+
+// option 3: bookkeeper provides a twitter-future-like event listener for 
processing result and exception asynchronously
+addFuture.whenComplete(new FutureEventListener() {
+    @Override
+    public void onSuccess(long entryId) {
+        // process the result
+    }
+    @Override
+    public void onFailure(Throwable cause) {
+        // handle the exception
+    }
+});
+```
+
+The append method supports three representations of a bytes array: the native 
java `byte[]`, java nio `ByteBuffer` and netty `ByteBuf`.
+It is recommended to use `ByteBuf` as it is more gc friendly.
+
+### Open ledgers
+
+You can open ledgers to read entries. Opening ledgers is done by 
[`openBuilder`](../javadoc/org/apache/bookkeeper/client/api/openBuilder). You 
must specify the ledgerId and the password
+in order to open the ledgers.
+
+here's an example:
+
+```java
+BookKeeper bk = ...;
+
+long ledgerId = ...;
+byte[] password = "some-password".getBytes();
+
+ReadHandle rh = bk.newOpenLedgerOp()
+    .withLedgerId(ledgerId)
+    .withPassword(password)
+    .execute()          // execute the open op
+    .get();             // wait for the execution to complete
+```
+
+A [`ReadHandle`](../javadoc/org/apache/bookkeeper/client/api/ReadHandle) is 
returned for applications to read entries to and from the ledger.
+
+#### Recovery vs NoRecovery
+
+By default, the 
[`openBuilder`](../javadoc/org/apache/bookkeeper/client/api/openBuilder) opens 
the ledger in a `NoRecovery` mode. You can open the ledger in `Recovery` mode 
by specifying
+`withRecovery(true)` in the open builder.
+
+```java
+BookKeeper bk = ...;
+
+long ledgerId = ...;
+byte[] password = "some-password".getBytes();
+
+ReadHandle rh = bk.newOpenLedgerOp()
+    .withLedgerId(ledgerId)
+    .withPassword(password)
+    .withRecovery(true)
+    .execute()
+    .get();
+
+```
+
+**What is the difference between "Recovery" and "NoRecovery"?**
+
+If you are opening a ledger in "Recovery" mode, it will basically fence and 
seal the ledger -- no more entries are allowed
+to be appended to it. The writer which is currently appending entries to the 
ledger will fail with 
[`LedgerFencedException`](../javadoc/org/apache/bookkeeper/client/api/BKException.Code#LedgerFencedException).
+
+In constrat, opening a ledger in "NoRecovery" mode, it will not fence and seal 
the ledger. "NoRecovery" mode is usually used by applications to tailing-read 
from a ledger.
+
+### Read entries from ledgers
+
+The [`ReadHandle`](../javadoc/org/apache/bookkeeper/client/api/ReadHandle) 
returned from the open builder can be used for applications to read entries 
from the ledgers.
+
+```java
+ReadHandle rh = ...;
+
+long startEntryId = ...;
+long endEntryId = ...;
+CompletableFuture<LedgerEntries> readFuture = rh.read(startEntryId, 
endEntryId);
+
+// option 1: you can wait for read to complete synchronously
+try {
+    LedgerEntries entries = FutureUtils.result(readFuture.get());
+} catch (BKException bke) {
+    // error handling
+}
+
+// option 2: you can process the result and exception asynchronously
+readFuture
+    .thenApply(entries -> {
+        // process the result
+    })
+    .exceptionally(cause -> {
+        // handle the exception
+    })
+
+// option 3: bookkeeper provides a twitter-future-like event listener for 
processing result and exception asynchronously
+readFuture.whenComplete(new FutureEventListener<>() {
+    @Override
+    public void onSuccess(LedgerEntries entries) {
+        // process the result
+    }
+    @Override
+    public void onFailure(Throwable cause) {
+        // handle the exception
+    }
+});
+```
+
+Once you are done with processing the 
[`LedgerEntries`](../javadoc/org/apache/bookkeeper/client/api/LedgerEntries), 
you can call `#close()` on the `LedgerEntries` instance to
+release the buffers held by it.
+
+Applications are allowed to read any entries between `0` and 
[`LastAddConfirmed`](../javadoc/org/apache/bookkeeper/client/api/ReadHandle.html#getLastAddConfirmed).
 If the applications
+attempts to read entries beyond `LastAddConfirmed`, they will receive 
[`IncorrectParameterException`](../javadoc/org/apache/bookkeeper/client/api/BKException.Code#IncorrectParameterException).
+
+### Read unconfirmed entries from ledgers
+
+`readUnconfirmed` is provided the mechanism for applications to read entries 
beyond `LastAddConfirmed`. Applications should be aware of `readUnconfirmed` 
doesn't provide any
+repeatable read consistency.
+
+```java
+CompletableFuture<LedgerEntries> readFuture = rh.readUnconfirmed(startEntryId, 
endEntryId);
+```
+
+### Tailing Reads
+
+There are two methods for applications to achieve tailing reads: `Polling` and 
`Long-Polling`.
+
+#### Polling
+
+You can do this in synchronous way:
+
+```java
+ReadHandle rh = ...;
+
+long startEntryId = 0L;
+long nextEntryId = startEntryId;
+int numEntriesPerBatch = 4;
+while (!rh.isClosed() || nextEntryId <= rh.getLastAddConfirmed()) {
+    long lac = rh.getLastAddConfirmed();
+    if (nextEntryId > lac) {
+        // no more entries are added
+        Thread.sleep(1000);
+
+        lac = rh.readLastAddConfirmed().get();
+        continue;
+    }
+
+    long endEntryId = Math.min(lac, nextEntryId + numEntriesPerBatch - 1);
+    LedgerEntries entries = rh.read(nextEntryId, endEntryId).get();
+
+    // process the entries
+
+    nextEntryId = endEntryId + 1;
+}
+```
+
+#### Long Polling
+
+```java
+ReadHandle rh = ...;
+
+long startEntryId = 0L;
+long nextEntryId = startEntryId;
+int numEntriesPerBatch = 4;
+while (!rh.isClosed() || nextEntryId <= rh.getLastAddConfirmed()) {
+    long lac = rh.getLastAddConfirmed();
+    if (nextEntryId > lac) {
+        // no more entries are added
+        try (LastConfirmedAndEntry lacAndEntry = 
rh.readLastAddConfirmedAndEntry(nextEntryId, 1000, false).get()) {
+            if (lacAndEntry.hasEntry()) {
+                // process the entry
+
+                ++nextEntryId;
+            }
+        }
+    } else {
+        long endEntryId = Math.min(lac, nextEntryId + numEntriesPerBatch - 1);
+        LedgerEntries entries = rh.read(nextEntryId, endEntryId).get();
+
+        // process the entries
+        nextEntryId = endEntryId + 1;
+    }
+}
+```
+
+### Delete ledgers
+
+{% pop Ledgers %} can be deleted by using 
[`DeleteBuilder`](../javadoc/org/apache/bookkeeper/client/api/DeleteBuilder).
+
+```java
+BookKeeper bk = ...;
+long ledgerId = ...;
+
+bk.newDeleteLedgerOp()
+    .withLedgerId(ledgerId)
+    .execute()
+    .get();
+```
diff --git a/site/docs/latest/api/ledger-adv-api.md 
b/site/docs/latest/api/ledger-adv-api.md
index f46950d..df6224d 100644
--- a/site/docs/latest/api/ledger-adv-api.md
+++ b/site/docs/latest/api/ledger-adv-api.md
@@ -60,6 +60,26 @@ LedgerHandleAdv handle = bkClient.createLedgerAdv(
 > If a ledger already exists when users try to create an advanced ledger with 
 > same ledger id,
 > a 
 > [LedgerExistsException](../javadoc/org/apache/bookkeeper/client/BKException.BKLedgerExistException.html)
 >  is thrown by the bookkeeper client.
 
+Creating advanced ledgers can be done throught a fluent API since 4.6.
+
+```java
+BookKeeper bk = ...;
+
+byte[] passwd = "some-passwd".getBytes();
+
+WriteHandle wh = bk.newCreateLedgerOp()
+    .withDigestType(DigestType.CRC32)
+    .withPassword(passwd)
+    .withEnsembleSize(3)
+    .withWriteQuorumSize(3)
+    .withAckQuorumSize(2)
+    .makeAdv()                  // convert the create ledger builder to create 
ledger adv builder
+    .withLedgerId(1234L)
+    .execute()                  // execute the creation op
+    .get();                     // wait for the execution to complete
+
+```
+
 ### Add Entries
 
 The normal [add entries api](ledger-api/#adding-entries-to-ledgers) in 
advanced ledgers are disabled. Instead, when users want to add entries
@@ -71,6 +91,15 @@ long entryId = ...; // entry id generated externally
 ledger.addEntry(entryId, "Some entry data".getBytes());
 ```
 
+If you are using the new API, you can do as following:
+
+```java
+WriteHandle wh = ...;
+long entryId = ...; // entry id generated externally
+
+wh.write(entryId, "Some entry data".getBytes()).get();
+```
+
 A few notes when using this API:
 
 - The entry id has to be non-negative.

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to