From 42e8a61ba940424f880720b5f26bb183731f8e44 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 09:09:36 -0700 Subject: [PATCH 01/31] Added license and serialVersionUID --- src/main/com/mongodb/CommandResult.java | 26 ++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/com/mongodb/CommandResult.java b/src/main/com/mongodb/CommandResult.java index df13f80b2a3..e6b18c6dda9 100644 --- a/src/main/com/mongodb/CommandResult.java +++ b/src/main/com/mongodb/CommandResult.java @@ -1,10 +1,27 @@ // CommandResult.java +/** + * Copyright (C) 2008 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.mongodb; +/** A simple wrapper for the result of getLastError() calls, and network (socket) errors. */ public class CommandResult extends BasicDBObject { - CommandResult(){ + CommandResult(){ } public boolean ok(){ @@ -47,9 +64,12 @@ public void throwOnError() DBObject _cmd; + private static final long serialVersionUID = 1L; + + static class CommandFailure extends MongoException { + private static final long serialVersionUID = 1L; - static class CommandFailure extends MongoException { - CommandFailure( CommandResult res , String msg ){ + CommandFailure( CommandResult res , String msg ){ super( ServerError.getCode( res ) , msg ); } } From d93f2aef50231499f3740215f5815cb70c877ecd Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 09:26:05 -0700 Subject: [PATCH 02/31] general cleanup --- src/main/com/mongodb/DB.java | 2 ++ src/main/com/mongodb/DBConnector.java | 4 ---- src/main/com/mongodb/DBCursor.java | 1 - src/main/com/mongodb/DBTCPConnector.java | 2 -- src/main/com/mongodb/WriteConcern.java | 6 ++++-- src/main/org/bson/types/ObjectId.java | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/com/mongodb/DB.java b/src/main/com/mongodb/DB.java index 518e5d8e6d7..f97dd90c30c 100644 --- a/src/main/com/mongodb/DB.java +++ b/src/main/com/mongodb/DB.java @@ -34,6 +34,7 @@ public abstract class DB { * updates, and removes). * @deprecated */ + @Deprecated public static class WriteConcern { /** * Don't check for or report any errors on writes. @@ -301,6 +302,7 @@ public CommandResult getLastError( int w , int wtimeout , boolean fsync ) * @param concern write concern to use */ public void setWriteConcern( com.mongodb.WriteConcern concern ){ + if (concern == null) throw new IllegalArgumentException(); _concern = concern; } diff --git a/src/main/com/mongodb/DBConnector.java b/src/main/com/mongodb/DBConnector.java index 765223b5353..23b0f66f7e5 100644 --- a/src/main/com/mongodb/DBConnector.java +++ b/src/main/com/mongodb/DBConnector.java @@ -18,10 +18,6 @@ package com.mongodb; -import java.io.*; -import java.net.*; -import java.nio.*; -import java.util.*; public interface DBConnector { diff --git a/src/main/com/mongodb/DBCursor.java b/src/main/com/mongodb/DBCursor.java index 746c69da13d..000227f3c47 100644 --- a/src/main/com/mongodb/DBCursor.java +++ b/src/main/com/mongodb/DBCursor.java @@ -332,7 +332,6 @@ private DBObject _next() _cur = null; _cur = _it.next(); - _collection.apply( _cur , false ); _num++; if ( _keysWanted != null && _keysWanted.keySet().size() > 0 ){ diff --git a/src/main/com/mongodb/DBTCPConnector.java b/src/main/com/mongodb/DBTCPConnector.java index 7cc2e4a38a7..11a4faf240e 100644 --- a/src/main/com/mongodb/DBTCPConnector.java +++ b/src/main/com/mongodb/DBTCPConnector.java @@ -20,7 +20,6 @@ import java.io.*; import java.net.*; -import java.nio.*; import java.util.*; import java.util.logging.*; @@ -268,7 +267,6 @@ DBPort get( boolean keep ){ void done( DBPort p ){ if ( _internalStack <= 0 ){ - int prev = _internalStack; _reset(); throw new IllegalStateException( "done called and _internalStack was: " + _internalStack ); } diff --git a/src/main/com/mongodb/WriteConcern.java b/src/main/com/mongodb/WriteConcern.java index 5c456323f8a..711b532b3ca 100644 --- a/src/main/com/mongodb/WriteConcern.java +++ b/src/main/com/mongodb/WriteConcern.java @@ -40,9 +40,11 @@ public class WriteConcern { public final static WriteConcern NONE = new WriteConcern(-1); public final static WriteConcern NORMAL = new WriteConcern(0); - public final static WriteConcern STRICT = new WriteConcern(1); // STRICT is deprecated should use SAFE - public final static WriteConcern SAFE = new WriteConcern(1); + + @Deprecated /** use SAFE */ + public final static WriteConcern STRICT = SAFE; + public final static WriteConcern FSYNC_SAFE = new WriteConcern(1,0,true); public final static WriteConcern REPLICAS_SAFE = new WriteConcern(2); diff --git a/src/main/org/bson/types/ObjectId.java b/src/main/org/bson/types/ObjectId.java index 701c7e1f3e1..d9d8b95dc80 100644 --- a/src/main/org/bson/types/ObjectId.java +++ b/src/main/org/bson/types/ObjectId.java @@ -80,7 +80,7 @@ public static boolean isValid( String s ){ * @param o the object to convert * @return an ObjectId if it can be massaged, null otherwise */ - public static ObjectId massageToObjectId( Object o ){ + protected static ObjectId massageToObjectId( Object o ){ if ( o == null ) return null; From 720c6e13790a1f942fc03f8be65fd31fd064cd51 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 09:26:42 -0700 Subject: [PATCH 03/31] WriteResult.getLastError(concern) changes --- src/main/com/mongodb/DBPort.java | 16 ++++----- src/main/com/mongodb/WriteResult.java | 41 ++++++++++++++++-------- src/test/com/mongodb/JavaClientTest.java | 41 +++++++++++++++++++++++- 3 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/main/com/mongodb/DBPort.java b/src/main/com/mongodb/DBPort.java index 583e4139deb..054f18ec129 100644 --- a/src/main/com/mongodb/DBPort.java +++ b/src/main/com/mongodb/DBPort.java @@ -20,7 +20,6 @@ import java.io.*; import java.net.*; -import java.nio.*; import java.util.*; import java.util.logging.*; @@ -91,7 +90,12 @@ private synchronized Response go( OutMessage msg , DBCollection coll ) } } - synchronized CommandResult runCommand( DB db , DBObject cmd ){ + synchronized CommandResult getLastError( DB db , WriteConcern concern){ + DBApiLayer dbAL = (DBApiLayer) db; + return runCommand( dbAL , concern.getCommand() ); + } + + synchronized CommandResult runCommand( DB db , DBObject cmd ) { OutMessage msg = OutMessage.query( 0 , db.getName() + ".$cmd" , 0 , -1 , cmd , null ); try { @@ -106,15 +110,11 @@ synchronized CommandResult runCommand( DB db , DBObject cmd ){ } - synchronized CommandResult getLastError( DB db ){ - return runCommand( db , new BasicDBObject( "getlasterror" , 1 ) ); - } - - synchronized CommandResult tryGetLastError( DB db , long last ){ + synchronized CommandResult tryGetLastError( DB db , long last, WriteConcern concern){ if ( last != _calls ) return null; - return getLastError( db ); + return getLastError( db , concern ); } public synchronized void ensureOpen() diff --git a/src/main/com/mongodb/WriteResult.java b/src/main/com/mongodb/WriteResult.java index 473ddecc3db..25f68a7d2bf 100644 --- a/src/main/com/mongodb/WriteResult.java +++ b/src/main/com/mongodb/WriteResult.java @@ -21,7 +21,7 @@ /** - * This class lets you access the results of the previous write + * This class lets you access the results of the previous write. * if you have STRICT mode on, this just stores the result of that getLastError call * if you don't, then this will actually to the getlasterror call. * if another op has been done on this connection in the interim, this will fail @@ -32,6 +32,8 @@ public class WriteResult { _lastErrorResult = o; _lastConcern = concern; _lazy = false; + _port = null; + _db = null; } WriteResult( DB db , DBPort p , WriteConcern concern ){ @@ -53,19 +55,32 @@ public WriteConcern getLastConcern(){ } + /** + *

Calling this will either return the cache result if getLastError has been called, + * or execute a new getLastError command on the sever.

+ * @throws MongoInternalException if the connection has been used since the last write operation. + * @return {@link CommandResult} from the last write operation. + */ public synchronized CommandResult getLastError(){ + return getLastError(null); + + } + + public synchronized CommandResult getLastError(WriteConcern concern){ + //if the concern hasn't changed and it is cached. if ( _lastErrorResult != null ) - return _lastErrorResult; + if ( ( _lastConcern != null && _lastConcern.equals( concern ) ) || ( concern != null && concern.equals( _lastConcern ) ) ) + return _lastErrorResult; if ( _port != null ){ - _lastErrorResult = _port.tryGetLastError( _db , _lastCall ); - _port = null; - _db = null; + _lastErrorResult = _port.tryGetLastError( _db , _lastCall , (concern == null) ? new WriteConcern() : concern ); + _lastConcern = concern; } if ( _lastErrorResult == null ) - throw new IllegalStateException( "this port has been used since the last call, can't call getLastError anymore" ); + throw new IllegalStateException( "The connection has been used since the last call, can't call getLastError anymore" ); + _lastCall++; return _lastErrorResult; } @@ -93,12 +108,10 @@ public String toString(){ return getLastError().toString(); } - DB _db; - DBPort _port; - long _lastCall; - WriteConcern _lastConcern; - - CommandResult _lastErrorResult; - - final boolean _lazy; + private long _lastCall; + private WriteConcern _lastConcern; + private CommandResult _lastErrorResult; + final private DB _db; + final private DBPort _port; + final private boolean _lazy; } diff --git a/src/test/com/mongodb/JavaClientTest.java b/src/test/com/mongodb/JavaClientTest.java index 3e855bd9554..281a805890b 100644 --- a/src/test/com/mongodb/JavaClientTest.java +++ b/src/test/com/mongodb/JavaClientTest.java @@ -304,7 +304,7 @@ public void testTimestamp() } @Test - public void testStrictWrite(){ + public void testStrictWriteSetInCollection(){ DBCollection c = _db.getCollection( "write1" ); c.drop(); c.setWriteConcern( WriteConcern.STRICT ); @@ -321,6 +321,23 @@ public void testStrictWrite(){ assertEquals( 1 , c.find().count() ); } + @Test + public void testStrictWriteSetInMethod(){ + DBCollection c = _db.getCollection( "write1" ); + c.drop(); + c.insert( new BasicDBObject( "_id" , 1 )); + boolean gotError = false; + try { + c.insert( new BasicDBObject( "_id" , 1 ) , WriteConcern.STRICT); + } + catch ( MongoException.DuplicateKey e ){ + gotError = true; + } + assertEquals( true , gotError ); + + assertEquals( 1 , c.find().count() ); + } + @Test public void testPattern(){ DBCollection c = _db.getCollection( "jp1" ); @@ -554,6 +571,28 @@ public void testIn(){ assertEquals( 2 , a.size() ); } + @Test + public void testWriteResultWithGetLastErrorWithDifferentConcerns(){ + DBCollection c = _db.getCollection( "writeresultwfle1" ); + c.drop(); + + WriteResult res = c.insert( new BasicDBObject( "_id" , 1 ) ); + res = c.update( new BasicDBObject( "_id" , 1 ) , new BasicDBObject( "$inc" , new BasicDBObject( "x" , 1 ) ) ); + assertEquals( 1 , res.getN() ); + assertTrue( res.isLazy() ); + + CommandResult cr = res.getLastError( WriteConcern.FSYNC_SAFE ); + assertEquals( 1 , cr.getInt( "n" ) ); + assertTrue( cr.containsField( "fsyncFiles" )); + + CommandResult cr2 = res.getLastError( WriteConcern.FSYNC_SAFE ); + assertTrue( cr == cr2 ); + + CommandResult cr3 = res.getLastError( WriteConcern.NONE ); + assertTrue( cr != cr3 && cr2 != cr3 ); + + } + @Test public void testWriteResult(){ DBCollection c = _db.getCollection( "writeresult1" ); From 1ab87f5af63b63406a53ff80f40524227f3a29e0 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 09:35:07 -0700 Subject: [PATCH 04/31] inc version for release --- src/main/com/mongodb/Mongo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/com/mongodb/Mongo.java b/src/main/com/mongodb/Mongo.java index 0878ccd090b..5f4dd9c496c 100644 --- a/src/main/com/mongodb/Mongo.java +++ b/src/main/com/mongodb/Mongo.java @@ -68,7 +68,7 @@ public class Mongo { public static final int MAJOR_VERSION = 2; - public static final int MINOR_VERSION = 0; + public static final int MINOR_VERSION = 1; public static DB connect( DBAddress addr ){ return new Mongo( addr ).getDB( addr.getDBName() ); From dbd099231c41560653335d313987f16c0f6a598f Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 09:39:27 -0700 Subject: [PATCH 05/31] added upsert to findAndModify --- src/main/com/mongodb/DBCollection.java | 11 +++++++---- src/test/com/mongodb/JavaClientTest.java | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index 4547b7c790f..a5d589d9a74 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -241,13 +241,14 @@ public final DBObject findOne( Object obj, DBObject fields ) { * You can also specify the fields to return in the document, optionally. * @return the found document (before, or after the update) */ - public DBObject findAndModify(DBObject query, DBObject fields, DBObject sort, boolean remove, DBObject update, boolean returnNew) { + public DBObject findAndModify(DBObject query, DBObject fields, DBObject sort, boolean remove, DBObject update, boolean returnNew, boolean upsert) { if ( DEBUG ) System.out.println( "findAndModify: " + _fullName + " query:" + JSON.serialize( query ) + " sort:" + JSON.serialize( sort )+ " remove:" + remove + " update: " + JSON.serialize( update )+ + " upsert: " + upsert+ " returnNew:" + returnNew); BasicDBObject cmd = new BasicDBObject( "findandmodify", _name); @@ -265,6 +266,8 @@ public DBObject findAndModify(DBObject query, DBObject fields, DBObject sort, bo cmd.append( "update", update ); if (returnNew) cmd.append( "new", returnNew ); + if (upsert) + cmd.append( "upsert", returnNew ); } if (remove && !(update == null || update.keySet().isEmpty() || returnNew)) @@ -279,7 +282,7 @@ public DBObject findAndModify(DBObject query, DBObject fields, DBObject sort, bo * @return the old document */ public DBObject findAndModify( DBObject query , DBObject sort , DBObject update){ - return findAndModify( query, null, null, false, update, false ); + return findAndModify( query, null, null, false, update, false, false); } /** @@ -287,7 +290,7 @@ public DBObject findAndModify( DBObject query , DBObject sort , DBObject update) * @return the old document */ public DBObject findAndModify( DBObject query , DBObject update ) { - return findAndModify( query, null, null, false, update, false ); + return findAndModify( query, null, null, false, update, false, false ); } /** @@ -295,7 +298,7 @@ public DBObject findAndModify( DBObject query , DBObject update ) { * @return the removed document */ public DBObject findAndRemove( DBObject query ) { - return findAndModify( query, null, null, true, null, false ); + return findAndModify( query, null, null, true, null, false, false ); } // --- START INDEX CODE --- diff --git a/src/test/com/mongodb/JavaClientTest.java b/src/test/com/mongodb/JavaClientTest.java index 281a805890b..789f9d66129 100644 --- a/src/test/com/mongodb/JavaClientTest.java +++ b/src/test/com/mongodb/JavaClientTest.java @@ -636,7 +636,7 @@ public void testFindAndModify(){ assertEquals( 1 , c.findOne(new BasicDBObject( "_id" , 1 ) ).get( "x" )); //return new one - dbObj = c.findAndModify( new BasicDBObject( "_id" , 1 ) , null, null, false, new BasicDBObject( "x", 5), true); + dbObj = c.findAndModify( new BasicDBObject( "_id" , 1 ) , null, null, false, new BasicDBObject( "x", 5), true, false); assertEquals( 2 , dbObj.keySet().size()); assertEquals( 5 , dbObj.get( "x" )); assertEquals( 5 , c.findOne(new BasicDBObject( "_id" , 1 ) ).get( "x" )); From 7a6beb1efe8941e109099556347e9570bb05d8fe Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 11:52:06 -0700 Subject: [PATCH 06/31] added missing WriteConcern optoin on save --- src/main/com/mongodb/DBCollection.java | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index a5d589d9a74..1094d61a0cc 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -519,7 +519,15 @@ public final Object apply( DBObject jo , boolean ensureID ){ * @param jo the DBObject to save * will add _id field to jo if needed */ - public final WriteResult save( DBObject jo ) + public final WriteResult save( DBObject jo ) { + return save(jo, null); + } + + /** Saves an object to this collection. + * @param jo the DBObject to save + * will add _id field to jo if needed + */ + public final WriteResult save( DBObject jo, WriteConcern concern ) throws MongoException { if ( checkReadOnly( true ) ) return null; @@ -535,13 +543,20 @@ public final WriteResult save( DBObject jo ) if ( DEBUG ) System.out.println( "saving new object" ); if ( id != null && id instanceof ObjectId ) ((ObjectId)id).notNew(); - return insert( jo ); + if ( concern == null ) + return insert( jo ); + else + return insert( jo, concern ); } if ( DEBUG ) System.out.println( "doing implicit upsert : " + jo.get( "_id" ) ); DBObject q = new BasicDBObject(); q.put( "_id" , id ); - return update( q , jo , true , false ); + if ( concern == null ) + return update( q , jo , true , false ); + else + return update( q , jo , true , false , concern ); + } // ---- DB COMMANDS ---- From bb1ee01befcae35a0b66cce8cc7af30a723d5591 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 19 Aug 2010 11:53:50 -0700 Subject: [PATCH 07/31] removed comment about old method --- src/main/com/mongodb/DBCollection.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index 1094d61a0cc..c118bcc7f2b 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -534,8 +534,6 @@ public final WriteResult save( DBObject jo, WriteConcern concern ) _checkObject( jo , false , false ); - //_findSubObject( s , jo , null ); - Object id = jo.get( "_id" ); if ( DEBUG ) System.out.println( "id : " + id ); From 171ad66ce158565a98664b427573b70b56763923 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Tue, 24 Aug 2010 10:38:58 -0700 Subject: [PATCH 08/31] better javadocs --- src/main/com/mongodb/WriteConcern.java | 58 +++++++++++++++++++------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/src/main/com/mongodb/WriteConcern.java b/src/main/com/mongodb/WriteConcern.java index 711b532b3ca..39f98b7638a 100644 --- a/src/main/com/mongodb/WriteConcern.java +++ b/src/main/com/mongodb/WriteConcern.java @@ -20,46 +20,76 @@ /** *

WriteConcern control the write behavior for with various options, as well as exception raising on error conditions.

* - * w - * -1 = don't even report network errors - * 0 = default, don't call getLastError by default - * 1 = basic, call getLastError, but don't wait for slaves - * 2+= wait for slaves - * - * wtimeout - * how long to wait for slaves before failing - * 0 = indefinite - * > 0 = ms to wait - * - * fsync - * force fsync to disk + *

+ * w + *

    + *
  • -1 = don't even report network errors
  • + *
  • 0 = default, don't call getLastError by default
  • + *
  • 1 = basic, call getLastError, but don't wait for slaves
  • + *
  • 2+= wait for slaves
  • + *
+ * wtimeout how long to wait for slaves before failing + *
    + *
  • 0 = indefinite
  • + *
  • > 0 = ms to wait
  • + *
+ *

+ *

fsync force fsync to disk

+ * * @dochub databases */ public class WriteConcern { + /** No exceptions are raised, even for network issues */ public final static WriteConcern NONE = new WriteConcern(-1); + /** Exceptions are raised for network issues, but not server errors */ public final static WriteConcern NORMAL = new WriteConcern(0); + /** Exceptions are raised for network issues, and server errors; waits on a server for the write operation */ public final static WriteConcern SAFE = new WriteConcern(1); @Deprecated /** use SAFE */ public final static WriteConcern STRICT = SAFE; - public final static WriteConcern FSYNC_SAFE = new WriteConcern(1,0,true); + /** Exceptions are raised for network issues, and server errors and the write operation waits for the server to flush the data to disk*/ + public final static WriteConcern FSYNC_SAFE = new WriteConcern(true); + /** Exceptions are raised for network issues, and server errors; waits for at least 2 servers for the write operation*/ public final static WriteConcern REPLICAS_SAFE = new WriteConcern(2); public WriteConcern(){ this(0); } + /**

Specifies the number of servers to wait for on the write operation, and exception raising behavior

+ *

w represents # of servers: + *

    + *
  • {@code w=-1} None, no checking is done
  • + *
  • {@code w=0} None, network socket errors raised
  • + *
  • {@code w=1} Checks server for errors as well as network socket errors raised
  • + *
  • {@code w>1} Checks servers (w) for errors as well as network socket errors raised
  • + *
+ *

+ * + **/ public WriteConcern( int w ){ this( w , 0 , false ); } + /**

Specifies the number of servers to wait for on the write operation, and the amount of time (ms) to wait.

+ *

Note: w should be > 1

+ * + **/ public WriteConcern( int w , int wtimeout ){ this( w , wtimeout , false ); } + public WriteConcern( boolean fsync ){ + this( 1 , 0 , fsync); + } + + /**

Specifies the number of servers to wait for on the write operation, and the amount of time (ms) to wait.

+ *

Note: w should be > 1

+ **/ public WriteConcern( int w , int wtimeout , boolean fsync ){ _w = w; _wtimeout = wtimeout; From ce35ed2c27d74a06ced8dbd711febab94bdb6283 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Tue, 24 Aug 2010 11:16:28 -0700 Subject: [PATCH 09/31] BSONEncoder map optimization JAVA-153 --- src/main/org/bson/BSONEncoder.java | 41 ++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/main/org/bson/BSONEncoder.java b/src/main/org/bson/BSONEncoder.java index eb576a11a7e..d578dd66ca7 100644 --- a/src/main/org/bson/BSONEncoder.java +++ b/src/main/org/bson/BSONEncoder.java @@ -7,6 +7,7 @@ import java.nio.*; import java.nio.charset.*; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.atomic.*; import java.util.regex.*; @@ -105,19 +106,33 @@ int putObject( String name , BSONObject o ){ } } - - for ( String s : o.keySet() ){ - - if ( rewriteID && s.equals( "_id" ) ) - continue; - - if ( transientFields != null && transientFields.contains( s ) ) - continue; - - Object val = o.get( s ); - - _putObjectField( s , val ); - + //TODO: reduce repeated code below. + if ( o instanceof Map ){ + for ( Entry e : ((Map)o).entrySet() ){ + + if ( rewriteID && e.getKey().equals( "_id" ) ) + continue; + + if ( transientFields != null && transientFields.contains( e.getKey() ) ) + continue; + + _putObjectField( e.getKey() , e.getValue() ); + + } + } else { + for ( String s : o.keySet() ){ + + if ( rewriteID && s.equals( "_id" ) ) + continue; + + if ( transientFields != null && transientFields.contains( s ) ) + continue; + + Object val = o.get( s ); + + _putObjectField( s , val ); + + } } _buf.write( EOO ); From 7f1ba21e301c2a6803100c7311fa42461f3af7b5 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 1 Sep 2010 12:14:45 -0700 Subject: [PATCH 10/31] more general support for Iterable in JSON.serialize - JAVA-161 --- src/main/com/mongodb/util/JSON.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/com/mongodb/util/JSON.java b/src/main/com/mongodb/util/JSON.java index c17e0fad977..c07a5666d71 100644 --- a/src/main/com/mongodb/util/JSON.java +++ b/src/main/com/mongodb/util/JSON.java @@ -2,14 +2,15 @@ package com.mongodb.util; -import com.mongodb.*; -import org.bson.*; -import org.bson.types.*; - import java.text.*; import java.util.*; import java.util.regex.*; +import org.bson.*; +import org.bson.types.*; + +import com.mongodb.*; + /** * Helper methods for JSON serialization and de-serialization */ @@ -69,12 +70,12 @@ public static void serialize( Object o , StringBuilder buf ){ return; } - if ( o instanceof Collection){ + if ( o instanceof Iterable){ boolean first = true; buf.append( "[ " ); - for ( Object n : (Collection)o ){ + for ( Object n : (Iterable)o ){ if ( first ) first = false; else buf.append( " , " ); From 6ad17bd0251134674595ff188593efc4f1624363 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Sat, 11 Sep 2010 06:35:00 -0700 Subject: [PATCH 11/31] fixed stale collection cache JAVA-164 --- src/main/com/mongodb/DB.java | 52 +++++++++++++++++++++++- src/main/com/mongodb/DBCollection.java | 20 +++------ src/test/com/mongodb/JavaClientTest.java | 10 +++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/main/com/mongodb/DB.java b/src/main/com/mongodb/DB.java index ce15798bb69..1187511e94b 100644 --- a/src/main/com/mongodb/DB.java +++ b/src/main/com/mongodb/DB.java @@ -72,6 +72,55 @@ public DB( Mongo mongo , String name ){ */ protected abstract DBCollection doGetCollection( String name ); + DBCollection renameCollection ( String name, String newName ) + throws MongoException { + + String fullName = _name + "." + name; + + CommandResult ret = + getSisterDB( "admin" ) + .command( BasicDBObjectBuilder.start() + .add( "renameCollection" , fullName ) + .add( "to" , _name + "." + newName ) + .get() ); + ret.throwOnError(); + + removeFromCollectionCache( name , newName ); + + return getCollection( newName ); + } + + void dropCollection( String name ) + throws MongoException { + + CommandResult res = command( new BasicDBObjectBuilder().add( "drop" , name ).get() ); + if ( res.ok() || res.getErrorMessage().equals( "ns not found" ) ) { + removeFromCollectionCache( name ); + return; + } + throw new MongoException( "error dropping : " + res ); + + } + + public void removeFromCollectionCache( String...names ) + throws MongoException { + + if (names == null || names.length == 0) return; + + for ( String name : names ) { + String fullName = _name + "." + name; + //remove collection from cache + DBCollection collToRemove = null; + for (DBCollection coll : _seenCollections) + if (coll.getFullName().equals( fullName )) { + collToRemove = coll; + break; + } + if (collToRemove != null) + _seenCollections.remove( collToRemove ); + } + } + /** Gets a collection with a given name. * If the collection does not exist, a new collection is created. * @param name the name of the collection to return @@ -84,7 +133,8 @@ public final DBCollection getCollection( String name ){ } return c; } - + + /** Creates a collection with a given name and options. * If the collection does not exist, a new collection is created. * Possible options: diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index b4f7c7e0382..f0a96779c62 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -33,7 +33,7 @@ * * @dochub collections */ -@SuppressWarnings("unchecked") +@SuppressWarnings({"unchecked", "rawtypes"}) public abstract class DBCollection { final static boolean DEBUG = Boolean.getBoolean( "DEBUG.DB" ); @@ -584,12 +584,9 @@ public void dropIndexes( String name ) /** Drops (deletes) this collection */ - public void drop() + public void drop() throws MongoException { - CommandResult res =_db.command( BasicDBObjectBuilder.start().add( "drop" , getName() ).get() ); - if ( res.ok() || res.getErrorMessage().equals( "ns not found" ) ) - return; - throw new MongoException( "error dropping : " + res ); + _db.dropCollection( _name ); } public long count() @@ -685,14 +682,7 @@ public long getCount(DBObject query, DBObject fields, long limit, long skip ) public DBCollection rename( String newName ) throws MongoException { - CommandResult ret = - _db.getSisterDB( "admin" ) - .command( BasicDBObjectBuilder.start() - .add( "renameCollection" , _fullName ) - .add( "to" , _db._name + "." + newName ) - .get() ); - ret.throwOnError(); - return _db.getCollection( newName ); + return _db.renameCollection( _name , newName ); } /** @@ -987,7 +977,7 @@ public WriteConcern getWriteConcern(){ final DB _db; - final protected String _name; + final protected String _name; final protected String _fullName; protected List _hintFields; diff --git a/src/test/com/mongodb/JavaClientTest.java b/src/test/com/mongodb/JavaClientTest.java index 8285eac8991..e84650069a3 100644 --- a/src/test/com/mongodb/JavaClientTest.java +++ b/src/test/com/mongodb/JavaClientTest.java @@ -303,6 +303,16 @@ public void testTimestamp() assert( t.getInc() > 0 ); } + @Test + public void testDrop(){ + DBCollection c = _db.getCollection( "drop1" ); + c.drop(); + c.insert( new BasicDBObject( "_id" , 1 ) ); + assertEquals( 1 , c.find().count() ); + c.drop(); + assertEquals( 0 , c.find().count() ); + } + @Test public void testStrictWriteSetInCollection(){ DBCollection c = _db.getCollection( "write1" ); From 66952e18ea560a4befbd07e0a48c852ec9040084 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 15 Sep 2010 07:59:04 -0700 Subject: [PATCH 12/31] fixes JAVA-155 --- src/main/com/mongodb/DBApiLayer.java | 4 ++ src/main/com/mongodb/Response.java | 6 +-- src/test/com/mongodb/DBCursorTest.java | 51 +++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/main/com/mongodb/DBApiLayer.java b/src/main/com/mongodb/DBApiLayer.java index 7d10557c74f..83e0dcdbd61 100644 --- a/src/main/com/mongodb/DBApiLayer.java +++ b/src/main/com/mongodb/DBApiLayer.java @@ -309,6 +309,10 @@ public boolean hasNext(){ return false; _advance(); + + if ( ( _options & Bytes.QUERYOPTION_TAILABLE ) == Bytes.QUERYOPTION_TAILABLE && !_cur.hasNext()) + return false; + return hasNext(); } diff --git a/src/main/com/mongodb/Response.java b/src/main/com/mongodb/Response.java index 8f833ed968b..85c8d60964a 100644 --- a/src/main/com/mongodb/Response.java +++ b/src/main/com/mongodb/Response.java @@ -22,7 +22,7 @@ import java.util.*; import org.bson.*; -import org.bson.io.*; +import org.bson.io.Bits; class Response { @@ -90,8 +90,8 @@ public boolean hasGetMore( int queryOptions ){ if ( _num > 0 ) return true; - if ( ( queryOptions & Bytes.QUERYOPTION_TAILABLE ) == 0 ) - return false; +// if ( ( queryOptions & Bytes.QUERYOPTION_TAILABLE ) == Bytes.QUERYOPTION_TAILABLE ) +// return false; // have a tailable cursor if ( ( _flags & Bytes.RESULTFLAG_AWAITCAPABLE ) > 0 ) diff --git a/src/test/com/mongodb/DBCursorTest.java b/src/test/com/mongodb/DBCursorTest.java index b16a7d159ca..77028286749 100644 --- a/src/test/com/mongodb/DBCursorTest.java +++ b/src/test/com/mongodb/DBCursorTest.java @@ -19,7 +19,7 @@ import java.io.*; import java.util.*; -import org.testng.annotations.Test; +import org.testng.annotations.*; import com.mongodb.util.*; @@ -66,6 +66,55 @@ public void testSnapshot() { assertEquals( 50 , c.find().snapshot().limit(50).toArray().size() ); } + @Test//(enabled = false) + public void testTailable() { + DBCollection c = _db.getCollection("tail1"); + c.drop(); + _db.createCollection( "tail1", new BasicDBObject("capped", true).append( "size", 10000 ) ); + for ( int i=0; i<10; i++ ) + c.save( new BasicDBObject( "x" , i ) ); + + + DBCursor cur = c.find().sort( new BasicDBObject( "$natural" , 1 ) ) + .addOption( Bytes.QUERYOPTION_TAILABLE ); + + while ( cur.hasNext() ) { + cur.next(); + //do nothing... + } + + assert( !cur.hasNext() ); + c.save( new BasicDBObject( "x" , 12 ) ); + assert( cur.hasNext() ); + assertNotNull( cur.next() ); + assert( !cur.hasNext() ); + + } + + @Test//(enabled = false) + public void testTailableAwait() { + DBCollection c = _db.getCollection("tail1"); + c.drop(); + _db.createCollection( "tail1", new BasicDBObject("capped", true).append( "size", 10000 ) ); + for ( int i=0; i<10; i++ ) + c.save( new BasicDBObject( "x" , i ) ); + + + DBCursor cur = c.find().sort( new BasicDBObject( "$natural" , 1 ) ) + .addOption( Bytes.QUERYOPTION_TAILABLE | Bytes.QUERYOPTION_AWAITDATA ); + + while ( cur.hasNext() ) { + cur.next(); + //do nothing... + } + + assert( !cur.hasNext() ); + c.save( new BasicDBObject( "x" , 12 ) ); + assert( cur.hasNext() ); + assertNotNull( cur.next() ); + assert( !cur.hasNext() ); + } + @Test public void testBig(){ DBCollection c = _db.getCollection("big1"); From efb91dbc42cff1d9c138bf27eda4062d27458741 Mon Sep 17 00:00:00 2001 From: hmeiser Date: Mon, 27 Sep 2010 15:02:29 +0200 Subject: [PATCH 13/31] improved version von BSONDecoder --- src/main/org/bson/BSONDecoder.java | 404 ++++++++++++++++++++++++----- 1 file changed, 346 insertions(+), 58 deletions(-) diff --git a/src/main/org/bson/BSONDecoder.java b/src/main/org/bson/BSONDecoder.java index fb1fcac13ce..f90826ff919 100644 --- a/src/main/org/bson/BSONDecoder.java +++ b/src/main/org/bson/BSONDecoder.java @@ -2,12 +2,37 @@ package org.bson; -import static org.bson.BSON.*; - -import java.io.*; - -import org.bson.io.*; -import org.bson.types.*; +import static org.bson.BSON.ARRAY; +import static org.bson.BSON.BINARY; +import static org.bson.BSON.BOOLEAN; +import static org.bson.BSON.B_BINARY; +import static org.bson.BSON.B_GENERAL; +import static org.bson.BSON.B_UUID; +import static org.bson.BSON.CODE; +import static org.bson.BSON.CODE_W_SCOPE; +import static org.bson.BSON.DATE; +import static org.bson.BSON.EOO; +import static org.bson.BSON.MAXKEY; +import static org.bson.BSON.MINKEY; +import static org.bson.BSON.NULL; +import static org.bson.BSON.NUMBER; +import static org.bson.BSON.NUMBER_INT; +import static org.bson.BSON.NUMBER_LONG; +import static org.bson.BSON.OBJECT; +import static org.bson.BSON.OID; +import static org.bson.BSON.REF; +import static org.bson.BSON.REGEX; +import static org.bson.BSON.STRING; +import static org.bson.BSON.SYMBOL; +import static org.bson.BSON.TIMESTAMP; +import static org.bson.BSON.UNDEFINED; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.SoftReference; + +import org.bson.types.ObjectId; public class BSONDecoder { @@ -63,7 +88,7 @@ public int decode( Input in , BSONCallback callback ) int decode() throws IOException { - final int start = _in._read; + final int start = _in.getBytesRead(); final int len = _in.readInt(); @@ -71,7 +96,7 @@ int decode() while ( decodeElement() ); _callback.objectDone(); - final int read = _in._read - start; + final int read = _in.getBytesRead() - start; if ( read != len ){ //throw new IllegalArgumentException( "bad data. lengths don't match " + read + " != " + len ); @@ -251,32 +276,148 @@ Object _readBasicObject() } class Input { - Input( InputStream in ){ + /** + * Maximum size of readahead. This ensures that we copy in memory at most + * readahead bytes if the buffer does not contain enough continuous bytes. + * Must be lower or equal than size of _charBuffer to prevent a buffer overflow. + */ + final private static int MAX_READAHEADSIZE = 512; + + Input( final InputStream in ){ _in = in; _read = 0; } - - int readInt() - throws IOException { - _read += 4; - return Bits.readInt( _in ); + /** + * Ensures that a continuous block of bytes is loaded to the buffer. Its responsibility to consume + * the complete block. + * + * @param blockSize + * @throws IOException + */ + void ensureContinuousBlock(int blockSize) throws IOException { + // + // Enough bytes already loaded? + if(_o + blockSize <= _l) + return; + + final int remaining = _l - _o; + // + // Is buffer large enough for block? + if(blockSize < _random.length) + { + // + // copy the rest in the buffer to the front + System.arraycopy(_random, _o, _random, 0, remaining); + } + else + { + // + // Allocate a larger buffer + final byte largerBuffer[] = new byte[blockSize + MAX_READAHEADSIZE]; + // + // copy the rest of the old buffer to the front of the new + System.arraycopy(_random, _o, largerBuffer, 0, remaining); + // + // swap the buffers + _random = largerBuffer; + } + // + // Increase the numbers of bytes by all processed bytes (offset with current buffer) + // Buffer is now aligned with the front + _read += _o; + + _o = 0; + _l = remaining; + // + // + final int readahead = Math.min(MAX_READAHEADSIZE, _random.length - remaining); + int wanted = Math.max(readahead, blockSize - remaining); + + while(wanted > 0 && _l < blockSize) { + // + // Read as much as we wanted at the end of the buffer + int rd = _in.read(_random, _l, wanted); + // + // EOS reached? + if(rd < 0) + break; + // + // Increase end and reduced wanted by bytes read from InputStream + _l = _l + rd; + wanted -=rd; + } + // + // Ups, we were not able to read enough bytes from stream + if(_l < blockSize) { + System.out.println("ups"); + } } - long readLong() + /** + * Reads an integer. + * + * @return + * @throws IOException + */ + final int readInt() throws IOException { - _read += 8; - return Bits.readLong( _in ); + // + // All integers are 4 bytes + ensureContinuousBlock(4); + // + // Code copied from java.io.Bits + return + ((_random[_o++] & 0xFF) << 0) + + ((_random[_o++] & 0xFF) << 8) + + ((_random[_o++] & 0xFF) << 16) + + ((_random[_o++]) << 24); } - + /** + * Reads a long. + * + * @return + * @throws IOException + */ + long readLong() + throws IOException { + // + // All longs are 8 bytes + ensureContinuousBlock(8); + // + // Code copied from java.io.Bits + return ((_random[_o++] & 0xFFL) << 0) + + ((_random[_o++] & 0xFFL) << 8) + + ((_random[_o++] & 0xFFL) << 16) + + ((_random[_o++] & 0xFFL) << 24) + + ((_random[_o++] & 0xFFL) << 32) + + ((_random[_o++] & 0xFFL) << 40) + + ((_random[_o++] & 0xFFL) << 48) + + (((long) _random[_o++]) << 56); + } + /** + * Simply read a double + * + * @return + * @throws IOException + */ double readDouble() throws IOException { return Double.longBitsToDouble( readLong() ); } - + /** + * Read the next byte from stream. + * + * @return + * @throws IOException + */ byte read() - throws IOException { - _read++; - return (byte)(_in.read() & 0xFF); + throws IOException { + // + // Ensure that one byte can be read + ensureContinuousBlock(1); + // + // Simply return the byte + return _random[_o++]; } void fill( byte b[] ) @@ -285,64 +426,211 @@ void fill( byte b[] ) } void fill( byte b[] , int len ) - throws IOException { - int off = 0; - while ( len > 0 ){ - int x = _in.read( b , off , len ); - _read += x; - off += x; - len -= x; + throws IOException { + // + // Take the remaining bytes from the buffer + int outputOffset = _l - _o; + + if(outputOffset > 0) + { + System.arraycopy(_random, _o, b, 0, outputOffset); + // + // Reduced needed bytes + len -= outputOffset; + // + // leave it up to the next ensure a continuous block + _o = _l; + } + // + // Read the rest direct from the InputStream + while ( len > 0 ) { + final int bytesRead = _in.read( b , outputOffset , len ); + // + // Reduced needed bytes + len -= bytesRead; + // + // Increase the number of read bytes because we reading directly from _in + _read += bytesRead; + + outputOffset += bytesRead; + } + } + /** + * Read a multibyte character with the first given as parameter c1. + * + * @param c1 + * @return + * @throws IOException + */ + char readMultiByte(int c1) throws IOException + { + switch (c1 >> 4) { + case 12: + case 13: { + // + // We need at least one byte for the character and one for the null to terminate + ensureContinuousBlock(2); + // + // Read next byte and check for correctness + final int c2 = _random[_o++]; + + if ((c2 & 0xC0) != 0x80) + return '\uFFFD'; + + return (char)(((c1 & 0x1F) << 6) | (c2 & 0x3F)); + } + case 14: { + // + // We need at least two bytes for the character and one for the null to terminate + ensureContinuousBlock(3); + // + // Read next bytes and check for correctness + final int c2 = _random[_o++]; + final int c3 = _random[_o++]; + + if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) + return '\uFFFD'; + + return (char)(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | ((c3 & 0x3F) << 0)); + } + default: + return '\uFFFD'; } } + /** + * Read an null terminated string in UTF8 from {@link InputStream}. + * We assume that null terminated strings have small lengths and are mostly ascii. + * + * @return + * @throws IOException + */ String readCStr() - throws IOException { - - _stringBuffer.reset(); - - while ( true ){ - byte b = read(); - if ( b == 0 ) - break; - _stringBuffer.write( b ); - } - - String out = null; - try { - out = _stringBuffer.asString( "UTF-8" ); - } - catch ( UnsupportedOperationException e ){ - throw new RuntimeException( "impossible" , e ); - } - _stringBuffer.reset(); - return out; + throws IOException { + // + // Position within _charBuffer + int charBufferPosition = 0; + // + // Claim a StringBuilder for bulding strings longer than charBuffer + StringBuilder stringBuilder = _stringBuilder.get(); + + if(stringBuilder == null) { + stringBuilder = new StringBuilder(_charBuffer.length * 2); + _stringBuilder = new SoftReference(stringBuilder); + } + else + stringBuilder.setLength(0); + // + // Fille the buffer with the first byte + ensureContinuousBlock(1); + + outer: + while ( true ) { + // + // This is the fast inner loop where every character is completely located in the buffer + // Since we read at maximum MAX_READAHEADSIZE and _charBuffer.length is greater than MAX_READAHEADSIZE + // there is no need to check for a buffer overflow in _charBuffer. + assert(_l - _o < _charBuffer.length - charBufferPosition); + + while(_o < _l) { + // + // Read next byte from buffer + final int b = _random[_o++]; + // + // Normal ascii character? Its the most common case + if( b > 0) { + // + // Append it to the end of our buffer + assert charBufferPosition < _charBuffer.length; + _charBuffer[charBufferPosition++] = (char)b; + } + else if( b == 0) { + break outer; + } + else { + // + // Read a multibyte. Its currently not optimized because this case is infrequent + assert charBufferPosition < _charBuffer.length; + _charBuffer[charBufferPosition++] = readMultiByte(b & 0xff); + } + } + // + // We need more bytes in the buffer, at least one byte + ensureContinuousBlock(1); + // + // If there are to much characters in the buffer, then append _charBuffer to StringBuilder + // and reset the _charBuffer. This ensures that the byteBuffer does not rise a char buffer overflow + if(_l - _o > _charBuffer.length - charBufferPosition) + { + stringBuilder.append(_charBuffer, 0, charBufferPosition); + charBufferPosition = 0; + } + } + // + // Some characters in _charBuffer + if(charBufferPosition > 0) { + // + // if string is empty then create the string direct from _charBuffer + if(stringBuilder.length() == 0) + return new String(_charBuffer, 0, charBufferPosition); + // + // Append _charBuffer to final string + stringBuilder.append(_charBuffer, 0, charBufferPosition); + } + + return stringBuilder.toString(); } - + /** + * Read an UTF8-String from {@link InputStream}. + * + * @return + * @throws IOException + */ String readUTF8String() throws IOException { - int size = readInt(); + // + // Read size and ensure that the complete string is in the buffer + final int size = readInt(); if ( size < 0 || size > ( 3 * 1024 * 1024 ) ) throw new RuntimeException( "bad string size: " + size ); - byte[] b = size < _random.length ? _random : new byte[size]; - - fill( b , size ); + ensureContinuousBlock(size); + // + // Start of the string is the current pointer in buffer + final int startOfString = _o; + // + // Increase offset by size of string + _o += size; + try { - return new String( b , 0 , size - 1 , "UTF-8" ); + return new String( _random, startOfString , size - 1 , "UTF-8" ); } catch ( java.io.UnsupportedEncodingException uee ){ throw new RuntimeException( "impossible" , uee ); } } + /** + * Returns the number of bytes read so far. + * + * @return + */ + int getBytesRead() { + return _read + _o; + } + int _o; + int _l; int _read; + final InputStream _in; } - private Input _in; private BSONCallback _callback; private byte[] _random = new byte[1024]; - - private PoolOutputBuffer _stringBuffer = new PoolOutputBuffer(); + private char _charBuffer[] = new char[1024]; + /** + * {@link SoftReference} to {@link StringBuilder} to allow reclaiming of memory by GC + */ + private SoftReference _stringBuilder = new SoftReference(null); } From fbd97ea04f196e09e68d71877ca68e7c72474d17 Mon Sep 17 00:00:00 2001 From: hmeiser Date: Wed, 29 Sep 2010 09:31:32 +0200 Subject: [PATCH 14/31] coding conventions --- src/main/org/bson/BSONDecoder.java | 58 ++++++++---------------------- 1 file changed, 15 insertions(+), 43 deletions(-) diff --git a/src/main/org/bson/BSONDecoder.java b/src/main/org/bson/BSONDecoder.java index f90826ff919..67b8a8220db 100644 --- a/src/main/org/bson/BSONDecoder.java +++ b/src/main/org/bson/BSONDecoder.java @@ -2,37 +2,12 @@ package org.bson; -import static org.bson.BSON.ARRAY; -import static org.bson.BSON.BINARY; -import static org.bson.BSON.BOOLEAN; -import static org.bson.BSON.B_BINARY; -import static org.bson.BSON.B_GENERAL; -import static org.bson.BSON.B_UUID; -import static org.bson.BSON.CODE; -import static org.bson.BSON.CODE_W_SCOPE; -import static org.bson.BSON.DATE; -import static org.bson.BSON.EOO; -import static org.bson.BSON.MAXKEY; -import static org.bson.BSON.MINKEY; -import static org.bson.BSON.NULL; -import static org.bson.BSON.NUMBER; -import static org.bson.BSON.NUMBER_INT; -import static org.bson.BSON.NUMBER_LONG; -import static org.bson.BSON.OBJECT; -import static org.bson.BSON.OID; -import static org.bson.BSON.REF; -import static org.bson.BSON.REGEX; -import static org.bson.BSON.STRING; -import static org.bson.BSON.SYMBOL; -import static org.bson.BSON.TIMESTAMP; -import static org.bson.BSON.UNDEFINED; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.SoftReference; - -import org.bson.types.ObjectId; +import static org.bson.BSON.*; + +import java.io.*; +import java.lang.ref.*; + +import org.bson.types.*; public class BSONDecoder { @@ -294,7 +269,8 @@ class Input { * @param blockSize * @throws IOException */ - void ensureContinuousBlock(int blockSize) throws IOException { + void ensureContinuousBlock(int blockSize) + throws IOException { // // Enough bytes already loaded? if(_o + blockSize <= _l) @@ -303,14 +279,12 @@ void ensureContinuousBlock(int blockSize) throws IOException { final int remaining = _l - _o; // // Is buffer large enough for block? - if(blockSize < _random.length) - { + if(blockSize < _random.length) { // // copy the rest in the buffer to the front System.arraycopy(_random, _o, _random, 0, remaining); } - else - { + else { // // Allocate a larger buffer final byte largerBuffer[] = new byte[blockSize + MAX_READAHEADSIZE]; @@ -426,13 +400,12 @@ void fill( byte b[] ) } void fill( byte b[] , int len ) - throws IOException { + throws IOException { // // Take the remaining bytes from the buffer int outputOffset = _l - _o; - if(outputOffset > 0) - { + if(outputOffset > 0) { System.arraycopy(_random, _o, b, 0, outputOffset); // // Reduced needed bytes @@ -462,8 +435,8 @@ void fill( byte b[] , int len ) * @return * @throws IOException */ - char readMultiByte(int c1) throws IOException - { + char readMultiByte(int c1) + throws IOException { switch (c1 >> 4) { case 12: case 13: { @@ -560,8 +533,7 @@ else if( b == 0) { // // If there are to much characters in the buffer, then append _charBuffer to StringBuilder // and reset the _charBuffer. This ensures that the byteBuffer does not rise a char buffer overflow - if(_l - _o > _charBuffer.length - charBufferPosition) - { + if(_l - _o > _charBuffer.length - charBufferPosition) { stringBuilder.append(_charBuffer, 0, charBufferPosition); charBufferPosition = 0; } From e6e164c6fcadfcf9a50b4b4723ba516afeb49c85 Mon Sep 17 00:00:00 2001 From: hmeiser Date: Wed, 29 Sep 2010 10:12:37 +0200 Subject: [PATCH 15/31] BSONEncoder now can handle primitive arrays JAVA-103 --- src/main/org/bson/BSONEncoder.java | 16 +++++++++++++++- src/test/org/bson/BSONTest.java | 20 +++++++++++--------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/org/bson/BSONEncoder.java b/src/main/org/bson/BSONEncoder.java index d578dd66ca7..62b305296d8 100644 --- a/src/main/org/bson/BSONEncoder.java +++ b/src/main/org/bson/BSONEncoder.java @@ -4,6 +4,7 @@ import static org.bson.BSON.*; +import java.lang.reflect.*; import java.nio.*; import java.nio.charset.*; import java.util.*; @@ -182,7 +183,7 @@ else if ( val instanceof Binary ) else if ( val instanceof UUID ) putUUID( name , (UUID)val ); else if ( val.getClass().isArray() ) - putIterable( name , Arrays.asList( (Object[])val ) ); + putArray( name , val ); else if (val instanceof Symbol) { putSymbol(name, (Symbol) val); @@ -204,7 +205,20 @@ else if ( putSpecial( name , val ) ){ } } + + private void putArray( String name , Object array ) { + _put( ARRAY , name ); + final int sizePos = _buf.getPosition(); + _buf.writeInt( 0 ); + + int size = Array.getLength(array); + for ( int i = 0; i < size; i++ ) + _putObjectField( String.valueOf( i ) , Array.get( array, i ) ); + _buf.write( EOO ); + _buf.writeInt( sizePos , _buf.getPosition() - sizePos ); + } + private void putIterable( String name , Iterable l ){ _put( ARRAY , name ); final int sizePos = _buf.getPosition(); diff --git a/src/test/org/bson/BSONTest.java b/src/test/org/bson/BSONTest.java index afddc273afd..c1c7cafa7b6 100644 --- a/src/test/org/bson/BSONTest.java +++ b/src/test/org/bson/BSONTest.java @@ -19,17 +19,13 @@ package org.bson; import java.io.*; -import java.nio.*; import java.util.*; -import java.util.zip.*; -import com.mongodb.*; -import com.mongodb.util.*; - -import org.testng.annotations.Test; - -import org.bson.types.*; import org.bson.io.*; +import org.bson.types.*; +import org.testng.annotations.*; + +import com.mongodb.util.*; public class BSONTest extends TestCase { @@ -70,7 +66,7 @@ void _test( BSONObject o , int size , String hash ) @Test public void testBasic1() throws IOException { - BSONObject o = new BasicBSONObject(); +// BSONObject o = new BasicBSONObject(); _test( new BasicBSONObject( "x" , true ) , 9 , "6fe24623e4efc5cf07f027f9c66b5456" ); _test( new BasicBSONObject( "x" , null ) , 8 , "12d43430ff6729af501faf0638e68888" ); @@ -85,6 +81,12 @@ public void testBasic1() _test( new BasicBSONObject( "x" , 4 ) , 12 , "d1ed8dbf79b78fa215e2ded74548d89d" ); } + + @Test + public void testArray() + throws IOException { + _test( new BasicBSONObject( "x" , new int[]{ 1 , 2 , 3 , 4} ) , 41 , "e63397fe37de1349c50e1e4377a45e2d" ); + } @Test public void testOB1(){ From 2722cbf36c66fcae0609561881805157ebf5c2ff Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 30 Sep 2010 17:36:54 -0700 Subject: [PATCH 16/31] eclipse formatting files (v3.5) --- eclipse-java-code-formatters.xml | 279 +++++++++++++++++++++++++++++++ eclipse-java.importorder | 6 + 2 files changed, 285 insertions(+) create mode 100755 eclipse-java-code-formatters.xml create mode 100755 eclipse-java.importorder diff --git a/eclipse-java-code-formatters.xml b/eclipse-java-code-formatters.xml new file mode 100755 index 00000000000..dc6b047b014 --- /dev/null +++ b/eclipse-java-code-formatters.xml @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse-java.importorder b/eclipse-java.importorder new file mode 100755 index 00000000000..30c47df0ea6 --- /dev/null +++ b/eclipse-java.importorder @@ -0,0 +1,6 @@ +#Organize Import Order +#Fri Sep 24 11:18:51 PDT 2010 +3=com +2=org +1=javax +0=java From ac11b1ce697838117cf8a6bf6d1cb6be9f00d46b Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Tue, 5 Oct 2010 11:28:42 -0700 Subject: [PATCH 17/31] javadoc cleanup --- src/main/com/mongodb/DB.java | 2 +- src/main/com/mongodb/DBCollection.java | 2 +- src/main/com/mongodb/DBCursor.java | 2 +- src/main/com/mongodb/Mongo.java | 3 +-- src/main/com/mongodb/MongoOptions.java | 14 ++++++++------ 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/com/mongodb/DB.java b/src/main/com/mongodb/DB.java index b5431145bbe..b60322c31a1 100644 --- a/src/main/com/mongodb/DB.java +++ b/src/main/com/mongodb/DB.java @@ -481,7 +481,7 @@ public DB getSisterDB( String name ){ } /** - * makes thisq query ok to run on a slave node + * makes this query ok to run on a slave node */ public void slaveOk(){ addOption( Bytes.QUERYOPTION_SLAVEOK ); diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index 3dbc9fa4520..d52cc77accd 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -965,7 +965,7 @@ public WriteConcern getWriteConcern(){ } /** - * makes thisq query ok to run on a slave node + * makes this query ok to run on a slave node */ public void slaveOk(){ addOption( Bytes.QUERYOPTION_SLAVEOK ); diff --git a/src/main/com/mongodb/DBCursor.java b/src/main/com/mongodb/DBCursor.java index 898ef84b161..e8be3188b1e 100644 --- a/src/main/com/mongodb/DBCursor.java +++ b/src/main/com/mongodb/DBCursor.java @@ -230,7 +230,7 @@ public DBCursor skip( int n ){ } /** - * makes thisq query ok to run on a slave node + * makes this query ok to run on a slave node */ public void slaveOk(){ addOption( Bytes.QUERYOPTION_SLAVEOK ); diff --git a/src/main/com/mongodb/Mongo.java b/src/main/com/mongodb/Mongo.java index 0600d5b6b2d..76fc899f325 100644 --- a/src/main/com/mongodb/Mongo.java +++ b/src/main/com/mongodb/Mongo.java @@ -22,7 +22,6 @@ import java.util.*; import java.util.concurrent.*; -import org.bson.util.*; import org.bson.io.*; /** @@ -316,7 +315,7 @@ public WriteConcern getWriteConcern(){ } /** - * makes thisq query ok to run on a slave node + * makes this query ok to run on a slave node */ public void slaveOk(){ addOption( Bytes.QUERYOPTION_SLAVEOK ); diff --git a/src/main/com/mongodb/MongoOptions.java b/src/main/com/mongodb/MongoOptions.java index e293d23dc92..b8a0d3da9a5 100644 --- a/src/main/com/mongodb/MongoOptions.java +++ b/src/main/com/mongodb/MongoOptions.java @@ -18,6 +18,8 @@ package com.mongodb; +import java.net.*; + /** * Various settings for the driver */ @@ -37,8 +39,8 @@ public void reset(){ } /** - number of connections allowed per host - will block if run out +

The number of connections allowed per host (the pool size, per host)

+

Once the pool is exhausted, this will block. See {@linkplain MongoOptions.threadsAllowedToBlockForConnectionMultiplier}

*/ public int connectionsPerHost; @@ -51,22 +53,22 @@ public void reset(){ public int threadsAllowedToBlockForConnectionMultiplier; /** - * max wait time of a blocking thread for a connection + * The max wait time for a blocking thread for a connection from the pool */ public int maxWaitTime; /** - connect timeout in milliseconds. 0 is default and infinite + The connection timeout in milliseconds; this is for establishing the socket connections (open). 0 is default and infinite */ public int connectTimeout; /** - socket timeout. 0 is default and infinite + The socket timeout; this value is passed to {@link Socket.setSoTimeout}. 0 is default and infinite */ public int socketTimeout; /** - this controls whether or not on a connect, the system retries automatically. defaults to false + This controls whether the system retries automatically on connection errors. defaults to false */ public boolean autoConnectRetry; From 483b0372d37a3f699cacee7af852cfb809e08cbc Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 6 Oct 2010 13:28:13 -0700 Subject: [PATCH 18/31] Use weakrefs. --- src/main/com/mongodb/Mongo.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/com/mongodb/Mongo.java b/src/main/com/mongodb/Mongo.java index 76fc899f325..70aea98babd 100644 --- a/src/main/com/mongodb/Mongo.java +++ b/src/main/com/mongodb/Mongo.java @@ -18,6 +18,7 @@ package com.mongodb; +import java.lang.ref.*; import java.net.*; import java.util.*; import java.util.concurrent.*; @@ -76,6 +77,12 @@ public static DB connect( DBAddress addr ){ return new Mongo( addr ).getDB( addr.getDBName() ); } + /** Returns the count of mongo instances used by static methods**/ + public static int getStaticInstanceCount () { + return _mongos.size(); + } + + /** returns a mongo instance based on the host **/ public static Mongo getStaticMongo( String host ) throws UnknownHostException , MongoException { return getStaticMongo( host , null ); @@ -83,17 +90,19 @@ public static Mongo getStaticMongo( String host ) private static final MongoOptions _defaultOptions = new MongoOptions(); + /** Returns a Mongo instance based on the host + options. **/ public static Mongo getStaticMongo( String host , MongoOptions options ) throws UnknownHostException , MongoException { final String key = host + "-" + options; - Mongo m = _mongos.get( key ); + WeakReference mRef = _mongos.get( key ); + Mongo m = mRef.get(); if ( m != null ) return m; m = new Mongo( host , options == null ? _defaultOptions : options ); - Mongo temp = _mongos.putIfAbsent( key , m ); + Mongo temp = _mongos.putIfAbsent( key , new WeakReference(m) ).get(); if ( temp != null ){ m.close(); return temp; @@ -355,6 +364,5 @@ protected PoolOutputBuffer createNew(){ }; - - private static final ConcurrentMap _mongos = new ConcurrentHashMap(); + private static final ConcurrentMap> _mongos = new ConcurrentHashMap>(); } From 8bdc38782b444a942d07e5b64942d44538fd5f46 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 7 Oct 2010 18:01:37 -0700 Subject: [PATCH 19/31] Add constructor with size. --- src/main/com/mongodb/BasicDBObject.java | 8 ++++++-- src/main/org/bson/BasicBSONObject.java | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/com/mongodb/BasicDBObject.java b/src/main/com/mongodb/BasicDBObject.java index fdc6087fb60..9fca85331de 100644 --- a/src/main/com/mongodb/BasicDBObject.java +++ b/src/main/com/mongodb/BasicDBObject.java @@ -20,10 +20,10 @@ import java.util.*; -import com.mongodb.util.*; - import org.bson.*; +import com.mongodb.util.*; + /** * A simple implementation of DBObject. * A DBObject can be created as follows, using this class: @@ -39,6 +39,10 @@ public class BasicDBObject extends BasicBSONObject implements DBObject { */ public BasicDBObject(){ } + + public BasicDBObject(int size){ + super(size); + } /** * Convenience CTOR diff --git a/src/main/org/bson/BasicBSONObject.java b/src/main/org/bson/BasicBSONObject.java index 257285ca506..eca918fca32 100644 --- a/src/main/org/bson/BasicBSONObject.java +++ b/src/main/org/bson/BasicBSONObject.java @@ -20,8 +20,6 @@ import java.util.*; -import org.bson.*; - /** * A simple implementation of DBObject. * A DBObject can be created as follows, using this class: @@ -38,6 +36,10 @@ public class BasicBSONObject extends LinkedHashMap implements BSO public BasicBSONObject(){ } + public BasicBSONObject(int size){ + super(size); + } + /** * Convenience CTOR * @param key key under which to store From 22d8edf7d157b7f75a57e9afa3fdc437a27f7769 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Fri, 8 Oct 2010 19:01:03 -0700 Subject: [PATCH 20/31] expose cursorId/kill() for JAVA-178 --- src/main/com/mongodb/DBCursor.java | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/com/mongodb/DBCursor.java b/src/main/com/mongodb/DBCursor.java index e8be3188b1e..b6f2b82080d 100644 --- a/src/main/com/mongodb/DBCursor.java +++ b/src/main/com/mongodb/DBCursor.java @@ -20,6 +20,9 @@ import java.util.*; +import com.mongodb.DBApiLayer.MyCollection; +import com.mongodb.DBApiLayer.Result; + /** An iterator over database results. * Doing a find() query on a collection returns a @@ -229,6 +232,34 @@ public DBCursor skip( int n ){ return this; } + /** The cursor (id) on the server; 0 = no cursor */ + public long getCursorId() { + if (_it instanceof Result) { + Response curRes = ((Result)_it)._curResult; + if ( curRes != null ) + return curRes._cursor; + } + + return 0; + } + + /** kill the current cursor on the server. */ + public boolean kill() { + long cursorId = getCursorId(); + if ( cursorId > 0 ) { + if ( _it instanceof Result ) { + Result res = (Result)_it; + ((MyCollection) res._collection).killCursors( Arrays.asList( cursorId ) ); + + //null the current results so it doesn't get killed again. + res._curResult = null; + } + } + + //TODO: how can we tell if it was successful? getLastError? + return true; + } + /** * makes this query ok to run on a slave node */ From c30892cc06baef0a7df1877f1d2efc941ec15142 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Oct 2010 14:30:51 +0200 Subject: [PATCH 21/31] corrected BSONDecoder to prevent from reading beyond object boundary --- src/main/org/bson/BSONDecoder.java | 55 +++++++++++++++++++----------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/main/org/bson/BSONDecoder.java b/src/main/org/bson/BSONDecoder.java index 67b8a8220db..d66afba8c55 100644 --- a/src/main/org/bson/BSONDecoder.java +++ b/src/main/org/bson/BSONDecoder.java @@ -7,6 +7,7 @@ import java.io.*; import java.lang.ref.*; +import org.bson.io.*; import org.bson.types.*; public class BSONDecoder { @@ -42,7 +43,7 @@ public int decode( InputStream in , BSONCallback callback ) return decode( new Input( in ) , callback ); } - public int decode( Input in , BSONCallback callback ) + int decode( Input in , BSONCallback callback ) throws IOException { if ( _in != null || _callback != null ) @@ -62,22 +63,21 @@ public int decode( Input in , BSONCallback callback ) int decode() throws IOException { - - final int start = _in.getBytesRead(); + // + // We already read four bytes for length + final int start = _in.getBytesRead() - 4; - final int len = _in.readInt(); - _callback.objectStart(); while ( decodeElement() ); _callback.objectDone(); final int read = _in.getBytesRead() - start; - if ( read != len ){ + if ( read != _in._length ) { //throw new IllegalArgumentException( "bad data. lengths don't match " + read + " != " + len ); } - return len; + return _in._length; } boolean decodeElement() @@ -258,9 +258,14 @@ class Input { */ final private static int MAX_READAHEADSIZE = 512; - Input( final InputStream in ){ + Input( final InputStream in ) + throws IOException { _in = in; _read = 0; + // + // Limit Buffer to only read 4 bytes for the real length + _length = 4; + _length = readInt(); } /** * Ensures that a continuous block of bytes is loaded to the buffer. Its responsibility to consume @@ -303,8 +308,10 @@ void ensureContinuousBlock(int blockSize) _o = 0; _l = remaining; // - // - final int readahead = Math.min(MAX_READAHEADSIZE, _random.length - remaining); + // Calculate possible readahead. It is not allowed to read beyond the end of the current object (_length) + final int bytesTillEnd = _length - _read - _l; + final int readahead = Math.min(Math.min(MAX_READAHEADSIZE, _random.length - remaining), bytesTillEnd); + int wanted = Math.max(readahead, blockSize - remaining); while(wanted > 0 && _l < blockSize) { @@ -323,7 +330,7 @@ void ensureContinuousBlock(int blockSize) // // Ups, we were not able to read enough bytes from stream if(_l < blockSize) { - System.out.println("ups"); + throw new RuntimeException("end of stream reached"); } } @@ -403,13 +410,22 @@ void fill( byte b[] , int len ) throws IOException { // // Take the remaining bytes from the buffer - int outputOffset = _l - _o; - - if(outputOffset > 0) { - System.arraycopy(_random, _o, b, 0, outputOffset); + int remaining = _l - _o; + // + // Did we alread read enough bytes? + if(remaining >= len) { + System.arraycopy(_random, _o, b, 0, len); + _o += len; + + return; + } + // + // Take the complete remaining bytes from buffer + if(remaining > 0) { + System.arraycopy(_random, _o, b, 0, remaining); // // Reduced needed bytes - len -= outputOffset; + len -= remaining; // // leave it up to the next ensure a continuous block _o = _l; @@ -417,7 +433,7 @@ void fill( byte b[] , int len ) // // Read the rest direct from the InputStream while ( len > 0 ) { - final int bytesRead = _in.read( b , outputOffset , len ); + final int bytesRead = _in.read( b , remaining , len ); // // Reduced needed bytes len -= bytesRead; @@ -425,7 +441,7 @@ void fill( byte b[] , int len ) // Increase the number of read bytes because we reading directly from _in _read += bytesRead; - outputOffset += bytesRead; + remaining += bytesRead; } } /** @@ -494,7 +510,7 @@ String readCStr() else stringBuilder.setLength(0); // - // Fille the buffer with the first byte + // Fill the buffer with the first byte ensureContinuousBlock(1); outer: @@ -595,6 +611,7 @@ int getBytesRead() { int _read; final InputStream _in; + int _length; } private Input _in; From 1557f5723d1b5fff05174177d2bb110e881404f3 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Mon, 18 Oct 2010 17:32:51 -0700 Subject: [PATCH 22/31] add valueOf for issue JAVA-175 --- src/main/com/mongodb/WriteConcern.java | 27 ++++++++++++++++++++++++ src/test/com/mongodb/JavaClientTest.java | 10 +++++++++ 2 files changed, 37 insertions(+) diff --git a/src/main/com/mongodb/WriteConcern.java b/src/main/com/mongodb/WriteConcern.java index 39f98b7638a..86ced5eefaa 100644 --- a/src/main/com/mongodb/WriteConcern.java +++ b/src/main/com/mongodb/WriteConcern.java @@ -17,6 +17,10 @@ */ package com.mongodb; + +import java.lang.reflect.*; +import java.util.*; + /** *

WriteConcern control the write behavior for with various options, as well as exception raising on error conditions.

* @@ -56,6 +60,29 @@ public class WriteConcern { /** Exceptions are raised for network issues, and server errors; waits for at least 2 servers for the write operation*/ public final static WriteConcern REPLICAS_SAFE = new WriteConcern(2); + //map of the constants from above for use by fromString + private static Map _namedConcerns = null; + + /** Get the WriteConcern constants by name: NONE, NORMAL, SAFE, FSYNC_SAFE, REPLICA_SAFE. (matching is done case insensitively)*/ + public static WriteConcern valueOf(String name) { + if (_namedConcerns == null) { + HashMap newMap = new HashMap( 8 , 1 ); + for (Field f : WriteConcern.class.getFields()) + if (Modifier.isStatic( f.getModifiers() ) && f.getType().equals( WriteConcern.class )) { + try { + newMap.put( f.getName().toLowerCase(), (WriteConcern) f.get( null ) ); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + //Thought about doing a synchronize but this seems just as safe and I don't care about race conditions. + _namedConcerns = newMap; + } + + return _namedConcerns.get(name.toLowerCase()); + } + public WriteConcern(){ this(0); } diff --git a/src/test/com/mongodb/JavaClientTest.java b/src/test/com/mongodb/JavaClientTest.java index e84650069a3..465534995b8 100644 --- a/src/test/com/mongodb/JavaClientTest.java +++ b/src/test/com/mongodb/JavaClientTest.java @@ -634,6 +634,16 @@ public void testWriteResultMethodLevelWriteConcern(){ assertFalse( res.isLazy() ); } + @Test + public void testWriteConcernValueOf(){ + WriteConcern wc1 = WriteConcern.NORMAL; + WriteConcern wc2 = WriteConcern.valueOf( "normal" ); + WriteConcern wc3 = WriteConcern.valueOf( "NORMAL" ); + + assertEquals( wc1._w , wc2._w ); + assertEquals( wc1._w , wc3._w ); + } + @Test public void testFindAndModify(){ DBCollection c = _db.getCollection( "findandmodify" ); From df95f02cedbbdd0c596c4eaaff493bcd94ba7c74 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Mon, 18 Oct 2010 17:33:09 -0700 Subject: [PATCH 23/31] disable broken tests --- src/test/com/mongodb/DBCursorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/com/mongodb/DBCursorTest.java b/src/test/com/mongodb/DBCursorTest.java index ee8f7c1cf71..1d9ba25d136 100644 --- a/src/test/com/mongodb/DBCursorTest.java +++ b/src/test/com/mongodb/DBCursorTest.java @@ -66,7 +66,7 @@ public void testSnapshot() { assertEquals( 50 , c.find().snapshot().limit(50).toArray().size() ); } - @Test//(enabled = false) + @Test(enabled = false) public void testTailable() { DBCollection c = _db.getCollection("tail1"); c.drop(); @@ -91,7 +91,7 @@ public void testTailable() { } - @Test//(enabled = false) + @Test(enabled = false) public void testTailableAwait() { DBCollection c = _db.getCollection("tail1"); c.drop(); From 3d12dd96661f2d8dc6f6e993bb08f66d963ced1a Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 20 Oct 2010 12:10:20 -0700 Subject: [PATCH 24/31] added BasicDBObjectBuilder.isEmpty() and more tests --- .../com/mongodb/BasicDBObjectBuilder.java | 6 +++-- src/test/com/mongodb/BasicDBObjectTest.java | 25 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/com/mongodb/BasicDBObjectBuilder.java b/src/main/com/mongodb/BasicDBObjectBuilder.java index 5dcf92dd59b..d152e7b5f3f 100644 --- a/src/main/com/mongodb/BasicDBObjectBuilder.java +++ b/src/main/com/mongodb/BasicDBObjectBuilder.java @@ -68,8 +68,7 @@ public BasicDBObjectBuilder append( String key , Object val ){ * @return returns itself so you can chain .add( "a" , 1 ).add( "b" , 1 ) */ public BasicDBObjectBuilder add( String key , Object val ){ - _cur().put( key , val ); - return this; + return append( key, val ); } public BasicDBObjectBuilder push( String key ){ @@ -90,6 +89,9 @@ public DBObject get(){ return _stack.getFirst(); } + public boolean isEmpty(){ + return ((BasicDBObject) _stack.getFirst()).size() == 0; + } private DBObject _cur(){ return _stack.getLast(); } diff --git a/src/test/com/mongodb/BasicDBObjectTest.java b/src/test/com/mongodb/BasicDBObjectTest.java index c6e235912b9..6acc7118edd 100644 --- a/src/test/com/mongodb/BasicDBObjectTest.java +++ b/src/test/com/mongodb/BasicDBObjectTest.java @@ -18,11 +18,7 @@ package com.mongodb; -import java.util.*; -import java.util.regex.*; -import java.io.IOException; - -import org.testng.annotations.Test; +import org.testng.annotations.*; import com.mongodb.util.*; @@ -48,6 +44,25 @@ public void testBasic2(){ assert( ! a.equals( JSON.parse( "{ 'x' : 2 }" ) ) ); } + + @Test(groups = {"basic"}) + public void testBuilderIsEmpty(){ + BasicDBObjectBuilder b = BasicDBObjectBuilder.start(); + assert( b.isEmpty() ); + b.append( "a" , 1 ); + assert( !b.isEmpty() ); + assert( b.get().equals( JSON.parse( "{ 'a' : 1 }" ) ) ); + } + + @Test(groups = {"basic"}) + public void testBuilderNested(){ + BasicDBObjectBuilder b = BasicDBObjectBuilder.start(); + b.add( "a", 1 ); + b.push( "b" ).append( "c", 2 ).pop(); + DBObject a = b.get(); + assert( a.equals( JSON.parse( "{ 'a' : 1, 'b' : { 'c' : 2 } }" ) ) ); + } + @Test(groups = {"basic"}) public void testDown1(){ BasicDBObjectBuilder b = BasicDBObjectBuilder.start(); From 07dd5519c48a82f09e999348374cc720be41753b Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 20 Oct 2010 18:35:24 -0700 Subject: [PATCH 25/31] formatting changes for previous commit --- src/main/com/mongodb/WriteConcern.java | 44 +++++++++++++----------- src/test/com/mongodb/JavaClientTest.java | 16 ++++----- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/main/com/mongodb/WriteConcern.java b/src/main/com/mongodb/WriteConcern.java index 86ced5eefaa..8bd5287c2e9 100644 --- a/src/main/com/mongodb/WriteConcern.java +++ b/src/main/com/mongodb/WriteConcern.java @@ -59,30 +59,34 @@ public class WriteConcern { public final static WriteConcern FSYNC_SAFE = new WriteConcern(true); /** Exceptions are raised for network issues, and server errors; waits for at least 2 servers for the write operation*/ public final static WriteConcern REPLICAS_SAFE = new WriteConcern(2); - - //map of the constants from above for use by fromString + + // map of the constants from above for use by fromString private static Map _namedConcerns = null; - /** Get the WriteConcern constants by name: NONE, NORMAL, SAFE, FSYNC_SAFE, REPLICA_SAFE. (matching is done case insensitively)*/ + /** + * Get the WriteConcern constants by name: NONE, NORMAL, SAFE, FSYNC_SAFE, + * REPLICA_SAFE. (matching is done case insensitively) + */ public static WriteConcern valueOf(String name) { - if (_namedConcerns == null) { - HashMap newMap = new HashMap( 8 , 1 ); - for (Field f : WriteConcern.class.getFields()) - if (Modifier.isStatic( f.getModifiers() ) && f.getType().equals( WriteConcern.class )) { - try { - newMap.put( f.getName().toLowerCase(), (WriteConcern) f.get( null ) ); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //Thought about doing a synchronize but this seems just as safe and I don't care about race conditions. - _namedConcerns = newMap; - } - - return _namedConcerns.get(name.toLowerCase()); + if (_namedConcerns == null) { + HashMap newMap = new HashMap( 8 , 1 ); + for (Field f : WriteConcern.class.getFields()) + if (Modifier.isStatic( f.getModifiers() ) && f.getType().equals( WriteConcern.class )) { + try { + newMap.put( f.getName().toLowerCase(), (WriteConcern) f.get( null ) ); + } catch (Exception e) { + throw new RuntimeException( e ); + } + } + + // Thought about doing a synchronize but this seems just as safe and + // I don't care about race conditions. + _namedConcerns = newMap; + } + + return _namedConcerns.get( name.toLowerCase() ); } - + public WriteConcern(){ this(0); } diff --git a/src/test/com/mongodb/JavaClientTest.java b/src/test/com/mongodb/JavaClientTest.java index 465534995b8..7612fbefc50 100644 --- a/src/test/com/mongodb/JavaClientTest.java +++ b/src/test/com/mongodb/JavaClientTest.java @@ -635,15 +635,15 @@ public void testWriteResultMethodLevelWriteConcern(){ } @Test - public void testWriteConcernValueOf(){ - WriteConcern wc1 = WriteConcern.NORMAL; - WriteConcern wc2 = WriteConcern.valueOf( "normal" ); - WriteConcern wc3 = WriteConcern.valueOf( "NORMAL" ); - - assertEquals( wc1._w , wc2._w ); - assertEquals( wc1._w , wc3._w ); + public void testWriteConcernValueOf() { + WriteConcern wc1 = WriteConcern.NORMAL; + WriteConcern wc2 = WriteConcern.valueOf( "normal" ); + WriteConcern wc3 = WriteConcern.valueOf( "NORMAL" ); + + assertEquals( wc1._w, wc2._w ); + assertEquals( wc1._w, wc3._w ); } - + @Test public void testFindAndModify(){ DBCollection c = _db.getCollection( "findandmodify" ); From 26acc0bd386ec5d023d5a91526b55805244cec18 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 20 Oct 2010 18:55:55 -0700 Subject: [PATCH 26/31] tab -> spaces --- eclipse-java-code-formatters.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclipse-java-code-formatters.xml b/eclipse-java-code-formatters.xml index dc6b047b014..382925cf11b 100755 --- a/eclipse-java-code-formatters.xml +++ b/eclipse-java-code-formatters.xml @@ -88,7 +88,7 @@ - + From e9939e283fcb0765f2ebd4893a9420c688108161 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Wed, 27 Oct 2010 14:32:31 -0700 Subject: [PATCH 27/31] updated mongo constructor javadocs --- src/main/com/mongodb/Mongo.java | 64 ++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/src/main/com/mongodb/Mongo.java b/src/main/com/mongodb/Mongo.java index b9ebc92e903..cf89475bb29 100644 --- a/src/main/com/mongodb/Mongo.java +++ b/src/main/com/mongodb/Mongo.java @@ -82,7 +82,7 @@ public Mongo() } /** - * Connects to the local mongo instance on default port. + * Connects to a (single) mongodb node (default port) * * @param host server to connect to * @throws UnknownHostException if the database host cannot be resolved @@ -93,11 +93,10 @@ public Mongo( String host ) } /** - * Connects to the local mongo instance on default port. - * - * @param host server to connect to - * @param options options to use - * @throws UnknownHostException if the database host cannot be resolved + * Connects to a (single) mongodb node (default port) + * @param host server to connect to + * @param options options to use + * @throws UnknownHostException if the database host cannot be resolved */ public Mongo( String host , MongoOptions options ) throws UnknownHostException , MongoException { @@ -105,7 +104,7 @@ public Mongo( String host , MongoOptions options ) } /** - * Connects to Mongo using a given host, port, and database. + * Connects to a (single) mongodb node * @param host the database's host address * @param port the port on which the database is running * @throws UnknownHostException if the database host cannot be resolved @@ -116,8 +115,8 @@ public Mongo( String host , int port ) } /** - * Connects to Mongo using a given DBAddress - * @see com.mongodb.DBAddress + * Connects to a (single) mongodb node + * @see com.mongodb.ServerAddress * @param addr the database address */ public Mongo( ServerAddress addr ) @@ -127,8 +126,8 @@ public Mongo( ServerAddress addr ) /** - * Connects to Mongo using a given DBAddress - * @see com.mongodb.DBAddress + * Connects to a (single) mongo node using a given ServerAddress + * @see com.mongodb.ServerAddress * @param addr the database address */ public Mongo( ServerAddress addr , MongoOptions options ) @@ -142,9 +141,13 @@ public Mongo( ServerAddress addr , MongoOptions options ) } /** - creates a Mongo connection in paired mode - * @param left left side of the pair - * @param right right side of the pair + *

Creates a Mongo connection in paired mode.
This will also work for + * a replica set and will find all members (the master will be used by + * default).

+ * + * @see com.mongodb.ServerAddress + * @param left left side of the pair + * @param right right side of the pair */ public Mongo( ServerAddress left , ServerAddress right ) throws MongoException { @@ -152,9 +155,13 @@ public Mongo( ServerAddress left , ServerAddress right ) } /** - creates a Mongo connection in paired mode - * @param left left side of the pair - * @param right right side of the pair + *

Creates a Mongo connection in paired mode.
This will also work for + * a replica set and will find all members (the master will be used by + * default).

+ * + * @see com.mongodb.ServerAddress + * @param left left side of the pair + * @param right right side of the pair */ public Mongo( ServerAddress left , ServerAddress right , MongoOptions options ) throws MongoException { @@ -167,7 +174,11 @@ public Mongo( ServerAddress left , ServerAddress right , MongoOptions options ) } /** - * creates a Mongo connection to a replica set + *

Creates a Mongo connection.
This will work for + * a replica set, or pair, and will find all members (the master will be used by + * default).

+ * + * @see com.mongodb.ServerAddress * @pair replicaSetSeeds put as many servers as you can in the list. * the system will figure the rest out */ @@ -177,8 +188,12 @@ public Mongo( List replicaSetSeeds ) } /** - * creates a Mongo connection to a replica set - * @pair replicaSetSeeds put as many servers as you can in the list. + *

Creates a Mongo connection.
This will work for + * a replica set, or pair, and will find all members (the master will be used by + * default).

+ * + * @see com.mongodb.ServerAddress + * @param replicaSetSeeds put as many servers as you can in the list. * the system will figure the rest out */ public Mongo( List replicaSetSeeds , MongoOptions options ) @@ -191,6 +206,15 @@ public Mongo( List replicaSetSeeds , MongoOptions options ) _connector.checkMaster( true , false ); } + /** + * Creates a Mongo connection. If only one address is used it will only connect to that node, otherwise it will discover all nodes. + * @see MongoURI + *

examples: + *

  • mongodb://localhost
  • + *
  • mongodb://fred:foobar@localhost/
  • + *

    + * @dochub connections + */ public Mongo( MongoURI uri ) throws MongoException , UnknownHostException { From 2b1e3c598abe15ad3438e943df6cb24cf4d545c3 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Fri, 29 Oct 2010 10:30:31 -0700 Subject: [PATCH 28/31] DBCollection.setObjectClass bug; JAVA-206 --- src/main/com/mongodb/DBCollection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index 84bcc99ea69..3b0cceb3c51 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -908,11 +908,14 @@ public String toString(){ return _name; } - /** Set a default class for objects in this collection + /** Set a default class for objects in this collection; null resets the class to nothing. * @param c the class * @throws IllegalArgumentException if c is not a DBObject */ public void setObjectClass( Class c ){ + if ( c == null ) + _wrapper = null; + if ( ! DBObject.class.isAssignableFrom( c ) ) throw new IllegalArgumentException( c.getName() + " is not a DBObject" ); _objectClass = c; From 019b26532bc8f643da6ec0a6cdb8386e02682dc6 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Sun, 28 Nov 2010 20:03:17 -0800 Subject: [PATCH 29/31] helper methods --- src/main/com/mongodb/BasicDBObject.java | 4 ++++ src/main/org/bson/BasicBSONObject.java | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/com/mongodb/BasicDBObject.java b/src/main/com/mongodb/BasicDBObject.java index 9fca85331de..6100429bc74 100644 --- a/src/main/com/mongodb/BasicDBObject.java +++ b/src/main/com/mongodb/BasicDBObject.java @@ -90,4 +90,8 @@ public BasicDBObject append( String key , Object val ){ private boolean _isPartialObject = false; + + public BasicDBObject getObj(String key) { + return (BasicDBObject) super.getObj( key ); + } } diff --git a/src/main/org/bson/BasicBSONObject.java b/src/main/org/bson/BasicBSONObject.java index eca918fca32..44d5475b47a 100644 --- a/src/main/org/bson/BasicBSONObject.java +++ b/src/main/org/bson/BasicBSONObject.java @@ -108,6 +108,16 @@ public int getInt( String key ){ return BSON.toInt( o ); } + /** Returns the value of a field as a BSONObject. + * @param key the field to look for + * @return the field value cast to a BSONObject. + */ + public BSONObject getObj( String key ){ + Object foo = get( key ); + return (BSONObject) foo ; + } + + /** Returns the value of a field as an int. * @param key the field to look for * @param def the default to return From 66fee89b78214add73f0b94cd6495fc2afac0a58 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Tue, 30 Nov 2010 15:09:00 -0800 Subject: [PATCH 30/31] now handles primitive arrays as well --- src/main/com/mongodb/util/JSON.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/com/mongodb/util/JSON.java b/src/main/com/mongodb/util/JSON.java index ea831119aea..0674a3b039c 100644 --- a/src/main/com/mongodb/util/JSON.java +++ b/src/main/com/mongodb/util/JSON.java @@ -2,6 +2,7 @@ package com.mongodb.util; +import java.lang.reflect.*; import java.text.*; import java.util.*; import java.util.regex.*; @@ -166,13 +167,11 @@ public static void serialize( Object o , StringBuilder buf ){ } if ( o.getClass().isArray() ){ - Object[] arr = (Object[])o; - buf.append( "[ " ); - for ( int i=0; i 0 ) buf.append( " , " ); - serialize( arr[i] , buf ); + serialize( Array.get( o , i ) , buf ); } buf.append( "]" ); From cbbf165c83f3df4577ddefb637b11face65fb855 Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Thu, 3 Feb 2011 14:16:06 -0800 Subject: [PATCH 31/31] Deprecate getCount methods JAVA-264 --- src/main/com/mongodb/DBCollection.java | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/com/mongodb/DBCollection.java b/src/main/com/mongodb/DBCollection.java index 2ddfe643261..ae447bacb88 100644 --- a/src/main/com/mongodb/DBCollection.java +++ b/src/main/com/mongodb/DBCollection.java @@ -700,9 +700,27 @@ public long count() * @return * @throws MongoException */ - public long count(DBObject query) + public long count(DBObject query) throws MongoException { - return getCount(query, null); + BasicDBObject cmd = new BasicDBObject(); + cmd.put( "count", getName() ); + cmd.put( "query", query ); + + CommandResult res = _db.command( cmd, getOptions() ); + + if ( ! res.ok() ){ + String errmsg = res.getErrorMessage(); + + if ( errmsg.equals("ns does not exist") || + errmsg.equals("ns missing" ) ){ + // for now, return 0 - lets pretend it does exist + return 0; + } + + throw new MongoException( "error counting : " + res ); + } + + return res.getLong("n"); } @@ -711,6 +729,7 @@ public long count(DBObject query) * @return number of documents that match query * @throws MongoException */ + @Deprecated public long getCount() throws MongoException { return getCount(new BasicDBObject(), null); @@ -722,6 +741,7 @@ public long getCount() * @return * @throws MongoException */ + @Deprecated public long getCount(DBObject query) throws MongoException { return getCount(query, null); @@ -734,6 +754,7 @@ public long getCount(DBObject query) * @return * @throws MongoException */ + @Deprecated public long getCount(DBObject query, DBObject fields) throws MongoException { return getCount( query , fields , 0 , 0 ); @@ -750,6 +771,7 @@ public long getCount(DBObject query, DBObject fields) * @return number of documents that match query and fields * @throws MongoException */ + @Deprecated public long getCount(DBObject query, DBObject fields, long limit, long skip ) throws MongoException {