001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.hadoop.hdfs.server.namenode; 019 020 import java.io.File; 021 import java.io.IOException; 022 import java.net.URI; 023 import java.util.ArrayList; 024 import java.util.Collection; 025 import java.util.HashMap; 026 import java.util.Map; 027 028 import org.apache.commons.logging.Log; 029 import org.apache.commons.logging.LogFactory; 030 import org.apache.hadoop.conf.Configuration; 031 import org.apache.hadoop.fs.DF; 032 import org.apache.hadoop.hdfs.DFSConfigKeys; 033 import org.apache.hadoop.hdfs.server.common.Util; 034 035 import com.google.common.annotations.VisibleForTesting; 036 037 /** 038 * 039 * NameNodeResourceChecker provides a method - 040 * <code>hasAvailableDiskSpace</code> - which will return true if and only if 041 * the NameNode has disk space available on all volumes which are configured to 042 * be checked. Volumes containing file system name/edits dirs are added by 043 * default, and arbitrary extra volumes may be configured as well. 044 */ 045 public class NameNodeResourceChecker { 046 private static final Log LOG = LogFactory.getLog(NameNodeResourceChecker.class.getName()); 047 048 // Space (in bytes) reserved per volume. 049 private long duReserved; 050 051 private final Configuration conf; 052 private Map<String, DF> volumes; 053 054 /** 055 * Create a NameNodeResourceChecker, which will check the name dirs and edits 056 * dirs set in <code>conf</code>. 057 * 058 * @param conf 059 * @throws IOException 060 */ 061 public NameNodeResourceChecker(Configuration conf) throws IOException { 062 this.conf = conf; 063 volumes = new HashMap<String, DF>(); 064 065 duReserved = conf.getLong(DFSConfigKeys.DFS_NAMENODE_DU_RESERVED_KEY, 066 DFSConfigKeys.DFS_NAMENODE_DU_RESERVED_DEFAULT); 067 068 Collection<URI> extraCheckedVolumes = Util.stringCollectionAsURIs(conf 069 .getTrimmedStringCollection(DFSConfigKeys.DFS_NAMENODE_CHECKED_VOLUMES_KEY)); 070 071 addDirsToCheck(FSNamesystem.getNamespaceDirs(conf)); 072 addDirsToCheck(FSNamesystem.getNamespaceEditsDirs(conf)); 073 addDirsToCheck(extraCheckedVolumes); 074 } 075 076 /** 077 * Add the passed-in directories to the list of volumes to check. 078 * 079 * @param directoriesToCheck 080 * The directories whose volumes will be checked for available space. 081 * @throws IOException 082 */ 083 private void addDirsToCheck(Collection<URI> directoriesToCheck) 084 throws IOException { 085 for (URI directoryUri : directoriesToCheck) { 086 File dir = new File(directoryUri.getPath()); 087 if (!dir.exists()) { 088 throw new IOException("Missing directory "+dir.getAbsolutePath()); 089 } 090 DF df = new DF(dir, conf); 091 volumes.put(df.getFilesystem(), df); 092 } 093 } 094 095 /** 096 * Return true if disk space is available on at least one of the configured 097 * volumes. 098 * 099 * @return True if the configured amount of disk space is available on at 100 * least one volume, false otherwise. 101 * @throws IOException 102 */ 103 boolean hasAvailableDiskSpace() 104 throws IOException { 105 return getVolumesLowOnSpace().size() < volumes.size(); 106 } 107 108 /** 109 * Return the set of directories which are low on space. 110 * @return the set of directories whose free space is below the threshold. 111 * @throws IOException 112 */ 113 Collection<String> getVolumesLowOnSpace() throws IOException { 114 if (LOG.isDebugEnabled()) { 115 LOG.debug("Going to check the following volumes disk space: " + volumes); 116 } 117 Collection<String> lowVolumes = new ArrayList<String>(); 118 for (DF volume : volumes.values()) { 119 long availableSpace = volume.getAvailable(); 120 String fileSystem = volume.getFilesystem(); 121 if (LOG.isDebugEnabled()) { 122 LOG.debug("Space available on volume '" + fileSystem + "' is " + availableSpace); 123 } 124 if (availableSpace < duReserved) { 125 LOG.warn("Space available on volume '" + fileSystem + "' is " 126 + availableSpace + 127 ", which is below the configured reserved amount " + duReserved); 128 lowVolumes.add(volume.getFilesystem()); 129 } 130 } 131 return lowVolumes; 132 } 133 134 @VisibleForTesting 135 void setVolumes(Map<String, DF> volumes) { 136 this.volumes = volumes; 137 } 138 }