📄 persistentstorage.java
字号:
createDirectory(appDirectory); lostDirectory = new File(backupDirectory, LOST_AND_FOUND_DIRECTORY); createDirectory(lostDirectory); } /** * Reads in the in-memory map of directories for use. * * @param dir The directory to recurse */ private void initDirectoryMap(File dir) { File[] files = dir.listFiles(new DirectoryFilter()); directories.put(dir, files); for (int i = 0; i < files.length; i++) { initDirectoryMap(files[i]); } } /** * Ensures that all files are in the correct directories, and moves files * which are in the wrong directory. Also checks for any temporary files and * resolves any detected conflicts. * * @param dir The directory to start on * @exception IOException DESCRIBE THE EXCEPTION */ private void initFiles(File dir) throws IOException { String[] dirs = dir.list(new DirectoryFilter()); String[] files = dir.list(new FileFilter()); /* * first, init any files, and relocate any files if there are dirs */ for (int i = 0; i < files.length; i++) { try { if (!initTemporaryFile(dir, files[i])) { /* * if there are directories in the dir, then move the file */ if (dirs.length > 0) { moveFileToCorrectDirectory(dir, files[i]); } } } catch (Exception e) { if (logger.level <= Logger.WARNING) { logger.logException("Got exception " + e + " initting file " + files[i] + " - moving to lost+found.", e); } moveToLost(new File(dir, files[i])); } } /* * next, recurse into any dirs */ for (int i = 0; i < dirs.length; i++) { initFiles(new File(dir, dirs[i])); } /* * and delete the old metadata file, if it exists */ if (dirs.length > 0) { deleteFile(new File(dir, METADATA_FILENAME)); } } /** * Method which initializes a temporary file by doing the following: 1. If * this file is not a temporary file, simply returns the file 2. If so, it * simply moves this file to the lost and found and returns null This is done * since all temporary files are, by definition, temporary until they are * renamed to an actual ID name. Thus, if we detect a temporary file during * start-up, it is likely that the file is corrupted and should be deleted. * * @param parent DESCRIBE THE PARAMETER * @param name DESCRIBE THE PARAMETER * @return DESCRIBE THE RETURN VALUE * @exception IOException DESCRIBE THE EXCEPTION * @returns Whether or not the file was a temporary file */ private boolean initTemporaryFile(File parent, String name) throws IOException { if (!isTemporaryFile(name)) { return false; } moveToLost(new File(parent, name)); return true; } /** * Inititializes the idSet data structure In doing this it must resolve * conflicts and aborted transactions. After this is run the most current * stable state should be restored. Also record the total used space for all * files in the root. Lastly, deletes any files which are of zero length. * * @param dir DESCRIBE THE PARAMETER * @exception IOException DESCRIBE THE EXCEPTION */ private void initFileMap(File dir) throws IOException { if (logger.level <= Logger.FINE) { logger.log("Initting directory " + dir); } /* * first, see if this directory needs to be expanded */ checkDirectory(dir); /* * make sure the directory was not pruned */ if (!dir.exists()) { return; } /* * now, read the metadata file in this directory */ long modified = 0; if (index) { try { modified = readMetadataFile(dir); } catch (IOException e) { if (logger.level <= Logger.SEVERE) { logger.logException("Got exception " + e + " reading metadata file - regenerating", e); } } } /* * next, start processing by listing the number of files and going from there */ File[] files = dir.listFiles(new FileFilter()); File[] dirs = dir.listFiles(new DirectoryFilter()); for (int i = 0; i < files.length; i++) { try { Id id = readKey(files[i]); long len = getFileLength(files[i]); if (id == null) { if (logger.level <= Logger.INFO) { logger.log("READING " + files[i] + " RETURNED NULL!"); } } if (len > 0) { increaseUsedSpace(len); /* * if the file is newer than the metadata file, update the metadata * if we don't have the metadata for this file, update it */ if (index && ((!metadata.containsKey(id)) || (files[i].lastModified() > modified))) { if (logger.level <= Logger.FINER) { logger.log("Reading newer metadata out of file " + files[i] + " id " + id.toStringFull() + " " + files[i].lastModified() + " " + modified + " " + metadata.containsKey(id)); } metadata.put(id, readMetadata(files[i])); dirty.add(dir); } } else { moveToLost(files[i]); if (index && metadata.containsKey(id)) { metadata.remove(id); dirty.add(dir); } } } catch (Exception e) { if (logger.level <= Logger.WARNING) { logger.logException( "ERROR: Received Exception " + e + " while initing file " + files[i] + " - moving to lost+found.", e); } moveToLost(files[i]); } } /* * now recurse and check all of the children */ for (int i = 0; i < dirs.length; i++) { initFileMap(dirs[i]); } /* * and finally see if this directory needs to be pruned or expanded */ checkDirectory(dir); } /** * Resolves a conflict between the two provided files by picking the newer one * and renames it to the given output file. * * @param file1 The first file * @param file2 The second file * @param output The file to store the result in * @exception IOException DESCRIBE THE EXCEPTION */ private void resolveConflict(File file1, File file2, File output) throws IOException { if (!file2.exists()) { renameFile(file1, output); } else if (!file1.exists()) { renameFile(file2, output); } else if (file1.equals(file2)) { renameFile(file1, output); } else { if (logger.level <= Logger.FINE) { logger.log("resolving conflict between " + file1 + " and " + file2); } if (readVersion(file1) < readVersion(file2)) { moveToLost(file1); renameFile(file2, output); } else { moveToLost(file2); renameFile(file1, output); } } } /** * Moves a file to the lost and found directory for this instance * * @param file the file to be moved * @exception IOException DESCRIBE THE EXCEPTION */ private void moveToLost(File file) throws IOException { renameFile(file, new File(lostDirectory, getPrefix(file.getParentFile()) + file.getName())); } /** * @param directory DESCRIBE THE PARAMETER * @return DESCRIBE THE RETURN VALUE * @exception IOException DESCRIBE THE EXCEPTION */ /* * Helper functions for Directory Splitting Management */ /** * @param directory DESCRIBE THE PARAMETER * @return DESCRIBE THE RETURN VALUE * @exception IOException DESCRIBE THE EXCEPTION */ /** * Method which checks to see if a directory has too many files, and if so, * expands the directory in order to bring it to the correct size * * @param directory DESCRIBE THE PARAMETER * @return Whether or not the directory was modified * @exception IOException DESCRIBE THE EXCEPTION */ private boolean checkDirectory(File directory) throws IOException { int files = numFilesDir(directory); int dirs = numDirectoriesDir(directory); if (logger.level <= Logger.FINE) { logger.log("Checking directory " + directory + " for oversize " + files + "/" + dirs); } if (files > MAX_FILES) { expandDirectory(directory); return true; } else if (dirs > MAX_DIRECTORIES) { reformatDirectory(directory); return true; } else if ((files == 0) && (dirs == 0) && (!directory.equals(appDirectory))) { pruneDirectory(directory); return true; } return false; } /** * This method removes an empty directory from the storage root, and updates * all of the associated metadata. * * @param dir The directory to remove * @exception IOException DESCRIBE THE EXCEPTION */ private void pruneDirectory(File dir) throws IOException { if (logger.level <= Logger.FINE) { logger.log("Pruning directory " + dir + " due to emptiness"); } /* * First delete the metadata file, if it exists */ deleteFile(new File(dir, METADATA_FILENAME)); /* * Then remove the directory */ deleteDirectory(dir); /* * Finally update the metadata */ directories.remove(dir); prefixes.remove(dir); this.directories.put(dir.getParentFile(), dir.getParentFile().listFiles(new DirectoryFilter())); } /** * This method expands the directory when there are too many subdirectories in * one directory. Basically uses the same logic as expandDirectory(), but also * updates the metadata. This is used to keep less then NUM_FILES in any * directory at one time. This speeds up look up time in a particular * directory under certain circumstances. * * @param dir The directory to expand * @exception IOException DESCRIBE THE EXCEPTION */ private void reformatDirectory(File dir) throws IOException { if (logger.level <= Logger.FINE) { logger.log("Expanding directory " + dir + " due to too many subdirectories"); } /* * first, determine what directories we should create (ignoring the ! directories) */ String[] newDirNames = getDirectories(dir.list(new DirectoryFilter())); reformatDirectory(dir, newDirNames); if (logger.level <= Logger.FINE) { logger.log("Done expanding directory " + dir); } } /** * This method performs a directory expansion, given the names of the * subdirectories to create. * * @param dir The directory to expand * @param newDirNames The array containing the names of the new directories * @exception IOException DESCRIBE THE EXCEPTION */ private void reformatDirectory(File dir, String[] newDirNames) throws IOException { String[] dirNames = dir.list(new DirectoryFilter()); File[] newDirs = new File[newDirNames.length]; /* * create the new directories, move the old ones */ for (int i = 0; i < newDirNames.length; i++) { newDirs[i] = new File(dir, newDirNames[i]); createDirectory(newDirs[i]); if (logger.level <= Logger.FINE) { logger.log("Creating directory " + newDirNames[i]); } /* * now look through the original directory and move any matching dirs */ String[] subDirNames = getMatchingDirectories(newDirNames[i], dirNames); File[] newSubDirs = new File[subDirNames.length]; for (int j = 0; j < subDirNames.length; j++) { /* * move the directory */ File oldDir = new File(dir, subDirNames[j]); newSubDirs[j] = new File(newDirs[i], subDirNames[j].substring(newDirNames[i].length())); if (logger.level <= Logger.FINE) { logger.log("Moving the old direcotry " + oldDir + " to " + newSubDirs[j]); } renameFile(oldDir, newSubDirs[j]); /* * remove the stale entry, add the new one */ this.directories.remove(oldDir); this.directories.put(newSubDirs[j], new File[0]); } this.directories.put(newDirs[i], newSubDirs); } /* * lastly, update the root directory */ this.directories.put(dir, newDirs); } /** * This method expands the directory in to a subdirectory for each prefix, * contained in the directory This is used to keep less then NUM_FILES in any * directory at one time. This speeds up look up time in a particular * directory under certain circumstances. * * @param dir The directory to expand * @exception IOException DESCRIBE THE EXCEPTION */ private void expandDirectory(File dir) throws IOException { if (logger.level <= Logger.FINE) { logger.log("Expanding directory " + dir + " due to too many files"); } /* * first, determine what directories we should create */ String[] fileNames = dir.list(new FileFilter()); String[] dirNames = getDirectories(fileNames); File[] dirs = new File[dirNames.length]; /* * create the directories */ for (int i = 0; i < dirNames.length; i++) { dirs[i] = new File(dir, dirNames[i]); directories.put(dirs[i], new File[0]); if (dirs[i].exists() && dirs[i].isFile()) { renameFile(dirs[i], new File(dir, dirs[i].getName() + ZERO_LENGTH_NAME)); } createDirectory(dirs[i]); if (logger.level <= Logger.FINE) { logger.log("Creating directory " + dirNames[i]); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -