mirror of https://github.com/apache/jclouds.git
[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.
This commit is contained in:
parent
5f8961723f
commit
e8ef5c0665
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue