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
So 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 how the client code will look like:
BookKeeper bookeeper = ....;
CompletableFuture<WriteHandler> future = bookkeeper.createLedger()
.withEnsembleSize(3)
.withWriteQuorumSize(2)
.withAckQuorumSize(1)
.withDigestType(DigestType.CRC32)
.withCustomMetadata(metadata)
.withPassword(password)
.apply();
IWriterHandler lh = future.get();
CompletableFuture<WriteHandlerAdv> future = bookkeeper.createLedger()
.withEnsembleSize(3)
.withWriteQuorumSize(2)
.withAckQuorumSize(1)
.withDigestType(DigestType.CRC32)
.withCustomMetadata(metadata)
.withPassword(password)
.withLedgerId(ledgerId)
.makeAdv()
.apply();
IWriterHandlerAdv lh = future.get();
In order to achieve this goal we are going to introduce a ICreateBuilder and ICreateAdvBuilder interfaces
interface ICreateBuilder {
ICreateBuilder withEnsembleSize(...);
ICreateBuilder withWriteQuorumSize(...);
...
ICreateAdvBuilder makeAdv();
// old style callbacks
void execute(CreateCallback callback, Object ctx);
// support java8 completable future
CompletableFuture<IWriteHandler> apply();
// sync method
IWriteHandler create() throws BKException, InterruptedException;
}
interface ICreateAdvBuilder {
// old style callbacks
void execute(CreateCallback callback, Object ctx);
// support java8 completable future
CompletableFuture<IWriteHandlerAdv> apply();
// sync method
IWriteHandlerAdv create() throws BKException, InterruptedException;
}
And we will make CrateLedgerOp implement such interfaces.
We are going to introduce an IBookKeeper interface
interface IBookKeeper {
ICreateBuilder createLedger();
IOpenBuilder openLedger();
}
We are going to introduce IWriteHandler and IWriteHandlerAdv 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 IReadHandler which contains only the API related to reading to a Ledger and a IOpenBuilder.
Please note that IWriteHandler and IWriteHandlerAdv will extend IReadHandler as writer need to be able to read its own writes.
A common ILedgerHandler interface will be a base interface for IReadHandler and it will contain basic operations like 'close'
interface IOpenBuilder {
IOpenBuilder withRecovery(boolean)
IOpenBuilder withPassword(password)
IOpenBuilder withDigestType(digestType)
CompleableFuture<IReadHandler> apply(long ledgerId)
void open(long ledgerId, OpenCallback cb, Object ctx)
IReadHandler open(long ledgerId)
}
interface ILedgerHandler {
void close();
void asyncClose();
}
interface IReadHandler extends ILedgerHandler {
void readEntries();
long readLastAddConfirmed();
.....
}
interface IWriteHandler extends IReadHandler {
void addEntry(byte[] data)
void sync(...)
}
interface IWriteHandlerAdv extends IReadHandler {
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 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 and other operations which need an extensible API.
Rejected Alternatives
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
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);