Skip to content

Commit 2bbfac6

Browse files
committed
JAVA-635: Added MongoInterruptedException, a runtime exception that wraps an InterruptedException. An instance of this class is thrown in cases where the driver is sleeping or waiting on a condition, and has to catch InterruptedException and do something besides swallowing it. Since InterruptedException is checked and so can't be thrown from methods that don't declare it, best thing to do it throw a runtime exception that can be handled in the application
1 parent 7963728 commit 2bbfac6

File tree

8 files changed

+112
-36
lines changed

8 files changed

+112
-36
lines changed

src/main/com/mongodb/DBApiLayer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ public boolean hasNext(){
411411
try {
412412
Thread.sleep(500);
413413
} catch (InterruptedException e) {
414-
// ignore
414+
throw new MongoInterruptedException(e);
415415
}
416416
}
417417
}

src/main/com/mongodb/DBPortPool.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.mongodb.util.management.JMException;
2424
import com.mongodb.util.management.MBeanServerFactory;
2525

26+
import java.io.InterruptedIOException;
2627
import java.util.ArrayList;
2728
import java.util.Collections;
2829
import java.util.HashMap;
@@ -193,8 +194,9 @@ public DBPort get() {
193194

194195
try {
195196
port = get( _options.maxWaitTime );
196-
}
197-
finally {
197+
} catch (InterruptedException e) {
198+
throw new MongoInterruptedException(e);
199+
} finally {
198200
_waitingSem.release();
199201
}
200202

@@ -207,15 +209,14 @@ public DBPort get() {
207209

208210
// return true if the exception is recoverable
209211
boolean gotError( Exception e ){
210-
if ( e instanceof java.nio.channels.ClosedByInterruptException ||
211-
e instanceof InterruptedException ){
212+
if (e instanceof java.nio.channels.ClosedByInterruptException){
212213
// this is probably a request that is taking too long
213214
// so usually doesn't mean there is a real db problem
214215
return true;
215216
}
216217

217-
if ( e instanceof java.net.SocketTimeoutException ){
218-
// we don't want to clear the port pool for a connection timing out
218+
if ( e instanceof InterruptedIOException){
219+
// we don't want to clear the port pool for a connection timing out or interrupted
219220
return true;
220221
}
221222
Bytes.LOGGER.log( Level.WARNING , "emptying DBPortPool to " + getServerAddress() + " b/c of error" , e );
@@ -224,10 +225,14 @@ boolean gotError( Exception e ){
224225

225226
List<DBPort> all = new ArrayList<DBPort>();
226227
while ( true ){
227-
DBPort temp = get(0);
228-
if ( temp == null )
229-
break;
230-
all.add( temp );
228+
try {
229+
DBPort temp = get(0);
230+
if ( temp == null )
231+
break;
232+
all.add( temp );
233+
} catch (InterruptedException interruptedException) {
234+
throw new MongoInterruptedException(interruptedException);
235+
}
231236
}
232237

233238
for ( DBPort p : all ){

src/main/com/mongodb/DynamicConnectionStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ private synchronized ConnectionStatus getConnectionStatus() {
183183
try {
184184
wait(_mongoOptions.connectTimeout);
185185
} catch (InterruptedException e) {
186-
throw new MongoException("Interrupted while waiting for next update to dynamic status", e);
186+
throw new MongoInterruptedException("Interrupted while waiting for next update to dynamic status", e);
187187
}
188188
}
189189
return connectionStatus;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright (c) 2008 - 2012 10gen, Inc. <http://10gen.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.mongodb;
19+
20+
/**
21+
* A non-checked exception indicating that the driver has been interrupted by a call to Thread.interrupt.
22+
*
23+
* @see Thread#interrupt()
24+
* @see InterruptedException
25+
*/
26+
public class MongoInterruptedException extends MongoException {
27+
public MongoInterruptedException(final InterruptedException e) {
28+
super("A driver operation has been interrupted", e);
29+
}
30+
31+
public MongoInterruptedException(final String message, final InterruptedException e) {
32+
super(message, e);
33+
}
34+
}

src/main/com/mongodb/MongosStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ private synchronized Node getPreferred() {
122122
wait();
123123
}
124124
} catch (InterruptedException e) {
125-
throw new MongoException("Interrupted while waiting for next update to mongos status", e);
125+
throw new MongoInterruptedException("Interrupted while waiting for next update to mongos status", e);
126126
}
127127
}
128128
return preferred;

src/main/com/mongodb/ReplicaSetStatus.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ synchronized ReplicaSet get() {
134134
wait(ReplicaSetStatus.mongoOptionsDefaults.socketTimeout);
135135
}
136136
catch (InterruptedException e) {
137-
throw new MongoException("Interrupted while waiting for next update to replica set status", e);
137+
throw new MongoInterruptedException("Interrupted while waiting for next update to replica set status", e);
138138
}
139139
}
140140
return members;
@@ -156,7 +156,7 @@ synchronized void waitForNextUpdate() {
156156
wait(ReplicaSetStatus.mongoOptionsDefaults.socketTimeout);
157157
}
158158
catch (InterruptedException e) {
159-
throw new MongoException("Interrupted while waiting for next update to replica set status", e);
159+
throw new MongoInterruptedException("Interrupted while waiting for next update to replica set status", e);
160160
}
161161
}
162162

src/main/com/mongodb/util/SimplePool.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void remove( T t ) {
9595
/** Gets an object from the pool - will block if none are available
9696
* @return An object from the pool
9797
*/
98-
public T get() {
98+
public T get() throws InterruptedException {
9999
return get(-1);
100100
}
101101

@@ -106,7 +106,7 @@ public T get() {
106106
* positive ms to wait
107107
* @return An object from the pool, or null if can't get one in the given waitTime
108108
*/
109-
public T get(long waitTime) {
109+
public T get(long waitTime) throws InterruptedException {
110110
if (!permitAcquired(waitTime)) {
111111
return null;
112112
}
@@ -143,18 +143,14 @@ private T createNewAndReleasePermitIfFailure() {
143143
}
144144
}
145145

146-
private boolean permitAcquired(final long waitTime) {
147-
try {
148-
if (waitTime > 0) {
149-
return _sem.tryAcquire(waitTime, TimeUnit.MILLISECONDS);
150-
} else if (waitTime < 0) {
151-
_sem.acquire();
152-
return true;
153-
} else {
154-
return _sem.tryAcquire();
155-
}
156-
} catch (InterruptedException e) {
157-
return false;
146+
private boolean permitAcquired(final long waitTime) throws InterruptedException {
147+
if (waitTime > 0) {
148+
return _sem.tryAcquire(waitTime, TimeUnit.MILLISECONDS);
149+
} else if (waitTime < 0) {
150+
_sem.acquire();
151+
return true;
152+
} else {
153+
return _sem.tryAcquire();
158154
}
159155
}
160156

src/test/com/mongodb/util/SimplePoolTest.java

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616

1717
package com.mongodb.util;
1818

19+
import java.util.concurrent.Callable;
20+
import java.util.concurrent.ExecutionException;
21+
import java.util.concurrent.ExecutorService;
22+
import java.util.concurrent.Executors;
23+
import java.util.concurrent.Future;
24+
1925
public class SimplePoolTest extends com.mongodb.util.TestCase {
2026

2127
class MyPool extends SimplePool<Integer> {
@@ -41,7 +47,7 @@ public Integer createNew(){
4147
}
4248

4349
@org.testng.annotations.Test
44-
public void testBasic1(){
50+
public void testBasic1() throws InterruptedException {
4551
MyPool p = new MyPool( 10 );
4652

4753
int a = p.get();
@@ -56,7 +62,7 @@ public void testBasic1(){
5662
}
5763

5864
@org.testng.annotations.Test
59-
public void testMax1(){
65+
public void testMax1() throws InterruptedException {
6066
MyPool p = new MyPool( 10 );
6167

6268
int a = p.get();
@@ -70,7 +76,7 @@ public void testMax1(){
7076
}
7177

7278
@org.testng.annotations.Test
73-
public void testMax2(){
79+
public void testMax2() throws InterruptedException {
7480
MyPool p = new MyPool( 10 );
7581

7682
int a = p.get();
@@ -83,7 +89,7 @@ public void testMax2(){
8389
}
8490

8591
@org.testng.annotations.Test
86-
public void testMax3(){
92+
public void testMax3() throws InterruptedException {
8793
MyPool p = new MyPool( 10 );
8894

8995
int a = p.get();
@@ -96,7 +102,7 @@ public void testMax3(){
96102
}
97103

98104
@org.testng.annotations.Test
99-
public void testThrowErrorFromCreate(){
105+
public void testThrowErrorFromCreate() throws InterruptedException {
100106
MyPool p = new MyPool( 1 );
101107
p._throwError = true;
102108

@@ -115,7 +121,7 @@ public void testThrowErrorFromCreate(){
115121
}
116122

117123
@org.testng.annotations.Test
118-
public void testCouldCreate() {
124+
public void testCouldCreate() throws InterruptedException {
119125
SimplePool<Integer> p = new SimplePool<Integer>("pool", 2) {
120126
@Override
121127
protected Integer createNew() {
@@ -145,7 +151,7 @@ protected int pick(int recommended, boolean couldCreate) {
145151
}
146152

147153
@org.testng.annotations.Test
148-
public void testReturnNullFromCreate(){
154+
public void testReturnNullFromCreate() throws InterruptedException {
149155
MyPool p = new MyPool( 1 );
150156
p._returnNull = true;
151157

@@ -163,6 +169,41 @@ public void testReturnNullFromCreate(){
163169
assertEquals( Integer.valueOf(0) , a );
164170
}
165171

172+
@org.testng.annotations.Test()
173+
public void testThrowsInterruptedException() {
174+
final MyPool p = new MyPool(1);
175+
try {
176+
p.get();
177+
} catch (InterruptedException e) {
178+
fail("Should not throw InterruptedException here");
179+
}
180+
181+
ExecutorService executor = Executors.newSingleThreadExecutor();
182+
Callable<Boolean> callable = new Callable<Boolean>() {
183+
@Override
184+
public Boolean call() {
185+
try {
186+
p.get();
187+
return false;
188+
} catch (InterruptedException e) {
189+
// return true if interrupted
190+
return true;
191+
}
192+
}
193+
};
194+
Future<Boolean> future = executor.submit(callable);
195+
196+
// Interrupt the thread
197+
executor.shutdownNow();
198+
199+
try {
200+
assertEquals(true, future.get());
201+
} catch (InterruptedException e) {
202+
fail("Should not happen, since this thread was not interrupted");
203+
} catch (ExecutionException e) {
204+
fail("Should not happen");
205+
}
206+
}
166207

167208
public static void main( String args[] ){
168209
SimplePoolTest t = new SimplePoolTest();

0 commit comments

Comments
 (0)