DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
Motivation
Currently (in BookKeeper 4.5) we have several overloaded versions of the methods createLedger/createLedegerAdv/asyncCreateLeader/asyncCreateLeaderAdv. This methods are present because from version to version we added new configuration options for the Ledger.
In order to support new features in the future we need to have a more extensible API.
Proposed Change
We can use the Builder design pattern to define a new unified createLedger and asyncCreateLedger APISo we will introduce a new set of APIs to construct Ledgers, in the future this pattern will be extended to other operations, like deleteLedger/closeLedger/addEntry.
This is an example of the new API BookKeeper bookeeper = how the client code will look like:
| Code Block |
|---|
BookKeeper bookeeper = ....; |
...
LedgerConfiguration ledgerConfiguration = LedgerConfiguration.builder()
.ensembleSize(3)
.writeQuorumSize(2)
.ackQuorumSize(1)
.digestType(DigestType.CRC32)
.customMetadata(Map<String, byte[]> metadata)
.password(password)
.advanced(true|false);
LedgerHandle ledger = bookeeper.createLedger(ledgerConfiguration);
bookeeper.createLedgerAsync(ledgerConfiguration, createCallback, ctx);
So we will introduce a new LedgerConfiguration class which defines the configuration options of the Ledger and we will support a new simple API which takes that structure.
Existing API will be supported, and maybe it will be deprecated and finally dropped in new major releases (5.0.0)
New or Changed Public Interfaces
We are going to introduce the LedgerConfiguration class which defines the specification for new ledgers.
| Code Block |
|---|
public final LedgerConfiguration { CompletableFuture<WriteHandler> future = bookkeeper.createLedger() .withEnsembleSize(3) .withWriteQuorumSize(2) .withAckQuorumSize(1) .withDigestType(DigestType.CRC32) private final int ensembleSize = 1; .withCustomMetadata(metadata) private final int writeQuorumSize = 1; private final int ackQuorumSize = 1; .withPassword(password) .apply(); WriteHandler lh = future.get(); CompletableFuture<WriteAdvHandler> future = bookkeeper.createLedger() .withEnsembleSize(3) .withWriteQuorumSize(2) .withAckQuorumSize(1) .withDigestType(DigestType.CRC32) private final DigestType digestType = DigestType.CRC32; private final byte[] password = EMPTY_ARRAY; .withCustomMetadata(metadata) .withPassword(password) .withLedgerId(ledgerId) private final.makeAdv() boolean advanced = false .apply(); WriteAdvHandler lh = future.get(); |
In order to achieve this goal we are going to introduce CreateBuilder and CreateBuilderAdv interfaces
| Code Block |
|---|
interface CreateBuilder { CreateBuilder withEnsembleSize(...); private final Map<String, byte[]> customMetadata = null; (will be an un-modifiable Map) CreateBuilder withWriteQuorumSize(...); ... CreateAdvBuilder makeAdv(); // old style callbacks void /**execute(CreateCallback callback, Object ctx); // support java8 completable future CompletableFuture<WriteHandler> *apply(); Create a new LedgerConfiguration with// defaultsync valuesmethod WriteHandler create() throws BKException, InterruptedException; } interface **/ CreateAdvBuilder { // old style callbacks public static Builder builder() { return new Builder(); }void execute(CreateCallback callback, Object ctx); // support java8 completable future /**CompletableFuture<WriteAdvHandler> apply(); // sync method WriteAdvHandler create() throws * Create a new LedgerConfiguration using another configuration as starting values BKException, InterruptedException; } interface OpenBuilder { OpenBuilder withRecovery(boolean) OpenBuilder withPassword(password) **/ OpenBuilder withDigestType(digestType) CompletableFuture<ReadHandler> apply(long ledgerId) void open(long publicledgerId, staticOpenCallback Builder cloning(LedgerConfiguration configuration) {......} cb, Object ctx) ReadHandler open(long ledgerId) } |
And we will make CrateLedgerOp implement such interfaces.
We are going to introduce a new BookKeeper interface
| Code Block |
|---|
interface BookKeeper extends AutoCloseable { public static final classCreateBuilder BuildercreateLedger() {; OpenBuilder openLedger(); } |
We are going to introduce WriteHandler and WriteHandlerAdv interfaces which contains only the API related to writing to a Ledger, following the LedgerHandler/LedgerHandlerAdv semantics.
In a similar way we are going to introduce a ReadHandler which contains only the API related to reading to a Ledger and a OpenBuilder.
Please note that WriteHandler and WriteAdvHandler will extend ReadHandler as writer need to be able to read its own writes.
A common Handler interface will be a base interface for ReadHandler and it will contain basic operations like 'close'
| Code Block |
|---|
interface Handler extends AutoCloseable { void close(); ... builder methods... void asyncClose(CloseCallback cb, Object ctx); } interface ReadHandler extends Handler { void readEntries(); long readLastAddConfirmed(); ..... public LedgerConfiguration build() throws BKException; } interface WriteHandler extends ReadHandler { void addEntry(byte[] data) void sync(...) } interface WriteAdvHandler extends }ReadHandler } |
This new class will be immutable and it will provide only getters.
On BookKeeper class we are going to introduce this new methods
| Code Block |
|---|
public LedgerHandle createLedger(LedgerConfiguration ledgerConfiguration); public void asyncCreateLedger(LedgerConfiguration ledgerConfiguration, CreateCallback callback, Object context); public CompletableFuture<LedgerHandle> asyncCreateLedger(LedgerConfiguration ledgerConfiguration);{ void addEntry(long entryID, byte[] data) void sync(...) } |
Migration Plan and Compatibility
No issue about migration and compatibility.
Legacy methods will be retained. No @Deprecated annotation will be added.
Further Futher removal of existing APIs will be evaluated in the future, maybe while starting a new major release, like 5.0.0
Further works
We can create similar API style for addEntry, readEntries and other operations which need an extensible API.
We would leverage CompletableFuture for operations like close, delete, addEntry, readEntries....
Rejected Alternatives
An alternative is not to explicitly add a LedgerConfiguration class but to add some builder method to the BookKeper class, like
This is an example of an alternative API which has been rejected, as it will not be really extensible in the future.
The rejected idea is about using the builder pattern for creating LedgerConfiguration structures and not directly ledgers
| Code Block |
|---|
BookKeeper bookeeper = |
| Code Block |
BookKeeper bookkeeper =.....; CompletableFuture<LedgerHandle> lh LedgerConfiguration ledgerConfiguration = bookkeeperLedgerConfiguration.newLedgerBuilderbuilder() .ensembleSize(5) .ensembleSize(3) .writeQuorumSize(2) .ackQuorumSize(1) .digestType(DigestType.CRC32) .customMetadata(Map<String, byte[]> metadata) .password(password) .advanced(true|false); LedgerHandle ledger = bookeeper.createLedger(ledgerConfiguration); |
...
|