net.timewalker.ffmq4.storage.data.impl.BlockBasedDataStoreTools.java Source code

Java tutorial

Introduction

Here is the source code for net.timewalker.ffmq4.storage.data.impl.BlockBasedDataStoreTools.java

Source

/*
 * This file is part of FFMQ.
 *
 * FFMQ is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * FFMQ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with FFMQ; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package net.timewalker.ffmq4.storage.data.impl;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Comparator;

import net.timewalker.ffmq4.storage.data.DataStoreException;
import net.timewalker.ffmq4.storage.data.impl.journal.JournalFile;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * BlockFileDataStoreTools
 */
public class BlockBasedDataStoreTools {
    private static final Log log = LogFactory.getLog(BlockBasedDataStoreTools.class);

    /**
      * Create the filesystem for a new store
      */
    public static void create(String baseName, File dataFolder, int blockCount, int blockSize, boolean forceSync)
            throws DataStoreException {
        if (blockCount <= 0)
            throw new DataStoreException("Block count should be > 0");
        if (blockSize <= 0)
            throw new DataStoreException("Block size should be > 0");

        File atFile = new File(dataFolder, baseName + AbstractBlockBasedDataStore.ALLOCATION_TABLE_SUFFIX);
        File dataFile = new File(dataFolder, baseName + AbstractBlockBasedDataStore.DATA_FILE_SUFFIX);
        if (atFile.exists())
            throw new DataStoreException(
                    "Cannot create store filesystem : " + atFile.getAbsolutePath() + " already exists");
        if (dataFile.exists())
            throw new DataStoreException(
                    "Cannot create store filesystem : " + dataFile.getAbsolutePath() + " already exists");

        initAllocationTable(atFile, blockCount, blockSize, forceSync);
        initDataFile(dataFile, blockCount, blockSize, forceSync);
    }

    private static final byte[] EMPTY_BLOCK = { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // one 0 byte and three -1 ints

    private static void initAllocationTable(File atFile, int blockCount, int blockSize, boolean forceSync)
            throws DataStoreException {
        log.debug("Creating allocation table (size=" + blockCount + ") ...");

        // Create the file
        try {
            FileOutputStream outFile = new FileOutputStream(atFile);
            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outFile));

            out.writeInt(blockCount); // Block count
            out.writeInt(blockSize); // Block size
            out.writeInt(-1); // First block index
            for (int n = 0; n < blockCount; n++)
                out.write(EMPTY_BLOCK);
            out.flush();
            if (forceSync)
                outFile.getFD().sync();

            out.close();
        } catch (IOException e) {
            throw new DataStoreException("Cannot initialize allocation table " + atFile.getAbsolutePath(), e);
        }
    }

    private static void initDataFile(File dataFile, int blockCount, int blockSize, boolean forceSync)
            throws DataStoreException {
        log.debug("Creating an empty map file (size=" + blockCount + "x" + blockSize + ") ...");

        // Create an empty file
        try {
            RandomAccessFile dataFileMap = new RandomAccessFile(dataFile, "rw");
            dataFileMap.setLength((long) blockSize * blockCount);
            if (forceSync)
                dataFileMap.getFD().sync();
            dataFileMap.close();
        } catch (IOException e) {
            throw new DataStoreException("Cannot initialize map file " + dataFile.getAbsolutePath(), e);
        }
    }

    /**
      * Delete the filesystem of a store
      */
    public static void delete(String baseName, File dataFolder, boolean force) throws DataStoreException {
        File[] journalFiles = findJournalFiles(baseName, dataFolder);
        if (journalFiles.length > 0) {
            if (force) {
                for (int i = 0; i < journalFiles.length; i++) {
                    if (!journalFiles[i].delete())
                        throw new DataStoreException("Cannot delete file : " + journalFiles[i].getAbsolutePath());
                }
            } else
                throw new DataStoreException("Journal file exist : " + journalFiles[0].getAbsolutePath());
        }

        File atFile = new File(dataFolder, baseName + AbstractBlockBasedDataStore.ALLOCATION_TABLE_SUFFIX);
        if (atFile.exists())
            if (!atFile.delete())
                throw new DataStoreException("Cannot delete file : " + atFile.getAbsolutePath());

        File dataFile = new File(dataFolder, baseName + AbstractBlockBasedDataStore.DATA_FILE_SUFFIX);
        if (dataFile.exists())
            if (!dataFile.delete())
                throw new DataStoreException("Cannot delete file : " + dataFile.getAbsolutePath());
    }

    /**
     * Find existing journal files for a given base name
     * @param baseName
     * @param dataFolder
     * @return an array of journal files
     */
    public static File[] findJournalFiles(String baseName, File dataFolder) {
        final String journalBase = baseName + JournalFile.SUFFIX;
        File[] journalFiles = dataFolder.listFiles(new FileFilter() {
            /*
             * (non-Javadoc)
             * @see java.io.FileFilter#accept(java.io.File)
             */
            @Override
            public boolean accept(File pathname) {
                if (!pathname.isFile())
                    return false;

                return pathname.getName().startsWith(journalBase)
                        && !pathname.getName().endsWith(JournalFile.RECYCLED_SUFFIX);
            }
        });

        // Sort them in ascending order
        Arrays.sort(journalFiles, new Comparator<File>() {
            @Override
            public int compare(File f1, File f2) {
                return f1.getName().compareTo(f2.getName());
            }
        });

        return journalFiles;
    }

    /**
     * Find recycled journal files for a given base name
     * @param baseName
     * @param dataFolder
     * @return an array of journal files
     */
    public static File[] findRecycledJournalFiles(String baseName, File dataFolder) {
        final String journalBase = baseName + JournalFile.SUFFIX;
        File[] recycledFiles = dataFolder.listFiles(new FileFilter() {
            /*
             * (non-Javadoc)
             * @see java.io.FileFilter#accept(java.io.File)
             */
            @Override
            public boolean accept(File pathname) {
                if (!pathname.isFile())
                    return false;

                return pathname.getName().startsWith(journalBase)
                        && pathname.getName().endsWith(JournalFile.RECYCLED_SUFFIX);
            }
        });

        return recycledFiles;
    }
}