1 8 package org.ozoneDB.core.storage.gammaStore; 9 10 import java.io.File ; 11 import java.io.IOException ; 12 import java.util.Collection ; 13 import java.util.LinkedList ; 14 import java.util.List ; 15 import java.util.Properties ; 16 import java.util.Random ; 17 import java.util.logging.Level ; 18 import java.util.logging.Logger ; 19 import org.ozoneDB.core.ConfigurationException; 20 import org.ozoneDB.core.storage.PropertyConfigurable; 21 import org.ozoneDB.core.storage.PropertyInfo; 22 23 29 public abstract class FileStorageFactory implements StorageFactory, PropertyConfigurable { 30 31 private static Logger log = Logger.getLogger(FileStorageFactory.class.getName()); 32 33 public static final PropertyInfo DIRECTORY = new PropertyInfo( 34 ".directory", 35 "string (path)", 36 null, 37 "directory, either relative to the database directory or an absolute path", 38 new String [] { 39 "/var/ozone/index (*nix absolute path)", 40 "c:\\ozoneFiles\\index (windows absolute path)", 41 "index (*nix or windows relative path in database dir)", 42 "./index (*nix relative path in database dir)", 43 ".\\index (windows relative path in database dir)", 44 } 45 ); 46 47 private static final String SUBDIRECTORYDEPTH_KEY = ".subdirectoryDepth"; 48 private static final String SUBDIRECTORYCOUNT_KEY = ".subdirectoryCount"; 49 public static final PropertyInfo SUBDIRECTORYDEPTH = new PropertyInfo( 50 SUBDIRECTORYDEPTH_KEY, 51 "integer (>=0)", 52 "1", 53 "depth of subdirectories to use, to prevent too much files in the " + 54 "directory specified by '.directory' (see: " + SUBDIRECTORYCOUNT_KEY + ")", 55 new String [] { 56 "/var/ozone/index (*nix absolute path)", 57 "c:\\ozoneFiles\\index (windows absolute path)", 58 "index (*nix or windows relative path in database dir)", 59 "./index (*nix relative path in database dir)", 60 ".\\index (windows relative path in database dir)", 61 } 62 ); 63 64 public static final PropertyInfo SUBDIRECTORYCOUNT = new PropertyInfo( 65 SUBDIRECTORYCOUNT_KEY, 66 "integer (>=2)", 67 "50", 68 "number of subdirectories to use when " + SUBDIRECTORYDEPTH_KEY + 69 " is greater than 0", 70 new String [] { 71 "/var/ozone/index (*nix absolute path)", 72 "c:\\ozoneFiles\\index (windows absolute path)", 73 "index (*nix or windows relative path in database dir)", 74 "./index (*nix relative path in database dir)", 75 ".\\index (windows relative path in database dir)", 76 } 77 ); 78 79 86 private static final int NAMECONVERTRADIX = 16; 87 88 private File directory; 89 90 private String prefix; 91 92 private int subdirectoryDepth; 93 94 private int subdirectoryCount; 95 96 99 protected FileStorageFactory(Properties properties, String prefix) { 100 setPrefix(prefix); 101 String property = getPrefix() + DIRECTORY.getKey(); 102 String dirName = properties.getProperty(property); 103 if (dirName == null) { 104 String msg = "could not find property: '" + property + "'"; 105 if (log.isLoggable(Level.SEVERE)) log.severe(msg + "\ncould find: " + properties.entrySet()); 106 107 throw new ConfigurationException(msg); 108 } 109 File directory = new File (dirName); 110 if (!directory.isAbsolute()) { 111 File databaseRoot = new File (properties.getProperty(GammaStore.DIRECTORY.getKey())); 112 directory = new File (databaseRoot, dirName); 113 } 114 if (!directory.isDirectory() && !directory.mkdir()) { 115 String msg = "could not find nor create directory: '" + dirName + "'"; 116 if (log.isLoggable(Level.SEVERE)) log.severe(msg); 117 throw new ConfigurationException(msg); 118 } else { 119 if (log.isLoggable(Level.CONFIG)) log.config(getPrefix() + " using directory " + directory); 120 } 121 setDirectory(directory); 122 123 subdirectoryDepth = findDepth(getDirectory(), 0); 126 log.config("current directoryDepth: " + subdirectoryDepth); 127 128 int newDepth = Integer.parseInt(properties.getProperty(getPrefix() + SUBDIRECTORYDEPTH.getKey(), SUBDIRECTORYDEPTH.getDefaultValue())); 129 log.config("new directoryDepth: " + newDepth); 130 try { 131 setSubdirectoryDepth(newDepth); 132 } catch (IOException e) { 133 ConfigurationException ee = new ConfigurationException("could not change directory depth to " + newDepth, e); 134 log.severe(ee.getMessage()); 135 throw ee; 136 } 137 int newCount = Integer.parseInt(properties.getProperty(getPrefix() + SUBDIRECTORYCOUNT.getKey(), SUBDIRECTORYCOUNT.getDefaultValue())); 138 setSubdirectoryCount(newCount); 139 } 140 141 private int findDepth(File directory, int startDepth) { 142 File [] files = directory.listFiles(); 143 for (int i = 0; i < files.length; i++) { 144 if (files[i].isDirectory()) { 145 int result = findDepth(files[i], startDepth + 1); 146 if (result > startDepth) { 147 return result; 148 } 149 } 150 } 151 for (int i = 0; i < files.length; i++) { 152 if (files[i].isFile()) { 153 return startDepth; 154 } 155 } 156 return 0; 157 } 158 159 public void delete(String name) throws IOException { 160 File file = nameToFile(name); 161 if (file.exists() && !file.delete()) { 162 String msg = "could not delete file '" + file + "'"; 163 if (log.isLoggable(Level.SEVERE)) log.severe(msg); 164 throw new IOException (msg); 165 } 166 } 167 168 public void deleteAll() throws IOException { 169 deleteDirectory(getDirectory()); 170 } 171 172 176 private void deleteDirectory(File directory) throws IOException { 177 File [] files = directory.listFiles(); 178 for (int i = 0; i < files.length; i++) { 179 if (files[i].isDirectory()) { 180 deleteDirectory(files[i]); 181 } 182 if (!files[i].delete()) { 183 String msg = "could not delete '" + files[i] + "'"; 184 if (log.isLoggable(Level.SEVERE)) log.severe(msg); 185 throw new IOException (msg); 186 } 187 } 188 } 189 190 198 private void setSubdirectoryDepth(int depth) throws IOException { 199 if (depth != subdirectoryDepth) { 200 subdirectoryDepth = depth; 203 } 204 } 205 206 private void moveFiles(File directory, int relDepth, int targetDepth, int targetCount) throws IOException { 208 File [] files = directory.listFiles(); 209 if (relDepth == 0) { 210 for (int i = 0; i < files.length; i++) { 211 File dest = nameToFile(files[i].getName(), targetDepth, targetCount); 212 ensureParentsExist(dest); 213 files[i].renameTo(dest); 214 } 215 recursiveDeleteIfEmpty(directory); 216 } else { 217 for (int i = 0; i < files.length; i++) { 218 if (files[i].isDirectory()) { 219 moveFiles(files[i], relDepth - 1, targetDepth, targetCount); 220 } 221 } 222 } 223 } 224 225 private void recursiveDeleteIfEmpty(File directory) throws IOException { 226 if (directory.isDirectory() && directory.list().length == 0) { 227 if (!directory.delete()) { 228 throw new IOException ("could not delete directory " + directory); 229 } 230 recursiveDeleteIfEmpty(directory.getParentFile()); 231 } 232 } 233 234 private int getSubdirectoryDepth() { 235 return subdirectoryDepth; 236 } 237 238 public String getPrefix() { 239 return prefix; 240 } 241 242 246 protected File nameToFile(String name, int depth, int count) { 247 StringBuffer subPath = new StringBuffer (); 248 249 long code = 1; 250 for (int i = 0; i < name.length(); i++) { 253 code = 1 + (code * name.charAt(i)) + (name.charAt(i) * i); 254 } 255 Random random = new Random (); 256 for (int i = 0; i < depth; i++) { 257 random.setSeed(code * (i + 1)); 260 int dirName = Math.abs(random.nextInt() % count); 261 subPath.append(Integer.toString(dirName, NAMECONVERTRADIX)); 262 subPath.append(File.separatorChar); 263 } 264 subPath.append(name); 265 File result = new File (getDirectory(), subPath.toString()); 266 return result; 267 } 268 269 protected File nameToFile(String name) { 270 return nameToFile(name, getSubdirectoryDepth(), getSubdirectoryCount()); 271 } 272 273 protected void ensureParentsExist(File file) throws IOException { 274 File parent = file.getParentFile(); 275 if (!parent.exists() && !parent.mkdirs()) { 276 throw new IOException ("could not create directory " + parent); 277 } 278 } 279 280 private void setPrefix(String prefix) { 282 this.prefix = prefix; 283 } 284 285 protected File getDirectory() { 286 return directory; 287 } 288 289 private void setDirectory(File directory) { 291 this.directory = directory; 292 } 293 294 298 public Collection getPropertyInfos() { 299 Collection result = new LinkedList (); 300 result.add(DIRECTORY); 301 result.add(SUBDIRECTORYDEPTH); 302 result.add(SUBDIRECTORYCOUNT); 303 return result; 304 } 305 306 private int getSubdirectoryCount() { 307 return subdirectoryCount; 308 } 309 310 private void setSubdirectoryCount(int subdirectoryCount) { 311 this.subdirectoryCount = subdirectoryCount; 312 } 313 314 } 315 | Popular Tags |