Skip to content

Commit eb06150

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 ebbf0dc commit eb06150

2 files changed

Lines changed: 75 additions & 35 deletions

File tree

src/main/com/mongodb/DBTCPConnector.java

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

@@ -464,14 +464,27 @@ void requestEnsureConnection(){
464464
}
465465

466466
void requestStart(){
467-
pinnedRequestStatusThreadLocal.set(new PinnedRequestStatus());
467+
PinnedRequestStatus current = getPinnedRequestStatusForThread();
468+
if (current == null) {
469+
pinnedRequestStatusThreadLocal.set(new PinnedRequestStatus());
470+
}
471+
else {
472+
current.nestedBindings++;
473+
}
468474
}
469475

470476
void requestDone(){
471-
DBPort requestPort = getPinnedRequestPortForThread();
472-
if ( requestPort != null )
473-
requestPort.getPool().done( requestPort );
474-
pinnedRequestStatusThreadLocal.remove();
477+
PinnedRequestStatus current = getPinnedRequestStatusForThread();
478+
if (current != null) {
479+
if (current.nestedBindings > 0) {
480+
current.nestedBindings--;
481+
}
482+
else {
483+
pinnedRequestStatusThreadLocal.remove();
484+
if (current.requestPort != null)
485+
current.requestPort.getPool().done(current.requestPort);
486+
}
487+
}
475488
}
476489

477490
PinnedRequestStatus getPinnedRequestStatusForThread() {
@@ -495,6 +508,7 @@ void setPinnedRequestPortForThread(final DBPort port) {
495508

496509
static class PinnedRequestStatus {
497510
DBPort requestPort;
511+
public int nestedBindings;
498512
}
499513

500514
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)