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

com.sleepycat.je.rep.utilint.DbStreamVerify 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.utilint;

import java.io.File;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import com.sleepycat.bind.tuple.LongBinding;
import com.sleepycat.bind.tuple.StringBinding;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.dbi.DatabaseId;
import com.sleepycat.je.dbi.DbType;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.log.FileReader;
import com.sleepycat.je.log.LogEntryType;
import com.sleepycat.je.log.entry.LNLogEntry;
import com.sleepycat.je.rep.impl.RepGroupDB;
import com.sleepycat.je.rep.impl.RepGroupDB.GroupBinding;
import com.sleepycat.je.rep.impl.RepGroupDB.NodeBinding;
import com.sleepycat.je.rep.impl.RepGroupImpl;
import com.sleepycat.je.rep.vlsn.VLSNBucket;
import com.sleepycat.je.rep.vlsn.VLSNIndex;
import com.sleepycat.je.rep.vlsn.VLSNRange;
import com.sleepycat.je.tree.LN;
import com.sleepycat.je.utilint.CmdUtil;
import com.sleepycat.je.utilint.DbLsn;
import com.sleepycat.je.utilint.VLSN;

/**
 * For internal use only.
 * Utility to verify the replication stream and VLSN index. Used file readers
 * to traverse the log and check that VLSNs are sequential and that the VLSN
 * index is consistent.
 */
public class DbStreamVerify {

    private static final String USAGE =
        "usage: " + CmdUtil.getJavaCommand(DbStreamVerify.class) + "\n" +
        " -h       # environment home directory\n" +
        " -s       # start file\n" +
        " -e       # end file\n" +
        " -verifyStream # check that replication stream is ascending\n" +
        " -dumpVLSN     # scan log file for log entries that make up the" +
                        " VLSN index, don't run verify.\n" +
        " -dumpRepGroup # scan log file for log entries that make up the" +
                        " rep group db, don't run verify.\n" +
        " -i            # show invisible. If true, print invisible entries"+
                        " when running verify mode.\n" +
        " -v            # verbose\n";

    public static void main(String argv[])
        throws Exception {

        DbStreamVerify verify = new DbStreamVerify(System.out);
        verify.parseArgs(argv);

        try {
            verify.run();
            System.exit(0);
        } catch (Throwable e) {
            e.printStackTrace(System.err);
            System.exit(1);
        }
    }

    private File envHome = null;
    private boolean showInvisible = false;
    private boolean verbose = false;
    private boolean vlsnDump = false;
    private boolean repGroupDump = false;
    private boolean verifyStream = false;
    private long startLsn = DbLsn.NULL_LSN;
    private long endLsn = DbLsn.NULL_LSN;

    private final PrintStream out;

    private DbStreamVerify(PrintStream out) {
        this.out = out;
    }

    private void printUsage(String msg) {
        if (msg != null) {
            out.println(msg);
        }
        out.println(USAGE);
        System.exit(-1);
    }

    private void parseArgs(String argv[]) {

        int argc = 0;
        int nArgs = argv.length;

        if (nArgs == 0) {
            printUsage(null);
            System.exit(0);
        }

        while (argc < nArgs) {
            String thisArg = argv[argc++];
            if (thisArg.equals("-i")) {
                showInvisible = true;
            } else if (thisArg.equals("-v")) {
                verbose = true;
            } else if (thisArg.equals("-verifyStream")) {
                verifyStream = true;
            } else if (thisArg.equals("-dumpVLSN")) {
                vlsnDump = true;
            } else if (thisArg.equals("-dumpRepGroup")) {
                repGroupDump = true;
            } else if (thisArg.equals("-s")) {
                startLsn = CmdUtil.readLsn(CmdUtil.getArg(argv, argc++));
            } else if (thisArg.equals("-e")) {
                endLsn = CmdUtil.readLsn(CmdUtil.getArg(argv, argc++));
            } else if (thisArg.equals("-h")) {
                if (argc < nArgs) {
                    envHome = new File(argv[argc++]);
                } else {
                    printUsage("-h requires an argument");
                }
            } else {
                printUsage(thisArg + " is not a valid argument");
            }
        }

        if (envHome == null) {
            printUsage("-h is a required argument");
        }

        if (!(vlsnDump || repGroupDump || verifyStream)) {
            printUsage("Must specify -dumpVLSN, -dumpRepGroup or " +
                       "-verifyStream");
        }
    }

    public void run() {
        EnvironmentConfig envConfig = new EnvironmentConfig();
        envConfig.setReadOnly(true);
        Environment env = new Environment(envHome, envConfig);
        EnvironmentImpl envImpl = DbInternal.getNonNullEnvImpl(env);

        try {
            FileReader reader;
            if (vlsnDump) {
                out.println("Dump VLSNIndex LNs");
                reader = new VLSNIndexReader(env, out, startLsn, endLsn);
            } else if (repGroupDump) {
                out.println("Dump RepGroup LNs");
                reader = new RepGroupReader(env, out, startLsn, endLsn);
            } else if (verifyStream) {
                out.println("Replication stream: check that vlsns ascend");
                reader = new VerifyReader(envImpl, out, startLsn, endLsn);
            } else {
                out.println("No action specified.");
                return;
            }

            while (reader.readNextEntry()) {
            }

            if ((!vlsnDump) && (!repGroupDump)) {
                ((VerifyReader) reader).displayLast();
                VLSNIndex.verifyDb(env, out, verbose);
            }

            System.exit(0);
        } catch (Throwable e) {
            e.printStackTrace(out);
            System.exit(1);
        } finally {
            try {
                env.close();
            } catch (Throwable e) {
                e.printStackTrace(out);
                System.exit(1);
            }
        }
    }

    private class VerifyReader extends FileReader {
        private VLSN lastVLSN = VLSN.NULL_VLSN;
        private long lastLSN = DbLsn.NULL_LSN;
        private final PrintStream out1;

        VerifyReader(EnvironmentImpl envImpl, PrintStream out, long startLsn,
                     long endLsn) {
            super(envImpl,
                  10000,
                  true,              // forward
                  startLsn,
                  null,              // singleFileNumber,
                  DbLsn.NULL_LSN,
                  endLsn);
            this.out1 = out;
        }

        @Override
        protected boolean isTargetEntry() {
            return (currentEntryHeader.getReplicated());
        }

        @Override
        protected boolean processEntry(ByteBuffer entryBuffer) {
            VLSN currentVLSN = currentEntryHeader.getVLSN();
            long currentLSN = getLastLsn();

            if (currentVLSN == null) {
                throw new RuntimeException
                     (DbLsn.getNoFormatString(currentLSN) +
                      "Should be a replicated entry");
            }

            if (currentVLSN.isNull()) {
                out1.println("unexpected LSN " +
                            DbLsn.getNoFormatString(getLastLsn()) +
                            " has vlsn " + currentVLSN);
            }

            if ((lastVLSN != null) && lastVLSN.isNull()) {

                /* First entry seen */
                out1.println("first VLSN = " + currentVLSN + " at lsn " +
                            DbLsn.getNoFormatString(getLastLsn()));
            } else if (!currentEntryHeader.isInvisible() &&
                       !currentVLSN.follows(lastVLSN)) {

                /* Note the first entry, check for a gap. */
                out1.println("gap of " +
                            (currentVLSN.getSequence() -
                            lastVLSN.getSequence()) +
                            " Last=" + lastVLSN + " at lsn " +
                            DbLsn.getNoFormatString(lastLSN) +
                            " next=" + currentVLSN + " at lsn " +
                            DbLsn.getNoFormatString(currentLSN));

            }

            /* Note the invisible log entries. */
            if (showInvisible && currentEntryHeader.isInvisible()) {
                out1.println("VLSN " + currentVLSN + " at lsn " +
                            DbLsn.getNoFormatString(currentLSN) +
                            " is invisible.");
            }

            if (!currentEntryHeader.isInvisible()) {
                lastVLSN = currentVLSN;
                lastLSN = currentLSN;
            }
            entryBuffer.position(entryBuffer.position() +
                                 currentEntryHeader.getItemSize());
            return true;
        }

        void displayLast() {
            out1.println("LastVLSN = " + lastVLSN + " at " +
                         DbLsn.getNoFormatString(lastLSN));
        }
    }

    /**
     * A Decoder reader can dump the LNs from one of the JE internal databases
     * and display the LNs in a deserialized format, for easy debugging. The
     * target internal databases are the VLSNIndex and the RepGroup. We could
     * add FileSummaryLNs later.
     */
    private abstract class DecoderReader extends FileReader {
        protected final PrintStream outStream;
        private final Map> targetMap;
        protected LNLogEntry targetEntry;
        private final DatabaseId targetDbId;

        DecoderReader(Environment env,
                      PrintStream out,
                      long startLsn,
                      long endLsn,
                      String dbName) {
            super(DbInternal.getNonNullEnvImpl(env),
                  10000,
                  true,              // forward
                  startLsn,
                  null,              // singleFileNumber,
                  DbLsn.NULL_LSN,
                  endLsn);
            this.outStream = out;

            targetMap = new HashMap>();

            for (LogEntryType entryType : LogEntryType.getAllTypes()) {
                if (entryType.isUserLNType()) {
                    targetMap.put(entryType.getTypeNum(),
                                  (LNLogEntry) entryType.getNewLogEntry());
                }
            }

            DatabaseConfig dbConfig = new DatabaseConfig();
            dbConfig.setReadOnly(true);
            DbInternal.setUseExistingConfig(dbConfig, true);
            Database db = env.openDatabase(null, dbName, dbConfig);
            targetDbId = DbInternal.getDbImpl(db).getId();
            db.close();
        }

        @Override
        protected boolean isTargetEntry() {
            /* Is it a target entry? */
            targetEntry = targetMap.get(currentEntryHeader.getType());
            return targetEntry != null;
        }

        @Override
        protected boolean processEntry(ByteBuffer entryBuffer) {
            targetEntry.readEntry(envImpl, currentEntryHeader, entryBuffer);
            targetEntry.postFetchInit(false /*isDupDb*/);

            if (!targetEntry.getDbId().equals(targetDbId)) {
                return false;
            }

            outStream.print("LSN=" + DbLsn.getNoFormatString(getLastLsn()));

            display();
            return true;
        }

        protected abstract void display();
    }

    /*
     * Read the LNs that compose the VLSNIndex. Displays the contents of each
     * LN in VLSNBucket form.
     */
    private class VLSNIndexReader extends DecoderReader {

        VLSNIndexReader(Environment env,
                        PrintStream out,
                        long startLsn,
                        long endLsn) {
            super(env, out, startLsn, endLsn,
                  DbType.VLSN_MAP.getInternalName());
        }

        @Override
        protected void display() {
            DatabaseEntry key = new DatabaseEntry(targetEntry.getKey());
            long keyVal = LongBinding.entryToLong(key);
            LN ln = targetEntry.getLN();
            if (ln.isDeleted()) {
                outStream.println("key=" + keyVal + " ");
            } else {
                DatabaseEntry data = new DatabaseEntry(ln.getData());

                if (keyVal == VLSNRange.RANGE_KEY) {
                    outStream.print(" range: ");
                    VLSNRange range = VLSNRange.readFromDatabase(data);
                    outStream.println(range);
                } else {
                    outStream.print(" key=" + keyVal);
                    VLSNBucket bucket = VLSNBucket.readFromDatabase(data);
                    outStream.println(" " + bucket);
                    if (verbose) {
                        outStream.println("-------------------------------");
                        bucket.dump(outStream);
                        outStream.println("-------------------------------\n");
                    }
                }
            }
        }
    }

    /**
     * Display the LNs that compose the RepGroupDb.
     */
    private class RepGroupReader extends DecoderReader {
        private NodeBinding nodeBinding;

        RepGroupReader(Environment env, PrintStream out,
                       long startLsn, long endLsn) {
            super(env, out, startLsn, endLsn,
                  DbType.REP_GROUP.getInternalName());
        }

        @Override
        protected void display() {
            out.print(" VLSN=" + currentEntryHeader.getVLSN());

            DatabaseEntry key = new DatabaseEntry(targetEntry.getKey());

            LN ln = targetEntry.getLN();
            if (ln.isDeleted()) {
                outStream.print("");
            } else {
                DatabaseEntry data = new DatabaseEntry(ln.getData());
                String keyVal = StringBinding.entryToString(key);
                if (keyVal.equals(RepGroupDB.GROUP_KEY)) {
                    final RepGroupImpl group =
                        new GroupBinding().entryToObject(data);
                    nodeBinding = new NodeBinding(group.getFormatVersion());
                    outStream.print(" GroupInfo: ");
                    outStream.println(group);
                } else {
                    outStream.print(" NodeInfo: " + keyVal);
                    if (nodeBinding == null) {
                        throw new IllegalStateException(
                            "Node entry before group entry");
                    }
                    outStream.print(nodeBinding.entryToObject(data));
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy