killbill-uncached

util: optimize GC in EntitySqlDaoWrapperInvocationHandler Signed-off-by:

5/23/2017 9:12:05 AM

Details

diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index 654d0da..17a84e0 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -32,6 +32,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.annotation.Nullable;
 
@@ -84,6 +85,8 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
 
     private final Logger logger = LoggerFactory.getLogger(EntitySqlDaoWrapperInvocationHandler.class);
 
+    private final Map<String, Annotation[][]> parameterAnnotationsByMethod = new ConcurrentHashMap<String, Annotation[][]>();
+
     private final Class<S> sqlDaoClass;
     private final S sqlDao;
     private final Handle handle;
@@ -227,7 +230,7 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
         if (cache != null && objectType != null) {
             // Find all arguments marked with @CachableKey
             final Map<Integer, Object> keyPieces = new LinkedHashMap<Integer, Object>();
-            final Annotation[][] annotations = method.getParameterAnnotations();
+            final Annotation[][] annotations = getAnnotations(method);
             for (int i = 0; i < annotations.length; i++) {
                 for (int j = 0; j < annotations[i].length; j++) {
                     final Annotation annotation = annotations[i][j];
@@ -408,7 +411,8 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
     }
 
     private List<String> retrieveEntityIdsFromArguments(final Method method, final Object[] args) {
-        final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+        final Annotation[][] parameterAnnotations = getAnnotations(method);
+
         int i = -1;
         for (final Object arg : args) {
             i++;
@@ -438,6 +442,19 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
         return ImmutableList.<String>of();
     }
 
+    private Annotation[][] getAnnotations(final Method method) {
+        // Expensive to compute
+        final String methodString = method.toString();
+
+        // Method.getParameterAnnotations() generates lots of garbage objects
+        Annotation[][] parameterAnnotations = parameterAnnotationsByMethod.get(methodString);
+        if (parameterAnnotations == null) {
+            parameterAnnotations = method.getParameterAnnotations();
+            parameterAnnotationsByMethod.put(methodString, parameterAnnotations);
+        }
+        return parameterAnnotations;
+    }
+
     private Builder<String> extractEntityIdsFromBatchArgument(final Iterable arg) {
         final Iterator iterator = arg.iterator();
         final Builder<String> entityIds = new Builder<String>();