Package com.sleepycat.je.log

Source Code of com.sleepycat.je.log.LogBuffer

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002, 2011 Oracle and/or its affiliates.  All rights reserved.
*
*/

package com.sleepycat.je.log;

import java.nio.ByteBuffer;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.latch.Latch;
import com.sleepycat.je.utilint.DbLsn;

/**
* LogBuffers hold outgoing, newly written log entries.
*/
public class LogBuffer implements LogSource {

    private static final String DEBUG_NAME = LogBuffer.class.getName();

    /* Storage */
    private final ByteBuffer buffer;

    /* Information about what log entries are held here. */
    private long firstLsn;
    private long lastLsn;

    /* The read latch serializes access to and modification of the LSN info. */
    private Latch readLatch;

    /*
     * Buffer may be rewritten because an IOException previously occurred.
     */
    private boolean rewriteAllowed;

    LogBuffer(int capacity, EnvironmentImpl env)
        throws DatabaseException {

        buffer = ByteBuffer.allocate(capacity);
        readLatch = new Latch(DEBUG_NAME);
        reinit();
    }

    /*
     * Used by LogManager for the case when we have a temporary buffer in hand
     * and no LogBuffers in the LogBufferPool are large enough to hold the
     * current entry being written.  We just wrap the temporary ByteBuffer
     * in a LogBuffer and pass it to FileManager. [#12674].
     */
    LogBuffer(ByteBuffer buffer, long firstLsn) {
        this.buffer = buffer;
        this.firstLsn = firstLsn;
        this.lastLsn = firstLsn;
        rewriteAllowed = false;
    }

    void reinit()
        throws DatabaseException {

        readLatch.acquire();
        buffer.clear();
        firstLsn = DbLsn.NULL_LSN;
        lastLsn = DbLsn.NULL_LSN;
        rewriteAllowed = false;
        readLatch.release();
    }

    /*
     * Write support
     */

    /**
     * Return first LSN held in this buffer. Assumes the log write latch is
     * held.
     */
    public long getFirstLsn() {
        return firstLsn;
    }

    /**
     * This LSN has been written to the log.
     */
    void registerLsn(long lsn)
        throws DatabaseException {

        readLatch.acquire();
        try {
            if (lastLsn != DbLsn.NULL_LSN) {
                assert (DbLsn.compareTo(lsn, lastLsn) > 0):
                    "lsn=" + lsn + " lastlsn=" + lastLsn;
            }
            lastLsn = lsn;
            if (firstLsn == DbLsn.NULL_LSN) {
                firstLsn = lsn;
            }
        } finally {
            readLatch.release();
        }
    }

    /**
     * Check capacity of buffer. Assumes that the log write latch is held.
     * @return true if this buffer can hold this many more bytes.
     */
    boolean hasRoom(int numBytes) {
        return (numBytes <= (buffer.capacity() - buffer.position()));
    }

    /**
     * @return the actual data buffer.
     */
    public ByteBuffer getDataBuffer() {
        return buffer;
    }

    /**
     * @return capacity in bytes
     */
    int getCapacity() {
        return buffer.capacity();
    }

    /*
     * Read support
     */

    /**
     * Support for reading out of a still-in-memory log.  Can be used to
     * determine if a log entry with a given LSN is contained in this buffer,
     * or whether an arbitrary LSN location is present in the buffer.
     *
     * @return true if this buffer holds the data at this LSN location. If true
     * is returned, the buffer will be latched for read. Returns false if LSN
     * is not here, and releases the read latch.
     */
    boolean containsLsn(long lsn) {
        assert lsn != DbLsn.NULL_LSN;

        /* Latch before we look at the LSNs. */
        readLatch.acquire();
        boolean found = false;

        if ((firstLsn != DbLsn.NULL_LSN) &&
            (DbLsn.getFileNumber(firstLsn) == DbLsn.getFileNumber(lsn))) {

            final long fileOffset = DbLsn.getFileOffset(lsn);
            final int contentSize;
            if (buffer.position() == 0) {
                /* Buffer was flipped for reading. */
                contentSize = buffer.limit();
            } else {
                /* Buffer is still being written into. */
                contentSize = buffer.position();
            }
            final long firstLsnOffset = DbLsn.getFileOffset(firstLsn);
            final long lastContentOffset = firstLsnOffset + contentSize;

            if ((firstLsnOffset <= fileOffset) &&
                (lastContentOffset > fileOffset)) {
                found = true;
            }
        }

        if (found) {
            return true;
        } else {
            readLatch.release();
            return false;
        }
    }

    /**
     * When modifying the buffer, acquire the readLatch.  Call release() to
     * release the latch.  Note that containsLsn() acquires the latch for
     * reading.
     */
    public void latchForWrite()
        throws DatabaseException  {

        readLatch.acquire();
    }

    /*
     * LogSource support
     */

    /**
     * @see LogSource#release
     */
    public void release()  {
        readLatch.releaseIfOwner();
    }

    boolean getRewriteAllowed() {
        return rewriteAllowed;
    }

    void setRewriteAllowed() {
        rewriteAllowed = true;
    }

    /**
     * @see LogSource#getBytes
     */
    public ByteBuffer getBytes(long fileOffset) {

        /*
         * Make a copy of this buffer (doesn't copy data, only buffer state)
         * and position it to read the requested data.
         *
         * Note that we catch Exception here because it is possible that
         * another thread is modifying the state of buffer simultaneously.
         * Specifically, this can happen if another thread is writing this log
         * buffer out and it does (e.g.) a flip operation on it.  The actual
         * mark/pos of the buffer may be caught in an unpredictable state.  We
         * could add another latch to protect this buffer, but that's heavier
         * weight than we need.  So the easiest thing to do is to just retry
         * the duplicate operation.  See [#9822].
         */
        ByteBuffer copy = null;
        while (true) {
            try {
                copy = buffer.duplicate();
                copy.position((int)
                              (fileOffset - DbLsn.getFileOffset(firstLsn)));
                break;
            } catch (IllegalArgumentException IAE) {
                continue;
            }
        }
        return copy;
    }

    /**
     * @see LogSource#getBytes
     */
    public ByteBuffer getBytes(long fileOffset, int numBytes)
        throws ChecksumException {

        ByteBuffer copy = getBytes(fileOffset);
        /* Log Buffer should always hold a whole entry. */
        if (copy.remaining() < numBytes) {
            throw new ChecksumException("copy.remaining=" + copy.remaining() +
                                        " numBytes=" + numBytes);
        }
        return copy;
    }

    /**
     * Entries in write buffers are always the current version.
     */
    public int getLogVersion() {
        return LogEntryType.LOG_VERSION;
    }
}
TOP

Related Classes of com.sleepycat.je.log.LogBuffer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.