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]>'].