diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java index f97f6b2..918086b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java @@ -83,6 +83,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellComparator; @@ -1097,14 +1098,25 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi FileSystem fs = tablePath.getFileSystem(conf); HRegionFileSystem regionFs = new HRegionFileSystem(conf, fs, tablePath, regionInfo); - for (HColumnDescriptor family: tableDescriptor.getFamilies()) { - Collection storeFiles = regionFs.getStoreFiles(family.getNameAsString()); - if (storeFiles == null) continue; - for (StoreFileInfo storeFileInfo : storeFiles) { + for (HColumnDescriptor family : tableDescriptor.getFamilies()) { + Collection> storeFiles = regionFs + .getStoreFilesWithLocation(family.getNameAsString()); + if (storeFiles == null) { + continue; + } + for (Pair entry : storeFiles) { try { - hdfsBlocksDistribution.add(storeFileInfo.computeHDFSBlocksDistribution(fs)); + StoreFileInfo storeFileInfo = entry.getFirst(); + if (storeFileInfo.isNormalHFile()) { + hdfsBlocksDistribution.add(FSUtils.getHDFSBlocksDistribution(entry + .getSecond().getBlockLocations())); + } else { + hdfsBlocksDistribution.add(storeFileInfo + .computeHDFSBlocksDistribution(fs)); + } } catch (IOException ioe) { - LOG.warn("Error getting hdfs block distribution for " + storeFileInfo); + LOG.warn("Error getting hdfs block distribution for " + + entry.getFirst()); } } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java index 995b111..4b591d6 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionFileSystem.java @@ -30,13 +30,13 @@ import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileUtil; +import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hbase.Cell; @@ -47,11 +47,13 @@ import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValueUtil; import org.apache.hadoop.hbase.backup.HFileArchiver; +import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.fs.HFileSystem; import org.apache.hadoop.hbase.io.Reference; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.FSHDFSUtils; import org.apache.hadoop.hbase.util.FSUtils; +import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil; /** @@ -220,6 +222,37 @@ public class HRegionFileSystem { } /** + * Returns the store files with locations available for the family. This + * methods performs the filtering based on the valid store files. + * + * @param familyName + * Column Family Name + * @return a set of {@link StoreFileInfo and LocatedFileStatus} for the + * specified family. + */ + public Collection> getStoreFilesWithLocation( + final String familyName) throws IOException { + Path familyDir = getStoreDir(familyName); + List files = FSUtils.listLocatedStatus(fs, familyDir); + if (files == null) { + LOG.debug("No StoreFiles for: " + familyDir); + return null; + } + ArrayList> storeFiles = new ArrayList>( + files.size()); + for (LocatedFileStatus status : files) { + if (!StoreFileInfo.isValid(status)) { + LOG.warn("Invalid StoreFile: " + status.getPath()); + continue; + } + StoreFileInfo info = ServerRegionReplicaUtil.getStoreFileInfo(conf, fs, + regionInfo, regionInfoForFs, familyName, status.getPath()); + storeFiles.add(new Pair(info, status)); + } + return storeFiles; + } + + /** * Return Qualified Path of the specified family/file * * @param familyName Column Family Name diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileInfo.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileInfo.java index 3c12045..2b5d9ab 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileInfo.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileInfo.java @@ -26,12 +26,12 @@ import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.HDFSBlocksDistribution; +import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper; import org.apache.hadoop.hbase.io.HFileLink; import org.apache.hadoop.hbase.io.HalfStoreFileReader; @@ -222,6 +222,13 @@ public class StoreFileInfo { return this.link != null && this.reference == null; } + /** + * @return True if the store file is a normal hfile and not a link or reference + */ + public boolean isNormalHFile() { + return this.link == null && this.reference == null; + } + /** @return the HDFS block distribution */ public HDFSBlocksDistribution getHDFSBlockDistribution() { return this.hdfsBlocksDistribution; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java index 15f079d..d034ea4 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java @@ -52,7 +52,6 @@ import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.HadoopIllegalArgumentException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.BlockLocation; @@ -60,8 +59,10 @@ import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathFilter; +import org.apache.hadoop.fs.RemoteIterator; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hbase.ClusterId; @@ -70,18 +71,20 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HDFSBlocksDistribution; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.fs.HFileSystem; import org.apache.hadoop.hbase.master.HMaster; -import org.apache.hadoop.hbase.regionserver.StoreFileInfo; -import org.apache.hadoop.hbase.security.AccessDeniedException; -import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.generated.FSProtos; import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.regionserver.StoreFileInfo; +import org.apache.hadoop.hbase.security.AccessDeniedException; +import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter; import org.apache.hadoop.hdfs.DFSClient; import org.apache.hadoop.hdfs.DFSHedgedReadMetrics; import org.apache.hadoop.hdfs.DistributedFileSystem; +import org.apache.hadoop.hdfs.protocol.HdfsConstants; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.security.UserGroupInformation; @@ -1052,15 +1055,18 @@ public abstract class FSUtils { static public HDFSBlocksDistribution computeHDFSBlocksDistribution( final FileSystem fs, FileStatus status, long start, long length) throws IOException { + return getHDFSBlocksDistribution(fs.getFileBlockLocations(status, start, + length)); + } + + static public HDFSBlocksDistribution getHDFSBlocksDistribution( + BlockLocation[] blockLocations) throws IOException { HDFSBlocksDistribution blocksDistribution = new HDFSBlocksDistribution(); - BlockLocation [] blockLocations = - fs.getFileBlockLocations(status, start, length); for(BlockLocation bl : blockLocations) { String [] hosts = bl.getHosts(); long len = bl.getLength(); blocksDistribution.addHostsAndBlockWeight(hosts, len); } - return blocksDistribution; } @@ -1857,6 +1863,38 @@ public abstract class FSUtils { } /** + * Calls fs.listLocatedStatus() and treats FileNotFoundException as non-fatal + * + * @param fs + * file system + * @param dir + * directory + * @return null if dir is empty or doesn't exist, otherwise LocatedFileStatus + * list + */ + public static List listLocatedStatus(final FileSystem fs, + final Path dir) throws IOException { + List status = null; + try { + RemoteIterator iter = fs.listLocatedStatus(dir); + while (iter.hasNext()) { + if (status == null) { + status = new ArrayList(); + } + status.add(iter.next()); + } + } catch (FileNotFoundException fnfe) { + // if directory doesn't exist, return null + if (LOG.isTraceEnabled()) { + LOG.trace(dir + " doesn't exist"); + } + } + if (status == null || status.size() < 1) + return null; + return status; + } + + /** * Calls fs.delete() and returns the value returned by the fs.delete() * * @param fs