Package com.persistit

Source Code of com.persistit.VolumeSpecification

/**
* Copyright © 2011-2012 Akiban Technologies, Inc.  All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This program may also be available under different license terms.
* For more information, see www.akiban.com or contact licensing@akiban.com.
*
* Contributors:
* Akiban Technologies, Inc.
*/

/**
*
*/
package com.persistit;

import java.io.File;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import com.persistit.exception.InvalidVolumeSpecificationException;
import com.persistit.exception.VolumeAlreadyExistsException;
import com.persistit.util.Util;

/**
* A structure holding all the specification details for a {@link Volume}.
*
* @author peter
*
*/
public class VolumeSpecification {

    private final static String ATTR_NAME = "name";
    private final static String ATTR_ALIAS = "alias";
    private final static String ATTR_CREATE = "create";
    private final static String ATTR_READONLY = "readOnly";
    private final static String ATTR_CREATEONLY = "createOnly";
    private final static String ATTR_PAGE_SIZE = "pageSize";

    private final static String ATTR_INITIAL_SIZE = "initialSize";
    private final static String ATTR_EXTENSION_SIZE = "extensionSize";
    private final static String ATTR_MAXIMUM_SIZE = "maximumSize";

    private final static String ATTR_INITIAL_PAGES = "initialPages";
    private final static String ATTR_EXTENSION_PAGES = "extensionPages";
    private final static String ATTR_MAXIMUM_PAGES = "maximumPages";

    private String path;
    private String name = null;
    private boolean readOnly = false;
    private boolean create = false;
    private boolean createOnly = false;
    private boolean aliased = false;

    private int pageSize = -1;
    private int version = -1;
    private long id = 0;

    private long initialPages = -1;
    private long extensionPages = -1;
    private long maximumPages = -1;
    private long initialSize = -1;
    private long extensionSize = -1;
    private long maximumSize = -1;

    public static String nameFromFile(final File file) {
        final String name = file.getName();
        final int p = name.lastIndexOf('.');
        return p < 1 ? name : name.substring(0, p);
    }

    /**
     * Construct a <code>VolumeSpecification</code> having the supplied
     * parameter values.
     *
     * @param path
     *            File system path to volume file
     * @param name
     *            Name of volume. If <code>null</code> the file name in the
     *            specified <code>path</code> is used.
     * @param pageSize
     *            Page size: one of 1024, 2048, 4096, 8192 or 6384
     * @param initialPages
     *            Initial page count
     * @param maximumPages
     *            Maximum page count
     * @param extensionPages
     *            Number of pages to extend by when file must grow
     * @param create
     *            <code>true</code> to allow creation of a new volume
     * @param createOnly
     *            <code>true</code> to require creation of a new volume
     * @param readOnly
     *            <code>true</code> to open volume file in read-only mode
     */
    public VolumeSpecification(final String path, final String name, final int pageSize, final long initialPages,
            final long maximumPages, final long extensionPages, final boolean create, final boolean createOnly,
            final boolean readOnly) {
        this.path = path;
        if (name == null) {
            this.name = nameFromFile(new File(path));
        } else {
            setName(name);
        }
        this.pageSize = pageSize;
        this.initialPages = initialPages;
        this.maximumPages = maximumPages;
        this.extensionPages = extensionPages;
        this.create = create;
        this.createOnly = createOnly;
        this.readOnly = readOnly;
    }

    /**
     * Construct a <code>VolumeSpecification</code> from the supplied
     * specification string. The specification has the form: <br />
     * <i>pathname</i>[,<i>options</i>]... <br />
     * where options include: <br />
     * <dl>
     * <dt><code>name</code></dt>
     * <dd>The Volume name used in looking up the volume within Persistit
     * programs (see {@link com.persistit.Persistit#getVolume(String)}). If the
     * name attribute is not specified, the last name in the Volume's path name
     * sequence is used instead.</dd>
     *
     * <dt><code>readOnly</code></dt>
     * <dd>Open in Read-Only mode. (Incompatible with create mode.)</dd>
     *
     * <dt><code>create</code></dt>
     * <dd>Creates the volume if it does not exist. Requires
     * <code>pageSize</code>, <code>initialPagesM</code>,
     * <code>extensionPages</code> and <code>maximumPages</code> to be
     * specified.</dd>
     *
     * <dt><code>createOnly</code></dt>
     * <dd>Creates the volume, or throw a {@link VolumeAlreadyExistsException}
     * if it already exists.</dd>
     *
     * <dt><code>temporary</code></dt>
     * <dd>Creates the a new, empty volume regardless of whether an existing
     * volume file already exists.</dd>
     *
     * <dt><code>pageSize:<i>NNN</i></code></dt>
     * <dd>Specifies <i>NNN</i> as the volume's buffer size when creating a new
     * volume. <i>NNN</i> must be 1024, 2048, 4096, 8192 or 16384.</dd>
     *
     * <dt><code>initialPages:<i>NNN</i></code></dt>
     * <dd><i>NNN</i> is the initial number of pages to be allocated when this
     * volume is first created.</dd>
     *
     * <dt><code>extensionPages:<i>NNN</i></code></dt>
     * <dd><i>NNN</i> is the number of pages by which to extend the volume when
     * more pages are required.</dd>
     *
     * <dt><code>maximumPages:<i>NNN</i></code></dt>
     * <dd><i>NNN</i> is the maximum number of pages to which this volume can
     * extend.</dd>
     *
     * </dl>
     * <p>
     *
     * @param specification
     *            the specification String
     * @throws InvalidVolumeSpecificationException
     */

    public VolumeSpecification(final String specification) throws InvalidVolumeSpecificationException {
        final StringTokenizer mainTokenizer = new StringTokenizer(specification, ",");
        try {
            path = mainTokenizer.nextToken().trim();
            name = nameFromFile(new File(path));

            while (mainTokenizer.hasMoreTokens()) {
                final String token = mainTokenizer.nextToken().trim();
                final StringTokenizer innerTokenizer = new StringTokenizer(token, ":");
                final String attr = innerTokenizer.nextToken().trim();
                if (ATTR_READONLY.equals(attr)) {
                    readOnly = true;
                } else if (ATTR_CREATE.equals(attr)) {
                    create = true;
                } else if (ATTR_CREATEONLY.equals(attr)) {
                    createOnly = true;
                } else if (ATTR_NAME.equals(attr) || ATTR_ALIAS.equals(attr)) {
                    final String valueString = innerTokenizer.nextToken().trim();
                    if (valueString != null && !valueString.isEmpty()) {
                        setName(valueString);
                    }
                } else {
                    final String valueString = innerTokenizer.nextToken().trim();
                    boolean bad = false;
                    final long value = Configuration.parseLongProperty(attr, valueString);

                    if (ATTR_PAGE_SIZE.equals(attr)) {
                        if (value < Integer.MAX_VALUE && value > 0 && Volume.isValidPageSize((int) value)) {
                            pageSize = (int) value;
                        } else {
                            throw new InvalidVolumeSpecificationException("Invalid pageSize " + specification);
                        }
                    } else if (ATTR_INITIAL_PAGES.equals(attr)) {
                        initialPages = value;
                    } else if (ATTR_EXTENSION_PAGES.equals(attr)) {
                        extensionPages = value;
                    } else if (ATTR_MAXIMUM_PAGES.equals(attr)) {
                        maximumPages = value;
                    } else if (ATTR_INITIAL_SIZE.equals(attr)) {
                        initialSize = value;
                    } else if (ATTR_EXTENSION_SIZE.equals(attr)) {
                        extensionSize = value;
                    } else if (ATTR_MAXIMUM_SIZE.equals(attr)) {
                        maximumSize = value;
                    } else {
                        bad = true;
                    }

                    if (bad || innerTokenizer.hasMoreTokens()) {
                        throw new InvalidVolumeSpecificationException("Unknown attribute " + attr + " in "
                                + specification);
                    }
                }
            }
            int n = 0;
            if (readOnly) {
                n++;
            }
            if (create) {
                n++;
            }
            if (createOnly) {
                n++;
            }
            if (n > 1) {
                throw new InvalidVolumeSpecificationException(specification + ": readOnly, create and createOnly "
                        + "attributes are mutually exclusive");
            }
            //
            // Allows size specification in bytes rather than pages.
            //
            if (pageSize > 0) {
                if (initialPages == -1 && initialSize > 0) {
                    initialPages = (initialSize + (pageSize - 1)) / pageSize;
                }
                if (extensionPages == -1 && extensionSize > 0) {
                    extensionPages = (extensionSize + (pageSize - 1)) / pageSize;
                }
                if (maximumPages == -1 && maximumSize > 0) {
                    maximumPages = (maximumSize + (pageSize - 1)) / pageSize;
                }
            }

            // Validate initial, maximum and extension sizes
            if (maximumPages <= 0) {
                maximumPages = initialPages;
            }

            if (create || createOnly) {
                if (initialPages < 1 || initialPages > Long.MAX_VALUE / pageSize) {
                    throw new InvalidVolumeSpecificationException("Invalid initial page count: " + initialPages);
                }

                if (extensionPages < 0 || extensionPages > Long.MAX_VALUE / pageSize) {
                    throw new InvalidVolumeSpecificationException("Invalid extension page count: " + extensionPages);
                }

                if (maximumPages < initialPages || maximumPages > Long.MAX_VALUE / pageSize) {
                    throw new InvalidVolumeSpecificationException("Invalid maximum page count: " + maximumPages);
                }
            }
        } catch (final NumberFormatException nfe) {
            throw new InvalidVolumeSpecificationException(specification + ": invalid number");
        } catch (final NoSuchElementException nste) {
            throw new InvalidVolumeSpecificationException(specification + ": " + nste);
        }
    }

    public void setPageSize(final int value) throws InvalidVolumeSpecificationException {
        if (!Volume.isValidPageSize(value)) {
            throw new InvalidVolumeSpecificationException("Invalid pageSize " + value);
        }

        if (pageSize == value || pageSize == -1) {
            pageSize = value;
        } else {
            throw new InvalidVolumeSpecificationException("Mismatched volume pageSize " + value + " for " + this);
        }
    }

    public void setVersion(final int value) throws InvalidVolumeSpecificationException {
        if (version == value || version == -1) {
            version = value;
        } else {
            throw new InvalidVolumeSpecificationException("Mismatched volume version " + value + " for " + this);
        }
    }

    public void setId(final long value) throws InvalidVolumeSpecificationException {
        if (id == value || id == 0) {
            id = value;
        } else {
            throw new InvalidVolumeSpecificationException("Mismatched volume version " + value + " for " + this);
        }
    }

    public String getPath() {
        return path;
    }

    public void setPath(final String path) {
        this.path = path;
    }

    public File getAbsoluteFile() {
        return new File(path).getAbsoluteFile();
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.aliased = !nameFromFile(new File(path)).equals(name);
        this.name = name;
    }

    public boolean isReadOnly() {
        return readOnly;
    }

    public void setReadOnly(final boolean readOnly) {
        this.readOnly = readOnly;
    }

    public boolean isAliased() {
        return aliased;
    }

    public boolean isCreate() {
        return create || createOnly;
    }

    public void setCreate(final boolean create) {
        this.create = create;
    }

    public boolean isCreateOnly() {
        return createOnly;
    }

    public void setCreateOnly(final boolean createOnly) {
        this.createOnly = createOnly;
    }

    public int getPageSize() {
        return pageSize;
    }

    public long getInitialPages() {
        return initialPages;
    }

    void setInitialPages(final long initialPages) {
        this.initialSize = sizeFromPages(initialPages);
        this.initialPages = initialPages;
    }

    public long getExtensionPages() {
        return extensionPages;
    }

    void setExtensionPages(final long extensionPages) {
        this.extensionSize = sizeFromPages(extensionPages);
        this.extensionPages = extensionPages;
    }

    public long getMaximumPages() {
        return maximumPages;
    }

    void setMaximumPages(final long maximumPages) {
        this.maximumSize = sizeFromPages(maximumPages);
        this.maximumPages = maximumPages;
    }

    public long getInitialSize() {
        return initialSize;
    }

    public void setInitialSize(final long initialSize) {
        this.initialPages = pagesFromSize(initialSize);
        this.initialSize = roundSize(initialSize);
    }

    public long getExtensionSize() {
        return extensionSize;
    }

    public void setExtensionSize(final long extensionSize) {
        this.extensionPages = pagesFromSize(extensionSize);
        this.extensionSize = roundSize(extensionSize);
    }

    public long getMaximumSize() {
        return maximumSize;
    }

    public void setMaximumSize(final long maximumSize) {
        this.maximumPages = pagesFromSize(maximumSize);
        this.maximumSize = roundSize(maximumSize);
    }

    public int getVersion() {
        return version;
    }

    public long getId() {
        return id;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append(path);
        if (aliased) {
            sb.append(',').append(ATTR_NAME).append(':').append(name);
        }
        if (pageSize > 0) {
            sb.append(',').append(ATTR_PAGE_SIZE).append(':').append(pageSize);
        }

        appendSize(sb, ATTR_INITIAL_SIZE, ATTR_INITIAL_PAGES, initialSize, initialPages);
        appendSize(sb, ATTR_MAXIMUM_SIZE, ATTR_MAXIMUM_PAGES, maximumSize, maximumPages);
        appendSize(sb, ATTR_EXTENSION_SIZE, ATTR_EXTENSION_PAGES, extensionSize, extensionPages);

        if (readOnly) {
            sb.append(',').append(ATTR_READONLY);
        }
        if (createOnly) {
            sb.append(',').append(ATTR_CREATEONLY);
        } else if (create) {
            sb.append(',').append(ATTR_CREATE);
        }
        return sb.toString();
    }

    private void appendSize(final StringBuilder sb, final String sizeName, final String pagesName, final long size,
            final long pages) {
        if (pageSize <= 0) {
            if (pages > 0) {
                sb.append(',').append(pagesName).append(':').append(ds(pages));
            } else if (size > 0) {
                sb.append(',').append(sizeName).append(':').append(ds(size));
            }
        } else if (pages > 0) {
            sb.append(',').append(sizeName).append(':').append(ds(pages * pageSize));
        } else if (size > 0) {
            sb.append(',').append(sizeName).append(':').append(ds(size));
        }
    }

    @Override
    public boolean equals(final Object object) {
        if (!(object instanceof VolumeSpecification)) {
            return false;
        }
        final VolumeSpecification v = (VolumeSpecification) object;
        return path.equals(v.path) && name.equals(v.name) && readOnly == v.readOnly && create == v.create
                && createOnly == v.createOnly && aliased == v.aliased && pageSize == v.pageSize && version == v.version
                && id == v.id && initialPages == v.initialPages && initialSize == v.initialSize
                && extensionPages == v.extensionPages && extensionSize == v.extensionSize
                && maximumPages == v.maximumPages && maximumSize == v.maximumSize;
    }

    private String ds(final long s) {
        return Configuration.displayableLongValue(s);
    }

    public String summary() {
        return name + "(" + path + ")";
    }

    private long sizeFromPages(final long pages) {
        Util.rangeCheck(pages, 0, Long.MAX_VALUE / Buffer.MAX_BUFFER_SIZE);
        return pageSize > 0 ? pages * pageSize : 0;
    }

    private long pagesFromSize(final long size) {
        Util.rangeCheck(size, 0, Long.MAX_VALUE);
        return pageSize > 0 ? size / pageSize : 0;
    }

    private long roundSize(final long size) {
        if (pageSize > 0) {
            return (size / pageSize) * pageSize;
        } else {
            return size;
        }
    }
}
TOP

Related Classes of com.persistit.VolumeSpecification

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.