diff --git a/db/clientcursor.cpp b/db/clientcursor.cpp index 6d058cbeb91..cac55506263 100644 --- a/db/clientcursor.cpp +++ b/db/clientcursor.cpp @@ -258,8 +258,7 @@ namespace mongo { _cursorid = allocCursorId_inlock(); clientCursorsById.insert( make_pair(_cursorid, this) ); -#if 0 - { + if ( ! _c->modifiedKeys() ) { // store index information so we can decide if we can // get something out of the index key rather than full object @@ -274,7 +273,7 @@ namespace mongo { x++; } } -#endif + } @@ -292,6 +291,24 @@ namespace mongo { } } + bool ClientCursor::getFieldsDotted( const string& name, BSONElementSet &ret ) { + + map::const_iterator i = _indexedFields.find( name ); + if ( i == _indexedFields.end() ){ + current().getFieldsDotted( name , ret ); + return false; + } + + int x = i->second; + + BSONObjIterator it( currKey() ); + while ( x && it.more() ) + it.next(); + assert( x == 0 ); + ret.insert( it.next() ); + return true; + } + /* call when cursor's location changes so that we can update the cursorsbylocation map. if you are locked and internally iterating, only need to call when you are ready to "unlock". diff --git a/db/clientcursor.h b/db/clientcursor.h index 0f08a97134d..ddd39a18b25 100644 --- a/db/clientcursor.h +++ b/db/clientcursor.h @@ -221,7 +221,15 @@ namespace mongo { bool advance(){ return _c->advance(); } BSONObj current() { return _c->current(); } DiskLoc currLoc() { return _c->currLoc(); } - BSONObj currKey() { return _c->currKey(); } + BSONObj currKey() const { return _c->currKey(); } + + + /** + * same as BSONObj::getFieldsDotted + * if it can be retrieved from key, it is + * @return if this was retrieved from key + */ + bool getFieldsDotted( const string& name, BSONElementSet &ret ); bool currentIsDup() { return _c->getsetdup( _c->currLoc() ); } diff --git a/db/commands/distinct.cpp b/db/commands/distinct.cpp index 13aa82d4d23..9042239f0ef 100644 --- a/db/commands/distinct.cpp +++ b/db/commands/distinct.cpp @@ -47,8 +47,9 @@ namespace mongo { BSONArrayBuilder arr( bb ); BSONElementSet values; - long long nscanned = 0; - long long n = 0; + long long nscanned = 0; // locations looked at + long long nscannedObjects = 0; // full objects looked at + long long n = 0; // matches MatchDetails md; shared_ptr cursor = bestGuessCursor(ns.c_str() , query , BSONObj() ); @@ -59,11 +60,10 @@ namespace mongo { bool loadedObject = false; if ( !cursor->matcher() || cursor->matcher()->matchesCurrent( cursor.get() , &md ) ){ - loadedObject = true; - BSONObj o = cursor->current(); + n++; BSONElementSet temp; - o.getFieldsDotted( key, temp ); + loadedObject = ! cc->getFieldsDotted( key , temp ); for ( BSONElementSet::iterator i=temp.begin(); i!=temp.end(); ++i ){ BSONElement e = *i; @@ -82,7 +82,7 @@ namespace mongo { } if ( loadedObject || md.loadedObject ) - n++; + nscannedObjects++; cursor->advance(); @@ -100,6 +100,7 @@ namespace mongo { BSONObjBuilder b; b.appendNumber( "n" , n ); b.appendNumber( "nscanned" , nscanned ); + b.appendNumber( "nscannedObjects" , nscannedObjects ); result.append( "stats" , b.obj() ); } diff --git a/jstests/distinct_index1.js b/jstests/distinct_index1.js index cf8036042a9..7d6dfbe31d4 100644 --- a/jstests/distinct_index1.js +++ b/jstests/distinct_index1.js @@ -2,8 +2,8 @@ t = db.distinct_index1 t.drop(); -function r(){ - return Math.floor( Math.random() * 10 ); +function r( x ){ + return Math.floor( Math.sqrt( x * 123123 ) ) % 10; } function d( k , q ){ @@ -11,17 +11,32 @@ function d( k , q ){ } for ( i=0; i<1000; i++ ){ - o = { a : r() , b : r() }; + o = { a : r(i*5) , b : r(i) }; t.insert( o ); } x = d( "a" ); assert.eq( 1000 , x.stats.n , "A1" ) assert.eq( 1000 , x.stats.nscanned , "A2" ) +assert.eq( 1000 , x.stats.nscannedObjects , "A3" ) x = d( "a" , { a : { $gt : 5 } } ); -assert.eq( 1000 , x.stats.n , "A1" ) -assert.eq( 1000 , x.stats.nscanned , "A2" ) +assert.eq( 398 , x.stats.n , "B1" ) +assert.eq( 1000 , x.stats.nscanned , "B2" ) +assert.eq( 1000 , x.stats.nscannedObjects , "B3" ) + +t.ensureIndex( { a : 1 } ) + +x = d( "a" ); +assert.eq( 1000 , x.stats.n , "C1" ) +assert.eq( 1000 , x.stats.nscanned , "C2" ) +assert.eq( 1000 , x.stats.nscannedObjects , "C3" ) + +x = d( "a" , { a : { $gt : 5 } } ); +assert.eq( 398 , x.stats.n , "D1" ) +assert.eq( 398 , x.stats.nscanned , "D2" ) +assert.eq( 0 , x.stats.nscannedObjects , "D3" ) +