From 49f4fa73fbf8b09fa0575a46db9c1ebd55fd393f Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Thu, 3 Oct 2024 19:58:31 -0700 Subject: [PATCH 01/10] Use reflection to access recoverlease(), setSafeMode() APIs. Change-Id: I1a7b7bad0e8967553490b70439b18f8ddfed6d14 --- .../hbase/util/RecoverLeaseFSUtils.java | 46 ++++++++++++---- .../hbase/util/TestRecoverLeaseFSUtils.java | 8 +++ .../org/apache/hadoop/hbase/util/FSUtils.java | 52 ++++++++++++++++--- .../apache/hadoop/hbase/util/TestFSUtils.java | 12 +++++ 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index ff457cb5074e..92e562afb708 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -20,6 +20,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InterruptedIOException; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; @@ -39,6 +40,16 @@ public final class RecoverLeaseFSUtils { private static final Logger LOG = LoggerFactory.getLogger(RecoverLeaseFSUtils.class); + private static Class leaseRecoverableClazz = null; + + { + try { + leaseRecoverableClazz = Class.forName("org.apache.hadoop.fs.LeaseRecoverable"); + } catch (ClassNotFoundException e) { + LOG.debug("LeaseRecoverable interface not in the classpath, this means Hadoop 3.3.5 or below."); + } + } + private RecoverLeaseFSUtils() { } @@ -48,18 +59,31 @@ public static void recoverFileLease(FileSystem fs, Path p, Configuration conf) } /** - * Recover the lease from HDFS, retrying multiple times. + * Recover the lease from HDFS or LeaseRecoverable fs, retrying multiple times. */ public static void recoverFileLease(FileSystem fs, Path p, Configuration conf, CancelableProgressable reporter) throws IOException { if (fs instanceof FilterFileSystem) { fs = ((FilterFileSystem) fs).getRawFileSystem(); } + // lease recovery not needed for local file system case. - if (!(fs instanceof DistributedFileSystem)) { - return; + if (isLeaseRecoverable(fs)) { + recoverDFSFileLease(fs, p, conf, reporter); } - recoverDFSFileLease((DistributedFileSystem) fs, p, conf, reporter); + } + + public static boolean isLeaseRecoverable(FileSystem fs) { + // return true if HDFS. + if (fs instanceof DistributedFileSystem) { + return true; + } + // return true if the file system implements LeaseRecoverable interface. + if (leaseRecoverableClazz != null) { + return (leaseRecoverableClazz.isAssignableFrom(fs.getClass())); + } + // return false if the file system is not HDFS and does not implement LeaseRecoverable. + return false; } /* @@ -81,7 +105,7 @@ public static void recoverFileLease(FileSystem fs, Path p, Configuration conf, * false, repeat starting at step 5. above. If HDFS-4525 is available, call it every second, and * we might be able to exit early. */ - private static boolean recoverDFSFileLease(final DistributedFileSystem dfs, final Path p, + private static boolean recoverDFSFileLease(final Object dfs, final Path p, final Configuration conf, final CancelableProgressable reporter) throws IOException { LOG.info("Recover lease on dfs file " + p); long startWaiting = EnvironmentEdgeManager.currentTime(); @@ -167,14 +191,16 @@ private static boolean checkIfTimedout(final Configuration conf, final long reco * Try to recover the lease. * @return True if dfs#recoverLease came by true. */ - private static boolean recoverLease(final DistributedFileSystem dfs, final int nbAttempt, + private static boolean recoverLease(final Object dfs, final int nbAttempt, final Path p, final long startWaiting) throws FileNotFoundException { boolean recovered = false; try { - recovered = dfs.recoverLease(p); + recovered = (Boolean) dfs.getClass().getMethod("recoverLease", new Class[] { Path.class }) + .invoke(dfs, p); LOG.info((recovered ? "Recovered lease, " : "Failed to recover lease, ") + getLogMessageDetail(nbAttempt, p, startWaiting)); - } catch (IOException e) { + } catch (InvocationTargetException ite) { + final Throwable e = ite.getCause(); if (e instanceof LeaseExpiredException && e.getMessage().contains("File does not exist")) { // This exception comes out instead of FNFE, fix it throw new FileNotFoundException("The given WAL wasn't found at " + p); @@ -182,6 +208,8 @@ private static boolean recoverLease(final DistributedFileSystem dfs, final int n throw (FileNotFoundException) e; } LOG.warn(getLogMessageDetail(nbAttempt, p, startWaiting), e); + } catch (IllegalAccessException | NoSuchMethodException e) { + throw new RuntimeException(e); } return recovered; } @@ -197,7 +225,7 @@ private static String getLogMessageDetail(final int nbAttempt, final Path p, * Call HDFS-4525 isFileClosed if it is available. * @return True if file is closed. */ - private static boolean isFileClosed(final DistributedFileSystem dfs, final Method m, + private static boolean isFileClosed(final Object dfs, final Method m, final Path p) { try { return (Boolean) m.invoke(dfs, p); diff --git a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java index 3740cab6937a..b2c9cc97b0d1 100644 --- a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java @@ -17,10 +17,12 @@ */ package org.apache.hadoop.hbase.util; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.LocalFileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseCommonTestingUtil; @@ -92,6 +94,12 @@ public void testIsFileClosed() throws IOException { Mockito.verify(dfs, Mockito.times(1)).isFileClosed(FILE); } + @Test + public void testIsLeaseRecoverable() { + assertTrue(RecoverLeaseFSUtils.isLeaseRecoverable(new DistributedFileSystem())); + assertFalse(RecoverLeaseFSUtils.isLeaseRecoverable(new LocalFileSystem())); + } + /** * Version of DFS that has HDFS-4525 in it. */ 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 0c61a1b27030..ac306fac9c3a 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 @@ -113,6 +113,21 @@ public final class FSUtils { // currently only used in testing. TODO refactor into a test class public static final boolean WINDOWS = System.getProperty("os.name").startsWith("Windows"); + private static Class safeModeClazz = null; + private static Class safeModeActionClazz = null; + private static Object safeModeGet = null; + { + try { + safeModeClazz = Class.forName("org.apache.hadoop.fs.SafeMode"); + safeModeActionClazz = Class.forName("org.apache.hadoop.fs.SafeModeAction"); + safeModeGet = safeModeClazz.getField("SAFEMODE_GET").get(null); + } catch (ClassNotFoundException | NoSuchFieldException e) { + LOG.debug("SafeMode interface not in the classpath, this means Hadoop 3.3.5 or below."); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + private FSUtils() { } @@ -247,8 +262,18 @@ public static void checkFileSystemAvailable(final FileSystem fs) throws IOExcept * @param dfs A DistributedFileSystem object representing the underlying HDFS. * @return whether we're in safe mode */ - private static boolean isInSafeMode(DistributedFileSystem dfs) throws IOException { - return dfs.setSafeMode(SAFEMODE_GET, true); + private static boolean isInSafeMode(FileSystem dfs) throws IOException { + if (isDistributedFileSystem(dfs)) { + return ((DistributedFileSystem)dfs).setSafeMode(SAFEMODE_GET, true); + } else { + try { + Object ret = dfs.getClass().getMethod("setSafeMode", new Class[] { safeModeActionClazz, Boolean.class }) + .invoke(dfs, safeModeGet, true); + return (Boolean) ret; + } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + } } /** @@ -257,9 +282,8 @@ private static boolean isInSafeMode(DistributedFileSystem dfs) throws IOExceptio public static void checkDfsSafeMode(final Configuration conf) throws IOException { boolean isInSafeMode = false; FileSystem fs = FileSystem.get(conf); - if (fs instanceof DistributedFileSystem) { - DistributedFileSystem dfs = (DistributedFileSystem) fs; - isInSafeMode = isInSafeMode(dfs); + if (supportSafeMode(fs)) { + isInSafeMode = isInSafeMode(fs); } if (isInSafeMode) { throw new IOException("File system is in safemode, it can't be written now"); @@ -644,10 +668,9 @@ public static void setClusterId(final FileSystem fs, final Path rootdir, */ public static void waitOnSafeMode(final Configuration conf, final long wait) throws IOException { FileSystem fs = FileSystem.get(conf); - if (!(fs instanceof DistributedFileSystem)) return; - DistributedFileSystem dfs = (DistributedFileSystem) fs; + if (!supportSafeMode(fs)) return; // Make sure dfs is not in safe mode - while (isInSafeMode(dfs)) { + while (isInSafeMode(fs)) { LOG.info("Waiting for dfs to exit safe mode..."); try { Thread.sleep(wait); @@ -658,6 +681,19 @@ public static void waitOnSafeMode(final Configuration conf, final long wait) thr } } + public static boolean supportSafeMode(FileSystem fs) { + // return true if HDFS. + if (fs instanceof DistributedFileSystem) { + return true; + } + // return true if the file system implements SafeMode interface. + if (safeModeClazz != null) { + return (safeModeClazz.isAssignableFrom(fs.getClass())); + } + // return false if the file system is not HDFS and does not implement SafeMode interface. + return false; + } + /** * Checks if meta region exists * @param fs file system diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java index 8e2ce8dd8c11..929511e551f8 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java @@ -35,6 +35,7 @@ import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LocalFileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.StreamCapabilities; import org.apache.hadoop.fs.permission.FsPermission; @@ -46,6 +47,7 @@ import org.apache.hadoop.hbase.client.RegionInfoBuilder; import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.fs.HFileSystem; +import org.apache.hadoop.hbase.regionserver.TestHStore; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.MiscTests; import org.apache.hadoop.hdfs.DFSConfigKeys; @@ -92,6 +94,8 @@ public void testIsHDFS() throws Exception { try { cluster = htu.startMiniDFSCluster(1); assertTrue(CommonFSUtils.isHDFS(conf)); + assertTrue(FSUtils.supportSafeMode(cluster.getFileSystem())); + FSUtils.checkDfsSafeMode(conf); } finally { if (cluster != null) { cluster.shutdown(); @@ -99,6 +103,14 @@ public void testIsHDFS() throws Exception { } } + @Test + public void testLocalFileSystemSafeMode() throws Exception { + conf.setClass("fs.file.impl", LocalFileSystem.class, FileSystem.class); + assertFalse(CommonFSUtils.isHDFS(conf)); + assertFalse(FSUtils.supportSafeMode(FileSystem.get(conf))); + FSUtils.checkDfsSafeMode(conf); + } + private void WriteDataToHDFS(FileSystem fs, Path file, int dataSize) throws Exception { FSDataOutputStream out = fs.create(file); byte[] data = new byte[dataSize]; From 15852091a642ef6689bd6df1af91cc7f6c1fab7f Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Fri, 4 Oct 2024 10:27:13 -0700 Subject: [PATCH 02/10] Fix checkstyle Change-Id: Ibf0ded6e104e9ed16f887f8411f4816eab8cea00 --- .../org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 3 ++- .../main/java/org/apache/hadoop/hbase/util/FSUtils.java | 7 +++++-- .../java/org/apache/hadoop/hbase/util/TestFSUtils.java | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index 92e562afb708..7b4ed0adb1f8 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -46,7 +46,8 @@ public final class RecoverLeaseFSUtils { try { leaseRecoverableClazz = Class.forName("org.apache.hadoop.fs.LeaseRecoverable"); } catch (ClassNotFoundException e) { - LOG.debug("LeaseRecoverable interface not in the classpath, this means Hadoop 3.3.5 or below."); + LOG.debug("LeaseRecoverable interface not in the classpath, " + + "this means Hadoop 3.3.5 or below."); } } 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 ac306fac9c3a..351bd4db3568 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 @@ -267,7 +267,8 @@ private static boolean isInSafeMode(FileSystem dfs) throws IOException { return ((DistributedFileSystem)dfs).setSafeMode(SAFEMODE_GET, true); } else { try { - Object ret = dfs.getClass().getMethod("setSafeMode", new Class[] { safeModeActionClazz, Boolean.class }) + Object ret = dfs.getClass() + .getMethod("setSafeMode", new Class[] { safeModeActionClazz, Boolean.class }) .invoke(dfs, safeModeGet, true); return (Boolean) ret; } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { @@ -668,7 +669,9 @@ public static void setClusterId(final FileSystem fs, final Path rootdir, */ public static void waitOnSafeMode(final Configuration conf, final long wait) throws IOException { FileSystem fs = FileSystem.get(conf); - if (!supportSafeMode(fs)) return; + if (!supportSafeMode(fs)) { + return; + } // Make sure dfs is not in safe mode while (isInSafeMode(fs)) { LOG.info("Waiting for dfs to exit safe mode..."); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java index 929511e551f8..7d18b584d7df 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFSUtils.java @@ -47,7 +47,6 @@ import org.apache.hadoop.hbase.client.RegionInfoBuilder; import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.fs.HFileSystem; -import org.apache.hadoop.hbase.regionserver.TestHStore; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.MiscTests; import org.apache.hadoop.hdfs.DFSConfigKeys; From 8bc2b03aadc6c2ec4da862b5daa4118c5e01bf0e Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Fri, 4 Oct 2024 10:29:35 -0700 Subject: [PATCH 03/10] spotless Change-Id: I351226ea55545dea309c7ed33c78c338cb42c07e --- .../apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 11 +++++------ .../java/org/apache/hadoop/hbase/util/FSUtils.java | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index 7b4ed0adb1f8..ca649b92728a 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -46,8 +46,8 @@ public final class RecoverLeaseFSUtils { try { leaseRecoverableClazz = Class.forName("org.apache.hadoop.fs.LeaseRecoverable"); } catch (ClassNotFoundException e) { - LOG.debug("LeaseRecoverable interface not in the classpath, " + - "this means Hadoop 3.3.5 or below."); + LOG.debug( + "LeaseRecoverable interface not in the classpath, this means Hadoop 3.3.5 or below."); } } @@ -192,8 +192,8 @@ private static boolean checkIfTimedout(final Configuration conf, final long reco * Try to recover the lease. * @return True if dfs#recoverLease came by true. */ - private static boolean recoverLease(final Object dfs, final int nbAttempt, - final Path p, final long startWaiting) throws FileNotFoundException { + private static boolean recoverLease(final Object dfs, final int nbAttempt, final Path p, + final long startWaiting) throws FileNotFoundException { boolean recovered = false; try { recovered = (Boolean) dfs.getClass().getMethod("recoverLease", new Class[] { Path.class }) @@ -226,8 +226,7 @@ private static String getLogMessageDetail(final int nbAttempt, final Path p, * Call HDFS-4525 isFileClosed if it is available. * @return True if file is closed. */ - private static boolean isFileClosed(final Object dfs, final Method m, - final Path p) { + private static boolean isFileClosed(final Object dfs, final Method m, final Path p) { try { return (Boolean) m.invoke(dfs, p); } catch (SecurityException e) { 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 351bd4db3568..10c9003a1d4d 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 @@ -264,7 +264,7 @@ public static void checkFileSystemAvailable(final FileSystem fs) throws IOExcept */ private static boolean isInSafeMode(FileSystem dfs) throws IOException { if (isDistributedFileSystem(dfs)) { - return ((DistributedFileSystem)dfs).setSafeMode(SAFEMODE_GET, true); + return ((DistributedFileSystem) dfs).setSafeMode(SAFEMODE_GET, true); } else { try { Object ret = dfs.getClass() From 441e54a2685c870a34d53c334a8a11bae950b675 Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Tue, 15 Oct 2024 14:02:00 -0700 Subject: [PATCH 04/10] Update based on review comments. (1) Use FileSystem class instead of Object for file system object. (2) Added one more test case to properly test reflection code. Change-Id: I0710ae1023d81f68fb18ec3f8dd5b228d90df21e --- .../hbase/util/RecoverLeaseFSUtils.java | 33 ++++++-- .../hbase/util/TestRecoverLeaseFSUtils.java | 75 ++++++++++++++++--- 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index ca649b92728a..862f646dbbc9 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -22,6 +22,7 @@ import java.io.InterruptedIOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import com.google.errorprone.annotations.RestrictedApi; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FilterFileSystem; @@ -41,13 +42,30 @@ public final class RecoverLeaseFSUtils { private static final Logger LOG = LoggerFactory.getLogger(RecoverLeaseFSUtils.class); private static Class leaseRecoverableClazz = null; + private static Method recoverLeaseMethod = null; + public static final String LEASE_RECOVERABLE_CLASS_NAME = "org.apache.hadoop.fs.LeaseRecoverable"; + static { + LOG.debug("RecoverLeaseFSUtils loaded"); + initializeRecoverLeaseMethod(LEASE_RECOVERABLE_CLASS_NAME); + } - { + @RestrictedApi(explanation = "Should only be called in tests", link = "", + allowedOnPath = ".*/src/test/.*") + static void initializeRecoverLeaseMethod(String className) { try { - leaseRecoverableClazz = Class.forName("org.apache.hadoop.fs.LeaseRecoverable"); + leaseRecoverableClazz = Class.forName(className); + recoverLeaseMethod = leaseRecoverableClazz.getMethod("recoverLease", Path.class); + LOG.debug("set recoverLeaseMethod to " + className + ".recoverLease()"); } catch (ClassNotFoundException e) { LOG.debug( "LeaseRecoverable interface not in the classpath, this means Hadoop 3.3.5 or below."); + try { + recoverLeaseMethod = DistributedFileSystem.class.getMethod("recoverLease", Path.class); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); } } @@ -106,7 +124,7 @@ public static boolean isLeaseRecoverable(FileSystem fs) { * false, repeat starting at step 5. above. If HDFS-4525 is available, call it every second, and * we might be able to exit early. */ - private static boolean recoverDFSFileLease(final Object dfs, final Path p, + private static boolean recoverDFSFileLease(final FileSystem dfs, final Path p, final Configuration conf, final CancelableProgressable reporter) throws IOException { LOG.info("Recover lease on dfs file " + p); long startWaiting = EnvironmentEdgeManager.currentTime(); @@ -192,12 +210,11 @@ private static boolean checkIfTimedout(final Configuration conf, final long reco * Try to recover the lease. * @return True if dfs#recoverLease came by true. */ - private static boolean recoverLease(final Object dfs, final int nbAttempt, final Path p, + private static boolean recoverLease(final FileSystem dfs, final int nbAttempt, final Path p, final long startWaiting) throws FileNotFoundException { boolean recovered = false; try { - recovered = (Boolean) dfs.getClass().getMethod("recoverLease", new Class[] { Path.class }) - .invoke(dfs, p); + recovered = (Boolean) recoverLeaseMethod.invoke(dfs, p); LOG.info((recovered ? "Recovered lease, " : "Failed to recover lease, ") + getLogMessageDetail(nbAttempt, p, startWaiting)); } catch (InvocationTargetException ite) { @@ -209,7 +226,7 @@ private static boolean recoverLease(final Object dfs, final int nbAttempt, final throw (FileNotFoundException) e; } LOG.warn(getLogMessageDetail(nbAttempt, p, startWaiting), e); - } catch (IllegalAccessException | NoSuchMethodException e) { + } catch (IllegalAccessException e) { throw new RuntimeException(e); } return recovered; @@ -226,7 +243,7 @@ private static String getLogMessageDetail(final int nbAttempt, final Path p, * Call HDFS-4525 isFileClosed if it is available. * @return True if file is closed. */ - private static boolean isFileClosed(final Object dfs, final Method m, final Path p) { + private static boolean isFileClosed(final FileSystem dfs, final Method m, final Path p) { try { return (Boolean) m.invoke(dfs, p); } catch (SecurityException e) { diff --git a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java index b2c9cc97b0d1..92103ca68224 100644 --- a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java @@ -17,18 +17,32 @@ */ package org.apache.hadoop.hbase.util; +import static org.apache.hadoop.hbase.util.RecoverLeaseFSUtils.LEASE_RECOVERABLE_CLASS_NAME; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URI; 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.LocalFileSystem; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseCommonTestingUtil; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.MiscTests; import org.apache.hadoop.hdfs.DistributedFileSystem; +import org.apache.hadoop.util.Progressable; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -60,20 +74,57 @@ public class TestRecoverLeaseFSUtils { public void testRecoverLease() throws IOException { long startTime = EnvironmentEdgeManager.currentTime(); HTU.getConfiguration().setInt("hbase.lease.recovery.dfs.timeout", 1000); - CancelableProgressable reporter = Mockito.mock(CancelableProgressable.class); - Mockito.when(reporter.progress()).thenReturn(true); - DistributedFileSystem dfs = Mockito.mock(DistributedFileSystem.class); + CancelableProgressable reporter = mock(CancelableProgressable.class); + when(reporter.progress()).thenReturn(true); + DistributedFileSystem dfs = mock(DistributedFileSystem.class); // Fail four times and pass on the fifth. - Mockito.when(dfs.recoverLease(FILE)).thenReturn(false).thenReturn(false).thenReturn(false) + when(dfs.recoverLease(FILE)).thenReturn(false).thenReturn(false).thenReturn(false) .thenReturn(false).thenReturn(true); RecoverLeaseFSUtils.recoverFileLease(dfs, FILE, HTU.getConfiguration(), reporter); - Mockito.verify(dfs, Mockito.times(5)).recoverLease(FILE); + verify(dfs, times(5)).recoverLease(FILE); // Make sure we waited at least hbase.lease.recovery.dfs.timeout * 3 (the first two // invocations will happen pretty fast... the we fall into the longer wait loop). assertTrue((EnvironmentEdgeManager.currentTime() - startTime) > (3 * HTU.getConfiguration().getInt("hbase.lease.recovery.dfs.timeout", 61000))); } + private interface FakeLeaseRecoverable { + boolean recoverLease(Path p) throws IOException; + boolean isFileClosed(Path p) throws IOException; + } + + private static abstract class RecoverableFileSystem extends FileSystem implements FakeLeaseRecoverable { + @Override + public boolean recoverLease(Path p) throws IOException { + return true; + } + @Override + public boolean isFileClosed(Path p) throws IOException { + return true; + } + } + + /** + * + * Test that we can use reflection to access LeaseRecoverable methods. + * @throws IOException + */ + @Test + public void testLeaseRecoverable() throws IOException { + try { + // set LeaseRecoverable to FakeLeaseRecoverable for testing + RecoverLeaseFSUtils.initializeRecoverLeaseMethod(FakeLeaseRecoverable.class.getName()); + RecoverableFileSystem mockFS = mock(RecoverableFileSystem.class); + when(mockFS.recoverLease(FILE)).thenReturn(true); + RecoverLeaseFSUtils.recoverFileLease(mockFS, FILE, HTU.getConfiguration()); + verify(mockFS, times(1)).recoverLease(FILE); + + assertTrue(RecoverLeaseFSUtils.isLeaseRecoverable(mock(RecoverableFileSystem.class))); + } finally { + RecoverLeaseFSUtils.initializeRecoverLeaseMethod(LEASE_RECOVERABLE_CLASS_NAME); + } + } + /** * Test that isFileClosed makes us recover lease faster. */ @@ -81,17 +132,17 @@ public void testRecoverLease() throws IOException { public void testIsFileClosed() throws IOException { // Make this time long so it is plain we broke out because of the isFileClosed invocation. HTU.getConfiguration().setInt("hbase.lease.recovery.dfs.timeout", 100000); - CancelableProgressable reporter = Mockito.mock(CancelableProgressable.class); - Mockito.when(reporter.progress()).thenReturn(true); - IsFileClosedDistributedFileSystem dfs = Mockito.mock(IsFileClosedDistributedFileSystem.class); + CancelableProgressable reporter = mock(CancelableProgressable.class); + when(reporter.progress()).thenReturn(true); + IsFileClosedDistributedFileSystem dfs = mock(IsFileClosedDistributedFileSystem.class); // Now make it so we fail the first two times -- the two fast invocations, then we fall into // the long loop during which we will call isFileClosed.... the next invocation should // therefore return true if we are to break the loop. - Mockito.when(dfs.recoverLease(FILE)).thenReturn(false).thenReturn(false).thenReturn(true); - Mockito.when(dfs.isFileClosed(FILE)).thenReturn(true); + when(dfs.recoverLease(FILE)).thenReturn(false).thenReturn(false).thenReturn(true); + when(dfs.isFileClosed(FILE)).thenReturn(true); RecoverLeaseFSUtils.recoverFileLease(dfs, FILE, HTU.getConfiguration(), reporter); - Mockito.verify(dfs, Mockito.times(2)).recoverLease(FILE); - Mockito.verify(dfs, Mockito.times(1)).isFileClosed(FILE); + verify(dfs, times(2)).recoverLease(FILE); + verify(dfs, times(1)).isFileClosed(FILE); } @Test From 8b484018f55df2dd44410815ad1ca90b5e5f7d77 Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Tue, 15 Oct 2024 14:04:30 -0700 Subject: [PATCH 05/10] Fix java doc. Change-Id: I5e29bacec957d76555a0ff7483a462b614a8f3f5 --- .../java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index 862f646dbbc9..e1d4a06ae802 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -78,7 +78,7 @@ public static void recoverFileLease(FileSystem fs, Path p, Configuration conf) } /** - * Recover the lease from HDFS or LeaseRecoverable fs, retrying multiple times. + * Recover the lease from Hadoop file system, retrying multiple times. */ public static void recoverFileLease(FileSystem fs, Path p, Configuration conf, CancelableProgressable reporter) throws IOException { From ad06438695fa0483bd3db78c307c4a6899bef78e Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Tue, 15 Oct 2024 15:50:40 -0700 Subject: [PATCH 06/10] Spotless Change-Id: Ie0b74f4801de33e0683e97e234cad9fcf13e985a --- .../hadoop/hbase/util/RecoverLeaseFSUtils.java | 4 ++-- .../hbase/util/TestRecoverLeaseFSUtils.java | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index e1d4a06ae802..19860a57ef5e 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -17,12 +17,12 @@ */ package org.apache.hadoop.hbase.util; +import com.google.errorprone.annotations.RestrictedApi; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InterruptedIOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import com.google.errorprone.annotations.RestrictedApi; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FilterFileSystem; @@ -50,7 +50,7 @@ public final class RecoverLeaseFSUtils { } @RestrictedApi(explanation = "Should only be called in tests", link = "", - allowedOnPath = ".*/src/test/.*") + allowedOnPath = ".*/src/test/.*") static void initializeRecoverLeaseMethod(String className) { try { leaseRecoverableClazz = Class.forName(className); diff --git a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java index 92103ca68224..6dd60d152034 100644 --- a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java @@ -25,28 +25,19 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.io.FileNotFoundException; import java.io.IOException; -import java.lang.reflect.Method; -import java.net.URI; 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.LocalFileSystem; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseCommonTestingUtil; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.MiscTests; import org.apache.hadoop.hdfs.DistributedFileSystem; -import org.apache.hadoop.util.Progressable; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.mockito.Mockito; /** * Test our recoverLease loop against mocked up filesystem. @@ -90,14 +81,17 @@ public void testRecoverLease() throws IOException { private interface FakeLeaseRecoverable { boolean recoverLease(Path p) throws IOException; + boolean isFileClosed(Path p) throws IOException; } - private static abstract class RecoverableFileSystem extends FileSystem implements FakeLeaseRecoverable { + private static abstract class RecoverableFileSystem extends FileSystem + implements FakeLeaseRecoverable { @Override public boolean recoverLease(Path p) throws IOException { return true; } + @Override public boolean isFileClosed(Path p) throws IOException { return true; @@ -105,9 +99,7 @@ public boolean isFileClosed(Path p) throws IOException { } /** - * * Test that we can use reflection to access LeaseRecoverable methods. - * @throws IOException */ @Test public void testLeaseRecoverable() throws IOException { From e983c82e04fa83311318bd5fe1420ce6ad1d2785 Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Tue, 15 Oct 2024 15:54:57 -0700 Subject: [PATCH 07/10] Fix compilation error. Change-Id: I4dd951945920220678677acefd27710eaf0f5658 --- .../org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index 19860a57ef5e..c10554d1a5a0 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -49,8 +49,10 @@ public final class RecoverLeaseFSUtils { initializeRecoverLeaseMethod(LEASE_RECOVERABLE_CLASS_NAME); } - @RestrictedApi(explanation = "Should only be called in tests", link = "", - allowedOnPath = ".*/src/test/.*") + /** + * Initialize reflection classes and methods. If LeaseRecoverable class is not found, + * look for DistributedFilSystem#recoverLease method. + */ static void initializeRecoverLeaseMethod(String className) { try { leaseRecoverableClazz = Class.forName(className); @@ -99,7 +101,7 @@ public static boolean isLeaseRecoverable(FileSystem fs) { } // return true if the file system implements LeaseRecoverable interface. if (leaseRecoverableClazz != null) { - return (leaseRecoverableClazz.isAssignableFrom(fs.getClass())); + return leaseRecoverableClazz.isAssignableFrom(fs.getClass()); } // return false if the file system is not HDFS and does not implement LeaseRecoverable. return false; From 8f7d0589e32a92b4c24d328e5ee02dd07ee2e2ea Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Wed, 16 Oct 2024 11:05:53 -0700 Subject: [PATCH 08/10] Fix spotless and javac warnings. Change-Id: Iec1149e25f6a8ac3f5fe4d2eb7287af9c0c75021 --- .../org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 5 ++--- .../apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index c10554d1a5a0..4ecf12633006 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -17,7 +17,6 @@ */ package org.apache.hadoop.hbase.util; -import com.google.errorprone.annotations.RestrictedApi; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InterruptedIOException; @@ -50,8 +49,8 @@ public final class RecoverLeaseFSUtils { } /** - * Initialize reflection classes and methods. If LeaseRecoverable class is not found, - * look for DistributedFilSystem#recoverLease method. + * Initialize reflection classes and methods. If LeaseRecoverable class is not found, look for + * DistributedFilSystem#recoverLease method. */ static void initializeRecoverLeaseMethod(String className) { try { diff --git a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java index 6dd60d152034..5a8099eace35 100644 --- a/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/test/java/org/apache/hadoop/hbase/util/TestRecoverLeaseFSUtils.java @@ -80,8 +80,10 @@ public void testRecoverLease() throws IOException { } private interface FakeLeaseRecoverable { + @SuppressWarnings("unused") boolean recoverLease(Path p) throws IOException; + @SuppressWarnings("unused") boolean isFileClosed(Path p) throws IOException; } From d75d68f759252111a32f1ba3f160e27c727a8ffd Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Wed, 16 Oct 2024 11:25:20 -0700 Subject: [PATCH 09/10] Improve error message if something unexpected happens using reflection. Change-Id: Iee3f259a46b5f12ed5948c61738a19ef77e29b5a --- .../java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 3 +++ .../src/main/java/org/apache/hadoop/hbase/util/FSUtils.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index 4ecf12633006..1271c8fee096 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -63,9 +63,11 @@ static void initializeRecoverLeaseMethod(String className) { try { recoverLeaseMethod = DistributedFileSystem.class.getMethod("recoverLease", Path.class); } catch (NoSuchMethodException ex) { + LOG.error("Cannot find recoverLease method in DistributedFileSystem class. Abort.", ex); throw new RuntimeException(ex); } } catch (NoSuchMethodException e) { + LOG.error("Cannot find recoverLease method in LeaseRecoverable class. Abort.", e); throw new RuntimeException(e); } } @@ -228,6 +230,7 @@ private static boolean recoverLease(final FileSystem dfs, final int nbAttempt, f } LOG.warn(getLogMessageDetail(nbAttempt, p, startWaiting), e); } catch (IllegalAccessException e) { + LOG.error("Failed to call recoverLease on {}. Abort.", dfs, e); throw new RuntimeException(e); } return recovered; 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 10c9003a1d4d..815bab2c4687 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 @@ -124,6 +124,8 @@ public final class FSUtils { } catch (ClassNotFoundException | NoSuchFieldException e) { LOG.debug("SafeMode interface not in the classpath, this means Hadoop 3.3.5 or below."); } catch (IllegalAccessException e) { + LOG.error("SafeModeAction.SAFEMODE_GET is not accessible. " + + "Unexpected Hadoop version or messy classpath?", e); throw new RuntimeException(e); } } @@ -272,6 +274,7 @@ private static boolean isInSafeMode(FileSystem dfs) throws IOException { .invoke(dfs, safeModeGet, true); return (Boolean) ret; } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { + LOG.error("The file system does not support setSafeMode(). Abort.", e); throw new RuntimeException(e); } } From 07c0831a1cdb45cb467edf65b2a000693e295170 Mon Sep 17 00:00:00 2001 From: Wei-Chiu Chuang Date: Fri, 18 Oct 2024 17:30:49 -0700 Subject: [PATCH 10/10] Fix spotless warning and fix log messages. Change-Id: Iee20335148f41592ed5b36c7c526a544fce6ed87 --- .../org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java | 8 +++++--- .../main/java/org/apache/hadoop/hbase/util/FSUtils.java | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java index 1271c8fee096..bc0657fc0d82 100644 --- a/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java +++ b/hbase-asyncfs/src/main/java/org/apache/hadoop/hbase/util/RecoverLeaseFSUtils.java @@ -44,7 +44,7 @@ public final class RecoverLeaseFSUtils { private static Method recoverLeaseMethod = null; public static final String LEASE_RECOVERABLE_CLASS_NAME = "org.apache.hadoop.fs.LeaseRecoverable"; static { - LOG.debug("RecoverLeaseFSUtils loaded"); + LOG.debug("Initialize RecoverLeaseFSUtils"); initializeRecoverLeaseMethod(LEASE_RECOVERABLE_CLASS_NAME); } @@ -63,11 +63,13 @@ static void initializeRecoverLeaseMethod(String className) { try { recoverLeaseMethod = DistributedFileSystem.class.getMethod("recoverLease", Path.class); } catch (NoSuchMethodException ex) { - LOG.error("Cannot find recoverLease method in DistributedFileSystem class. Abort.", ex); + LOG.error("Cannot find recoverLease method in DistributedFileSystem class. " + + "It should never happen. Abort.", ex); throw new RuntimeException(ex); } } catch (NoSuchMethodException e) { - LOG.error("Cannot find recoverLease method in LeaseRecoverable class. Abort.", e); + LOG.error("Cannot find recoverLease method in LeaseRecoverable class. " + + "It should never happen. Abort.", e); throw new RuntimeException(e); } } 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 815bab2c4687..55b77b6aed1b 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 @@ -124,8 +124,8 @@ public final class FSUtils { } catch (ClassNotFoundException | NoSuchFieldException e) { LOG.debug("SafeMode interface not in the classpath, this means Hadoop 3.3.5 or below."); } catch (IllegalAccessException e) { - LOG.error("SafeModeAction.SAFEMODE_GET is not accessible. " + - "Unexpected Hadoop version or messy classpath?", e); + LOG.error("SafeModeAction.SAFEMODE_GET is not accessible. " + + "Unexpected Hadoop version or messy classpath?", e); throw new RuntimeException(e); } }