Skip to content

Commit 8a955e2

Browse files
committed
[JAVA-263]: NullPointerException due to race condition during concurrent access to DBTCPTransport, comprehensive refactoring
1 parent 2c6eb77 commit 8a955e2

File tree

4 files changed

+63
-52
lines changed

4 files changed

+63
-52
lines changed

src/main/com/mongodb/DBPort.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
* represents a Port to the database, which is effectively a single connection to a server
3131
* Methods implemented at the port level should throw the raw exceptions like IOException,
3232
* so that the connector above can make appropriate decisions on how to handle.
33-
* @author antoine
3433
*/
3534
public class DBPort {
3635

@@ -298,7 +297,15 @@ void checkAuth( DB db ) throws IOException {
298297
throw new MongoException( "couldn't re-auth, username/password change?" );
299298
_authed.put( db , true );
300299
}
301-
300+
301+
/**
302+
* Gets the pool that this port belongs to
303+
* @return
304+
*/
305+
public DBPortPool getPool() {
306+
return _pool;
307+
}
308+
302309
final int _hashCode;
303310
final ServerAddress _sa;
304311
final InetSocketAddress _addr;

src/main/com/mongodb/DBPortPool.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ protected DBPort createNew(){
228228
return new DBPort( _addr , this , _options );
229229
}
230230

231+
public ServerAddress getServerAddress() {
232+
return _addr;
233+
}
234+
231235
final MongoOptions _options;
232236
final private Semaphore _waitingSem;
233237
final ServerAddress _addr;

src/main/com/mongodb/DBTCPConnector.java

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public DBTCPConnector( Mongo m , ServerAddress addr )
4141
if ( addr.isPaired() ){
4242
_allHosts = new ArrayList<ServerAddress>( addr.explode() );
4343
_rsStatus = new ReplicaSetStatus( m, _allHosts );
44-
_createLogger.info( "switching to replica set mode : " + _allHosts + " -> " + _curMaster );
44+
_createLogger.info( "switching to replica set mode : " + _allHosts + " -> " + getAddress() );
4545
}
4646
else {
4747
_set( addr );
@@ -64,7 +64,7 @@ public DBTCPConnector( Mongo m , List<ServerAddress> all )
6464
_allHosts = new ArrayList<ServerAddress>( all ); // make a copy so it can't be modified
6565
_rsStatus = new ReplicaSetStatus( m, _allHosts );
6666

67-
_createLogger.info( all + " -> " + _curMaster );
67+
_createLogger.info( all + " -> " + getAddress() );
6868
}
6969

7070
private static ServerAddress _checkAddress( ServerAddress addr ){
@@ -245,7 +245,8 @@ public Response call( DB db , DBCollection coll , OutMessage m , ServerAddress h
245245
}
246246

247247
public ServerAddress getAddress(){
248-
return _curMaster;
248+
DBPortPool pool = _masterPortPool;
249+
return pool != null ? pool.getServerAddress() : null;
249250
}
250251

251252
/**
@@ -264,17 +265,21 @@ public List<ServerAddress> getAllAddress() {
264265
public List<ServerAddress> getServerAddressList() {
265266
if (_rsStatus != null) {
266267
return _rsStatus.getServerAddressList();
267-
} else if (_curMaster != null) {
268+
}
269+
270+
ServerAddress master = getAddress();
271+
if (master != null) {
268272
// single server
269273
List<ServerAddress> list = new ArrayList<ServerAddress>();
270-
list.add(_curMaster);
274+
list.add(master);
271275
return list;
272276
}
273277
return null;
274278
}
275279

276280
public String getConnectPoint(){
277-
return _curMaster.toString();
281+
ServerAddress master = getAddress();
282+
return master != null ? master.toString() : null;
278283
}
279284

280285
boolean _error( Throwable t, boolean slaveOk )
@@ -292,89 +297,85 @@ DBPort get( boolean keep , boolean slaveOk , ServerAddress hostNeeded ){
292297

293298
if ( hostNeeded != null ){
294299
// asked for a specific host
295-
_pool = _portHolder.get( hostNeeded );
296-
return _pool.get();
300+
return _portHolder.get( hostNeeded ).get();
297301
}
298302

299-
if ( _port != null ){
300-
// we are within a request, should stick to same port
301-
if ( _pool == _masterPortPool ) {
302-
return _port;
303+
if ( _requestPort != null ){
304+
// we are within a request, and have a port, should stick to it
305+
if ( _requestPort.getPool() == _masterPortPool || !keep ) {
306+
// if keep is false, it's a read, so we use port even if master changed
307+
return _requestPort;
303308
}
304-
// master has changed
305-
_pool.done( _port );
306-
_port = null;
307-
_pool = null;
309+
310+
// it's write and master has changed
311+
// we fall back on new master and try to go on with request
312+
// this may not be best behavior if spec of request is to stick with same server
313+
_requestPort.getPool().done(_requestPort);
314+
_requestPort = null;
308315
}
309316

310317
if ( slaveOk && _rsStatus != null ){
311318
// if slaveOk, try to use a secondary
312319
ServerAddress slave = _rsStatus.getASecondary();
313320
if ( slave != null ){
314-
_pool = _portHolder.get( slave );
315-
return _pool.get();
321+
return _portHolder.get( slave ).get();
316322
}
317323
}
318324

319325
// use master
320-
_pool = _masterPortPool;
321-
DBPort p = _pool.get();
326+
DBPort p = _masterPortPool.get();
322327
if ( keep && _inRequest ) {
323328
// if within request, remember port to stick to same server
324-
_port = p;
329+
_requestPort = p;
325330
}
326331

327332
return p;
328333
}
329334

330335
void done( DBPort p ){
331-
if ( p != _port ){
332-
_pool.done( p );
333-
_pool = null;
334-
_slave = null;
336+
// keep request port
337+
if ( p != _requestPort ){
338+
p.getPool().done(p);
335339
}
336-
337340
}
338341

342+
/**
343+
* call this method when there is an IOException or other low level error on port.
344+
* @param p
345+
* @param e
346+
*/
339347
void error( DBPort p , Exception e ){
340-
_pool.done( p );
348+
p.getPool().done( p );
341349
p.close();
342350

343-
_port = null;
344-
_pool = null;
345-
351+
_requestPort = null;
346352
_logger.log( Level.SEVERE , "MyPort.error called" , e );
347353
}
348354

349355
void requestEnsureConnection(){
350356
if ( ! _inRequest )
351357
return;
352358

353-
if ( _port != null )
359+
if ( _requestPort != null )
354360
return;
355361

356-
if ( _pool == null )
357-
_pool = _masterPortPool;
358-
359-
_port = _pool.get();
362+
_requestPort = _masterPortPool.get();
360363
}
361364

362365
void requestStart(){
363366
_inRequest = true;
364367
}
365368

366369
void requestDone(){
367-
if ( _port != null )
368-
_pool.done( _port );
369-
_port = null;
370-
_pool = null;
370+
if ( _requestPort != null )
371+
_requestPort.getPool().done( _requestPort );
372+
_requestPort = null;
371373
_inRequest = false;
372374
}
373375

374-
DBPort _port;
375-
DBPortPool _pool;
376+
DBPort _requestPort;
377+
// DBPortPool _requestPool;
376378
boolean _inRequest;
377-
ServerAddress _slave; // slave used for last read if any
378379
}
379380

380381
void checkMaster( boolean force , boolean failIfNoMaster )
@@ -409,19 +410,18 @@ void testMaster()
409410
}
410411

411412
private boolean _set( ServerAddress addr ){
412-
if ( _curMaster == addr && _masterPortPool != null )
413-
return false;
414-
_curMaster = addr;
415413
_masterPortPool = _portHolder.get( addr );
416414
return true;
417415
}
418416

419417
public String debugString(){
420418
StringBuilder buf = new StringBuilder( "DBTCPConnector: " );
421-
if ( _allHosts != null )
419+
if ( _rsStatus != null ) {
422420
buf.append( "replica set : " ).append( _allHosts );
423-
else
424-
buf.append( _curMaster ).append( " " ).append( _curMaster._addr );
421+
} else {
422+
ServerAddress master = getAddress();
423+
buf.append( master ).append( " " ).append( master != null ? master._addr : null );
424+
}
425425

426426
return buf.toString();
427427
}
@@ -440,7 +440,7 @@ public boolean isOpen(){
440440
}
441441

442442
private Mongo _mongo;
443-
private ServerAddress _curMaster;
443+
// private ServerAddress _curMaster;
444444
private DBPortPool _masterPortPool;
445445
private DBPortPool.Holder _portHolder;
446446
private final List<ServerAddress> _allHosts;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public SimplePool( String name , int maxToKeep , int maxTotal , boolean trackLea
5959
/**
6060
* callback to determine if an object is ok to be added back to the pool or used
6161
* will be called when something is put back into the queue and when it comes out
62-
* @return true iff the object is ok to be added back to pool
62+
* @return true if the object is ok to be added back to pool
6363
*/
6464
public boolean ok( T t ){
6565
return true;

0 commit comments

Comments
 (0)