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

com.persistit.VolumeStorageT2 Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
/**
 * 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 [email protected].
 * 
 * Contributors:
 * Akiban Technologies, Inc.
 */

package com.persistit;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import com.persistit.AlertMonitor.AlertLevel;
import com.persistit.AlertMonitor.Event;
import com.persistit.exception.InUseException;
import com.persistit.exception.InvalidPageAddressException;
import com.persistit.exception.PersistitException;
import com.persistit.exception.PersistitIOException;
import com.persistit.exception.PersistitInterruptedException;
import com.persistit.exception.ReadOnlyVolumeException;
import com.persistit.exception.VolumeClosedException;
import com.persistit.exception.VolumeFullException;

/**
 * Manage all details of file I/O for a temporary Volume backing
 * file. A temporary volume is intended to store data that does not need to be
 * durable. All trees in a temporary volume are lost when Persistit shuts down,
 * whether abruptly or gracefully. Therefore pages writes are not logged,
 * buffers are not flushed on shutdown and there is no volume header page to
 * hold metadata.
 * 
 * @author peter
 */
class VolumeStorageT2 extends VolumeStorage {

    private final static String TEMP_FILE_PREFIX = "persistit_tempvol_";
    private final static String TEMP_FILE_UNCREATED_NAME = "temp_volume_file_not_created_yet";
    private long _maxPages;
    private volatile String _path;
    private volatile FileChannel _channel;

    private volatile long _nextAvailablePage;
    private volatile boolean _opened;
    private volatile boolean _closed;

    VolumeStorageT2(final Persistit persistit, final Volume volume) {
        super(persistit, volume);
    }

    /**
     * Returns the path name by which this volume was opened.
     * 
     * @return The path name
     */
    @Override
    String getPath() {
        return _path;
    }

    /**
     * Indicate whether this Volume prohibits updates.
     * 
     * @return true if this Volume prohibits updates.
     */
    @Override
    boolean isReadOnly() {
        return false;
    }

    /**
     * Indicate whether this is a temporary volume
     * 
     * @return true if this volume is temporary
     */
    @Override
    boolean isTemp() {
        return true;
    }

    /**
     * @return the channel used to read and write pages of this volume.
     */
    @Override
    synchronized FileChannel getChannel() throws PersistitIOException {
        if (_channel == null) {
            try {
                final String directoryName = _persistit.getConfiguration().getTmpVolDir();
                final File directory = directoryName == null ? null : new File(directoryName);
                final File file = File.createTempFile(TEMP_FILE_PREFIX, null, directory);
                _path = file.getPath();
                _channel = new MediatedFileChannel(_path, "rw");
            } catch (final IOException ioe) {
                _persistit.getLogBase().tempVolumeCreateException.log(ioe, _path);
                throw new PersistitIOException(ioe);
            }
        }
        return _channel;
    }

    /**
     * Create a new Volume backing file according to the
     * {@link Volume}'s volume specification.
     * 
     * @throws PersistitException
     */
    @Override
    void create() throws PersistitException {
        final long maxSize = _persistit.getConfiguration().getTmpVolMaxSize();
        _maxPages = maxSize / _volume.getStructure().getPageSize();
        _path = TEMP_FILE_UNCREATED_NAME;
        _channel = null;
        truncate();
        _opened = true;
    }

    /**
     * Open an existing Volume backing file.
     * 
     * @throws PersistitException
     */
    @Override
    void open() throws PersistitException {
        throw new UnsupportedOperationException("Temporary volume can only be created.");
    }

    /**
     * @return true if a backing file exists on the specified path.
     * @throws PersistitException
     */
    @Override
    boolean exists() throws PersistitException {
        return false;
    }

    /**
     * Delete the backing file for this Volume if it exists.
     * 
     * @return true if there was a file and it was successfully
     *         deleted
     * @throws PersistitException
     */
    @Override
    boolean delete() throws PersistitException {
        return false;
    }

    /**
     * Force all file system buffers to disk.
     * 
     * @throws PersistitIOException
     */
    @Override
    void force() throws PersistitIOException {
        // No need to force a temporary Volume
    }

    /**
     * Close the file resources held by this Volume. After this
     * method is called no further file I/O is possible.
     * 
     * @throws PersistitException
     */
    @Override
    void close() throws PersistitException {
        synchronized (this) {
            if (_closed) {
                return;
            }
            _closed = true;
        }

        PersistitException pe = null;

        try {
            closeChannel();
        } catch (final Exception e) {
            _persistit.getLogBase().exception.log(e);
            // has priority over Exception thrown by
            // releasing file lock.
            pe = new PersistitException(e);
        }
        try {
            if (_path != null) {
                final File file = new File(_path);
                file.delete();
            }
        } catch (final Exception e) {
            _persistit.getLogBase().exception.log(e);
            // has priority over Exception thrown by
            // releasing file lock.
            pe = new PersistitException(e);
        }

        if (pe != null) {
            throw pe;
        }
    }

    private void closeChannel() throws IOException {
        final FileChannel channel = _channel;
        _channel = null;
        if (channel != null) {
            channel.close();
        }
    }

    @Override
    void truncate() throws PersistitException {
        if (!claim(true, 0)) {
            throw new InUseException("Unable to acquire claim on " + this);
        }
        try {
            final VolumeStatistics stat = _volume.getStatistics();
            final VolumeStructure struc = _volume.getStructure();

            final long now = System.currentTimeMillis();
            stat.setCreateTime(now);
            stat.setOpenTime(now);

            _nextAvailablePage = 1;

            struc.init(0, 0);
        } finally {
            release();
        }
        flushMetaData();

    }

    @Override
    boolean isOpened() {
        return _opened;
    }

    @Override
    boolean isClosed() {
        return _closed;
    }

    @Override
    long getExtentedPageCount() {
        return _nextAvailablePage;
    }

    @Override
    long getNextAvailablePage() {
        return _nextAvailablePage;
    }

    @Override
    void claimHeadBuffer() throws PersistitException {
    }

    @Override
    void releaseHeadBuffer() {
    }

    @Override
    void readPage(final Buffer buffer) throws PersistitIOException, InvalidPageAddressException, VolumeClosedException,
            InUseException, PersistitInterruptedException {
        // non-exclusive claim here intended to conflict with exclusive claim in
        // close and truncate
        if (!claim(false, 0)) {
            throw new InUseException("Unable to acquire claim on " + this);
        }
        try {
            final long page = buffer.getPageAddress();
            if (page < 1 || page >= _nextAvailablePage) {
                throw new InvalidPageAddressException("Page " + page + " out of bounds [0-" + _nextAvailablePage + "]");
            }
            try {
                final ByteBuffer bb = buffer.getByteBuffer();
                bb.position(0).limit(buffer.getBufferSize());
                int read = 0;
                while (read < buffer.getBufferSize()) {
                    final long position = (page - 1) * _volume.getStructure().getPageSize() + bb.position();
                    final int bytesRead = getChannel().read(bb, position);
                    if (bytesRead <= 0) {
                        throw new PersistitIOException("Unable to read bytes at position " + position + " in " + this);
                    }
                    read += bytesRead;
                }
                _persistit.getIOMeter().chargeReadPageFromVolume(this._volume, buffer.getPageAddress(),
                        buffer.getBufferSize(), buffer.getIndex());
                _volume.getStatistics().bumpReadCounter();
            } catch (final IOException ioe) {
                _persistit.getAlertMonitor().post(
                        new Event(AlertLevel.ERROR, _persistit.getLogBase().readException, ioe, _volume, page,
                                buffer.getIndex()), AlertMonitor.READ_PAGE_CATEGORY);
                throw new PersistitIOException(ioe);
            }
        } finally {
            release();
        }
    }

    @Override
    void writePage(final Buffer buffer) throws PersistitIOException, InvalidPageAddressException,
            ReadOnlyVolumeException, VolumeClosedException, InUseException, PersistitInterruptedException {
        final int pageSize = _volume.getStructure().getPageSize();
        final ByteBuffer bb = buffer.getByteBuffer();
        bb.position(0).limit(pageSize);
        writePage(bb, buffer.getPageAddress());
    }

    @Override
    void writePage(final ByteBuffer bb, final long page) throws PersistitIOException, InvalidPageAddressException,
            ReadOnlyVolumeException, VolumeClosedException, InUseException, PersistitInterruptedException {
        // non-exclusive claim here intended to conflict with exclusive claim in
        // close and truncate
        final int pageSize = _volume.getStructure().getPageSize();
        if (!claim(false, 0)) {
            throw new InUseException("Unable to acquire claim on " + this);
        }
        try {
            if (page < 0 || page >= _nextAvailablePage) {
                throw new InvalidPageAddressException("Page " + page + " out of bounds [0-" + _nextAvailablePage + "]");
            }

            try {
                getChannel().write(bb, (page - 1) * pageSize);

            } catch (final IOException ioe) {
                _persistit.getAlertMonitor().post(
                        new Event(AlertLevel.ERROR, _persistit.getLogBase().writeException, ioe, _volume, page),
                        AlertMonitor.WRITE_PAGE_CATEGORY);
                throw new PersistitIOException(ioe);
            }
        } finally {
            release();
        }
    }

    @Override
    long allocNewPage() throws PersistitException {
        if (_nextAvailablePage >= _maxPages) {
            throw new VolumeFullException(_volume.getName());
        }
        final long page = _nextAvailablePage++;
        _volume.getStatistics().setNextAvailablePage(page);
        return page;
    }

    @Override
    void flush() throws PersistitException {

    }

    @Override
    void flushMetaData() throws PersistitException {

    }

    @Override
    void extend(final long pageAddr) throws PersistitException {

    }

    @Override
    boolean updateMetaData(final byte[] bytes) {
        // Temporary volume has no head buffer
        return false;
    }

    @Override
    public String toString() {
        return _volume.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy