1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hdfs.server.datanode; 19 20 import java.io.File; 21 import java.io.FileInputStream; 22 import java.io.FileNotFoundException; 23 import java.io.IOException; 24 25 import org.apache.hadoop.classification.InterfaceAudience; 26 import org.apache.hadoop.hdfs.protocol.Block; 27 import org.apache.hadoop.hdfs.protocol.ExtendedBlock; 28 import org.apache.hadoop.hdfs.server.datanode.fsdataset.FsDatasetSpi; 29 import org.apache.hadoop.hdfs.server.datanode.fsdataset.LengthInputStream; 30 31 /** Provide utility methods for Datanode. */ 32 @InterfaceAudience.Private 33 public class DatanodeUtil { 34 public static final String UNLINK_BLOCK_SUFFIX = ".unlinked"; 35 36 public static final String DISK_ERROR = "Possible disk error: "; 37 38 private static final String SEP = System.getProperty("file.separator"); 39 40 /** Get the cause of an I/O exception if caused by a possible disk error 41 * @param ioe an I/O exception 42 * @return cause if the I/O exception is caused by a possible disk error; 43 * null otherwise. 44 */ getCauseIfDiskError(IOException ioe)45 static IOException getCauseIfDiskError(IOException ioe) { 46 if (ioe.getMessage()!=null && ioe.getMessage().startsWith(DISK_ERROR)) { 47 return (IOException)ioe.getCause(); 48 } else { 49 return null; 50 } 51 } 52 53 /** 54 * Create a new file. 55 * @throws IOException 56 * if the file already exists or if the file cannot be created. 57 */ createTmpFile(Block b, File f)58 public static File createTmpFile(Block b, File f) throws IOException { 59 if (f.exists()) { 60 throw new IOException("Failed to create temporary file for " + b 61 + ". File " + f + " should not be present, but is."); 62 } 63 // Create the zero-length temp file 64 final boolean fileCreated; 65 try { 66 fileCreated = f.createNewFile(); 67 } catch (IOException ioe) { 68 throw new IOException(DISK_ERROR + "Failed to create " + f, ioe); 69 } 70 if (!fileCreated) { 71 throw new IOException("Failed to create temporary file for " + b 72 + ". File " + f + " should be creatable, but is already present."); 73 } 74 return f; 75 } 76 77 /** 78 * @return the meta name given the block name and generation stamp. 79 */ getMetaName(String blockName, long generationStamp)80 public static String getMetaName(String blockName, long generationStamp) { 81 return blockName + "_" + generationStamp + Block.METADATA_EXTENSION; 82 } 83 84 /** @return the unlink file. */ getUnlinkTmpFile(File f)85 public static File getUnlinkTmpFile(File f) { 86 return new File(f.getParentFile(), f.getName()+UNLINK_BLOCK_SUFFIX); 87 } 88 89 /** 90 * Checks whether there are any files anywhere in the directory tree rooted 91 * at dir (directories don't count as files). dir must exist 92 * @return true if there are no files 93 * @throws IOException if unable to list subdirectories 94 */ dirNoFilesRecursive(File dir)95 public static boolean dirNoFilesRecursive(File dir) throws IOException { 96 File[] contents = dir.listFiles(); 97 if (contents == null) { 98 throw new IOException("Cannot list contents of " + dir); 99 } 100 for (File f : contents) { 101 if (!f.isDirectory() || (f.isDirectory() && !dirNoFilesRecursive(f))) { 102 return false; 103 } 104 } 105 return true; 106 } 107 108 /** 109 * Get the directory where a finalized block with this ID should be stored. 110 * Do not attempt to create the directory. 111 * @param root the root directory where finalized blocks are stored 112 * @param blockId 113 * @return 114 */ idToBlockDir(File root, long blockId)115 public static File idToBlockDir(File root, long blockId) { 116 int d1 = (int)((blockId >> 16) & 0xff); 117 int d2 = (int)((blockId >> 8) & 0xff); 118 String path = DataStorage.BLOCK_SUBDIR_PREFIX + d1 + SEP + 119 DataStorage.BLOCK_SUBDIR_PREFIX + d2; 120 return new File(root, path); 121 } 122 123 /** 124 * @return the FileInputStream for the meta data of the given block. 125 * @throws FileNotFoundException 126 * if the file not found. 127 * @throws ClassCastException 128 * if the underlying input stream is not a FileInputStream. 129 */ getMetaDataInputStream( ExtendedBlock b, FsDatasetSpi<?> data)130 public static FileInputStream getMetaDataInputStream( 131 ExtendedBlock b, FsDatasetSpi<?> data) throws IOException { 132 final LengthInputStream lin = data.getMetaDataInputStream(b); 133 if (lin == null) { 134 throw new FileNotFoundException("Meta file for " + b + " not found."); 135 } 136 return (FileInputStream)lin.getWrappedStream(); 137 } 138 } 139