Skip to content

Commit 84ebf9a

Browse files
daschlMichael Nitschinger
authored andcommitted
SPY-112: Throw CancellationException when future is cancelled.
This changeset throws the semantically more correct CancellationException when a operation future is cancelled. Old code that catches RuntimeExceptions will still work, but it allows for more flexible catching on the application level. Change-Id: I476f06e8989f06423be6e186c6565179e270df13 Reviewed-on: http://review.couchbase.org/24654 Reviewed-by: Matt Ingenthron <[email protected]> Tested-by: Michael Nitschinger <[email protected]>
1 parent 781cb7e commit 84ebf9a

File tree

4 files changed

+43
-9
lines changed

4 files changed

+43
-9
lines changed

src/main/java/net/spy/memcached/MemcachedClient.java

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.List;
3535
import java.util.Map;
3636
import java.util.Set;
37+
import java.util.concurrent.CancellationException;
3738
import java.util.concurrent.ConcurrentHashMap;
3839
import java.util.concurrent.ConcurrentLinkedQueue;
3940
import java.util.concurrent.ConcurrentMap;
@@ -558,6 +559,7 @@ public <T> CASResponse cas(String key, long casId, T value,
558559
* @param tc the transcoder to serialize and unserialize the value
559560
* @return a CASResponse
560561
* @throws OperationTimeoutException if global operation timeout is exceeded
562+
* @throws CancellationException if operation was canceled
561563
* @throws IllegalStateException in the rare circumstance where queue is too
562564
* full to accept any more requests
563565
*/
@@ -573,7 +575,11 @@ public <T> CASResponse cas(String key, long casId, int exp, T value,
573575
} catch (InterruptedException e) {
574576
throw new RuntimeException("Interrupted waiting for value", e);
575577
} catch (ExecutionException e) {
576-
throw new RuntimeException("Exception waiting for value", e);
578+
if(e.getCause() instanceof CancellationException) {
579+
throw (CancellationException) e.getCause();
580+
} else {
581+
throw new RuntimeException("Exception waiting for value", e);
582+
}
577583
} catch (TimeoutException e) {
578584
throw new OperationTimeoutException("Timeout waiting for value", e);
579585
}
@@ -922,6 +928,7 @@ public OperationFuture<CASValue<Object>> asyncGets(final String key) {
922928
* @param tc the transcoder to serialize and unserialize value
923929
* @return the result from the cache and CAS id (null if there is none)
924930
* @throws OperationTimeoutException if global operation timeout is exceeded
931+
* @throws CancellationException if operation was canceled
925932
* @throws IllegalStateException in the rare circumstance where queue is too
926933
* full to accept any more requests
927934
*/
@@ -931,7 +938,11 @@ public <T> CASValue<T> gets(String key, Transcoder<T> tc) {
931938
} catch (InterruptedException e) {
932939
throw new RuntimeException("Interrupted waiting for value", e);
933940
} catch (ExecutionException e) {
934-
throw new RuntimeException("Exception waiting for value", e);
941+
if(e.getCause() instanceof CancellationException) {
942+
throw (CancellationException) e.getCause();
943+
} else {
944+
throw new RuntimeException("Exception waiting for value", e);
945+
}
935946
} catch (TimeoutException e) {
936947
throw new OperationTimeoutException("Timeout waiting for value", e);
937948
}
@@ -947,6 +958,7 @@ public <T> CASValue<T> gets(String key, Transcoder<T> tc) {
947958
* @return the result from the cache (null if there is none)
948959
* @throws OperationTimeoutException if the global operation timeout is
949960
* exceeded
961+
* @throws CancellationException if operation was canceled
950962
* @throws IllegalStateException in the rare circumstance where queue is too
951963
* full to accept any more requests
952964
*/
@@ -957,7 +969,11 @@ public <T> CASValue<T> getAndTouch(String key, int exp, Transcoder<T> tc) {
957969
} catch (InterruptedException e) {
958970
throw new RuntimeException("Interrupted waiting for value", e);
959971
} catch (ExecutionException e) {
960-
throw new RuntimeException("Exception waiting for value", e);
972+
if(e.getCause() instanceof CancellationException) {
973+
throw (CancellationException) e.getCause();
974+
} else {
975+
throw new RuntimeException("Exception waiting for value", e);
976+
}
961977
} catch (TimeoutException e) {
962978
throw new OperationTimeoutException("Timeout waiting for value", e);
963979
}
@@ -1001,6 +1017,7 @@ public CASValue<Object> gets(String key) {
10011017
* @return the result from the cache (null if there is none)
10021018
* @throws OperationTimeoutException if the global operation timeout is
10031019
* exceeded
1020+
* @throws CancellationException if operation was canceled
10041021
* @throws IllegalStateException in the rare circumstance where queue is too
10051022
* full to accept any more requests
10061023
*/
@@ -1010,7 +1027,11 @@ public <T> T get(String key, Transcoder<T> tc) {
10101027
} catch (InterruptedException e) {
10111028
throw new RuntimeException("Interrupted waiting for value", e);
10121029
} catch (ExecutionException e) {
1013-
throw new RuntimeException("Exception waiting for value", e);
1030+
if(e.getCause() instanceof CancellationException) {
1031+
throw (CancellationException) e.getCause();
1032+
} else {
1033+
throw new RuntimeException("Exception waiting for value", e);
1034+
}
10141035
} catch (TimeoutException e) {
10151036
throw new OperationTimeoutException("Timeout waiting for value", e);
10161037
}
@@ -1294,6 +1315,7 @@ public void gotData(String k, int flags, long cas, byte[] data) {
12941315
* @return a map of the values (for each value that exists)
12951316
* @throws OperationTimeoutException if the global operation timeout is
12961317
* exceeded
1318+
* @throws CancellationException if operation was canceled
12971319
* @throws IllegalStateException in the rare circumstance where queue is too
12981320
* full to accept any more requests
12991321
*/
@@ -1305,9 +1327,13 @@ public <T> Map<String, T> getBulk(Iterator<String> keyIter,
13051327
} catch (InterruptedException e) {
13061328
throw new RuntimeException("Interrupted getting bulk values", e);
13071329
} catch (ExecutionException e) {
1308-
throw new RuntimeException("Failed getting bulk values", e);
1330+
if(e.getCause() instanceof CancellationException) {
1331+
throw (CancellationException) e.getCause();
1332+
} else {
1333+
throw new RuntimeException("Exception waiting for bulk values", e);
1334+
}
13091335
} catch (TimeoutException e) {
1310-
throw new OperationTimeoutException("Timeout waiting for bulkvalues", e);
1336+
throw new OperationTimeoutException("Timeout waiting for bulk values", e);
13111337
}
13121338
}
13131339

@@ -1681,7 +1707,11 @@ private long mutateWithDefault(Mutator t, String key, long by, long def,
16811707
} catch (InterruptedException e) {
16821708
throw new RuntimeException("Interrupted waiting for store", e);
16831709
} catch (ExecutionException e) {
1684-
throw new RuntimeException("Failed waiting for store", e);
1710+
if(e.getCause() instanceof CancellationException) {
1711+
throw (CancellationException) e.getCause();
1712+
} else {
1713+
throw new RuntimeException("Failed waiting for store", e);
1714+
}
16851715
} catch (TimeoutException e) {
16861716
throw new OperationTimeoutException("Timeout waiting to mutate or init"
16871717
+ " value", e);

src/main/java/net/spy/memcached/internal/BulkGetFuture.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.HashMap;
2828
import java.util.HashSet;
2929
import java.util.Map;
30+
import java.util.concurrent.CancellationException;
3031
import java.util.concurrent.CountDownLatch;
3132
import java.util.concurrent.ExecutionException;
3233
import java.util.concurrent.Future;
@@ -149,7 +150,7 @@ private Map<String, T> internalGet(long to, TimeUnit unit,
149150
}
150151
for (Operation op : ops) {
151152
if (op.isCancelled()) {
152-
throw new ExecutionException(new RuntimeException("Cancelled"));
153+
throw new ExecutionException(new CancellationException("Cancelled"));
153154
}
154155
if (op.hasErrored()) {
155156
throw new ExecutionException(op.getException());

src/main/java/net/spy/memcached/internal/OperationFuture.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
package net.spy.memcached.internal;
2525

26+
import java.util.concurrent.CancellationException;
2627
import java.util.concurrent.CountDownLatch;
2728
import java.util.concurrent.ExecutionException;
2829
import java.util.concurrent.Future;
@@ -166,7 +167,7 @@ public T get(long duration, TimeUnit units) throws InterruptedException,
166167
throw new ExecutionException(op.getException());
167168
}
168169
if (isCancelled()) {
169-
throw new ExecutionException(new RuntimeException("Cancelled"));
170+
throw new ExecutionException(new CancellationException("Cancelled"));
170171
}
171172
if (op != null && op.isTimedOut()) {
172173
throw new ExecutionException(new CheckedOperationTimeoutException(

src/test/java/net/spy/memcached/CancellationBaseCase.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.ArrayList;
2727
import java.util.Arrays;
2828
import java.util.Collections;
29+
import java.util.concurrent.CancellationException;
2930
import java.util.concurrent.ExecutionException;
3031
import java.util.concurrent.Future;
3132
import java.util.concurrent.TimeUnit;
@@ -57,6 +58,7 @@ private void tryCancellation(Future<?> f) throws Exception {
5758
fail("Expected cancellation, got " + o);
5859
} catch (ExecutionException e) {
5960
assertTrue(e.getCause() instanceof RuntimeException);
61+
assertTrue(e.getCause() instanceof CancellationException);
6062
assertEquals("Cancelled", e.getCause().getMessage());
6163
}
6264
}

0 commit comments

Comments
 (0)