From f1819fe8b9c0eb42d81306e67c51702252bab86a Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 12 Jan 2013 15:19:46 -0800 Subject: [PATCH] decorating cacheloader only used in s3 --- .../config/S3BlobStoreContextModule.java | 27 +-- .../BackoffOnNotFoundWhenGetBucketACL.java | 71 +++++++ ...BackoffOnNotFoundWhenGetBucketACLTest.java | 82 ++++++++ .../jclouds/cache/ForwardingCacheLoader.java | 58 ------ .../cache/RetryingCacheLoaderDecorator.java | 196 ------------------ ...ntiallyAndRetryOnThrowableCacheLoader.java | 139 ------------- ...onentiallyAndRetryOnThrowableCallable.java | 99 --------- .../cache/ForwardingCacheLoaderTest.java | 82 -------- .../RetryingCacheLoaderDecoratorTest.java | 85 -------- ...llyAndRetryOnThrowableCacheLoaderTest.java | 97 --------- ...tiallyAndRetryOnThrowableCallableTest.java | 75 ------- .../config/AWSS3BlobStoreContextModule.java | 28 --- 12 files changed, 161 insertions(+), 878 deletions(-) create mode 100644 apis/s3/src/main/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACL.java create mode 100644 apis/s3/src/test/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACLTest.java delete mode 100644 core/src/main/java/org/jclouds/cache/ForwardingCacheLoader.java delete mode 100644 core/src/main/java/org/jclouds/cache/RetryingCacheLoaderDecorator.java delete mode 100644 core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoader.java delete mode 100644 core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallable.java delete mode 100644 core/src/test/java/org/jclouds/cache/ForwardingCacheLoaderTest.java delete mode 100644 core/src/test/java/org/jclouds/cache/RetryingCacheLoaderDecoratorTest.java delete mode 100644 core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoaderTest.java delete mode 100644 core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallableTest.java diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java index 85e5b98543..11404911dc 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java +++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java @@ -18,6 +18,8 @@ */ package org.jclouds.s3.blobstore.config; +import static com.google.inject.Scopes.SINGLETON; + import java.util.concurrent.TimeUnit; import javax.inject.Singleton; @@ -29,21 +31,19 @@ import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.domain.Location; import org.jclouds.s3.S3AsyncClient; -import org.jclouds.s3.S3Client; import org.jclouds.s3.blobstore.S3AsyncBlobStore; import org.jclouds.s3.blobstore.S3BlobRequestSigner; import org.jclouds.s3.blobstore.S3BlobStore; import org.jclouds.s3.blobstore.S3BlobStoreContext; import org.jclouds.s3.blobstore.functions.LocationFromBucketName; +import org.jclouds.s3.blobstore.internal.BackoffOnNotFoundWhenGetBucketACL; import org.jclouds.s3.domain.AccessControlList; import com.google.common.base.Function; import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.inject.AbstractModule; import com.google.inject.Provides; -import com.google.inject.Scopes; import com.google.inject.TypeLiteral; /** @@ -57,8 +57,8 @@ public class S3BlobStoreContextModule extends AbstractModule { protected void configure() { install(new BlobStoreMapModule()); bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL); - bind(AsyncBlobStore.class).to(S3AsyncBlobStore.class).in(Scopes.SINGLETON); - bind(BlobStore.class).to(S3BlobStore.class).in(Scopes.SINGLETON); + bind(AsyncBlobStore.class).to(S3AsyncBlobStore.class).in(SINGLETON); + bind(BlobStore.class).to(S3BlobStore.class).in(SINGLETON); bind(new TypeLiteral>() { }).to(LocationFromBucketName.class); bindRequestSigner(); @@ -68,21 +68,10 @@ public class S3BlobStoreContextModule extends AbstractModule { bind(BlobRequestSigner.class).to(new TypeLiteral>() { }); } - + @Provides @Singleton - protected LoadingCache bucketAcls(final S3Client client) { - return CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build( - new CacheLoader() { - @Override - public AccessControlList load(String bucketName) { - return client.getBucketACL(bucketName); - } - - @Override - public String toString() { - return "getBucketAcl()"; - } - }); + protected LoadingCache bucketAcls(BackoffOnNotFoundWhenGetBucketACL loader) { + return CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build(loader); } } diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACL.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACL.java new file mode 100644 index 0000000000..4211d7b5d0 --- /dev/null +++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACL.java @@ -0,0 +1,71 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.s3.blobstore.internal; + +import static com.google.common.base.Throwables.propagate; + +import javax.inject.Inject; + +import org.jclouds.rest.ResourceNotFoundException; +import org.jclouds.s3.S3Client; +import org.jclouds.s3.domain.AccessControlList; + +import com.google.common.annotations.Beta; +import com.google.common.cache.CacheLoader; + + +@Beta +public class BackoffOnNotFoundWhenGetBucketACL extends CacheLoader { + private final S3Client client; + private final int maxTries = 5; + + @Inject + BackoffOnNotFoundWhenGetBucketACL(S3Client client) { + this.client = client; + } + + @Override + public AccessControlList load(String bucketName) { + ResourceNotFoundException last = null; + for (int currentTries = 0; currentTries < maxTries; currentTries++) { + try { + return client.getBucketACL(bucketName); + } catch (ResourceNotFoundException e) { + imposeBackoffExponentialDelay(100l, 200l, 2, currentTries, maxTries); + last = e; + } + } + throw last; + } + + private static void imposeBackoffExponentialDelay(long period, long maxPeriod, int pow, int failureCount, int max) { + long delayMs = (long) (period * Math.pow(failureCount, pow)); + delayMs = delayMs > maxPeriod ? maxPeriod : delayMs; + try { + Thread.sleep(delayMs); + } catch (InterruptedException e) { + throw propagate(e); + } + } + + @Override + public String toString() { + return "getBucketAcl()"; + } +} \ No newline at end of file diff --git a/apis/s3/src/test/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACLTest.java b/apis/s3/src/test/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACLTest.java new file mode 100644 index 0000000000..aa6011a1d2 --- /dev/null +++ b/apis/s3/src/test/java/org/jclouds/s3/blobstore/internal/BackoffOnNotFoundWhenGetBucketACLTest.java @@ -0,0 +1,82 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.s3.blobstore.internal; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertSame; + +import java.util.concurrent.TimeoutException; + +import org.jclouds.rest.ResourceNotFoundException; +import org.jclouds.s3.S3Client; +import org.jclouds.s3.domain.AccessControlList; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.util.concurrent.UncheckedExecutionException; + +@Test(groups = "unit", singleThreaded = true, testName = "BackoffOnNotFoundWhenGetBucketACLTest") +public class BackoffOnNotFoundWhenGetBucketACLTest { + private S3Client mock; + + @BeforeMethod + public void setUp() { + mock = createMock(S3Client.class); + } + + @Test + void testMaxRetriesNotExceededReturnsValue() { + AccessControlList acl = createMock(AccessControlList.class); + + int attempts = 5; + BackoffOnNotFoundWhenGetBucketACL backoff = new BackoffOnNotFoundWhenGetBucketACL(mock); + + expect(mock.getBucketACL("foo")).andThrow(new ResourceNotFoundException()).times(attempts - 1); + expect(mock.getBucketACL("foo")).andReturn(acl); + + replay(mock); + assertSame(backoff.load("foo"), acl); + verify(mock); + } + + @Test(expectedExceptions = ResourceNotFoundException.class) + void testMaxRetriesExceededThrowsException() { + int attempts = 5; + BackoffOnNotFoundWhenGetBucketACL backoff = new BackoffOnNotFoundWhenGetBucketACL(mock); + + expect(mock.getBucketACL("foo")).andThrow(new ResourceNotFoundException()).times(attempts); + + replay(mock); + backoff.load("foo"); + } + + @Test(expectedExceptions = UncheckedExecutionException.class) + void testDoesntCatchOtherExceptions() { + BackoffOnNotFoundWhenGetBucketACL backoff = new BackoffOnNotFoundWhenGetBucketACL(mock); + + expect(mock.getBucketACL("foo")).andThrow(new UncheckedExecutionException(new TimeoutException())); + + replay(mock); + backoff.load("foo"); + verify(mock); + } +} diff --git a/core/src/main/java/org/jclouds/cache/ForwardingCacheLoader.java b/core/src/main/java/org/jclouds/cache/ForwardingCacheLoader.java deleted file mode 100644 index 5686421399..0000000000 --- a/core/src/main/java/org/jclouds/cache/ForwardingCacheLoader.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.cache; - -import java.util.Map; - -import com.google.common.annotations.Beta; -import com.google.common.cache.CacheLoader; -import com.google.common.util.concurrent.ListenableFuture; - -/** - * A {@link CacheLoader} which forwards all its method calls to another {@link CacheLoader}. - * Subclasses should override one or more methods to modify the behavior of the backing cache as - * desired per the decorator pattern. - * - * @author Adrian Cole - * @since 1.5 - */ -@Beta -public abstract class ForwardingCacheLoader extends CacheLoader { - - /** Constructor for use by subclasses. */ - protected ForwardingCacheLoader() { - } - - protected abstract CacheLoader delegate(); - - @Override - public V load(K key) throws Exception { - return delegate().load(key); - } - - @Override - public ListenableFuture reload(K key, V oldValue) throws Exception { - return delegate().reload(key, oldValue); - } - - @Override - public Map loadAll(Iterable keys) throws Exception { - return delegate().loadAll(keys); - } -} diff --git a/core/src/main/java/org/jclouds/cache/RetryingCacheLoaderDecorator.java b/core/src/main/java/org/jclouds/cache/RetryingCacheLoaderDecorator.java deleted file mode 100644 index bd1a90ab41..0000000000 --- a/core/src/main/java/org/jclouds/cache/RetryingCacheLoaderDecorator.java +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.jclouds.cache; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import org.jclouds.cache.internal.BackoffExponentiallyAndRetryOnThrowableCacheLoader; - -import com.google.common.annotations.Beta; -import com.google.common.base.Objects; -import com.google.common.cache.CacheLoader; - -/** - *

- * A decorator of {@link CacheLoader} instances having any combination of the following features: - * - *

    - *
  • exponential backoff based on a particular Throwable type - *
- * - * These features are all optional; cache loaders can be created using all or none of them. By - * default, the input cache loader is returned unaffected. - * - *

- * Usage example: - * - *

- * @code
- * 
- *   CacheLoader loader = RetryingCacheLoaderDecorator.newDecorator()
- *       .on(ResourceNotFoundException.class).exponentiallyBackoff()
- *       .decorate(
- *           new CacheLoader() {
- *             public Graph load(Key key) throws AnyException {
- *               return createOnFlakeyConnection(key);
- *             }
- *           });}
- * 
- * - * @param - * the base key type for all cache loaders created by this decorator - * @param - * the base value type for all cache loaders created by this decorator - * @author Adrian Cole - * @since 1.5 - */ -@Beta -public class RetryingCacheLoaderDecorator { - protected RetryingCacheLoaderDecorator() { - } - - /** - * Constructs a new {@code RetryingCacheLoaderDecorator} instance with default settings, and no - * retrying any kind. - */ - // we can resolve generic type during decorate, as opposed to here - public static RetryingCacheLoaderDecorator newDecorator() { - return new RetryingCacheLoaderDecorator(); - } - - /** - * Determines the action to carry out on a particular throwable. - * - */ - public OnThrowableBuilder on(Class retryableThrowable) { - return new OnThrowableBuilder(retryableThrowable); - } - - public static class OnThrowableBuilder { - private Class retryableThrowable; - - private OnThrowableBuilder(Class retryableThrowable) { - this.retryableThrowable = checkNotNull(retryableThrowable, "retryableThrowable"); - } - - /** - * For each attempt, exponentially backoff - */ - public BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator exponentiallyBackoff() { - return new BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator(retryableThrowable); - } - - } - - public static class BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator extends - RetryingCacheLoaderDecorator { - private long periodMs = 100l; - private long maxPeriodMs = 200l; - private int maxTries = 5; - private final Class retryableThrowable; - - private BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator(Class retryableThrowable) { - this.retryableThrowable = checkNotNull(retryableThrowable, "retryableThrowable"); - } - - /** - * The initial period in milliseconds to delay between tries. with each try this period will - * increase exponentially. - *

- * default: {@code 100} - * - */ - public BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator periodMs(long periodMs) { - checkArgument(periodMs > 1, "maxTries must be positive: %d", periodMs); - this.periodMs = periodMs; - return this; - } - - /** - * The initial period in milliseconds to delay between tries. with each try this period will - * increase exponentially. - *

- * default: {@code 200} - * - */ - public BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator maxPeriodMs(long maxPeriodMs) { - checkArgument(maxPeriodMs > periodMs, "maxPeriodMs must be equal to or greater than periodMs: %d %d", - maxPeriodMs, periodMs); - this.maxPeriodMs = maxPeriodMs; - return this; - } - - /** - * The maximum attempts to try on the given exception type - *

- * default: {@code 5} - * - */ - public BackoffExponentiallyAndRetryOnThrowableCacheLoaderDecorator maxTries(int maxTries) { - checkArgument(maxTries > 1, "maxTries must be more than one: %d", maxTries); - this.maxTries = maxTries; - return this; - } - - @Override - public CacheLoader decorate(CacheLoader loader) { - return new BackoffExponentiallyAndRetryOnThrowableCacheLoader(retryableThrowable, periodMs, - maxPeriodMs, maxTries, super.decorate(loader)); - } - - @Override - protected Objects.ToStringHelper string() { - return Objects.toStringHelper(this).add("retryableThrowable", retryableThrowable).add("periodMs", periodMs).add("maxPeriodMs", - maxPeriodMs).add("maxTries", maxTries); - } - } - - /** - * Decorates a cacheloader, or returns the same value, if no retrying features were requested. - * - *

- * This method does not alter the state of this {@code RetryingCacheLoaderDecorator} instance, so - * it can be invoked again to create multiple independent cache loaders. - * - * @param loader - * the cache loader used to obtain new values - * @return a cache loader having the requested features - */ - public CacheLoader decorate(CacheLoader loader) { - return (CacheLoader) loader; - } - - /** - * Returns a string representation for this RetryingCacheLoaderDecorator instance. The exact form - * of the returned string is not specified. - */ - @Override - public String toString() { - return string().toString(); - } - - /** - * append any state that should be considered in {@link #toString} here. - */ - protected Objects.ToStringHelper string() { - return Objects.toStringHelper(this); - } -} diff --git a/core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoader.java b/core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoader.java deleted file mode 100644 index c4c713c2ee..0000000000 --- a/core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoader.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.cache.internal; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeoutException; - -import org.jclouds.cache.ForwardingCacheLoader; -import org.jclouds.util.Throwables2; - -import com.google.common.annotations.Beta; -import com.google.common.cache.CacheLoader; -import com.google.common.util.concurrent.ListenableFuture; - -/** - * Exponentially backs off, if we encounter an exception of the given type during any of the - * following methods: - *

    - *
  • load - *
  • reload - *
  • loadAll - *
- * - * @param - * the key type of the cache loader - * @param - * the value type of the cache loader - * @author Adrian Cole - * @since 1.5 - */ -@Beta -public class BackoffExponentiallyAndRetryOnThrowableCacheLoader extends ForwardingCacheLoader { - private final Class retryableThrowable; - private final long periodMs; - private final long maxPeriodMs; - private final int maxTries; - private final CacheLoader loader; - - /** - * - * @param retryableThrowable - * the exception which we can retry - * @param periodMs - * initial period, which exponentially increases with each try, specified in - * milliseconds - * @param maxPeriodMs - * maximum period duration, specified in milliseconds - * @param maxTries - * maximum amount of tries - * @param loader - * the loader we are able to retry - */ - public BackoffExponentiallyAndRetryOnThrowableCacheLoader(Class retryableThrowable, long periodMs, - long maxPeriodMs, int maxTries, CacheLoader loader) { - this.retryableThrowable = checkNotNull(retryableThrowable, "retryableThrowable"); - checkArgument(maxTries > 1, "maxTries must be more than one: %d", maxTries); - this.maxTries = maxTries; - checkArgument(periodMs > 0, "periodMs must be positive: %d", periodMs); - this.periodMs = periodMs; - checkArgument(maxPeriodMs > periodMs, "maxPeriodMs must be equal to or greater than periodMs: %d %d", - maxPeriodMs, periodMs); - this.maxPeriodMs = maxPeriodMs; - this.loader = checkNotNull(loader, "loader"); - } - - @Override - protected CacheLoader delegate() { - return loader; - } - - // TODO: refactor into a better closure in java pattern, if one exists - @Override - public V load(final K key) throws Exception { - return backoffExponentiallyAndRetryOnThrowable(new Callable() { - - @Override - public V call() throws Exception { - try { - return BackoffExponentiallyAndRetryOnThrowableCacheLoader.super.load(key); - } catch (Exception e) { - TimeoutException te = Throwables2.getFirstThrowableOfType(e, - TimeoutException.class); - if (te != null) { - throw te; - } - throw e; - } - } - }); - } - - @Override - public ListenableFuture reload(final K key, final V oldValue) throws Exception { - return backoffExponentiallyAndRetryOnThrowable(new Callable>() { - - @Override - public ListenableFuture call() throws Exception { - return BackoffExponentiallyAndRetryOnThrowableCacheLoader.super.reload(key, oldValue); - } - }); - } - - @Override - public Map loadAll(final Iterable keys) throws Exception { - return backoffExponentiallyAndRetryOnThrowable(new Callable>() { - - @Override - public Map call() throws Exception { - return BackoffExponentiallyAndRetryOnThrowableCacheLoader.super.loadAll(keys); - } - }); - } - - private T backoffExponentiallyAndRetryOnThrowable(Callable callable) throws Exception { - return new BackoffExponentiallyAndRetryOnThrowableCallable(retryableThrowable, periodMs, maxPeriodMs, - maxTries, callable).call(); - } - -} diff --git a/core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallable.java b/core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallable.java deleted file mode 100644 index 277dcbd5fc..0000000000 --- a/core/src/main/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallable.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.cache.internal; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.concurrent.Callable; - -import org.jclouds.util.Throwables2; - -import com.google.common.annotations.Beta; -import com.google.common.base.Objects; -import com.google.common.base.Throwables; -import com.google.common.collect.ForwardingObject; - -/** - * Exponentially backs off, if we encounter an exception of the given type during - * {@link Callable#call} - * - * @author Adrian Cole - * @since 1.5 - */ -@Beta -class BackoffExponentiallyAndRetryOnThrowableCallable extends ForwardingObject implements Callable { - private final Class retryableThrowable; - private final long periodMs; - private final long maxPeriodMs; - private final int maxTries; - private final Callable callable; - - BackoffExponentiallyAndRetryOnThrowableCallable(Class retryableThrowable, long periodMs, - long maxPeriodMs, int maxTries, Callable callable) { - this.retryableThrowable = checkNotNull(retryableThrowable, "retryableThrowable"); - checkArgument(maxTries > 1, "maxTries must be more than one: %d", maxTries); - this.maxTries = maxTries; - checkArgument(periodMs > 0, "periodMs must be positive: %d", periodMs); - this.periodMs = periodMs; - checkArgument(maxPeriodMs > periodMs, "maxPeriodMs must be equal to or greater than periodMs: %d %d", - maxPeriodMs, periodMs); - this.maxPeriodMs = maxPeriodMs; - this.callable = checkNotNull(callable, "callable"); - } - - @Override - protected Callable delegate() { - return callable; - } - - @Override - public T call() throws Exception { - Exception currentException = null; - for (int currentTries = 0; currentTries < maxTries; currentTries++) { - try { - return delegate().call(); - } catch (Exception e) { - currentException = e; - if (Throwables2.getFirstThrowableOfType(e, retryableThrowable) != null) { - imposeBackoffExponentialDelay(periodMs, maxPeriodMs, 2, currentTries, maxTries); - } else { - throw e; - } - } - } - throw currentException; - } - - private void imposeBackoffExponentialDelay(long period, long maxPeriod, int pow, int failureCount, int max) { - long delayMs = (long) (period * Math.pow(failureCount, pow)); - delayMs = delayMs > maxPeriod ? maxPeriod : delayMs; - try { - Thread.sleep(delayMs); - } catch (InterruptedException e) { - Throwables.propagate(e); - } - } - - @Override - public String toString() { - return Objects.toStringHelper("").add("retryableThrowable", retryableThrowable).add("periodMs", periodMs).add( - "maxPeriodMs", maxPeriodMs).add("maxTries", maxTries).add("callable", callable).toString(); - } -} diff --git a/core/src/test/java/org/jclouds/cache/ForwardingCacheLoaderTest.java b/core/src/test/java/org/jclouds/cache/ForwardingCacheLoaderTest.java deleted file mode 100644 index b0e434e652..0000000000 --- a/core/src/test/java/org/jclouds/cache/ForwardingCacheLoaderTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.jclouds.cache; - -import static org.easymock.EasyMock.createMockBuilder; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; - -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import com.google.common.cache.CacheLoader; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; - -/** - * Unit test for {@link ForwardingCacheLoader}. - * - * @author Adrian Cole - */ -@Test(testName = "ForwardingCacheLoaderTest", singleThreaded = true) -public class ForwardingCacheLoaderTest { - private CacheLoader forward; - private CacheLoader mock; - - @SuppressWarnings("unchecked") - @BeforeMethod - public void setUp() { - // add mocked methods for default forwarded ones - mock = createMockBuilder(CacheLoader.class).addMockedMethods("loadAll", "reload").createMock(); - forward = new ForwardingCacheLoader() { - @Override - protected CacheLoader delegate() { - return mock; - } - }; - } - - public void testLoad() throws Exception { - expect(mock.load("key")).andReturn(Boolean.TRUE); - replay(mock); - assertSame(Boolean.TRUE, forward.load("key")); - verify(mock); - } - - public void testReload() throws Exception { - ListenableFuture trueF = Futures.immediateFuture(true); - expect(mock.reload("key", false)).andReturn(trueF); - replay(mock); - assertSame(forward.reload("key", false), trueF); - verify(mock); - } - - public void testLoadAll() throws Exception { - expect(mock.loadAll(ImmutableList.of("key"))).andReturn(ImmutableMap.of("key", Boolean.TRUE)); - replay(mock); - assertEquals(ImmutableMap.of("key", Boolean.TRUE), forward.loadAll(ImmutableList.of("key"))); - verify(mock); - } -} diff --git a/core/src/test/java/org/jclouds/cache/RetryingCacheLoaderDecoratorTest.java b/core/src/test/java/org/jclouds/cache/RetryingCacheLoaderDecoratorTest.java deleted file mode 100644 index 4325dacb05..0000000000 --- a/core/src/test/java/org/jclouds/cache/RetryingCacheLoaderDecoratorTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.jclouds.cache; - -import static org.easymock.EasyMock.createMockBuilder; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.fail; - -import org.jclouds.rest.ResourceNotFoundException; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import com.google.common.cache.CacheLoader; - -/** - * Unit tests for RetryingCacheLoaderDecorator. - * - * @author Adrian Cole - */ -@Test(testName = "ForwardingCacheLoaderTest", singleThreaded = true) -public class RetryingCacheLoaderDecoratorTest { - private CacheLoader mock; - - @SuppressWarnings("unchecked") - @BeforeMethod - public void setUp() { - // add mocked methods for default forwarded ones - mock = createMockBuilder(CacheLoader.class).addMockedMethods("loadAll", "reload").createMock(); - } - - public void testNewDecoratorDecorateSameWhenNoParams() throws Exception { - assertSame(mock, RetryingCacheLoaderDecorator.newDecorator().decorate(mock)); - } - - @Test - void testDefaultMaxTriesIs5() throws Exception { - CacheLoader backoff = RetryingCacheLoaderDecorator.newDecorator().on( - ResourceNotFoundException.class).exponentiallyBackoff().decorate(mock); - - expect(mock.load("foo")).andThrow(new ResourceNotFoundException()).times(4); - expect(mock.load("foo")).andReturn(Boolean.TRUE); - - replay(mock); - assertSame(backoff.load("foo"), Boolean.TRUE); - verify(mock); - } - - @Test - void testMaxRetriesExceededThrowsException() throws Exception { - CacheLoader backoff = RetryingCacheLoaderDecorator.newDecorator() - .on(ResourceNotFoundException.class).exponentiallyBackoff() - .decorate(mock); - - expect(mock.load("foo")).andThrow(new ResourceNotFoundException()).times(5); - - replay(mock); - try { - backoff.load("foo"); - fail(); - } catch (ResourceNotFoundException e) { - - } - verify(mock); - } -} diff --git a/core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoaderTest.java b/core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoaderTest.java deleted file mode 100644 index c47314b3fe..0000000000 --- a/core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCacheLoaderTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.cache.internal; - -import static org.easymock.EasyMock.createMockBuilder; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.fail; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import org.jclouds.rest.ResourceNotFoundException; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import com.google.common.cache.CacheLoader; - -@Test(groups = "unit", singleThreaded = true, testName = "BackoffExponentiallyAndRetryOnThrowableCacheLoaderTest") -public class BackoffExponentiallyAndRetryOnThrowableCacheLoaderTest { - private CacheLoader mock; - - @SuppressWarnings("unchecked") - @BeforeMethod - public void setUp() { - // add mocked methods for default forwarded ones - mock = createMockBuilder(CacheLoader.class).addMockedMethods("loadAll", "reload").createMock(); - } - - @Test - void testMaxRetriesNotExceededReturnsValue() throws Exception { - int attempts = 3; - BackoffExponentiallyAndRetryOnThrowableCacheLoader backoff = new BackoffExponentiallyAndRetryOnThrowableCacheLoader( - ResourceNotFoundException.class, 50l, 500l, attempts, mock); - - expect(mock.load("foo")).andThrow(new ResourceNotFoundException()).times(attempts - 1); - expect(mock.load("foo")).andReturn(Boolean.TRUE); - - replay(mock); - assertSame(backoff.load("foo"), Boolean.TRUE); - verify(mock); - } - - @Test - void testMaxRetriesExceededThrowsException() throws Exception { - int attempts = 3; - BackoffExponentiallyAndRetryOnThrowableCacheLoader backoff = new BackoffExponentiallyAndRetryOnThrowableCacheLoader( - ResourceNotFoundException.class, 50l, 500l, attempts, mock); - - expect(mock.load("foo")).andThrow(new ResourceNotFoundException()).times(attempts); - - replay(mock); - try { - backoff.load("foo"); - fail(); - } catch (ResourceNotFoundException e) { - - } - verify(mock); - } - - @Test - void testThrowsTimeoutException() throws Exception { - int attempts = 3; - BackoffExponentiallyAndRetryOnThrowableCacheLoader backoff = new BackoffExponentiallyAndRetryOnThrowableCacheLoader( - ResourceNotFoundException.class, 50l, 500l, attempts, mock); - - expect(mock.load("foo")).andThrow(new ExecutionException(new TimeoutException())); - - replay(mock); - try { - backoff.load("foo"); - fail(); - } catch (TimeoutException e) { - - } - verify(mock); - } -} diff --git a/core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallableTest.java b/core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallableTest.java deleted file mode 100644 index a206d52a89..0000000000 --- a/core/src/test/java/org/jclouds/cache/internal/BackoffExponentiallyAndRetryOnThrowableCallableTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.cache.internal; - -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; - -import java.util.concurrent.Callable; - -import org.jclouds.rest.ResourceNotFoundException; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -@Test(groups = "unit", testName = "BackoffExponentiallyAndRetryOnThrowableCallableTest", singleThreaded = true) -public class BackoffExponentiallyAndRetryOnThrowableCallableTest { - private Callable mock; - - @SuppressWarnings("unchecked") - @BeforeMethod - public void setUp() { - mock = createMock(Callable.class); - } - - @Test - void testMaxRetriesNotExceededReturnsValue() throws Exception { - int attempts = 3; - BackoffExponentiallyAndRetryOnThrowableCallable backoff = new BackoffExponentiallyAndRetryOnThrowableCallable( - ResourceNotFoundException.class, 50l, 500l, attempts, mock); - - expect(mock.call()).andThrow(new ResourceNotFoundException()).times(attempts - 1); - expect(mock.call()).andReturn("foo"); - - replay(mock); - assertEquals(backoff.call(), "foo"); - verify(mock); - } - - @Test - void testMaxRetriesExceededThrowsException() throws Exception { - int attempts = 3; - BackoffExponentiallyAndRetryOnThrowableCallable backoff = new BackoffExponentiallyAndRetryOnThrowableCallable( - ResourceNotFoundException.class, 50l, 500l, attempts, mock); - - expect(mock.call()).andThrow(new ResourceNotFoundException()).times(attempts); - - replay(mock); - try { - backoff.call(); - fail(); - } catch (ResourceNotFoundException e) { - - } - verify(mock); - } -} diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java index 89cd87ad69..c9856da3db 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java @@ -18,8 +18,6 @@ */ package org.jclouds.aws.s3.blobstore.config; -import java.util.concurrent.TimeUnit; - import org.jclouds.aws.s3.AWSS3AsyncClient; import org.jclouds.aws.s3.blobstore.AWSS3AsyncBlobStore; import org.jclouds.aws.s3.blobstore.AWSS3BlobStore; @@ -28,18 +26,11 @@ import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy; import org.jclouds.aws.s3.blobstore.strategy.internal.ParallelMultipartUploadStrategy; import org.jclouds.aws.s3.blobstore.strategy.internal.SequentialMultipartUploadStrategy; import org.jclouds.blobstore.BlobRequestSigner; -import org.jclouds.cache.RetryingCacheLoaderDecorator; -import org.jclouds.rest.ResourceNotFoundException; -import org.jclouds.s3.S3Client; import org.jclouds.s3.blobstore.S3AsyncBlobStore; import org.jclouds.s3.blobstore.S3BlobRequestSigner; import org.jclouds.s3.blobstore.S3BlobStore; import org.jclouds.s3.blobstore.config.S3BlobStoreContextModule; -import org.jclouds.s3.domain.AccessControlList; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; @@ -64,23 +55,4 @@ public class AWSS3BlobStoreContextModule extends S3BlobStoreContextModule { bind(BlobRequestSigner.class).to(new TypeLiteral>() { }); } - - @Override - protected LoadingCache bucketAcls(final S3Client client) { - CacheLoader loader = RetryingCacheLoaderDecorator.newDecorator() - .on(ResourceNotFoundException.class).exponentiallyBackoff() - .decorate( - new CacheLoader() { - @Override - public AccessControlList load(String bucketName) { - return client.getBucketACL(bucketName); - } - - @Override - public String toString() { - return "getBucketAcl()"; - } - }); - return CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build(loader); - } }