Updated Branches:
  refs/heads/1.6.x 44e848723 -> 82708c98d

[JCLOUDS-301] Reduce reflection overhead of Invokable.getParameters()

By caching the results from Invokable.getParameters(), this commit
improves request signing performance (GETs and PUTs) for S3 by >
3X. These performance problems were seen in production and diagnosed
using the YourKit profiler.


Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/commit/82708c98
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/82708c98
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/82708c98

Branch: refs/heads/1.6.x
Commit: 82708c98de6eae74ccf53cf9b5415aafec6ff662
Parents: 44e8487
Author: Niraj Tolia <[email protected]>
Authored: Thu Sep 26 17:27:28 2013 -0700
Committer: Adrian Cole <[email protected]>
Committed: Fri Sep 27 07:50:15 2013 -0700

----------------------------------------------------------------------
 apis/s3/src/main/java/org/jclouds/s3/util/S3Utils.java   |  8 +++++---
 .../main/java/org/jclouds/rest/InputParamValidator.java  | 11 ++++++-----
 .../jclouds/rest/internal/RestAnnotationProcessor.java   | 11 +++++++++--
 .../java/org/jclouds/rest/InputParamValidatorTest.java   |  2 +-
 4 files changed, 21 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/82708c98/apis/s3/src/main/java/org/jclouds/s3/util/S3Utils.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/util/S3Utils.java 
b/apis/s3/src/main/java/org/jclouds/s3/util/S3Utils.java
index 19c08ad..4080b22 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/util/S3Utils.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/util/S3Utils.java
@@ -30,6 +30,8 @@ import org.jclouds.s3.Bucket;
 import org.jclouds.s3.S3Client;
 
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.Parameter;
 
 /**
  * Encryption, Hashing, and IO Utilities needed to sign and verify S3 requests 
and responses.
@@ -75,9 +77,9 @@ public class S3Utils {
 
       String bucketName = null;
 
-      for (int i = 0; i < 
request.getInvocation().getInvokable().getParameters().size(); i++) {
-         if 
(any(Arrays.asList(request.getInvocation().getInvokable().getParameters().get(i).getAnnotations()),
-               ANNOTATIONTYPE_BUCKET)) {
+      ImmutableList<Parameter> parameters = 
request.getInvocation().getInvokable().getParameters();
+      for (int i = 0; i < parameters.size(); i++) {
+         if (any(Arrays.asList(parameters.get(i).getAnnotations()), 
ANNOTATIONTYPE_BUCKET)) {
             bucketName = (String) request.getInvocation().getArgs().get(i);
             break;
          }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/82708c98/core/src/main/java/org/jclouds/rest/InputParamValidator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/rest/InputParamValidator.java 
b/core/src/main/java/org/jclouds/rest/InputParamValidator.java
index ed22c18..c7c5bb9 100644
--- a/core/src/main/java/org/jclouds/rest/InputParamValidator.java
+++ b/core/src/main/java/org/jclouds/rest/InputParamValidator.java
@@ -26,6 +26,7 @@ import org.jclouds.predicates.Validator;
 import org.jclouds.reflect.Invocation;
 import org.jclouds.rest.annotations.ParamValidators;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.reflect.Parameter;
@@ -66,12 +67,12 @@ public class InputParamValidator {
     * @throws IllegalStateException
     *            if validation failed
     */
-   public void validateMethodParametersOrThrow(Invocation invocation) {
+   public void validateMethodParametersOrThrow(Invocation invocation, 
ImmutableList<Parameter> parameters) {
       try {
          performMethodValidation(checkNotNull(invocation, "invocation"));
-         performParameterValidation(invocation);
+         performParameterValidation(invocation, checkNotNull(parameters, 
"parameters"));
       } catch (IllegalArgumentException e) {
-         throw new IllegalArgumentException(String.format("Validation on '%s' 
didn't pass:%n Reason: %s.", invocation,
+         throw new IllegalArgumentException(String.format("Validation on '%s' 
didn't pass:%n Reason: %s.", parameters,
                e.getMessage()), e);
       }
    }
@@ -104,8 +105,8 @@ public class InputParamValidator {
     * @param args
     *           arguments that correspond to the array of annotations
     */
-   private void performParameterValidation(Invocation invocation) {
-      for (Parameter param : invocation.getInvokable().getParameters()) {
+   private void performParameterValidation(Invocation invocation, 
ImmutableList<Parameter> parameters) {
+      for (Parameter param : parameters) {
          ParamValidators annotation = 
param.getAnnotation(ParamValidators.class);
          if (annotation == null)
             continue;

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/82708c98/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java 
b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
index 7fd789d..89b430c 100644
--- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
+++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
@@ -150,6 +150,13 @@ public class RestAnnotationProcessor implements 
Function<Invocation, HttpRequest
    private final GetAcceptHeaders getAcceptHeaders;
    private final Invocation caller;
    private final boolean stripExpectHeader;
+   private static final LoadingCache<Invokable<?, ?>, 
ImmutableList<Parameter>> invokableParamsCache =
+       CacheBuilder.newBuilder().maximumSize(100).build(new 
CacheLoader<Invokable<?, ?>, ImmutableList<Parameter>>() {
+               @Override
+               public ImmutableList<Parameter> load(Invokable<?, ?> invokable) 
{
+                   return invokable.getParameters();
+               }
+           });
 
    @Inject
    private RestAnnotationProcessor(Injector injector, @ApiVersion String 
apiVersion, @BuildVersion String buildVersion,
@@ -179,7 +186,7 @@ public class RestAnnotationProcessor implements 
Function<Invocation, HttpRequest
    @Override
    public GeneratedHttpRequest apply(Invocation invocation) {
       checkNotNull(invocation, "invocation");
-      inputParamValidator.validateMethodParametersOrThrow(invocation);
+      inputParamValidator.validateMethodParametersOrThrow(invocation, 
invokableParamsCache.getUnchecked(invocation.getInvokable()));
 
       Optional<URI> endpoint = Optional.absent();
       HttpRequest r = findOrNull(invocation.getArgs(), HttpRequest.class);
@@ -499,7 +506,7 @@ public class RestAnnotationProcessor implements 
Function<Invocation, HttpRequest
 
    private static Collection<Parameter> parametersWithAnnotation(Invokable<?, 
?> invokable,
          final Class<? extends Annotation> annotationType) {
-      return filter(invokable.getParameters(), new Predicate<Parameter>() {
+      return filter(invokableParamsCache.getUnchecked(invokable), new 
Predicate<Parameter>() {
          public boolean apply(Parameter in) {
             return in.isAnnotationPresent(annotationType);
          }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/82708c98/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java 
b/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java
index 893b986..5fb8a72 100644
--- a/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java
+++ b/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java
@@ -101,7 +101,7 @@ public class InputParamValidatorTest {
    public void testWrongPredicateTypeLiteral() throws Exception {
       Invocation invocation = Invocation.create(method(WrongValidator.class, 
"method", Integer.class),
             ImmutableList.<Object> of(55));
-      new 
InputParamValidator(injector).validateMethodParametersOrThrow(invocation);
+      new 
InputParamValidator(injector).validateMethodParametersOrThrow(invocation, 
invocation.getInvokable().getParameters());
    }
 
    Injector injector;

Reply via email to