Package org.chaidb.db.index.btree.bufmgr

Source Code of org.chaidb.db.index.btree.bufmgr.Storage$FileInfoMap

/*
* Copyright (C) 2006  http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
*/

package org.chaidb.db.index.btree.bufmgr;

import org.apache.log4j.Logger;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
import org.chaidb.db.index.btree.Debug;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;


class Storage {

    /**
     * keep storage information of data file.
     */
    class FileInfo {

        /**
         * This class implements the basic functions related to physical
         * file storage, like read a page from a file, store a page into a file, open the
         * database file, close the database file, etc.
         */
        class PagedFile {

            /**
             * the database file reference
             */
            private RandomAccessFile _file;

            /**
             * page size
             */
            private int _pageSize;

            PagedFile(int pgsize) {
                _pageSize = pgsize;
            }

            void open(File file) throws ChaiDBException {
                try {
                    this._file = new RandomAccessFile(file, "rw");
                } catch (FileNotFoundException fnfe) {
                    try {
                        String dir = file.getAbsolutePath();
                        dir = dir.substring(0, dir.lastIndexOf(File.separator));
                        new File(dir).mkdirs();
                        this._file = new RandomAccessFile(file, "rw");
                        //modified by Stanley
                        virtualFiles.remove(file.getAbsolutePath());
                    } catch (Exception e) {
                        // moved to details -ranjeet
                        String details = "Open for file " + file.getName() + " failed. " + e.toString() + ".";
                        throw new ChaiDBException(ErrorCode.BTREE_NOT_FOUND, details);
                    }
                } catch (IOException ioe) {
                    // moved to details -ranjeet
                    String details = "Open for file " + file.getName() + " failed. " + ioe.toString() + ".";
                    throw new ChaiDBException(ErrorCode.BTREE_IO_ERROR, details);
                }
            }

            /**
             * close the database file
             */
            synchronized void close() throws ChaiDBException {
                try {
                    _file.close();
                } catch (IOException ioe) {
                    // moved to details -ranjeet
                    String details = "Close for the page file failed. " + ioe.toString() + ".";
                    throw new ChaiDBException(ErrorCode.BTREE_IO_ERROR, details);
                }
            }

            synchronized void sync() throws ChaiDBException {
                try {
                    _file.getFD().sync();
                } catch (IOException ioe) {
                    String details = "Sync file to disk failed." + ioe.toString() + ".";
                    throw new ChaiDBException(ErrorCode.BTREE_IO_ERROR, details);
                }
            }

            /**
             * read a page from the database file
             *
             * @param pageIndex The position to read the page, unit is pageSize
             * @param page      The place to hold the page
             * @return if no such page, return false, and page is untouched; else return true,
             *         page will have the new data.
             */
            synchronized boolean readPage(int pageIndex, byte[] page) throws ChaiDBException {
                try {
                    if (_file.length() <= pageIndex * _pageSize) {
                        return false;
                    }
                    _file.seek(((long) pageIndex) * _pageSize);
                    _file.read(page);
                    return true;
                } catch (IOException e) {
                    // details -ranjeet
                    String details = "The operation read page failed for page index " + pageIndex + ". " + e.toString() + ".";
                    throw new ChaiDBException(ErrorCode.BTREE_IO_ERROR, details);
                }
            }

            /**
             * write a page back to the database file
             *
             * @param data      The page data
             * @param pageIndex The position to put the page, unit is pageSize
             */
            synchronized void writePage(int pageIndex, byte[] data) throws ChaiDBException {
                if (data.length > _pageSize) {
                    // details -ranjeet
                    String details = "Data length is less than page size.";
                    throw new ChaiDBException(ErrorCode.BTREE_DATA_SIZE_OVERFLOW, details);
                }
                try {
                    _file.seek(((long) pageIndex) * _pageSize);
                    _file.write(data);
                } catch (IOException ioe) {
                    // details -ranjeet
                    String details = "The operation write page failed for page index " + pageIndex + ". " + ioe.toString() + ".";
                    throw new ChaiDBException(ErrorCode.BTREE_IO_ERROR, details);
                }
            }
        } // end of class PagedFile

        private String _filePath; //which dirctory store data (full path?)
        private int _fileNumber; //file serial number {0,1,2...}
        private PagedFile _file;  // the reference to the pagedFile


        public FileInfo(String filePath, int fileNumber) {
            _filePath = filePath;
            _fileNumber = fileNumber;
            _file = new PagedFile(_PAGE_SIZE);
        }


        /*access method*/
        void open() throws ChaiDBException {
            _file.open(new File(_filePath));
        }


        /**
         * close the file
         * might need other clean up ######### Ying
         */
        void close() throws ChaiDBException {
            _file.close();
        }

        void sync() throws ChaiDBException {
            _file.sync();
        }


        int getFileNumber() {
            return _fileNumber;
        }


        /**
         * read a page from the database file
         *
         * @return if no such page, return false, and page is untouched; else return true,
         *         page will have the new data.
         */
        String getFilePath() {
            return _filePath;
        }


        boolean readPage(int pageNumber, byte[] page) throws ChaiDBException {
            return _file.readPage(pageNumber, page);
        }


        /**
         * write a page back to the database file
         *
         * @param data       The page data
         * @param pageNumber The position to put the page, unit is pageSize
         */
        void writePage(int pageNumber, byte[] data) throws ChaiDBException {
            _file.writePage(pageNumber, data);
        }
    } // end of class FileInfo

    // ------------------------------------------------------------ constants

    /** class debug flag */
//    private final static boolean _DEBUG = false;


    /**
     * The max pages a file can contain
     */
    public static final int MAX_FILESIZE_IN_PAGE = Debug.DEBUG_STORAGE_FILE_SIZE ? 0x100 : 0x7FFFF;


    /**
     * The maximize number of simultaneous open files
     */
    private static final short _MAX_OPEN_FILES = 1500;

//    private static final short _KICK_FILES = 300;


    private final int _PAGE_SIZE;

    // --------------------------------------------------------- class variables

    /**
     * logger, it may be null
     */
    private static Logger logger = Logger.getLogger(Storage.class);

    // ------------------------------------------------------ instance variables

    //no need synchronized, we synchronized on each method using this.
//    private Map _fileInfoList = new LinkedHashMap() {
//        protected boolean removeEldestEntry(Map.Entry eldest) {
//            if (_fileInfoList.size() > _MAX_OPEN_FILES) {
//                FileInfo fo = (FileInfo) eldest.getValue();
//                try {
//                    fo.close();
//                    if (_DEBUG) {
//                        logger.debug("kick off file " + fo.getFilePath());
//                    }
//                } catch (ChaiDBException e) {
//                    logger.error(e);
//                }
//                return true;
//            }
//            return false;
//        }
    //    };
    private FileInfoMap _fileInfoList = new FileInfoMap();

    // add by Stanley for storing Collection directories information
    private StorageMeta storageMeta = new StorageMeta();
    private LinkedList virtualFiles = new LinkedList();

    private class FileInfoMap {
        LinkedHashMap _infoMap = new LinkedHashMap() {
            protected boolean removeEldestEntry(Map.Entry eldest) {
//            return super.removeEldestEntry(eldest);
                if (this.size() > _MAX_OPEN_FILES) {
                    logger.debug("Begin to kick off opened files.");
                    Map files = (Map) eldest.getValue();
                    closeAll(files);
                    logger.debug("End of kicking off opened files.");
                    return true;
                }
                return false;
            }
        };

        FileInfoMap() {

        }

        boolean containsKey(Object key1) {
            assert key1 != null;
            return (_infoMap.containsKey(key1));
        }

        boolean containsKey(Object key1, int key2) {
            assert key1 != null;
            if (!_infoMap.containsKey(key1)) {
                return false;
            }
            Map alist = (Map) _infoMap.get(key1);
            if (alist.containsKey(new Integer(key2))) {
                return true;
            }
            return false;
        }

        Map get(Object key1) {
            assert key1 != null;
            return (Map) _infoMap.get(key1);
        }

        Object get(Object key1, int key2) {
            assert key1 != null;
            Map alist = (Map) _infoMap.get(key1);
            if (alist == null) {
                return null;
            }
            return alist.get(new Integer(key2));
        }

        Object put(Object key1, int key2, Object value) {
            assert key1 != null;
            Map alist = (Map) _infoMap.get(key1);
            Object oldValue = null;

            if (alist == null) {
                alist = new HashMap();
                alist.put(new Integer(key2), value);
                _infoMap.put(key1, alist);
            } else {
                oldValue = alist.put(new Integer(key2), value);
            }
            return oldValue;
        }

        Map remove(Object key1) {
            assert key1 != null;
            return (Map) _infoMap.remove(key1);
        }

        Set keySet() {
            return _infoMap.keySet();
        }

        Collection values() {
            return _infoMap.values();
        }
    }


    synchronized void closeAll(Map files) {
        Iterator it = files.keySet().iterator();
        while (it.hasNext()) {
            Integer fileno = (Integer) it.next();
            FileInfo fileInfo = (FileInfo) files.get(fileno);
            logger.debug("close file " + fileInfo.getFilePath());
            try {
                fileInfo.close();
            } catch (ChaiDBException e) {
                logger.error(e);
            }
        }
    }

    // ------------------------------------------------------ public methods

    /**
     * Constructor
     */
    Storage(int pageSize) {
        _PAGE_SIZE = pageSize;
    }

    synchronized void extendCollectionDir(int id, String primaryDir, String extendedDir) throws ChaiDBException {

    }


    synchronized void open(File file) throws ChaiDBException {
        assert file != null;
        final String filePath = file.getAbsolutePath();
        if (_fileInfoList.containsKey(filePath)) {
            return; //opened already
        }

        addNewFile(filePath, 0);
    }


    synchronized void close(String filePath) {
        assert filePath != null;
        logger.debug("storage.close filepath=" + filePath);

        Map files = _fileInfoList.remove(filePath);
        if (files != null) // files maybe closed becaue opened files count is larger than max open files.
            closeAll(files);

//        Iterator it = _fileInfoList.keySet().iterator();
//        while (it.hasNext()) {
//            FileInfo fileInfo = (FileInfo) it.next();
//            if (fileInfo.getFilePath().equals(filePath)) {
//                if (_DEBUG) {
//                    logger.debug("close file " + fileInfo.getFilePath());
//                }
//                it.remove();
//                try {
//                    fileInfo.close();
//                } catch (ChaiDBException e) {
//                    logger.error(e);
//                }
//            }
//        }
    }


    boolean readPage(String filePath, PageNumber pageIndex, byte[] page) throws ChaiDBException {
        assert filePath != null;
        assert pageIndex != null;
        FileInfo fo = getFile(filePath, pageIndex.getFileNumber());
        if (fo == null) return false;
        return fo.readPage(pageIndex.getPageInFile(), page);
    }


    /**
     * write a page back to the database file
     *
     * @param data      The page data
     * @param pageIndex The position to put the page, unit is pageSize
     */
    void writePage(String filePath, PageNumber pageIndex, byte[] data) throws ChaiDBException {
        assert filePath != null;
        assert pageIndex != null;
//        int tid = pageIndex.getTreeId();
        FileInfo fo = getFile(filePath, pageIndex.getFileNumber());
        if (fo != null) fo.writePage(pageIndex.getPageInFile(), data);

    }

    synchronized void sync() {
        Collection lists = _fileInfoList.values();
        for (Iterator itList = lists.iterator(); itList.hasNext();) {
            Map filesMap = (Map) itList.next();
            Collection files = filesMap.values();
            for (Iterator itFiles = files.iterator(); itFiles.hasNext();) {
                FileInfo fileInfo = (FileInfo) itFiles.next();
                logger.debug("sync file " + fileInfo.getFilePath());
                try {
                    fileInfo.sync();
                } catch (ChaiDBException e) {
                    logger.error(e);
                }
            }
        }
    }

    // ------------------------------------------------------ private methods

    /**
     * Kick out and close some old files for new open file.
     * Because JDK limits the maxise number of simulataneous open file up to 2030~2042.
     * Thus old files should be closed to free file descriptors preoccupied by them
     */
//    private void kickOffOldOpenedFiles() {
//        int count = 0;
//        while (count < _KICK_FILES) {
//            FileInfo fo = (FileInfo) _fileInfoList.remove(0);
//            try {
//                fo.close();
//                count++;
//                if (_DEBUG) {
//                    logger.debug("kick off file " + fo.getFilePath());
//                }
//            } catch (ChaiDBException e) {
//                logger.error(e);
//            }
//        }
//    }
//
    synchronized private FileInfo addNewFile(String fname, int fileno) throws ChaiDBException {
//        if (_fileInfoList.size() > _MAX_OPEN_FILES) {
//            kickOffOldOpenedFiles();
//        }

        boolean fileExists = false;
        String str = null;
        if (storageMeta.getCollectionID(fname) != null) {
            Iterator possibleFiles = storageMeta.getAllFileNames(fname);
            while (possibleFiles.hasNext()) {
                str = (String) possibleFiles.next();
                if (fileno > 0) str += fileno;
                File f = new File(str);
                if (f.exists()) {
                    fileExists = true;
                    break;
                }

            }
            if (!fileExists) {
                str = storageMeta.getCurrentFileName(fname);
                if (fileno > 0) str += fileno;
            }
        } else {
            str = fname;
            if (fileno > 0) str += fileno;
        }

        FileInfo fo = new FileInfo(str, fileno);
        fo.open();
        _fileInfoList.put(fname, fileno, fo);
        return fo;
    }


    synchronized private FileInfo getFile(String filePath, int fileNumber) throws ChaiDBException {
        FileInfo fi = (FileInfo) _fileInfoList.get(filePath, fileNumber);
        if (fi != null) return fi;

        return addNewFile(filePath, fileNumber);
    }

    /**
     * @param filePath
     * @param fileno
     * @return
     */
    synchronized public boolean curDirHasFile(String filePath, int fileno) {
        boolean fileExists = false;
        String str;
        str = storageMeta.getCurrentFileName(filePath);

        if (fileno > 0) str += fileno;
        if (virtualFiles.contains(str)) return true;

        FileInfo fi = (FileInfo) _fileInfoList.get(filePath, fileno);
        if (fi != null) {
            if (fi.getFilePath().equals(str)) return true;
        }
        File f = new File(str);
        if (f.exists()) {
            fileExists = true;
        }
        return fileExists;
    }

    synchronized public void addVirtualFile(String filePath, int fileno) {
        String str = storageMeta.getCurrentFileName(filePath);

        if (fileno > 0) str += fileno;

        if (!virtualFiles.contains(str)) virtualFiles.add(str);
    }

    public void addExtendedDir(int collectionID, String extendedDir) throws ChaiDBException {
        storageMeta.addExtendedDirectory(collectionID, extendedDir);
    }

    public String listCollectionDirs(int collectionID) throws ChaiDBException {
        return storageMeta.listCollectionDir(collectionID);
    }

    public Iterator listColDirs(int collectionID) throws ChaiDBException {
        return storageMeta.listColDirs(collectionID);
    }

    public Iterator removeExtendedColDirs(int collectionID) throws ChaiDBException {
        return storageMeta.removeExtendedColDirs(collectionID);
    }

    synchronized public CollectionStorage getColStorage(int collectionId) {
        return storageMeta.getColStorage(collectionId);
    }
}


TOP

Related Classes of org.chaidb.db.index.btree.bufmgr.Storage$FileInfoMap

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.
java.io.FileInputStream">java.io.FileInputStream
  • java.util.Date
  • java.net.URL
  • 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.