As part of BOOKKEEPER-643 (
https://github.com/apache/bookkeeper/commit/694568b0ff0d048c284c8d5db0c9455d30dfa3ce),
"entryLogFilePreallocationEnabled" logic is introduced in EntryLogger.java.

Because of this logic, preallocated entryLogChannel will be used as a newly
created logchannel even though the ledgerDir, in which it is created, is
full.

Consider the following example -

1) We have configured Bookies with two LedgerDirs - 'ledgerDir1',
'ledgerDir2'
2) lets say current active channel in EntryLogger is 'logChannel1' which is
created in 'ledgerDir1'
3) since 'entryLogFilePreallocationEnabled' is enabled by default, when we
set 'logChannel1' as the current active channel, we create async task to
create a new logChannel for future purpose (check
allocatorExecutor.submit(allocateNewLog task))
4) currently both the ledgerDirs are in writable state, so for precreation
of new logchannel it might pick any ledgerdir
5) lets say it chose 'ledgerDir1' again for the creation of new logchannel
- 'logChannel2'
6) now lets assume ledgerDir1 is full, in that case shouldCreateNewEntryLog
will be set to true
7) if a new entry is added to entrylogger, then since
shouldCreateNewEntryLog is set to true, it will close the current active
logchannel - 'logChannel1' and add it to logChannelsToFlush list.
8) For new logChannel it will get the preallocated log - 'logChannel2' and
will continue to use it as current active channel, though 'ledgerDir1' is
not writable anymore.

relevant code snippets in EntryLogger.java

    private LedgerDirsListener getLedgerDirsListener() {
        return new LedgerDirsListener() {
            @Override
            public void diskFull(File disk) {
                // If the current entry log disk is full, then create new
entry
                // log.
                if (currentDir != null && currentDir.equals(disk)) {
                    shouldCreateNewEntryLog.set(true);
                }
            }

            @Override
            public void diskAlmostFull(File disk) {
                // If the current entry log disk is almost full, then
create new entry
                // log.
                if (currentDir != null && currentDir.equals(disk)) {
                    shouldCreateNewEntryLog.set(true);
                }
            }
....
}

    synchronized long addEntry(long ledger, ByteBuffer entry, boolean
rollLog) throws IOException {
.....
        boolean createNewLog = shouldCreateNewEntryLog.get();
        if (createNewLog || reachEntryLogLimit) {
            if (doRegularFlushes) {
                flushCurrentLog();
            }
            createNewLog();
            // Reset the flag
            if (createNewLog) {
                shouldCreateNewEntryLog.set(false);
            }
        }
.....
    }


        synchronized BufferedLogChannel createNewLog() throws IOException {
            BufferedLogChannel bc;
            if (!entryLogPreAllocationEnabled || null == preallocation) {
                // initialization time to create a new log
                bc = allocateNewLog();
            } else {
                // has a preallocated entry log
                try {
                    bc = preallocation.get();
...
                preallocation = allocatorExecutor.submit(new
Callable<BufferedLogChannel>() {
                    @Override
                    public BufferedLogChannel call() throws IOException {
                        return allocateNewLog();
                    }
                });
            }
            LOG.info("Created new entry logger {}.", bc.getLogId());
            return bc;
        }

Thanks,
Charan

Reply via email to