From 7b338a9f2515310266436f215db2e1874f8c302f Mon Sep 17 00:00:00 2001 From: Mike Drob Date: Wed, 21 Jun 2017 16:57:51 -0500 Subject: [PATCH] HBASE-18177 ClientProtocol::create has API changes between Hadoop 2/3 Use reflection to select the proper types/argument list to call create at runtime based on which version of hadoop we have. --- .../java/org/apache/hadoop/hbase/util/Methods.java | 16 ++++++++++++--- .../FanOutOneBlockAsyncDFSOutputHelper.java | 24 +++++++++++++++++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Methods.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Methods.java index 51b141842e..51c98a1b50 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Methods.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Methods.java @@ -35,15 +35,25 @@ public class Methods { public static Object call(Class clazz, T instance, String methodName, Class[] types, Object[] args) throws Exception { try { + return callIfPresent(clazz, instance, methodName, types, args); + } catch (NoSuchMethodException nsme) { + throw new IllegalArgumentException( + "Can't find method " + methodName + " in " + clazz.getName() + "!", nsme); + } + } + + /* + * Like Methods::call, but will throw NoSuchMethodException back to the caller if the method does not exist + */ + public static Object callIfPresent(Class clazz, T instance, String methodName, + Class[] types, Object[] args) throws Exception { + try { Method m = clazz.getMethod(methodName, types); return m.invoke(instance, args); } catch (IllegalArgumentException arge) { LOG.fatal("Constructed invalid call. class="+clazz.getName()+ " method=" + methodName + " types=" + Classes.stringify(types), arge); throw arge; - } catch (NoSuchMethodException nsme) { - throw new IllegalArgumentException( - "Can't find method "+methodName+" in "+clazz.getName()+"!", nsme); } catch (InvocationTargetException ite) { // unwrap the underlying exception and rethrow if (ite.getTargetException() != null) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/asyncfs/FanOutOneBlockAsyncDFSOutputHelper.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/asyncfs/FanOutOneBlockAsyncDFSOutputHelper.java index 3eaacc42f7..74a1c2eec4 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/asyncfs/FanOutOneBlockAsyncDFSOutputHelper.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/asyncfs/FanOutOneBlockAsyncDFSOutputHelper.java @@ -78,6 +78,7 @@ import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.ConnectionUtils; import org.apache.hadoop.hbase.util.CancelableProgressable; import org.apache.hadoop.hbase.util.FSUtils; +import org.apache.hadoop.hbase.util.Methods; import org.apache.hadoop.hdfs.DFSClient; import org.apache.hadoop.hdfs.DFSOutputStream; import org.apache.hadoop.hdfs.DistributedFileSystem; @@ -680,7 +681,7 @@ public final class FanOutOneBlockAsyncDFSOutputHelper { ClientProtocol namenode = client.getNamenode(); HdfsFileStatus stat; try { - stat = namenode.create(src, + stat = create(namenode, src, FsPermission.getFileDefault().applyUMask(FsPermission.getUMask(conf)), clientName, new EnumSetWritable<>(overwrite ? EnumSet.of(CREATE, OVERWRITE) : EnumSet.of(CREATE)), createParent, replication, blockSize, CryptoProtocolVersion.supported()); @@ -735,6 +736,27 @@ public final class FanOutOneBlockAsyncDFSOutputHelper { } /** + * Hack around HDFS-10996 adding a parameter to {@link ClientProtocol#create} to make sure we call the right one + */ + private static HdfsFileStatus create(ClientProtocol namenode, String src, FsPermission masked, String clientName, + EnumSetWritable flag, boolean createParent, short replication, long blockSize, + CryptoProtocolVersion[] supportedVersions) throws Exception { + final String methodName = "create"; + try { + Class[] types = {String.class, FsPermission.class, String.class, EnumSetWritable.class, boolean.class, + short.class, long.class, CryptoProtocolVersion[].class }; + Object[] args = {src, masked, clientName, flag, createParent, replication, blockSize, supportedVersions}; + return (HdfsFileStatus) Methods.callIfPresent(ClientProtocol.class, namenode, methodName, types, args); + } catch (NoSuchMethodException e) { + // Same types as before, but with String appended + Class[] h3types = {String.class, FsPermission.class, String.class, EnumSetWritable.class, boolean.class, + short.class, long.class, CryptoProtocolVersion[].class, String.class }; + Object[] h3args = {src, masked, clientName, flag, createParent, replication, blockSize, supportedVersions, null}; + return (HdfsFileStatus) Methods.call(ClientProtocol.class, namenode, methodName, h3types, h3args); + } + } + + /** * Create a {@link FanOutOneBlockAsyncDFSOutput}. The method maybe blocked so do not call it * inside {@link EventLoop}. * @param eventLoop all connections to datanode will use the same event loop. -- 2.13.0