Skip to content

Commit f634fe8

Browse files
committed
[JAVA-289]: detect max bson size from servers. Update whenever master changes. Fetch on 1st op in single server mode.
1 parent 170127b commit f634fe8

File tree

8 files changed

+94
-47
lines changed

8 files changed

+94
-47
lines changed

src/main/com/mongodb/Bytes.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ public class Bytes extends BSON {
4949
/** Little-endian */
5050
public static final ByteOrder ORDER = ByteOrder.LITTLE_ENDIAN;
5151

52-
/** this size is used to prevent insertion of objects that are too large for db */
53-
static final int MAX_OBJECT_SIZE = 1024 * 1024 * 32;
52+
/** this size is set low to 4MB, but just serves as safe default */
53+
static final int MAX_OBJECT_SIZE = 1024 * 1024 * 4;
5454

55-
/** target size of an insert batch */
56-
static final int BATCH_INSERT_SIZE = 1024 * 1024 * 16;
55+
/** default target size of an insert batch */
56+
static final int BATCH_INSERT_SIZE = 1024 * 1024 * 8;
5757

5858
static final int CONNECTIONS_PER_HOST = Integer.parseInt( System.getProperty( "MONGO.POOLSIZE" , "10" ) );
5959

src/main/com/mongodb/DBApiLayer.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ protected WriteResult insert(DBObject[] arr, boolean shouldApply , com.mongodb.W
211211
WriteResult last = null;
212212

213213
int cur = 0;
214+
int maxsize = _mongo.getMaxBsonObjectSize();
214215
while ( cur < arr.length ){
215216
OutMessage om = new OutMessage( _mongo , 2002 );
216217

@@ -219,14 +220,10 @@ protected WriteResult insert(DBObject[] arr, boolean shouldApply , com.mongodb.W
219220

220221
for ( ; cur<arr.length; cur++ ){
221222
DBObject o = arr[cur];
222-
int sz = om.putObject( o );
223-
// server is better suited to decide on object size
224-
// indeed driver may be talking to dbs with different limits
225-
// also max size is tough to catch on updates, so here it's just an extra check
226-
if ( sz > Bytes.MAX_OBJECT_SIZE )
227-
throw new IllegalArgumentException( "object too big: " + sz );
228-
229-
if ( om.size() > Bytes.BATCH_INSERT_SIZE ){
223+
om.putObject( o );
224+
225+
// limit for batch insert is 4 x maxbson on server, use 2 x to be safe
226+
if ( om.size() > 2 * maxsize ){
230227
cur++;
231228
break;
232229
}

src/main/com/mongodb/DBPort.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,24 +141,17 @@ synchronized CommandResult runCommand( DB db , DBObject cmd ) throws IOException
141141
return (CommandResult)res;
142142
}
143143

144-
synchronized DBObject findOne( String ns , DBObject q ){
144+
synchronized DBObject findOne( String ns , DBObject q ) throws IOException{
145145
OutMessage msg = OutMessage.query( null , 0 , ns , 0 , -1 , q , null );
146-
147-
try {
148-
Response res = go( msg , null , true );
149-
if ( res.size() == 0 )
150-
return null;
151-
if ( res.size() > 1 )
152-
throw new MongoInternalException( "something is wrong. size:" + res.size() );
153-
return res.get(0);
154-
}
155-
catch ( IOException ioe ){
156-
throw new MongoException.Network( "DBPort.findOne failed" , ioe );
157-
}
158-
146+
Response res = go( msg , null , true );
147+
if ( res.size() == 0 )
148+
return null;
149+
if ( res.size() > 1 )
150+
throw new MongoInternalException( "something is wrong. size:" + res.size() );
151+
return res.get(0);
159152
}
160153

161-
synchronized CommandResult runCommand( String db , DBObject cmd ) {
154+
synchronized CommandResult runCommand( String db , DBObject cmd ) throws IOException {
162155
DBObject res = findOne( db + ".$cmd" , cmd );
163156
if ( res == null )
164157
throw new MongoInternalException( "something is wrong, no command result" );

src/main/com/mongodb/DBTCPConnector.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,11 +400,41 @@ void checkMaster( boolean force , boolean failIfNoMaster )
400400
}
401401
else {
402402
_set( n._addr );
403+
maxBsonObjectSize = _rsStatus.getMaxBsonObjectSize();
403404
}
404405
}
406+
} else {
407+
// single server, may have to obtain max bson size
408+
if (maxBsonObjectSize == 0)
409+
maxBsonObjectSize = fetchMaxBsonObjectSize();
410+
}
411+
}
412+
413+
/**
414+
* Fetches the maximum size for a BSON object from the current master server
415+
* @return the size, or 0 if it could not be obtained
416+
*/
417+
int fetchMaxBsonObjectSize() {
418+
if (_masterPortPool == null)
419+
return 0;
420+
DBPort port = _masterPortPool.get();
421+
try {
422+
CommandResult res = port.runCommand(_mongo.getDB("admin"), new BasicDBObject("isMaster", 1));
423+
// max size was added in 1.8
424+
if (res.containsField("maxBsonObjectSize")) {
425+
maxBsonObjectSize = ((Integer) res.get("maxBsonObjectSize")).intValue();
426+
} else {
427+
maxBsonObjectSize = Bytes.MAX_OBJECT_SIZE;
428+
}
429+
} catch (Exception e) {
430+
_logger.log(Level.WARNING, null, e);
431+
} finally {
432+
port.getPool().done(port);
405433
}
434+
return maxBsonObjectSize;
406435
}
407436

437+
408438
void testMaster()
409439
throws MongoException {
410440

@@ -469,13 +499,23 @@ public boolean isOpen(){
469499
return ! _closed;
470500
}
471501

502+
/**
503+
* Gets the maximum size for a BSON object supported by the current master server.
504+
* Note that this value may change over time depending on which server is master.
505+
* @return the maximum size, or 0 if not obtained from servers yet.
506+
*/
507+
public int getMaxBsonObjectSize() {
508+
return maxBsonObjectSize;
509+
}
510+
472511
private Mongo _mongo;
473512
// private ServerAddress _curMaster;
474513
private DBPortPool _masterPortPool;
475514
private DBPortPool.Holder _portHolder;
476515
private final List<ServerAddress> _allHosts;
477516
private final ReplicaSetStatus _rsStatus;
478517
private boolean _closed = false;
518+
private int maxBsonObjectSize = 0;
479519

480520
private ThreadLocal<MyPort> _myPort = new ThreadLocal<MyPort>(){
481521
protected MyPort initialValue(){

src/main/com/mongodb/Mongo.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -516,22 +516,15 @@ void _applyMongoOptions() {
516516

517517
/**
518518
* Gets the maximum size for a BSON object supported by the current master server.
519-
* Note that this method may make a request to the server to obtain the size.
520-
* @throws MongoException
521-
* @return the size supported, or 0 if it cannot be determined.
519+
* Note that this value may change over time depending on which server is master.
520+
* If the size is not known yet, a request may be sent to the master server
521+
* @return the maximum size
522522
*/
523523
public int getMaxBsonObjectSize() {
524-
int size = 0;
525-
if (_connector.getReplicaSetStatus() != null)
526-
size = _connector.getReplicaSetStatus().getMaxBsonObjectSize();
527-
if (size == 0) {
528-
// need to fetch size
529-
DB db = getDB("admin");
530-
CommandResult res = db.command("isMaster");
531-
if (res.containsField("maxBsonObjectSize"))
532-
size = ((Integer)res.get( "maxBsonObjectSize" )).intValue();
533-
}
534-
return size;
524+
int maxsize = _connector.getMaxBsonObjectSize();
525+
if (maxsize == 0)
526+
maxsize = _connector.fetchMaxBsonObjectSize();
527+
return maxsize > 0 ? maxsize : Bytes.MAX_OBJECT_SIZE;
535528
}
536529

537530
final ServerAddress _addr;

src/main/com/mongodb/OutMessage.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,20 @@ int getId(){
183183
return _id;
184184
}
185185

186+
@Override
187+
public int putObject(BSONObject o) {
188+
// check max size
189+
int sz = super.putObject(o);
190+
if (_mongo != null) {
191+
int maxsize = _mongo.getConnector().getMaxBsonObjectSize();
192+
maxsize = Math.max(maxsize, Bytes.MAX_OBJECT_SIZE);
193+
if (sz > maxsize) {
194+
throw new MongoInternalException("DBObject of size " + sz + " is over Max BSON size " + _mongo.getMaxBsonObjectSize());
195+
}
196+
}
197+
return sz;
198+
}
199+
186200
private Mongo _mongo;
187201
private PoolOutputBuffer _buffer;
188202
private int _id;

src/main/com/mongodb/ReplicaSetStatus.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,13 @@ synchronized void update(Set<Node> seenNodes){
170170
}
171171
}
172172

173-
if (_isMaster && res.containsField("maxBsonObjectSize"))
174-
_maxBsonObjectSize = ((Integer)res.get( "maxBsonObjectSize" )).intValue();
173+
if (_isMaster ) {
174+
// max size was added in 1.8
175+
if (res.containsField("maxBsonObjectSize"))
176+
maxBsonObjectSize = ((Integer)res.get( "maxBsonObjectSize" )).intValue();
177+
else
178+
maxBsonObjectSize = Bytes.MAX_OBJECT_SIZE;
179+
}
175180

176181
}
177182
catch ( MongoException e ){
@@ -392,15 +397,20 @@ void close(){
392397
_closed = true;
393398
}
394399

400+
/**
401+
* Gets the maximum size for a BSON object supported by the current master server.
402+
* Note that this value may change over time depending on which server is master.
403+
* @return the maximum size, or 0 if not obtained from servers yet.
404+
*/
395405
public int getMaxBsonObjectSize() {
396-
return _maxBsonObjectSize;
406+
return maxBsonObjectSize;
397407
}
398408

399409
final List<Node> _all;
400410
Updater _updater;
401411
Mongo _mongo;
402412
String _setName = null; // null until init
403-
int _maxBsonObjectSize = 0;
413+
int maxBsonObjectSize = 0;
404414
Logger _logger = _rootLogger; // will get changed to use set name once its found
405415

406416
String _lastPrimarySignal;

src/test/com/mongodb/JavaClientTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ public void testObjectIdCompat2(){
535535
@Test
536536
public void testLargeBulkInsert(){
537537
// max size should be obtained from server
538-
int maxObjSize = 16 * 1024 * 1024;
538+
int maxObjSize = _mongo.getMaxBsonObjectSize();
539539
DBCollection c = _db.getCollection( "largebulk" );
540540
c.drop();
541541
String s = "asdasdasd";
@@ -562,7 +562,7 @@ public void testLargeBulkInsert(){
562562
c.save( new BasicDBObject( "foo" , s ) );
563563
worked = true;
564564
}
565-
catch ( IllegalArgumentException ie ){}
565+
catch ( MongoException ie ){}
566566
assertFalse( worked );
567567

568568
assertEquals( num , c.find().count() );

0 commit comments

Comments
 (0)