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

com.sleepycat.je.rep.stream.MatchpointSearchResults 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 java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.rep.impl.RepParams;
import com.sleepycat.je.txn.TxnAbort;
import com.sleepycat.je.txn.TxnCommit;
import com.sleepycat.je.utilint.DbLsn;
import com.sleepycat.je.utilint.Timestamp;
import com.sleepycat.je.utilint.VLSN;

/**
 * Holds information seen by the ReplicaSyncupReader when
 * scanning a replica's log for a matchpoint.
 */
public class MatchpointSearchResults implements Serializable {
    private static final long serialVersionUID = 1L;

    private long matchpointLSN;

    /*
     * Track whether we passed a checkpoint which deleted cleaned log files.
     * If so, we cannot do a hard recovery.
     */
    private boolean passedCheckpointEnd;

    /*
     * If we skip a gap in the log file when searching for a matchpoint, we
     * no longer can be sure if we have passed checkpoints.
     */
    private boolean passedSkippedGap;

    /*
     * We save a set number of passed transactions for debugging information.
     * The list is limited in size in case we end up passing a large number
     * of transactions on our hunt for a matchpoint. Note that we save both
     * durable and non-durable transactions to aid with debugging.
     */
    private final List passedTxns;
    private final int passedTxnLimit;

    /*
     * We need to keep the penultimate passed txn so we can readjust the
     * passed transaction information when the matchpoint is found. For
     * example, suppose the log contains:
     *   txn A commit
     *   txn B commit
     *   txn C commit
     * and txn A commit is the matchpoint. The way the loop works, we'll
     * have earliestPassedTxn = txnA, and penultimate = txn B. If the
     * matchpoint is txnA, the log will be truncated at txnB, and we
     * should reset earliestPassedTxn = txnB.
     *
     * Note that numPassedDurableCommits is a subset of numPassedCommits
     */
    private PassedTxnInfo earliestPassedTxn;
    private PassedTxnInfo penultimatePassedTxn;
    private int numPassedCommits;
    private int numPassedDurableCommits;

    /*
     * The DTVLSN established when scanning the log backwards from high to low
     * VLSNS
     */
    private VLSN dtvlsn = VLSN.NULL_VLSN;

    public MatchpointSearchResults(EnvironmentImpl envImpl) {

        /*
         * The matchpointLSN should be a non-null value, because we always have
         * to provide a valid truncation point.
         */
        matchpointLSN = DbLsn.makeLsn(0, 0);

        passedTxnLimit =
            envImpl.getConfigManager().getInt(RepParams.TXN_ROLLBACK_LIMIT);
        passedTxns = new ArrayList();
        numPassedCommits = 0;
        numPassedDurableCommits = 0;
    }

    /**
     * If we see a checkpoint end record, see if it is a barrier to
     * rolling back, and advance the file reader position.
     */
    void notePassedCheckpointEnd() {
        passedCheckpointEnd = true;
    }

    /**
     * Keep track if we have jumped over a gap in the log files, and might have
     * missed a checkpoint end.
     */
    void noteSkippedGap() {
        passedSkippedGap = true;
    }

    /**
     * At the end of the search for a matchpoint, set the matchpointLSN and
     * adjust the debugging list of passed transactions. The matchpoint entry
     * is just before the truncation point, and does not get truncated.
     */
    void setMatchpoint(long match) {
        matchpointLSN = match;
        if ((earliestPassedTxn != null) &&
            (earliestPassedTxn.lsn == matchpointLSN)) {
            numPassedCommits--;

            if (passedTxns.size() > 0) {
               int lastSavedTxn = passedTxns.size() - 1;
               if (passedTxns.get(lastSavedTxn).lsn == match) {
                  passedTxns.remove(lastSavedTxn);
               }
               earliestPassedTxn = penultimatePassedTxn;
            }
        }
    }

    /**
     * The reader saw a transaction commit; record relevant information. Note
     * that we record all transactions (replicated and non-replicated) to avoid
     * cutting off a checkpoint. Note that the stream can be a combination of
     * log records from pre and post-dtvlsn masters. Note that we are scanning
     * the log backwards, so we are encountering commits in decreasing VLSN
     * sequence.
     *
     * @param commit the commit being passed. Note that this object is reused
     * and so should not be saved.
     *
     * @param commitVLSN the VLSN associated with the commit. It could be null
     * if the commit was local and not HA
     *
     * @param commitLSN the LSN at which the commit is located
     */
    void notePassedCommits(TxnCommit commit,
                           VLSN commitVLSN,
                           long commitLSN) {
        boolean durableCommit = false;
        final Timestamp commitTime = commit.getTime();
        final long txnId = commit.getId();
        final long commitDTVLSN = commit.getDTVLSN();

        if ((commitVLSN != null) && !commitVLSN.isNull()) {
            /* A replicated txn */
            processDTVLSN(commitVLSN, commitDTVLSN);

            if (commit.hasLoggedEntries() &&
                ((dtvlsn.getSequence() == VLSN.UNINITIALIZED_VLSN_SEQUENCE) ||
                 (commitVLSN.compareTo(dtvlsn) <= 0))) {
                numPassedDurableCommits++;
                durableCommit = true;
            }
        }

        numPassedCommits++;
        if (earliestPassedTxn != null) {
            penultimatePassedTxn = earliestPassedTxn;
        }
        earliestPassedTxn =
            new PassedTxnInfo(commitTime, txnId, commitVLSN, commitLSN,
                              durableCommit);

        /*
         * Save only a limited number of passed txns, for displaying to the log
         */
        if (numPassedCommits <= passedTxnLimit) {
            passedTxns.add(earliestPassedTxn);
        }
    }

    private void processDTVLSN(VLSN txnEndVLSN, final long txnEndDTVLSN) {
        if (dtvlsn.isNull()) {
            /*
             * The first commit/abort record, set the dtvlsn to a
             * non null value
             */
            dtvlsn = new VLSN(txnEndDTVLSN);
        } else {
            /*
             * Already set, verify sequencing. Make allowance for transitions
             * from pre to post-DTVLSN stream segments. Note that we are going
             * backwards in the log at this point.
             */
            if ((txnEndDTVLSN > dtvlsn.getSequence()) &&
                (dtvlsn.getSequence() != VLSN.UNINITIALIZED_VLSN_SEQUENCE)) {
                throw new IllegalStateException
                    ("DTVLSNs should only decrease with decreasing VLSNs." +
                     " prev:" + dtvlsn + " next:" + txnEndDTVLSN +
                     " commit VLSN:" + txnEndVLSN);
            }
        }
    }

    /**
     * Use the DTVLSN value from a replicated abort to set the dtvlsn.
     *
     * @param abort the abort log record
     *
     * @param abortVLSN the VLSN associated with the abort log record
     */
    void notePassedAborts(TxnAbort abort,
                          VLSN abortVLSN) {

        if (abortVLSN.isNull()) {
            /* A non-replicated abort. */
            return;
        }

        final long abortDTVLSN = abort.getDTVLSN();
        processDTVLSN(abortVLSN, abortDTVLSN);
    }

    boolean getPassedCheckpointEnd() {
        return passedCheckpointEnd;
    }

    boolean getSkippedGap() {
        return passedSkippedGap;
    }

    public long getMatchpointLSN() {
        return matchpointLSN;
    }

    public int getNumPassedCommits() {
        return numPassedCommits;
    }

    public int getNumPassedDurableCommits() {
        return numPassedDurableCommits;
    }

    public PassedTxnInfo getEarliestPassedTxn() {
        return earliestPassedTxn;
    }

    public VLSN getDTVLSN() {
        return dtvlsn;
    }

    /**
     * Display the saved transaction information.
     */
    public String dumpPassedTxns() {
        StringBuilder sb = new StringBuilder();
        for (PassedTxnInfo info : passedTxns) {
            sb.append(info);
            sb.append("\n");
        }
        return sb.toString();
    }

    @Override
    public String toString() {
        return "matchpointLSN=" + DbLsn.getNoFormatString(matchpointLSN) +
            " passedCkpt=" + passedCheckpointEnd +
            " passedTxnLimit=" + passedTxnLimit +
            " passedTxns=" + passedTxns +
            " earliestTxn=" + earliestPassedTxn +
            " penultimateTxn=" + penultimatePassedTxn +
            " numPassedCommits=" + numPassedCommits +
            " numPassedDurableCommits=" + numPassedDurableCommits +
            " passedSkippedGap=" + passedSkippedGap;
    }

    /**
     * If 1 or more commits was passed, construct a message that can
     * be used by RollbackException and RollbackProhibitedException.
     */
    public String getRollbackMsg() {
        if (numPassedCommits == 0) {
            return " uncommitted operations";
        }

        if (numPassedDurableCommits == 0) {
            return " " + numPassedCommits +
                " total commits to the earliest point indicated by transaction " +
                earliestPassedTxn;
        }

        return " " + numPassedCommits + " total commits(" +
                numPassedDurableCommits + " of which were durable) " +
                "to the earliest point indicated by transaction " +
            earliestPassedTxn;
    }

    /* Struct to hold information about passed txns. */
    public static class PassedTxnInfo  implements Serializable {
        private static final long serialVersionUID = 1L;

        public final Timestamp time;
        public final long id;
        public final VLSN vlsn;
        public final long lsn;
        public final boolean durableCommit;

        PassedTxnInfo(Timestamp time, long id, VLSN vlsn, long lsn,
                      boolean durableCommit) {
            this.time = time;
            this.id = id;
            this.vlsn = vlsn;
            this.lsn = lsn;
            this.durableCommit = durableCommit;
        }

        @Override
        public String toString() {
            return "id=" + id +
                " time=" + time +
                " vlsn=" + vlsn +
                " lsn=" + DbLsn.getNoFormatString(lsn) +
                " durable=" + durableCommit;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy