summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2010-11-16 16:11:43 -0500
committerEliot Horowitz <eliot@10gen.com>2010-11-16 16:11:43 -0500
commit2603a9632c21f9e56e780f57b15313ed9d8810ff (patch)
treebd576ef14dab3a10f05a72edeef4837e1b448d20
parent778d26e20c75ade65dc8b3a57d60d61651947df6 (diff)
downloadmongo-2603a9632c21f9e56e780f57b15313ed9d8810ff.tar.gz
use data from indexes if possivle SERVER-192
-rw-r--r--db/clientcursor.h7
-rw-r--r--db/query.cpp41
-rw-r--r--jstests/proj_key1.js28
3 files changed, 67 insertions, 9 deletions
diff --git a/db/clientcursor.h b/db/clientcursor.h
index 98cbdd8f7c2..97490b3b1fa 100644
--- a/db/clientcursor.h
+++ b/db/clientcursor.h
@@ -218,6 +218,9 @@ namespace mongo {
void setPos( int n ) { _pos = n; } // TODO : this is bad too
BSONObj indexKeyPattern() { return _c->indexKeyPattern(); }
+ bool modifiedKeys() const { return _c->modifiedKeys(); }
+ bool isMultiKey() const { return _c->isMultiKey(); }
+
bool ok() { return _c->ok(); }
bool advance(){ return _c->advance(); }
BSONObj current() { return _c->current(); }
@@ -354,8 +357,8 @@ namespace mongo {
ElapsedTracker _yieldSometimesTracker;
public:
- shared_ptr< ParsedQuery > pq;
- shared_ptr< Projection > fields; // which fields query wants returned
+ shared_ptr<ParsedQuery> pq;
+ shared_ptr<Projection> fields; // which fields query wants returned
Message originalMessage; // this is effectively an auto ptr for data the matcher points to
diff --git a/db/query.cpp b/db/query.cpp
index 7de5aa4f089..09afa14a4b2 100644
--- a/db/query.cpp
+++ b/db/query.cpp
@@ -290,7 +290,7 @@ namespace mongo {
int resultFlags = ResultFlag_AwaitCapable;
int start = 0;
int n = 0;
-
+
if ( !cc ) {
log() << "getMore: cursorid not found " << ns << " " << cursorid << endl;
cursorid = 0;
@@ -312,6 +312,10 @@ namespace mongo {
c->checkLocation();
DiskLoc last;
+ scoped_ptr<Projection::KeyOnly> keyFieldsOnly;
+ if ( cc->modifiedKeys() == false && cc->isMultiKey() == false && cc->fields )
+ keyFieldsOnly.reset( cc->fields->checkKey( cc->indexKeyPattern() ) );
+
while ( 1 ) {
if ( !c->ok() ) {
if ( c->tailable() ) {
@@ -350,11 +354,17 @@ namespace mongo {
}
else {
last = c->currLoc();
- BSONObj js = c->current();
-
- // show disk loc should be part of the main query, not in an $or clause, so this should be ok
- fillQueryResultFromObj(b, cc->fields.get(), js, ( cc->pq.get() && cc->pq->showDiskLoc() ? &last : 0));
n++;
+
+ if ( keyFieldsOnly ){
+ fillQueryResultFromObj(b, 0, keyFieldsOnly->hydrate( c->currKey() ) );
+ }
+ else {
+ BSONObj js = c->current();
+ // show disk loc should be part of the main query, not in an $or clause, so this should be ok
+ fillQueryResultFromObj(b, cc->fields.get(), js, ( cc->pq.get() && cc->pq->showDiskLoc() ? &last : 0));
+ }
+
if ( ( ntoreturn && n >= ntoreturn ) || b.len() > MaxBytesToReturnToClientAtOnce ){
c->advance();
cc->incPos( n );
@@ -547,7 +557,8 @@ namespace mongo {
b << "cursor" << c->toString() << "indexBounds" << c->prettyIndexBounds();
b.done();
}
- void noteScan( Cursor *c, long long nscanned, long long nscannedObjects, int n, bool scanAndOrder, int millis, bool hint, int nYields , int nChunkSkips ) {
+ void noteScan( Cursor *c, long long nscanned, long long nscannedObjects, int n, bool scanAndOrder,
+ int millis, bool hint, int nYields , int nChunkSkips , bool indexOnly ) {
if ( _i == 1 ) {
_c.reset( new BSONArrayBuilder() );
*_c << _b->obj();
@@ -570,6 +581,7 @@ namespace mongo {
*_b << "nYields" << nYields;
*_b << "nChunkSkips" << nChunkSkips;
*_b << "isMultiKey" << c->isMultiKey();
+ *_b << "indexOnly" << indexOnly;
*_b << "indexBounds" << c->prettyIndexBounds();
@@ -640,6 +652,15 @@ namespace mongo {
} else {
_c = qp().newCursor( DiskLoc() , _pq.getNumToReturn() + _pq.getSkip() );
_capped = _c->capped();
+
+ cout << "ELIOT : " << _pq.getFields() << endl;
+
+ // setup check for if we can only use index to extract
+ if ( _c->modifiedKeys() == false && _c->isMultiKey() == false && _pq.getFields() ){
+ cout << "\t YO" << endl;
+ _keyFieldsOnly.reset( _pq.getFields()->checkKey( _c->indexKeyPattern() ) );
+ cout << "\t " << _keyFieldsOnly.get() << endl;
+ }
}
if ( qp().scanAndOrderRequired() ) {
@@ -763,6 +784,9 @@ namespace mongo {
bb.appendKeys( _c->indexKeyPattern() , _c->currKey() );
bb.done();
}
+ else if ( _keyFieldsOnly ){
+ fillQueryResultFromObj( _buf , 0 , _keyFieldsOnly->hydrate( _c->currKey() ) );
+ }
else {
BSONObj js = _c->current();
assert( js.isValid() );
@@ -824,7 +848,9 @@ namespace mongo {
}
if ( _pq.isExplain() ) {
- _eb.noteScan( _c.get(), _nscanned, _nscannedObjects, _n, scanAndOrderRequired(), _curop.elapsedMillis(), useHints && !_pq.getHint().eoo(), _nYields , _nChunkSkips);
+ _eb.noteScan( _c.get(), _nscanned, _nscannedObjects, _n, scanAndOrderRequired(),
+ _curop.elapsedMillis(), useHints && !_pq.getHint().eoo(), _nYields ,
+ _nChunkSkips, _keyFieldsOnly.get() > 0 );
}
else {
if ( _buf.len() ) {
@@ -883,6 +909,7 @@ namespace mongo {
private:
BufBuilder _buf;
const ParsedQuery& _pq;
+ scoped_ptr<Projection::KeyOnly> _keyFieldsOnly;
long long _ntoskip;
long long _nscanned;
diff --git a/jstests/proj_key1.js b/jstests/proj_key1.js
new file mode 100644
index 00000000000..ad944f71827
--- /dev/null
+++ b/jstests/proj_key1.js
@@ -0,0 +1,28 @@
+
+t = db.proj_key1;
+t.drop();
+
+as = []
+
+for ( i=0; i<10; i++ ){
+ as.push( { a : i } )
+ t.insert( { a : i , b : i } );
+}
+
+assert( ! t.find( {} , { a : 1 } ).explain().indexOnly , "A1" )
+
+t.ensureIndex( { a : 1 } )
+
+assert( t.find( { a : { $gte : 0 } } , { a : 1 , _id : 0 } ).explain().indexOnly , "A2" )
+
+assert( ! t.find( { a : { $gte : 0 } } , { a : 1 } ).explain().indexOnly , "A3" ) // because id _id
+
+// assert( t.find( {} , { a : 1 , _id : 0 } ).explain().indexOnly , "A4" ); // TODO: need to modify query optimier SERVER-2109
+
+assert.eq( as , t.find( { a : { $gte : 0 } } , { a : 1 , _id : 0 } ).toArray() , "B1" )
+assert.eq( as , t.find( { a : { $gte : 0 } } , { a : 1 , _id : 0 } ).batchSize(2).toArray() , "B1" )
+
+
+
+
+