Skip to content

Commit cf49522

Browse files
committed
JAVA-853: Properly handling nested calls to DB.requestStart/requestDone by keeping tracking of the nesting depth, and only removing the thread local when the depth returns to 0.
1 parent 150e08e commit cf49522

File tree

2 files changed

+75
-35
lines changed

2 files changed

+75
-35
lines changed

src/main/com/mongodb/DBTCPConnector.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ public List<ServerAddress> getAllAddress() {
293293
* Gets the list of server addresses currently seen by the connector.
294294
* This includes addresses auto-discovered from a replica set.
295295
* @return
296-
* @throws MongoException
296+
* @throws MongoException
297297
*/
298298
public List<ServerAddress> getServerAddressList() {
299299
if (_connectionStatus != null) {
@@ -406,10 +406,10 @@ DBPort get( boolean keep , ReadPreference readPref, ServerAddress hostNeeded ){
406406
else {
407407
ReplicaSetStatus.ReplicaSet replicaSet = getReplicaSetStatus()._replicaSetHolder.get();
408408
ConnectionStatus.Node node = readPref.getNode(replicaSet);
409-
409+
410410
if (node == null)
411411
throw new MongoException("No replica set members available in " + replicaSet + " for " + readPref.toDBObject().toString());
412-
412+
413413
port = _portHolder.get(node.getServerAddress()).get();
414414
}
415415

@@ -460,14 +460,27 @@ void requestEnsureConnection(){
460460
}
461461

462462
void requestStart(){
463-
pinnedRequestStatusThreadLocal.set(new PinnedRequestStatus());
463+
PinnedRequestStatus current = getPinnedRequestStatusForThread();
464+
if (current == null) {
465+
pinnedRequestStatusThreadLocal.set(new PinnedRequestStatus());
466+
}
467+
else {
468+
current.nestedBindings++;
469+
}
464470
}
465471

466472
void requestDone(){
467-
DBPort requestPort = getPinnedRequestPortForThread();
468-
if ( requestPort != null )
469-
requestPort.getPool().done( requestPort );
470-
pinnedRequestStatusThreadLocal.remove();
473+
PinnedRequestStatus current = getPinnedRequestStatusForThread();
474+
if (current != null) {
475+
if (current.nestedBindings > 0) {
476+
current.nestedBindings--;
477+
}
478+
else {
479+
pinnedRequestStatusThreadLocal.remove();
480+
if (current.requestPort != null)
481+
current.requestPort.getPool().done(current.requestPort);
482+
}
483+
}
471484
}
472485

473486
PinnedRequestStatus getPinnedRequestStatusForThread() {
@@ -491,6 +504,7 @@ void setPinnedRequestPortForThread(final DBPort port) {
491504

492505
static class PinnedRequestStatus {
493506
DBPort requestPort;
507+
public int nestedBindings;
494508
}
495509

496510
void checkMaster( boolean force , boolean failIfNoMaster ){

src/test/com/mongodb/DBTest.java

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,67 +25,65 @@ public class DBTest extends TestCase {
2525

2626
public DBTest() {
2727
super();
28-
cleanupDB = "com_mongodb_unittest_DBTest";
29-
_db = cleanupMongo.getDB( cleanupDB );
28+
cleanupDB = "com_mongodb_unittest_DBTest";
29+
_db = cleanupMongo.getDB(cleanupDB);
3030
}
3131

3232
@Test(groups = {"basic"})
3333
public void testCreateCollection() {
34-
_db.getCollection( "foo1" ).drop();
35-
_db.getCollection( "foo2" ).drop();
36-
_db.getCollection( "foo3" ).drop();
37-
_db.getCollection( "foo4" ).drop();
34+
_db.getCollection("foo1").drop();
35+
_db.getCollection("foo2").drop();
36+
_db.getCollection("foo3").drop();
37+
_db.getCollection("foo4").drop();
3838

3939
BasicDBObject o1 = new BasicDBObject("capped", false);
4040
DBCollection c = _db.createCollection("foo1", o1);
4141

4242
DBObject o2 = BasicDBObjectBuilder.start().add("capped", true)
43-
.add("size", 100000).add("max", 10).get();
43+
.add("size", 100000).add("max", 10).get();
4444
c = _db.createCollection("foo2", o2);
45-
for (int i=0; i<30; i++) {
45+
for (int i = 0; i < 30; i++) {
4646
c.insert(new BasicDBObject("x", i));
4747
}
4848
assertTrue(c.find().count() <= 10);
4949

5050
DBObject o3 = BasicDBObjectBuilder.start().add("capped", true)
51-
.add("size", 1000).add("max", 2).get();
51+
.add("size", 1000).add("max", 2).get();
5252
c = _db.createCollection("foo3", o3);
53-
for (int i=0; i<30; i++) {
53+
for (int i = 0; i < 30; i++) {
5454
c.insert(new BasicDBObject("x", i));
5555
}
5656
assertEquals(c.find().count(), 2);
5757

5858
try {
5959
DBObject o4 = BasicDBObjectBuilder.start().add("capped", true)
60-
.add("size", -20).get();
60+
.add("size", -20).get();
6161
c = _db.createCollection("foo4", o4);
62-
}
63-
catch(MongoException e) {
62+
} catch (MongoException e) {
6463
return;
6564
}
6665
assertEquals(0, 1);
6766
}
6867

6968
@Test(groups = {"basic"})
70-
public void testForCollectionExistence()
71-
{
72-
_db.getCollection( "foo1" ).drop();
73-
_db.getCollection( "foo2" ).drop();
74-
_db.getCollection( "foo3" ).drop();
75-
_db.getCollection( "foo4" ).drop();
69+
public void testForCollectionExistence() {
70+
_db.getCollection("foo1").drop();
71+
_db.getCollection("foo2").drop();
72+
_db.getCollection("foo3").drop();
73+
_db.getCollection("foo4").drop();
7674

77-
assertFalse(_db.collectionExists( "foo1" ));
75+
assertFalse(_db.collectionExists("foo1"));
7876

7977
BasicDBObject o1 = new BasicDBObject("capped", false);
8078
DBCollection c = _db.createCollection("foo1", o1);
8179

82-
assertTrue(_db.collectionExists( "foo1" ), "Collection 'foo' was supposed to be created, but 'collectionExists' did not return true.");
83-
assertTrue(_db.collectionExists( "FOO1" ));
84-
assertTrue(_db.collectionExists( "fOo1" ));
80+
assertTrue(_db.collectionExists("foo1"), "Collection 'foo' was supposed to be created, but 'collectionExists' did not return true.");
81+
assertTrue(_db.collectionExists("FOO1"));
82+
assertTrue(_db.collectionExists("fOo1"));
8583

86-
_db.getCollection( "foo1" ).drop();
84+
_db.getCollection("foo1").drop();
8785

88-
assertFalse(_db.collectionExists( "foo1" ));
86+
assertFalse(_db.collectionExists("foo1"));
8987
}
9088

9189
@Test(groups = {"basic"})
@@ -148,6 +146,34 @@ public void testEnsureConnection() throws UnknownHostException {
148146
}
149147
}
150148

149+
@Test(groups = {"basic"})
150+
public void whenRequestStartCallsAreNestedThenTheConnectionShouldBeReleaseOnLastCallToRequestEnd() throws UnknownHostException {
151+
Mongo m = new MongoClient(Arrays.asList(new ServerAddress("localhost")),
152+
MongoClientOptions.builder().connectionsPerHost(1).maxWaitTime(10).build());
153+
DB db = m.getDB("com_mongodb_unittest_DBTest");
154+
155+
try {
156+
db.requestStart();
157+
try {
158+
db.command(new BasicDBObject("ping", 1));
159+
db.requestStart();
160+
try {
161+
db.command(new BasicDBObject("ping", 1));
162+
} finally {
163+
db.requestDone();
164+
}
165+
} finally {
166+
db.requestDone();
167+
}
168+
} finally {
169+
m.close();
170+
}
171+
}
172+
173+
@Test(groups = {"basic"})
174+
public void whenRequestDoneIsCalledWithoutFirstCallingRequestStartNoExceptionIsThrown() throws UnknownHostException {
175+
_db.requestDone();
176+
}
151177

152178

153179
/*public static class Person extends DBObject {
@@ -194,8 +220,8 @@ public void test1(){
194220

195221
final DB _db;
196222

197-
public static void main( String args[] )
198-
throws Exception {
223+
public static void main(String args[])
224+
throws Exception {
199225
(new DBTest()).runConsole();
200226
}
201227
}

0 commit comments

Comments
 (0)