Permalink
Browse files

SERVER-4980 Add Cursor::keyFieldsOnly() and use it to implement proje…

…ction in processGetMore via ClientCursor::fillQueryResultFromObject().
  • Loading branch information...
1 parent 131dd55 commit 4a17a039e05076364049d3903da4c6cb5b562c69 @astaple astaple committed Apr 20, 2012
View
4 jstests/coveredIndex4.js
@@ -1,8 +1,6 @@
// Test covered index projection with $or clause, specifically in getMore
// SERVER-4980
-if ( 0 ) { // SERVER-4980
-
t = db.jstests_coveredIndex4;
t.drop();
@@ -40,5 +38,3 @@ while( c.hasNext() ) {
assert.eq( 1, o.b % 2, 'unexpected result: ' + tojson( o ) );
}
}
-
-}
View
7 src/mongo/db/btree.h
@@ -1089,6 +1089,12 @@ namespace mongo {
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; }
+ virtual const Projection::KeyOnly *keyFieldsOnly() const { return _keyFieldsOnly.get(); }
+
+ virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly> &keyFieldsOnly ) {
+ _keyFieldsOnly = keyFieldsOnly;
+ }
+
virtual long long nscanned() { return _nscanned; }
/** for debugging only */
@@ -1141,6 +1147,7 @@ namespace mongo {
const shared_ptr< FieldRangeVector > _bounds;
auto_ptr< FieldRangeVectorIterator > _boundsIterator;
shared_ptr< CoveredIndexMatcher > _matcher;
+ shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _independentFieldRanges;
long long _nscanned;
};
View
12 src/mongo/db/clientcursor.cpp
@@ -32,6 +32,7 @@
#include "../util/processinfo.h"
#include "../util/timer.h"
#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/scanandorder.h"
namespace mongo {
@@ -418,6 +419,17 @@ namespace mongo {
return b.obj();
}
+ void ClientCursor::fillQueryResultFromObj( BufBuilder &b ) const {
+ const Projection::KeyOnly *keyFieldsOnly = c()->keyFieldsOnly();
+ if ( keyFieldsOnly ) {
+ mongo::fillQueryResultFromObj( b, 0, keyFieldsOnly->hydrate( c()->currKey() ) );
+ }
+ else {
+ DiskLoc loc = c()->currLoc();
+ mongo::fillQueryResultFromObj( b, fields.get(), c()->current(),
+ ( ( pq && pq->showDiskLoc() ) ? &loc : 0 ) );
+ }
+ }
/* call when cursor's location changes so that we can update the
cursorsbylocation map. if you are locked and internally iterating, only
View
2 src/mongo/db/clientcursor.h
@@ -286,6 +286,8 @@ namespace mongo {
*/
BSONObj extractFields(const BSONObj &pattern , bool fillWithNull = false) ;
+ void fillQueryResultFromObj( BufBuilder &b ) const;
+
bool currentIsDup() { return _c->getsetdup( _c->currLoc() ); }
bool currentMatches() {
View
19 src/mongo/db/cursor.h
@@ -21,6 +21,7 @@
#include "jsobj.h"
#include "diskloc.h"
#include "matcher.h"
+#include "mongo/db/projection.h"
namespace mongo {
@@ -187,12 +188,23 @@ namespace mongo {
}
// A convenience function for setting the value of matcher() manually
- // so it may accessed later. Implementations which must generate
+ // so it may be accessed later. Implementations which must generate
// their own matcher() should assert here.
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) {
massert( 13285, "manual matcher config not allowed", false );
}
+ /** @return the covered index projector for the current iterate, if any. */
+ virtual const Projection::KeyOnly *keyFieldsOnly() const { return 0; }
+
+ /**
+ * Manually set the value of keyFieldsOnly() so it may be accessed later. Implementations
+ * that generate their own keyFieldsOnly() must assert.
+ */
+ virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly> &keyFieldsOnly ) {
+ massert( 16151, "manual keyFieldsOnly config not allowed", false );
+ }
+
virtual void explainDetails( BSONObjBuilder& b ) { return; }
};
@@ -249,6 +261,10 @@ namespace mongo {
virtual CoveredIndexMatcher *matcher() const { return _matcher.get(); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { return _matcher; }
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; }
+ virtual const Projection::KeyOnly *keyFieldsOnly() const { return _keyFieldsOnly.get(); }
+ virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly> &keyFieldsOnly ) {
+ _keyFieldsOnly = keyFieldsOnly;
+ }
virtual long long nscanned() { return _nscanned; }
protected:
@@ -258,6 +274,7 @@ namespace mongo {
private:
bool tailable_;
shared_ptr< CoveredIndexMatcher > _matcher;
+ shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
long long _nscanned;
void init() { tailable_ = false; }
};
View
35 src/mongo/db/ops/query.cpp
@@ -113,10 +113,6 @@ namespace mongo {
c->recoverFromYield();
DiskLoc last;
- scoped_ptr<Projection::KeyOnly> keyFieldsOnly;
- if ( cc->modifiedKeys() == false && cc->isMultiKey() == false && cc->fields )
- keyFieldsOnly.reset( cc->fields->checkKey( cc->indexKeyPattern() ) );
-
// This manager may be stale, but it's the state of chunking when the cursor was created.
ShardChunkManagerPtr manager = cc->getChunkManager();
@@ -158,14 +154,7 @@ namespace mongo {
last = c->currLoc();
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));
- }
+ cc->fillQueryResultFromObj( b );
if ( ( ntoreturn && n >= ntoreturn ) || b.len() > MaxBytesToReturnToClientAtOnce ) {
c->advance();
@@ -176,7 +165,8 @@ namespace mongo {
}
c->advance();
- if ( ! cc->yieldSometimes( keyFieldsOnly ? ClientCursor::DontNeed : ClientCursor::WillNeed ) ) {
+ if ( ! cc->yieldSometimes( ( c->ok() && c->keyFieldsOnly() ) ?
+ ClientCursor::DontNeed : ClientCursor::WillNeed ) ) {
ClientCursor::erase(cursorid);
cursorid = 0;
cc = 0;
@@ -295,8 +285,7 @@ namespace mongo {
_parsedQuery( parsedQuery ),
_cursor( cursor ),
_queryOptimizerCursor( dynamic_pointer_cast<QueryOptimizerCursor>( _cursor ) ),
- _buf( buf ),
- _planKeyFieldsOnly( queryPlan._keyFieldsOnly ) {
+ _buf( buf ) {
}
void ResponseBuildStrategy::resetBuf() {
@@ -311,26 +300,16 @@ namespace mongo {
return bob.obj();
}
if ( allowCovered ) {
- const Projection::KeyOnly *fields = keyFieldsOnly();
- if ( fields ) {
- return fields->hydrate( _cursor->currKey() );
+ const Projection::KeyOnly *keyFieldsOnly = _cursor->keyFieldsOnly();
+ if ( keyFieldsOnly ) {
+ return keyFieldsOnly->hydrate( _cursor->currKey() );
}
}
BSONObj ret = _cursor->current();
verify( ret.isValid() );
return ret;
}
- const Projection::KeyOnly *ResponseBuildStrategy::keyFieldsOnly() const {
- if ( !_parsedQuery.getFields() ) {
- return 0;
- }
- if ( _queryOptimizerCursor ) {
- return _queryOptimizerCursor->keyFieldsOnly();
- }
- return _planKeyFieldsOnly.get();
- }
-
OrderedBuildStrategy::OrderedBuildStrategy( const ParsedQuery &parsedQuery,
const shared_ptr<Cursor> &cursor,
BufBuilder &buf,
View
4 src/mongo/db/ops/query.h
@@ -24,7 +24,6 @@
#include "../jsobj.h"
#include "../diskloc.h"
#include "../explain.h"
-#include "mongo/db/projection.h"
#include "../../s/d_chunk_manager.h"
// struct QueryOptions, QueryResult, QueryResultFlags in:
@@ -163,9 +162,6 @@ namespace mongo {
shared_ptr<Cursor> _cursor;
shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
BufBuilder &_buf;
- private:
- const Projection::KeyOnly *keyFieldsOnly() const;
- shared_ptr<Projection::KeyOnly> _planKeyFieldsOnly;
};
/** Build strategy for a cursor returning in order results. */
View
3 src/mongo/db/queryoptimizercursor.h
@@ -20,7 +20,6 @@
#include "cursor.h"
#include "diskloc.h"
-#include "projection.h"
namespace mongo {
@@ -97,8 +96,6 @@ namespace mongo {
/** @return true if the plan for the current iterate is out of order. */
virtual bool currentPlanScanAndOrderRequired() const = 0;
- /** @return the covered index projector for the current iterate (may be 0). */
- virtual const Projection::KeyOnly *keyFieldsOnly() const = 0;
/** @return true when there may be multiple plans running and some are in order. */
virtual bool runningInitialInOrderPlan() const = 0;
View
7 src/mongo/db/queryoptimizercursorimpl.cpp
@@ -215,7 +215,9 @@ namespace mongo {
}
shared_ptr<ExplainPlanInfo> explainInfo() const { return _explainPlanInfo; }
- const Projection::KeyOnly *keyFieldsOnly() const { return qp().keyFieldsOnly().get(); }
+ virtual const Projection::KeyOnly *keyFieldsOnly() const {
+ return qp().keyFieldsOnly().get();
+ }
private:
void mayAdvance() {
@@ -801,6 +803,9 @@ namespace mongo {
( new CoveredIndexMatcher( _query, single->indexKeyPattern() ) );
single->setMatcher( matcher );
}
+ if ( singlePlan->keyFieldsOnly() ) {
+ single->setKeyFieldsOnly( singlePlan->keyFieldsOnly() );
+ }
if ( _simpleEqualityMatch ) {
if ( singlePlan->exactKeyMatch() && !single->matcher()->needRecord() ) {
*_simpleEqualityMatch = true;

0 comments on commit 4a17a03

Please sign in to comment.