Updated Branches: refs/heads/master 5f8961723 -> e8ef5c066
[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/e8ef5c06 Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/e8ef5c06 Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/e8ef5c06 Branch: refs/heads/master Commit: e8ef5c06657319c22a307a45fe0f9aeeb94e37aa Parents: 5f89617 Author: Niraj Tolia <[email protected]> Authored: Thu Sep 26 17:27:28 2013 -0700 Committer: Adrian Cole <[email protected]> Committed: Fri Sep 27 07:49:09 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/e8ef5c06/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/e8ef5c06/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/e8ef5c06/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/e8ef5c06/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;
