diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInList.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInList.java index 6107a2045f..0bdd53d493 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInList.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInList.java @@ -27,6 +27,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; import javax.annotation.Resource; import javax.inject.Named; @@ -62,12 +63,10 @@ public class DeleteAllKeysInList implements ClearListStrategy, ClearContainerStr private final ExecutorService userExecutor; protected final AsyncBlobStore connection; - /** - * maximum duration of an blob Request - */ + /** Maximum duration in milliseconds of a request. */ @Inject(optional = true) @Named(Constants.PROPERTY_REQUEST_TIMEOUT) - protected Long maxTime; + protected Long maxTime = Long.MAX_VALUE; @Inject DeleteAllKeysInList(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor, @@ -98,7 +97,7 @@ public class DeleteAllKeysInList implements ClearListStrategy, ClearContainerStr Future> listFuture = connection.list(containerName, options); try { - listing = listFuture.get(); + listing = listFuture.get(maxTime, TimeUnit.MILLISECONDS); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); break; @@ -109,6 +108,13 @@ public class DeleteAllKeysInList implements ClearListStrategy, ClearContainerStr } retryHandler.imposeBackoffExponentialDelay(numErrors, message); continue; + } catch (TimeoutException te) { + ++numErrors; + if (numErrors == maxErrors) { + throw propagate(te); + } + retryHandler.imposeBackoffExponentialDelay(numErrors, message); + continue; } finally { listFuture.cancel(true); } diff --git a/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInListTest.java b/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInListTest.java index 9565d20119..0662580277 100644 --- a/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInListTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/strategy/internal/DeleteAllKeysInListTest.java @@ -18,16 +18,30 @@ */ package org.jclouds.blobstore.strategy.internal; +import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; import org.jclouds.ContextBuilder; +import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.options.ListContainerOptions; +import org.jclouds.blobstore.domain.PageSet; +import org.jclouds.blobstore.domain.StorageMetadata; +import org.jclouds.util.Throwables2; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import com.google.common.io.Closeables; +import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Injector; /** @@ -74,6 +88,27 @@ public class DeleteAllKeysInListTest { assertEquals(blobstore.countBlobs(containerName), 1111); } + public void testListTimeoutException() throws Exception { + ListenableFuture> future = createMock(ListenableFuture.class); + expect(future.get(anyLong(), anyObject(TimeUnit.class))).andThrow(new RuntimeException(new TimeoutException())); + expect(future.cancel(true)).andReturn(true); + replay(future); + + AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class); + expect(asyncBlobStore.list(anyObject(String.class), anyObject(ListContainerOptions.class))).andReturn(future); + replay(asyncBlobStore); + + deleter = new DeleteAllKeysInList(null, asyncBlobStore, null); + try { + deleter.execute(containerName, ListContainerOptions.NONE); + fail(); + } catch (Exception e) { + if (Throwables2.getFirstThrowableOfType(e, TimeoutException.class) == null) { + throw e; + } + } + } + /** * Create a container "container" with 1111 blobs named "blob-%d". Create a * subdirectory "directory" which contains 2222 more blobs named diff --git a/core/src/main/java/org/jclouds/Constants.java b/core/src/main/java/org/jclouds/Constants.java index 70e715f3ea..1b0d770378 100644 --- a/core/src/main/java/org/jclouds/Constants.java +++ b/core/src/main/java/org/jclouds/Constants.java @@ -153,7 +153,7 @@ public interface Constants { /** * Long property. *

- * longest time a single request can take before throwing an exception. + * Maximum duration in milliseconds a single request can take before throwing an exception. */ public static final String PROPERTY_REQUEST_TIMEOUT = "jclouds.request-timeout"; /**