浏览代码

svn merge -c 1350825 from trunk for HDFS-3518. Add a utility method HdfsUtils.isHealthy(uri) for checking if he given HDFS is healthy.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1350826 13f79535-47bb-0310-9956-ffa450edef68
Tsz-wo Sze 13 年之前
父节点
当前提交
2106c8bec8

+ 3 - 0
hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt

@@ -11,6 +11,9 @@ Release 2.0.1-alpha - UNRELEASED
     HDFS-3042. Automatic failover support for NameNode HA (todd)
     (see dedicated section below for breakdown of subtasks)
 
+    HDFS-3518. Add a utility method HdfsUtils.isHealthy(uri) for checking if
+    the given HDFS is healthy. (szetszwo)
+
   IMPROVEMENTS
 
     HDFS-3390. DFSAdmin should print full stack traces of errors when DEBUG

+ 1 - 1
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java

@@ -96,7 +96,7 @@ public class DistributedFileSystem extends FileSystem {
    */
   @Override
   public String getScheme() {
-    return "hdfs";
+    return HdfsConstants.HDFS_URI_SCHEME;
   }
 
   @Deprecated

+ 87 - 0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/client/HdfsUtils.java

@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hdfs.client;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.DistributedFileSystem;
+import org.apache.hadoop.hdfs.protocol.HdfsConstants;
+import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction;
+import org.apache.hadoop.io.IOUtils;
+
+/**
+ * The public utility API for HDFS.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public class HdfsUtils {
+  private static final Log LOG = LogFactory.getLog(HdfsUtils.class);
+
+  /**
+   * Is the HDFS healthy?
+   * HDFS is considered as healthy if it is up and not in safemode.
+   *
+   * @param uri the HDFS URI.  Note that the URI path is ignored.
+   * @return true if HDFS is healthy; false, otherwise.
+   */
+  public static boolean isHealthy(URI uri) {
+    //check scheme
+    final String scheme = uri.getScheme();
+    if (!HdfsConstants.HDFS_URI_SCHEME.equalsIgnoreCase(scheme)) {
+      throw new IllegalArgumentException("The scheme is not "
+          + HdfsConstants.HDFS_URI_SCHEME + ", uri=" + uri);
+    }
+    
+    final Configuration conf = new Configuration();
+    //disable FileSystem cache
+    conf.setBoolean(String.format("fs.%s.impl.disable.cache", scheme), true);
+    //disable client retry for rpc connection and rpc calls
+    conf.setBoolean(DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_ENABLED_KEY, false);
+    conf.setInt(
+        CommonConfigurationKeysPublic.IPC_CLIENT_CONNECT_MAX_RETRIES_KEY, 0);
+
+    DistributedFileSystem fs = null;
+    try {
+      fs = (DistributedFileSystem)FileSystem.get(uri, conf);
+      final boolean safemode = fs.setSafeMode(SafeModeAction.SAFEMODE_GET);
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Is namenode in safemode? " + safemode + "; uri=" + uri);
+      }
+
+      fs.close();
+      fs = null;
+      return !safemode;
+    } catch(IOException e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Got an exception for uri=" + uri, e);
+      }
+      return false;
+    } finally {
+      IOUtils.cleanup(LOG, fs);
+    }
+  }
+}

+ 15 - 1
hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSClientRetries.java

@@ -31,6 +31,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetSocketAddress;
 import java.net.SocketTimeoutException;
+import java.net.URI;
 import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -50,6 +51,7 @@ import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.hdfs.client.HdfsUtils;
 import org.apache.hadoop.hdfs.protocol.Block;
 import org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol;
 import org.apache.hadoop.hdfs.protocol.DatanodeID;
@@ -769,9 +771,11 @@ public class TestDFSClientRetries extends TestCase {
         .build();
     try {
       cluster.waitActive();
+      final DistributedFileSystem dfs = cluster.getFileSystem();
+      final URI uri = dfs.getUri();
+      assertTrue(HdfsUtils.isHealthy(uri));
 
       //create a file
-      final DistributedFileSystem dfs = cluster.getFileSystem();
       final long length = 1L << 20;
       final Path file1 = new Path(dir, "foo"); 
       DFSTestUtil.createFile(dfs, file1, length, numDatanodes, 20120406L);
@@ -781,7 +785,9 @@ public class TestDFSClientRetries extends TestCase {
       assertEquals(length, s1.getLen());
 
       //shutdown namenode
+      assertTrue(HdfsUtils.isHealthy(uri));
       cluster.shutdownNameNode(0);
+      assertFalse(HdfsUtils.isHealthy(uri));
 
       //namenode is down, create another file in a thread
       final Path file3 = new Path(dir, "file"); 
@@ -806,8 +812,10 @@ public class TestDFSClientRetries extends TestCase {
           try {
             //sleep, restart, and then wait active
             TimeUnit.SECONDS.sleep(30);
+            assertFalse(HdfsUtils.isHealthy(uri));
             cluster.restartNameNode(0, false);
             cluster.waitActive();
+            assertTrue(HdfsUtils.isHealthy(uri));
           } catch (Exception e) {
             exceptions.add(e);
           }
@@ -823,7 +831,9 @@ public class TestDFSClientRetries extends TestCase {
       assertEquals(dfs.getFileChecksum(file1), dfs.getFileChecksum(file3));
 
       //enter safe mode
+      assertTrue(HdfsUtils.isHealthy(uri));
       dfs.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
+      assertFalse(HdfsUtils.isHealthy(uri));
       
       //leave safe mode in a new thread
       new Thread(new Runnable() {
@@ -832,7 +842,9 @@ public class TestDFSClientRetries extends TestCase {
           try {
             //sleep and then leave safe mode
             TimeUnit.SECONDS.sleep(30);
+            assertFalse(HdfsUtils.isHealthy(uri));
             dfs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE);
+            assertTrue(HdfsUtils.isHealthy(uri));
           } catch (Exception e) {
             exceptions.add(e);
           }
@@ -844,6 +856,8 @@ public class TestDFSClientRetries extends TestCase {
       DFSTestUtil.createFile(dfs, file2, length, numDatanodes, 20120406L);
       assertEquals(dfs.getFileChecksum(file1), dfs.getFileChecksum(file2));
       
+      assertTrue(HdfsUtils.isHealthy(uri));
+
       //make sure it won't retry on exceptions like FileNotFoundException
       final Path nonExisting = new Path(dir, "nonExisting");
       LOG.info("setPermission: " + nonExisting);