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> {

Reply via email to