All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.rep.stream.FeederSyncupReader Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */
package com.sleepycat.je.rep.stream;

import static com.sleepycat.je.utilint.DbLsn.NULL_LSN;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.EnvironmentFailureException;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.log.ChecksumException;
import com.sleepycat.je.rep.vlsn.VLSNIndex;
import com.sleepycat.je.rep.vlsn.VLSNIndex.BackwardVLSNScanner;
import com.sleepycat.je.rep.vlsn.VLSNRange;
import com.sleepycat.je.utilint.VLSN;

/**
 * The FeederSyncupReader scans the log backwards for requested log entries.
 * It uses the vlsnIndex to optimize its search, repositioning when a concrete
 * {@literal vlsn->lsn} mapping is available.
 *
 * The FeederSyncupReader is not thread safe, and can only be used serially. It
 * will stop at the finishLsn, which should be set using the GlobalCBVLSN.
 */
public class FeederSyncupReader extends VLSNReader {
    /* The scanner is a cursor over the VLSNIndex. */
    private final BackwardVLSNScanner scanner;

    public FeederSyncupReader(EnvironmentImpl envImpl,
                              VLSNIndex vlsnIndex,
                              long endOfLogLsn,
                              int readBufferSize,
                              VLSN startVLSN,
                              long finishLsn)
        throws IOException, DatabaseException {

        /*
         * If we go backwards, endOfFileLsn and startLsn must not be null.
         * Make them the same, so we always start at the same very end.
         */
        super(envImpl,
              vlsnIndex,
              false,           // forward
              endOfLogLsn,
              readBufferSize,
              finishLsn);
        scanner = new BackwardVLSNScanner(vlsnIndex);
        initScan(startVLSN);
    }

    /**
     * Set up the FeederSyncupReader to start scanning from this VLSN. If we
     * find a mapping for this VLSN, we'll start precisely at its LSN, else
     * we'll have to start from an earlier location.
     *
     * @throws InterruptedException
     * @throws IOException
     * @throws DatabaseException
     */
    private void initScan(VLSN startVLSN)
        throws DatabaseException, IOException {

        if (startVLSN.equals(VLSN.NULL_VLSN)) {
            throw EnvironmentFailureException.unexpectedState
                ("FeederSyncupReader start can't be NULL_VLSN");
        }

        VLSN startPoint = startVLSN;
        startLsn = scanner.getStartingLsn(startPoint);
        assert startLsn != NULL_LSN;

        /*
         * Flush the log so that syncup can assume that all log entries that
         * are represented in the VLSNIndex  are safely out of the log buffers
         * and on disk. Simplifies this reader, so it can use the regular
         * ReadWindow, which only works on a file.
         */
        envImpl.getLogManager().flushNoSync();

        window.initAtFileStart(startLsn);
        currentEntryPrevOffset = window.getEndOffset();
        currentEntryOffset = window.getEndOffset();
        currentVLSN = startVLSN;
    }

    /**
     * Backward scanning for records for the feeder's part in syncup.
     * @throws ChecksumException 
     * @throws FileNotFoundException 
     */
    public OutputWireRecord scanBackwards(VLSN vlsn)
        throws FileNotFoundException, ChecksumException {

        VLSNRange range = vlsnIndex.getRange();
        if (vlsn.compareTo(range.getFirst()) < 0) {
            /*
             * The requested VLSN is before the start of our range, we don't
             * have this record.
             */
            return null;
        }

        currentVLSN = vlsn;

        /*
         * If repositionLsn is not NULL_LSN, the reader will seek to that
         * position when calling readNextEntry instead of scanning.
         * setPosition() is a noop if repositionLsn is null.
         */
        long repositionLsn = scanner.getPreciseLsn(vlsn);
        setPosition(repositionLsn);

        if (readNextEntry()) {
            return currentFeedRecord;
        }

        return null;
    }

    /**
     * @throw an EnvironmentFailureException if we were scanning for a
     * particular VLSN and we have passed it by.
     */
    private void checkForPassingTarget(int compareResult) {

        if (compareResult < 0) {
            /* Hey, we passed the VLSN we wanted. */
            throw EnvironmentFailureException.unexpectedState
                ("want to read " + currentVLSN + " but reader at " +
                 currentEntryHeader.getVLSN());
        }
    }

    @Override
    protected boolean isTargetEntry()
        throws DatabaseException {

        nScanned++;

        /* Skip invisible entries. */
        if (currentEntryHeader.isInvisible()) {
            return false;
        }

        /* 
         * Return true if this entry is replicated and its VLSN is currentVLSN.
         */
        if (entryIsReplicated()) {
            VLSN entryVLSN = currentEntryHeader.getVLSN();
            int compareResult = entryVLSN.compareTo(currentVLSN);
            checkForPassingTarget(compareResult);

            /* return true if this is the entry we want. */
            return (compareResult == 0);
        }

        return false;
    }

    /**
     * Instantiate a WireRecord to house this log entry.
     */
    @Override
    protected boolean processEntry(ByteBuffer entryBuffer) {

        ByteBuffer buffer = entryBuffer.slice();
        buffer.limit(currentEntryHeader.getItemSize());
        currentFeedRecord =
            new OutputWireRecord(envImpl, currentEntryHeader, buffer);

        entryBuffer.position(entryBuffer.position() +
                             currentEntryHeader.getItemSize());
        return true;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy