Package com.persistit

Source Code of com.persistit.VolumeHeader$VolumeInfoTask

/**
* Copyright 2011-2012 Akiban Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.persistit;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.persistit.CLI.Arg;
import com.persistit.CLI.Cmd;
import com.persistit.exception.CorruptVolumeException;
import com.persistit.exception.InvalidVolumeSpecificationException;
import com.persistit.exception.PersistitException;
import com.persistit.exception.PersistitIOException;
import com.persistit.util.ArgParser;
import com.persistit.util.Util;

/**
* A volume header represents the header information at the beginning of each
* volume file.
*/
class VolumeHeader {

    private final static String[] ARGS_TEMPLATE = { "path|string:|Volume file name" };

    private final static SimpleDateFormat SDF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");

    /**
     *
     * Signature value - human and machine readable confirmation that this file
     * resulted from Persistit.
     */
    private final static byte[] SIGNATURE = Util.stringToBytes("PERSISTIT VOLUME");
    /**
     * Minimum possible size for a volume
     */
    private final static int SIZE = Buffer.MIN_BUFFER_SIZE;
    /**
     * Current product version number.
     */
    private final static int CURRENT_VERSION = 221;

    /**
     * Minimum product version that can handle Volumes created by this version.
     */
    private final static int MIN_SUPPORTED_VERSION = 210;

    /**
     * Minimum product version that can handle Volumes created by this version.
     */
    private final static int MAX_SUPPORTED_VERSION = 299;

    static boolean verifySignature(final byte[] bytes) {
        return Util.bytesEqual(bytes, 0, SIGNATURE);
    }

    static boolean putSignature(final byte[] bytes) {
        return Util.changeBytes(bytes, 0, SIGNATURE);
    }

    static int getVersion(final byte[] bytes) {
        return Util.getInt(bytes, 16);
    }

    static void putVersion(final byte[] bytes) {
        Util.putInt(bytes, 16, CURRENT_VERSION);
    }

    static int getPageSize(final byte[] bytes) {
        return Util.getInt(bytes, 20);
    }

    static void putPageSize(final byte[] bytes, final int value) {
        Util.putInt(bytes, 20, value);
    }

    static long getTimestamp(final byte[] bytes) {
        return Util.getLong(bytes, 24);
    }

    static boolean changeTimestamp(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 24, value);
    }

    static long getId(final byte[] bytes) {
        return Util.getLong(bytes, 32);
    }

    static void putId(final byte[] bytes, final long value) {
        Util.putLong(bytes, 32, value);
    }

    static long getReadCounter(final byte[] bytes) {
        return Util.getLong(bytes, 40);
    }

    static boolean changeReadCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 40, value);
    }

    static long getWriteCounter(final byte[] bytes) {
        return Util.getLong(bytes, 48);
    }

    static boolean changeWriteCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 48, value);
    }

    static long getGetCounter(final byte[] bytes) {
        return Util.getLong(bytes, 56);
    }

    static boolean changeGetCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 56, value);
    }

    static long getOpenTime(final byte[] bytes) {
        return Util.getLong(bytes, 64);
    }

    static boolean changeOpenTime(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 64, value);
    }

    static long getCreateTime(final byte[] bytes) {
        return Util.getLong(bytes, 72);
    }

    static boolean changeCreateTime(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 72, value);
    }

    static long getLastReadTime(final byte[] bytes) {
        return Util.getLong(bytes, 80);
    }

    static boolean changeLastReadTime(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 80, value);
    }

    static long getLastWriteTime(final byte[] bytes) {
        return Util.getLong(bytes, 88);
    }

    static boolean changeLastWriteTime(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 88, value);
    }

    static long getLastExtensionTime(final byte[] bytes) {
        return Util.getLong(bytes, 96);
    }

    static boolean changeLastExtensionTime(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 96, value);
    }

    /**
     * +1 because the stored form of volumes created before 2.6.1 recorded
     * "highestUsedPage" rather than "nextAvailablePage" in this slot.
     *
     * @param bytes
     * @return page address of the next available page
     */
    static long getNextAvailablePage(final byte[] bytes) {
        return Util.getLong(bytes, 104) + 1;
    }

    /**
     * -1 because the stored form of volumes created before 2.6.1 recorded
     * "highestUsedPage" rather than "nextAvailablePage" in this slot.
     *
     * @param bytes
     * @param value
     *            next available page
     * @return whether the supplied value is different from the previously
     *         stored value
     */
    static boolean changeNextAvailablePage(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 104, value - 1);
    }

    static long getExtendedPageCount(final byte[] bytes) {
        return Util.getLong(bytes, 112);
    }

    static boolean changeExtendedPageCount(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 112, value);
    }

    static long getExtensionPages(final byte[] bytes) {
        return Util.getLong(bytes, 120);
    }

    static boolean changeExtensionPages(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 120, value);
    }

    static long getMaximumPages(final byte[] bytes) {
        return Util.getLong(bytes, 128);
    }

    static boolean changeMaximumPages(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 128, value);
    }

    static long getDirectoryRoot(final byte[] bytes) {
        return Util.getLong(bytes, 144);
    }

    static boolean changeDirectoryRoot(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 144, value);
    }

    static long getGarbageRoot(final byte[] bytes) {
        return Util.getLong(bytes, 152);
    }

    static boolean changeGarbageRoot(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 152, value);
    }

    static long getfetchCounter(final byte[] bytes) {
        return Util.getLong(bytes, 160);
    }

    static boolean changeFetchCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 160, value);
    }

    static long getTraverseCounter(final byte[] bytes) {
        return Util.getLong(bytes, 168);
    }

    static boolean changeTraverseCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 168, value);
    }

    static long getStoreCounter(final byte[] bytes) {
        return Util.getLong(bytes, 176);
    }

    static boolean changeStoreCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 176, value);
    }

    static long getRemoveCounter(final byte[] bytes) {
        return Util.getLong(bytes, 184);
    }

    static boolean changeRemoveCounter(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 184, value);
    }

    static long getInitialPages(final byte[] bytes) {
        return Util.getLong(bytes, 192);
    }

    static boolean changeInitialPages(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 192, value);
    }

    static long getGlobalTimestamp(final byte[] bytes) {
        return Util.getLong(bytes, 200);
    }

    static boolean changeGlobalTimestamp(final byte[] bytes, final long value) {
        return Util.changeLong(bytes, 200, value);
    }

    /**
     * Validate that the header conforms to the volume header specification and
     * if so, read the pageSize and version values from it and populate the
     * corresponding fields of the supplied <code>VolumeSpecification</code>.
     * CorruptVolumeExceptions are thrown when an inconsistency is observed.
     *
     * @return <code>true</code> if and only if there already exists a Volume
     *         file.
     * @throws PersistitException
     * @throws IOException
     * @throws InvalidVolumeSpecificationException
     * @throws CorruptVolumeException
     * @throws PersistitIOException
     */
    public static boolean verifyVolumeHeader(final VolumeSpecification specification, final long systemTimestamp)
            throws CorruptVolumeException, InvalidVolumeSpecificationException, PersistitIOException {
        FileInputStream stream = null;
        try {
            final File file = new File(specification.getPath());
            if (file.exists()) {
                if (file.isFile()) {
                    stream = new FileInputStream(file);
                    final byte[] bytes = new byte[SIZE];
                    final int readSize = stream.read(bytes);
                    if (readSize < SIZE) {
                        throw new CorruptVolumeException("Volume file " + file + " too short: " + readSize);
                    }
                    /*
                     * Check out the fixed Volume file and learn the buffer
                     * size.
                     */
                    if (!verifySignature(bytes)) {
                        throw new CorruptVolumeException("Invalid signature");
                    }

                    final int version = getVersion(bytes);
                    if (version < MIN_SUPPORTED_VERSION || version > MAX_SUPPORTED_VERSION) {
                        throw new CorruptVolumeException("Version " + version
                                + " is not supported by Persistit version " + Persistit.version());
                    }
                    final int pageSize = getPageSize(bytes);
                    final long nextAvailablePage = getNextAvailablePage(bytes);
                    final long id = getId(bytes);
                    final long totalPages = file.length() / pageSize;
                    if (totalPages < nextAvailablePage) {
                        throw new CorruptVolumeException(String.format("Volume has been truncated: "
                                + "minimum required/actual lengths=%,d/%,d bytes", nextAvailablePage * pageSize,
                                file.length()));
                    }
                    final long globalTimestamp = getGlobalTimestamp(bytes);
                    if (globalTimestamp > systemTimestamp) {
                        throw new CorruptVolumeException("Volume " + file + " has a global timestamp greater than "
                                + "system timestamp: " + globalTimestamp + " > " + systemTimestamp);
                    }
                    specification.setVersion(version);
                    specification.setPageSize(pageSize);
                    specification.setId(id);
                } else {
                    throw new CorruptVolumeException("Volume file " + file + " is a directory");
                }
                return true;
            } else {
                return false;
            }
        } catch (final IOException ioe) {
            throw new PersistitIOException(ioe);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (final IOException e) {
                }
            }
        }
    }

    /**
     * @return The version number of volumes created by this version of
     *         Persistit.
     */
    public static int getCurrentVersion() {
        return CURRENT_VERSION;
    }

    @Cmd("volumeinfo")
    static VolumeInfoTask createTask(@Arg("file|string:|Volume file") final String file) throws Exception {
        return new VolumeInfoTask(file);
    }

    private static class VolumeInfoTask extends Task {
        String _volumeFileName;

        private VolumeInfoTask(final String fileName) {
            _volumeFileName = fileName;
        }

        @Override
        protected void runTask() throws Exception {
            final File file = new File(_volumeFileName);
            final FileInputStream stream = new FileInputStream(file);
            final byte[] bytes = new byte[SIZE];
            final int readSize = stream.read(bytes);
            stream.close();
            if (readSize < SIZE) {
                throw new CorruptVolumeException(String.format(
                        "File %s of size %,d is too short to be a Volume file\n", file, readSize));
            }
            /*
             * Check out the fixed Volume file and learn the buffer size.
             */
            if (!verifySignature(bytes)) {
                throw new CorruptVolumeException(String.format("File %s is not a Volume file: Invalid signature", file));
            }
            postMessage(String.format("%30s: %s", "File", file), Task.LOG_NORMAL);
            outn("ID", getId(bytes));
            outn("Page size", getPageSize(bytes));
            outd("Creation time", getCreateTime(bytes));
            outd("Last open time", getOpenTime(bytes));
            outd("Last extension time", getLastExtensionTime(bytes));
            outd("Last read time", getLastReadTime(bytes));
            outd("Last write time", getLastWriteTime(bytes));
            outn("Global timestamp", getGlobalTimestamp(bytes));
            outn("Timestamp", getTimestamp(bytes));
            outn("Version", getVersion(bytes));

            outn("Directory root", getDirectoryRoot(bytes));
            outn("Garbage root", getGarbageRoot(bytes));
            outn("Initial pages", getInitialPages(bytes));
            outn("Next available page", getNextAvailablePage(bytes));
            outn("Extended page count", getExtendedPageCount(bytes));
            outn("Pages per extension", getExtensionPages(bytes));
            outn("Maximum pages", getMaximumPages(bytes));

            outn("Fetch counter", getfetchCounter(bytes));
            outn("Get counter", getGetCounter(bytes));
            outn("Read counter", getReadCounter(bytes));
            outn("Remove counter", getRemoveCounter(bytes));
            outn("Store counter", getStoreCounter(bytes));
            outn("Traverse counter", getTraverseCounter(bytes));
            outn("Write counter", getWriteCounter(bytes));

        }

        private void outd(final String legend, final long value) {
            postMessage(String.format("%30s: %s", legend, SDF.format(new Date(value))), Task.LOG_NORMAL);
        }

        private void outn(final String legend, final long value) {
            postMessage(String.format("%30s: %,12d", legend, value), Task.LOG_NORMAL);
        }

        @Override
        public String getStatus() {
            return "";
        }

    }

    public static void main(final String[] args) throws Exception {
        final ArgParser ap = new ArgParser("VolumeHeader", args, ARGS_TEMPLATE).strict();
        if (ap.isUsageOnly()) {
            return;
        }
        final Task task = new VolumeInfoTask(ap.getStringValue("path"));
        task.setMessageWriter(new PrintWriter(System.out));
        task.runTask();
    }

}
TOP

Related Classes of com.persistit.VolumeHeader$VolumeInfoTask

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.