Repository: hbase Updated Branches: refs/heads/hbase-6721-0.98 66e16163f -> 8726a60a5
HBASE-14232 Backwards compatiblity support for new MasterObserver APIs (Francis Liu) Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/8726a60a Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/8726a60a Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/8726a60a Branch: refs/heads/hbase-6721-0.98 Commit: 8726a60a52728730e46c46f4a6b9992530de2216 Parents: 66e1616 Author: Andrew Purtell <apurt...@apache.org> Authored: Wed Aug 26 13:28:44 2015 -0700 Committer: Andrew Purtell <apurt...@apache.org> Committed: Wed Aug 26 13:41:06 2015 -0700 ---------------------------------------------------------------------- .../hbase/coprocessor/CoprocessorHost.java | 74 ++++++++++++++++++++ .../hbase/master/MasterCoprocessorHost.java | 47 +++++++++---- 2 files changed, 109 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/8726a60a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java index 1c55738..16f6a86 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; +import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; @@ -870,4 +871,77 @@ public abstract class CoprocessorHost<E extends CoprocessorEnvironment> { "coprocessor set.", e); } } + + /** + * Used to gracefully handle fallback to deprecated methods when we + * evolve coprocessor APIs. + * + * When a particular Coprocessor API is updated to change methods, hosts can support fallback + * to the deprecated API by using this method to determine if an instance implements the new API. + * In the event that said support is partial, then in the face of a runtime issue that prevents + * proper operation {@link #legacyWarning(Class, String)} should be used to let operators know. + * + * For examples of this in action, see the implementation of + * <ul> + * <li>{@link org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost} + * <li>{@link org.apache.hadoop.hbase.regionserver.wal.WALCoprocessorHost} + * </ul> + * + * @param clazz Coprocessor you wish to evaluate + * @param methodName the name of the non-deprecated method version + * @param parameterTypes the Class of the non-deprecated method's arguments in the order they are + * declared. + */ + @InterfaceAudience.Private + protected static boolean useLegacyMethod(final Class<? extends Coprocessor> clazz, + final String methodName, final Class<?>... parameterTypes) { + boolean useLegacy; + // Use reflection to see if they implement the non-deprecated version + try { + clazz.getDeclaredMethod(methodName, parameterTypes); + LOG.debug("Found an implementation of '" + methodName + "' that uses updated method " + + "signature. Skipping legacy support for invocations in '" + clazz +"'."); + useLegacy = false; + } catch (NoSuchMethodException exception) { + useLegacy = true; + } catch (SecurityException exception) { + LOG.warn("The Security Manager denied our attempt to detect if the coprocessor '" + clazz + + "' requires legacy support; assuming it does. If you get later errors about legacy " + + "coprocessor use, consider updating your security policy to allow access to the package" + + " and declared members of your implementation."); + LOG.debug("Details of Security Manager rejection.", exception); + useLegacy = true; + } + return useLegacy; + } + + /** + * Used to limit legacy handling to once per Coprocessor class per classloader. + */ + private static final Set<Class<? extends Coprocessor>> legacyWarning = + new ConcurrentSkipListSet<Class<? extends Coprocessor>>( + new Comparator<Class<? extends Coprocessor>>() { + @Override + public int compare(Class<? extends Coprocessor> c1, Class<? extends Coprocessor> c2) { + if (c1.equals(c2)) { + return 0; + } + return c1.getName().compareTo(c2.getName()); + } + }); + + /** + * limits the amount of logging to once per coprocessor class. + * Used in concert with {@link #useLegacyMethod(Class, String, Class[])} when a runtime issue + * prevents properly supporting the legacy version of a coprocessor API. + * Since coprocessors can be in tight loops this serves to limit the amount of log spam we create. + */ + @InterfaceAudience.Private + protected void legacyWarning(final Class<? extends Coprocessor> clazz, final String message) { + if(legacyWarning.add(clazz)) { + LOG.error("You have a legacy coprocessor loaded and there are events we can't map to the " + + " deprecated API. Your coprocessor will not see these events. Please update '" + clazz + + "'. Details of the problem: " + message); + } + } } http://git-wip-us.apache.org/repos/asf/hbase/blob/8726a60a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index 73faf3c..15c357c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -60,12 +60,15 @@ public class MasterCoprocessorHost static class MasterEnvironment extends CoprocessorHost.Environment implements MasterCoprocessorEnvironment { private MasterServices masterServices; + final boolean supportGroupCPs; public MasterEnvironment(final Class<?> implClass, final Coprocessor impl, final int priority, final int seq, final Configuration conf, final MasterServices services) { super(impl, priority, seq, conf); this.masterServices = services; + supportGroupCPs = !useLegacyMethod(impl.getClass(), + "preBalanceGroup", ObserverContext.class, String.class); } public MasterServices getMasterServices() { @@ -852,14 +855,16 @@ public class MasterCoprocessorHost } }); } - + public void preMoveServers(final Set<HostPort> servers, final String targetGroup) throws IOException { execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() { @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.preMoveServers(ctx, servers, targetGroup); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preMoveServers(ctx, servers, targetGroup); + } } }); } @@ -870,7 +875,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.postMoveServers(ctx, servers, targetGroup); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postMoveServers(ctx, servers, targetGroup); + } } }); } @@ -881,7 +888,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.preMoveTables(ctx, tables, targetGroup); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preMoveTables(ctx, tables, targetGroup); + } } }); } @@ -892,7 +901,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.postMoveTables(ctx, tables, targetGroup); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postMoveTables(ctx, tables, targetGroup); + } } }); } @@ -903,7 +914,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.preAddGroup(ctx, name); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preAddGroup(ctx, name); + } } }); } @@ -914,7 +927,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.postAddGroup(ctx, name); + if (((MasterEnvironment) ctx.getEnvironment()).supportGroupCPs) { + oserver.postAddGroup(ctx, name); + } } }); } @@ -925,7 +940,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.preRemoveGroup(ctx, name); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preRemoveGroup(ctx, name); + } } }); } @@ -936,7 +953,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.postRemoveGroup(ctx, name); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postRemoveGroup(ctx, name); + } } }); } @@ -947,7 +966,9 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.preBalanceGroup(ctx, name); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.preBalanceGroup(ctx, name); + } } }); } @@ -958,10 +979,12 @@ public class MasterCoprocessorHost @Override public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException { - oserver.postBalanceGroup(ctx, name, balanceRan); + if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) { + oserver.postBalanceGroup(ctx, name, balanceRan); + } } }); - } + } private static abstract class CoprocessorOperation extends ObserverContext<MasterCoprocessorEnvironment> {