📄 persistentstorage.java
字号:
/* * mark this directory for metadata syncing */ if (index) { dirty.add(dirs[i]); } } /* * add the list of directories to the map */ directories.put(dir, dirs); /* * last, move the files into the correct directory */ File[] files = dir.listFiles(new FileFilter()); for (int i = 0; i < files.length; i++) { for (int j = 0; j < dirs.length; j++) { if (files[i].getName().startsWith(dirs[j].getName())) { if (logger.level <= Logger.FINEST) { logger.log("Renaming file " + files[i] + " to " + new File(dirs[j], files[i].getName().substring(dirs[j].getName().length()))); } renameFile(files[i], new File(dirs[j], files[i].getName().substring(dirs[j].getName().length()))); break; } } } /* * and remove the metadata file */ deleteFile(new File(dir, METADATA_FILENAME)); if (logger.level <= Logger.FINE) { logger.log("Done expanding directory " + dir); } } /** * Takes a file and moves it to the correct directory this is used in * cojunction with expand to move files to their correct subdirectories below * the expanded directory * * @param parent DESCRIBE THE PARAMETER * @param name DESCRIBE THE PARAMETER * @exception IOException DESCRIBE THE EXCEPTION */ private void moveFileToCorrectDirectory(File parent, String name) throws IOException { File file = new File(parent, name); Id id = readKeyFromFile(file); File dest = getDirectoryForId(id); /* * if it's in the wrong directory, then move it and resolve the conflict if necessary */ if (!dest.equals(parent)) { if (logger.level <= Logger.FINE) { logger.log("moving file " + file + " to correct directory " + dest + " from " + parent); } File other = new File(dest, id.toStringFull().substring(getPrefix(dest).length())); resolveConflict(file, other, other); checkDirectory(dest); } } /** * Method which recursively flushes a directory hierarchy, removing all data. * Be careful! * * @param dir The directory to flush * @exception IOException DESCRIBE THE EXCEPTION */ private void flushDirectory(File dir) throws IOException { if (logger.level <= Logger.FINE) { logger.log("Flushing file " + dir); } if (!dir.isDirectory()) { Id id = readKey(dir); /* * remove id from stored list */ if (index) { synchronized (metadata) { metadata.remove(id); } } /* * record the space collected and delete the file */ decreaseUsedSpace(dir.length()); deleteFile(dir); } else { File[] dirs = dir.listFiles(); /* * remove all subdirectories */ for (int i = 0; i < dirs.length; i++) { flushDirectory(dirs[i]); /* * update the metadata */ directories.remove(dirs[i]); prefixes.remove(dirs[i]); /* * delete the dir */ deleteFile(dirs[i]); } } } /** * Generates a new file name to assign for a given id * * @param id DESCRIBE THE PARAMETER * @return String the new File name This method will return the hashcode of * the object used as the id unless there is a collision, in which case * it will return a random number Since this mapping is only needed once * it does not matter what number is used to generate the filename, the * hashcode is the first try for effeciency. * @exception IOException DESCRIBE THE EXCEPTION */ private File makeTemporaryFile(Id id) throws IOException { File directory = getDirectoryForId(id); File file = new File(directory, id.toStringFull().substring(getPrefix(directory).length()) + "." + environment.getRandomSource().nextInt() % 100); while (file.exists()) { file = new File(directory, id.toStringFull().substring(getPrefix(directory).length()) + "." + environment.getRandomSource().nextInt() % 100); } return file; } /** * Method which the given file to the list of files * * @param file The file * @param files DESCRIBE THE PARAMETER * @return The new list */ private File[] append(File[] files, File file) { File[] result = new File[files.length + 1]; for (int i = 0; i < files.length; i++) { result[i] = files[i]; } result[files.length] = file; return result; } /** * Gets the number of subdirectories in directory * * @param dir the directory to check * @return int the number of directories */ private int numDirectoriesDir(File dir) { return dir.listFiles(new DirectoryFilter()).length; } /** * Gets the number of files in directory (excluding directories) * * @param dir the directory to check * @return int the number of files */ private int numFilesDir(File dir) { return dir.listFiles(new FileFilter()).length; } /** * Returns whether a directory contains subdirectories * * @param dir the directory to check * @return boolean whether directory contains subdirectories */ private boolean containsDir(File dir) { return (dir.listFiles(new DirectoryFilter()).length != 0); } /** */ /* * Helper functions for Metadata Storage */ /** */ /** * Function which writes out all of the dirty metadata files and marks them as * clean. */ protected void writeDirty() { File[] files = (File[]) dirty.toArray(new File[0]); for (int i = 0; i < files.length; i++) { HashMap map = new HashMap(); IdRange range = getRangeForDirectory(files[i]); Iterator keys = null; if (range.getCCWId().compareTo(range.getCWId()) <= 0) { keys = metadata.keySubMap(range.getCCWId(), range.getCWId()).keySet().iterator(); } else { keys = metadata.keyTailMap(range.getCCWId()).keySet().iterator(); } while (keys.hasNext()) { Id next = (Id) keys.next(); map.put(next, metadata.get(next)); } try { writeMetadataFile(files[i], map); synchronized (metadata) { dirty.remove(files[i]); } } catch (FileNotFoundException f) { try { synchronized (metadata) { dirty.remove(files[i]); } if (logger.level <= Logger.WARNING) { logger.logException("ERROR: Could not find directory while writing out metadata in '" + files[i].getCanonicalPath() + "' - removing from dirty list and continuing!", f); } } catch (IOException g) { if (logger.level <= Logger.SEVERE) { logger.logException("PANIC: Got IOException " + g + " trying to detail FNF exception " + f + " while writing out file " + files[i], g); } } } catch (IOException e) { try { if (logger.level <= Logger.WARNING) { logger.logException( "ERROR: Got error " + e + " while writing out metadata in '" + files[i].getCanonicalPath() + "' - aborting!", e); } } catch (IOException f) { if (logger.level <= Logger.SEVERE) { logger.logException("PANIC: Got IOException " + f + " trying to detail exception " + e + " while writing out file " + files[i], f); } } } } } /** * Utility function which reads the metadata file off of disk and stores the * result into the memory cache. * * @param file The directory to read the metadata file for * @return DESCRIBE THE RETURN VALUE * @exception IOException DESCRIBE THE EXCEPTION */ private long readMetadataFile(File file) throws IOException { File metadata = new File(file, METADATA_FILENAME); if (!metadata.exists()) { return -1L; } FileInputStream fin = null; try { fin = new FileInputStream(metadata); ObjectInputStream objin = new ObjectInputStream(new BufferedInputStream(fin)); IdRange range = getRangeForDirectory(file); try { HashMap map = (HashMap) objin.readObject(); Iterator keys = map.keySet().iterator(); while (keys.hasNext()) { Id id = (Id) keys.next(); if ((range.containsId(id)) && (new File(file, id.toStringFull().substring(getPrefix(file).length())).exists())) { this.metadata.put(id, map.get(id)); } else { dirty.add(file); } } return metadata.lastModified(); } catch (ClassNotFoundException e) { if (logger.level <= Logger.WARNING) { logger.logException("ERROR: Got exception " + e + " while reading metadata file " + metadata + " - rebuilding file", e); } deleteFile(metadata); return 0L; } catch (IOException e) { if (logger.level <= Logger.WARNING) { logger.logException("ERROR: Got exception " + e + " while reading metadata file " + metadata + " - rebuilding file", e); } deleteFile(metadata); return 0L; } } finally { fin.close(); } } /** * Reads in the metadata from the provided file, or returns null if no * metadata was found * * @param file The file which should be read for the metadata * @return DESCRIBE THE RETURN VALUE * @exception IOException DESCRIBE THE EXCEPTION */ private Serializable readMetadata(File file) throws IOException { if (file.length() < 32) { return null; } RandomAccessFile ras = null; try { ras = new RandomAccessFile(file, "r"); ras.seek(file.length() - 32); if (ras.readLong() != PERSISTENCE_MAGIC_NUMBER) { return null; } else if (ras.readLong() != PERSISTENCE_VERSION_2) { if (logger.level <= Logger.WARNING) { logger.log("Persistence version did not match - exiting!"); } return null; } else if (ras.readLong() > PERSISTENCE_REVISION_2_1) { if (logger.level <= Logger.WARNING) { logger.log("Persistence revision did not match - exiting!"); } return null; } long length = ras.readLong(); ras.seek(file.length() - 32 - length); FileInputStream fis = null; try { fis = new FileInputStream(ras.getFD()); ObjectInputStream objin = new XMLObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis))); try { return (Serializable) objin.readObject(); } catch (ClassNotFoundException e) { throw new IOException(e.getMessage()); } } finally { fis.close(); } } finally { ras.close(); } } /** * Abstract over reading a single key from a file using Java serialization. * * @param file The file to create the key from. * @return The key that was read in */ private Id readKey(File file) { String s = getPrefix(file.getParentFile()) + file.getName().replaceAll(ZERO_LENGTH_NAME, ""); if (s.indexOf(".") >= 0) { return factory.buildIdFromToString(s.toCharArray(), 0, s.indexOf(".")); } else { return factory.buildIdFromToString(s.toCharArray(), 0, s.length()); } } /** * Abstract over reading a single key from a file using Java serialization. * * @param file The file to create the key from. * @return The key that was read in * @exception IOException DESCRIBE THE EXCEPTION */ private Id readKeyFromFile(File file) throws IOException { return (Id) readObject(file, 0); } /** * Increases the amount of storage recorded as used * * @param i DESCRIBE THE PARAMETER */ private void increaseUsedSpace(long i) { usedSize = usedSize + i; } /** * decreases the amount of storage recorded as used * * @param i DESCRIBE THE PARAMETER */ private void decreaseUsedSpace(long i) { usedSize = usedSize - i; } /** * Returns the length of a file in bytes * * @param file file whose length to get * @return The FileLength value */ private static long getFileLength(File file) { return (((file != null) && file.exists()) ? f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -