📄 filestoragefactory.java
字号:
// You can redistribute this software and/or modify it under the terms of// the Ozone Core License version 1 published by ozone-db.org.//// Copyright (C) 2003-@year@, Leo Mekenkamp. All rights reserved.//// $Id: FileStorageFactory.java,v 1.3 2004/03/21 21:05:51 leomekenkamp Exp $package org.ozoneDB.core.storage.gammaStore;import java.io.File;import java.io.IOException;import java.util.Collection;import java.util.LinkedList;import java.util.List;import java.util.Properties;import java.util.Random;import java.util.logging.Level;import java.util.logging.Logger;import org.ozoneDB.core.ConfigurationException;import org.ozoneDB.core.storage.PropertyConfigurable;import org.ozoneDB.core.storage.PropertyInfo;/** * Abstract base class for storage factories that use files. * * @author <a href="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a> * @version $Id: FileStorageFactory.java,v 1.3 2004/03/21 21:05:51 leomekenkamp Exp $ */public abstract class FileStorageFactory implements StorageFactory, PropertyConfigurable { private static Logger log = Logger.getLogger(FileStorageFactory.class.getName()); public static final PropertyInfo DIRECTORY = new PropertyInfo( ".directory", "string (path)", null, "directory, either relative to the database directory or an absolute path", new String[] { "/var/ozone/index (*nix absolute path)", "c:\\ozoneFiles\\index (windows absolute path)", "index (*nix or windows relative path in database dir)", "./index (*nix relative path in database dir)", ".\\index (windows relative path in database dir)", } ); private static final String SUBDIRECTORYDEPTH_KEY = ".subdirectoryDepth"; private static final String SUBDIRECTORYCOUNT_KEY = ".subdirectoryCount"; public static final PropertyInfo SUBDIRECTORYDEPTH = new PropertyInfo( SUBDIRECTORYDEPTH_KEY, "integer (>=0)", "1", "depth of subdirectories to use, to prevent too much files in the " + "directory specified by '.directory' (see: " + SUBDIRECTORYCOUNT_KEY + ")", new String[] { "/var/ozone/index (*nix absolute path)", "c:\\ozoneFiles\\index (windows absolute path)", "index (*nix or windows relative path in database dir)", "./index (*nix relative path in database dir)", ".\\index (windows relative path in database dir)", } ); public static final PropertyInfo SUBDIRECTORYCOUNT = new PropertyInfo( SUBDIRECTORYCOUNT_KEY, "integer (>=2)", "50", "number of subdirectories to use when " + SUBDIRECTORYDEPTH_KEY + " is greater than 0", new String[] { "/var/ozone/index (*nix absolute path)", "c:\\ozoneFiles\\index (windows absolute path)", "index (*nix or windows relative path in database dir)", "./index (*nix relative path in database dir)", ".\\index (windows relative path in database dir)", } ); /** * <p>Used to name directories. We could take any value from 2 to * <code>Character.MAX_RADIX</code> (36) here, but we settle for 16 because * it looks nice and nerdy. 36 would look less nice because that could * lead to directories with very nasty words in them when SUBDIRECTORYCOUNT * is large enough. */ private static final int NAMECONVERTRADIX = 16; private File directory; private String prefix; private int subdirectoryDepth; private int subdirectoryCount; /** * As prescribed by the <code>PropertyConfigurable</code> interface. */ protected FileStorageFactory(Properties properties, String prefix) { setPrefix(prefix); String property = getPrefix() + DIRECTORY.getKey(); String dirName = properties.getProperty(property); if (dirName == null) { String msg = "could not find property: '" + property + "'"; if (log.isLoggable(Level.SEVERE)) log.severe(msg + "\ncould find: " + properties.entrySet()); throw new ConfigurationException(msg); } File directory = new File(dirName); if (!directory.isAbsolute()) { File databaseRoot = new File(properties.getProperty(GammaStore.DIRECTORY.getKey())); directory = new File(databaseRoot, dirName); } if (!directory.isDirectory() && !directory.mkdir()) { String msg = "could not find nor create directory: '" + dirName + "'"; if (log.isLoggable(Level.SEVERE)) log.severe(msg); throw new ConfigurationException(msg); } else { if (log.isLoggable(Level.CONFIG)) log.config(getPrefix() + " using directory " + directory); } setDirectory(directory); // find out the current directory depth by counting the number of dirs // we have to go to find the first file subdirectoryDepth = findDepth(getDirectory(), 0); log.config("current directoryDepth: " + subdirectoryDepth); int newDepth = Integer.parseInt(properties.getProperty(getPrefix() + SUBDIRECTORYDEPTH.getKey(), SUBDIRECTORYDEPTH.getDefaultValue())); log.config("new directoryDepth: " + newDepth); try { setSubdirectoryDepth(newDepth); } catch (IOException e) { ConfigurationException ee = new ConfigurationException("could not change directory depth to " + newDepth, e); log.severe(ee.getMessage()); throw ee; } int newCount = Integer.parseInt(properties.getProperty(getPrefix() + SUBDIRECTORYCOUNT.getKey(), SUBDIRECTORYCOUNT.getDefaultValue())); setSubdirectoryCount(newCount); } private int findDepth(File directory, int startDepth) { File[] files = directory.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { int result = findDepth(files[i], startDepth + 1); if (result > startDepth) { return result; } } } for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { return startDepth; } } return 0; } public void delete(String name) throws IOException { File file = nameToFile(name); if (file.exists() && !file.delete()) { String msg = "could not delete file '" + file + "'"; if (log.isLoggable(Level.SEVERE)) log.severe(msg); throw new IOException(msg); } } public void deleteAll() throws IOException { deleteDirectory(getDirectory()); } /** * deletes all files and subdirectories in the specified directory, but * does _not_ delete the specified directory */ private void deleteDirectory(File directory) throws IOException { File[] files = directory.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteDirectory(files[i]); } if (!files[i].delete()) { String msg = "could not delete '" + files[i] + "'"; if (log.isLoggable(Level.SEVERE)) log.severe(msg); throw new IOException(msg); } } } /** * <p>Sets the depth of subdirectories to use. You must make sure that no * reading or writing is taking place in the directory specified by * <code>getDirectory()</code>, either by this class, or outside this class * (for instance with 'cat' or 'type' in a shell / cmd window)</p>. * <p>The whole directory structure is changed when this method is called, * so it may take some time to complete.</p> */ private void setSubdirectoryDepth(int depth) throws IOException { if (depth != subdirectoryDepth) { // needs to be debugged or removed altogether// moveFiles(getDirectory(), depth, depth); subdirectoryDepth = depth; } } // DOES NOT WORK! private void moveFiles(File directory, int relDepth, int targetDepth, int targetCount) throws IOException { File[] files = directory.listFiles(); if (relDepth == 0) { for (int i = 0; i < files.length; i++) { File dest = nameToFile(files[i].getName(), targetDepth, targetCount); ensureParentsExist(dest); files[i].renameTo(dest); } recursiveDeleteIfEmpty(directory); } else { for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { moveFiles(files[i], relDepth - 1, targetDepth, targetCount); } } } } private void recursiveDeleteIfEmpty(File directory) throws IOException { if (directory.isDirectory() && directory.list().length == 0) { if (!directory.delete()) { throw new IOException("could not delete directory " + directory); } recursiveDeleteIfEmpty(directory.getParentFile()); } } private int getSubdirectoryDepth() { return subdirectoryDepth; } public String getPrefix() { return prefix; } /** * Returns the <code>File</code> that corresponds to the given name and * depth. */ protected File nameToFile(String name, int depth, int count) { StringBuffer subPath = new StringBuffer(); long code = 1; // together with the randomizer, this gives a nice even spread of files // in subdirectories for (int i = 0; i < name.length(); i++) { code = 1 + (code * name.charAt(i)) + (name.charAt(i) * i); } Random random = new Random(); for (int i = 0; i < depth; i++) { // all algorithms are fixed across all implementations of the java // specs, so 'random' will generate the same number in every jvm random.setSeed(code * (i + 1)); int dirName = Math.abs(random.nextInt() % count); subPath.append(Integer.toString(dirName, NAMECONVERTRADIX)); subPath.append(File.separatorChar); } subPath.append(name); File result = new File(getDirectory(), subPath.toString()); return result; } protected File nameToFile(String name) { return nameToFile(name, getSubdirectoryDepth(), getSubdirectoryCount()); } protected void ensureParentsExist(File file) throws IOException { File parent = file.getParentFile(); if (!parent.exists() && !parent.mkdirs()) { throw new IOException("could not create directory " + parent); } } // private so it can be inlined private void setPrefix(String prefix) { this.prefix = prefix; } protected File getDirectory() { return directory; } // private so it can be inlined private void setDirectory(File directory) { this.directory = directory; } /** * Implementing classes should override this method, call super and add * their own specific properties. */ public Collection getPropertyInfos() { Collection result = new LinkedList(); result.add(DIRECTORY); result.add(SUBDIRECTORYDEPTH); result.add(SUBDIRECTORYCOUNT); return result; } private int getSubdirectoryCount() { return subdirectoryCount; } private void setSubdirectoryCount(int subdirectoryCount) { this.subdirectoryCount = subdirectoryCount; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -