Status

Current state: Done.

Release: 4.5.0

Problem

Using BookKeeper as a low-latency distributed data storage achiving read-your-writes consistency outside the LAC protocol

The primary purpose of BookKeeper is to be used as distributed transaction log, but for its internal design it can be used as a distributed storage of binary data.

The idea is to store binary objects (BLOBS) as entries inside ledgers. In this case there is no need for "tailing reads" or "fencing".

This way of working can be drafted with this every simple scenario:

 

Design

In BookKeeper 4.4.0 the asyncReadEntries method checks that the range of entries to be retrieved is within the safe range of entry ids according to the LAC protocol:

public void asyncReadEntries(long firstEntry, long lastEntry, ReadCallback cb, Object ctx) {
        // Little sanity check
        if (firstEntry < 0 || firstEntry > lastEntry) {
            LOG.error("IncorrectParameterException on ledgerId:{} firstEntry:{} lastEntry:{}",
                    new Object[] { ledgerId, firstEntry, lastEntry });
            cb.readComplete(BKException.Code.IncorrectParameterException, this, null, ctx);
            return;
        }
        if (lastEntry > lastAddConfirmed) {
            LOG.error("ReadException on ledgerId:{} firstEntry:{} lastEntry:{}",
                    new Object[] { ledgerId, firstEntry, lastEntry });
            cb.readComplete(BKException.Code.ReadException, this, null, ctx);
            return;
        }
        asyncReadEntriesInternal(firstEntry, lastEntry, cb, ctx);
    }

The Idea is to add a new BookKeeper client side  method "readUnconfirmedEntries" (and the async counterpart) which does not check for the LastAddConfirmed range

public void asyncReadUnconfirmedEntries(long firstEntry, long lastEntry, ReadCallback cb, Object ctx) {
        // Little sanity check
        if (firstEntry < 0 || firstEntry > lastEntry) {
            LOG.error("IncorrectParameterException on ledgerId:{} firstEntry:{} lastEntry:{}",
                    new Object[] { ledgerId, firstEntry, lastEntry });
            cb.readComplete(BKException.Code.IncorrectParameterException, this, null, ctx);
            return;
        }
        asyncReadEntriesInternal(firstEntry, lastEntry, cb, ctx);
    }

 

We can say that there is an out-of-band contract between the writer and the readers, we only want to achieve "read-your-writes consistency"

Actions

Rejected Alternatives:

 

Related works: