Skip to content

Commit

Permalink
SERVER-4150 Separate match reporting from ordered match reporting for…
Browse files Browse the repository at this point in the history
… proper plan specific output when a single out of order plan runs; fix incorrect explain4 test.
  • Loading branch information
astaple committed Mar 14, 2012
1 parent f427d5c commit 88ea9f1
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 69 deletions.
40 changes: 20 additions & 20 deletions jstests/explain4.js
@@ -1,43 +1,43 @@
// Basic validation of explain output fields
// Basic validation of explain output fields.

t = db.jstests_explain4;
t.drop();

function checkField( name, value ) {
function checkField( explain, name, value ) {
assert( explain.hasOwnProperty( name ) );
if ( value != null ) {
assert.eq( value, explain[ name ], name );
}
}

function checkPlanFields( explain, matches, n ) {
checkField( "cursor", "BasicCursor" );
checkField( "n", n );
checkField( "nscannedObjects", matches );
checkField( "nscanned", matches );
checkField( "indexBounds", {} );
checkField( explain, "cursor", "BasicCursor" );
checkField( explain, "n", n );
checkField( explain, "nscannedObjects", matches );
checkField( explain, "nscanned", matches );
checkField( explain, "indexBounds", {} );
}

function checkFields( matches, sort, limit ) {
it = t.find();
cursor = t.find();
if ( sort ) {
it.sort({a:1});
cursor.sort({a:1});
}
if ( limit ) {
it.limit( limit );
cursor.limit( limit );
}
explain = it.explain( true );
explain = cursor.explain( true );
// printjson( explain );
checkPlanFields( explain, matches, matches > 0 ? 1 : 0 );
checkField( "scanAndOrder", sort );
checkField( "millis" );
checkField( "nYields" );
checkField( "nChunkSkips", 0 );
checkField( "isMultiKey", false );
checkField( "indexOnly", false );
checkField( "server" );
checkField( "allPlans" );
explain.allPlans.forEach( function( x ) { checkPlanFields( x, matches ); } );
checkField( explain, "scanAndOrder", sort );
checkField( explain, "millis" );
checkField( explain, "nYields" );
checkField( explain, "nChunkSkips", 0 );
checkField( explain, "isMultiKey", false );
checkField( explain, "indexOnly", false );
checkField( explain, "server" );
checkField( explain, "allPlans" );
explain.allPlans.forEach( function( x ) { checkPlanFields( x, matches, matches ); } );
}

checkFields( 0, false );
Expand Down
2 changes: 1 addition & 1 deletion jstests/explain6.js
Expand Up @@ -20,4 +20,4 @@ t.dropIndexes();
explain = t.find().skip( 1 ).sort({a:1}).explain( true );
// Skip is applied for an in memory sort.
assert.eq( 0, explain.n );
assert.eq( 0, explain.allPlans[ 0 ].n );
assert.eq( 1, explain.allPlans[ 0 ].n );
69 changes: 38 additions & 31 deletions src/mongo/db/ops/query.cpp
Expand Up @@ -234,13 +234,14 @@ namespace mongo {
MatchCountingExplainStrategy::MatchCountingExplainStrategy
( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo ) :
ExplainRecordingStrategy( ancillaryInfo ),
_matches() {
_orderedMatches() {
}

void MatchCountingExplainStrategy::noteIterate( bool match, bool loadedObject, bool chunkSkip ) {
_noteIterate( match, loadedObject, chunkSkip );
if ( match ) {
++_matches;
void MatchCountingExplainStrategy::noteIterate( bool match, bool orderedMatch,
bool loadedObject, bool chunkSkip ) {
_noteIterate( match, orderedMatch, loadedObject, chunkSkip );
if ( orderedMatch ) {
++_orderedMatches;
}
}

Expand All @@ -256,7 +257,8 @@ namespace mongo {
_explainInfo->notePlan( *_cursor, scanAndOrder, indexOnly );
}

void SimpleCursorExplainStrategy::_noteIterate( bool match, bool loadedObject, bool chunkSkip ) {
void SimpleCursorExplainStrategy::_noteIterate( bool match, bool orderedMatch,
bool loadedObject, bool chunkSkip ) {
_explainInfo->noteIterate( match, loadedObject, chunkSkip, *_cursor );
}

Expand All @@ -276,9 +278,11 @@ namespace mongo {
_cursor( cursor ) {
}

void QueryOptimizerCursorExplainStrategy::_noteIterate( bool match, bool loadedObject,
bool chunkSkip ) {
_cursor->noteIterate( match, loadedObject, chunkSkip );
void QueryOptimizerCursorExplainStrategy::_noteIterate( bool match, bool orderedMatch,
bool loadedObject, bool chunkSkip ) {
// Note ordered matches only; if an unordered plan is selected, the explain result will
// be updated with reviseN().
_cursor->noteIterate( orderedMatch, loadedObject, chunkSkip );
}

shared_ptr<ExplainQueryInfo> QueryOptimizerCursorExplainStrategy::_doneQueryInfo() {
Expand Down Expand Up @@ -336,22 +340,22 @@ namespace mongo {
_bufferedMatches() {
}

bool OrderedBuildStrategy::handleMatch() {
bool OrderedBuildStrategy::handleMatch( bool &orderedMatch ) {
DiskLoc loc = _cursor->currLoc();
if ( _cursor->getsetdup( loc ) ) {
return false;
return orderedMatch = false;
}
if ( _skip > 0 ) {
--_skip;
return false;
return orderedMatch = false;
}
// Explain does not obey soft limits, so matches should not be buffered.
if ( !_parsedQuery.isExplain() ) {
fillQueryResultFromObj( _buf, _parsedQuery.getFields(), current( true ),
( _parsedQuery.showDiskLoc() ? &loc : 0 ) );
++_bufferedMatches;
}
return true;
return orderedMatch = true;
}

ReorderBuildStrategy::ReorderBuildStrategy( const ParsedQuery &parsedQuery,
Expand All @@ -363,17 +367,18 @@ namespace mongo {
_bufferedMatches() {
}

bool ReorderBuildStrategy::handleMatch() {
bool ReorderBuildStrategy::handleMatch( bool &orderedMatch ) {
orderedMatch = false;
if ( _cursor->getsetdup( _cursor->currLoc() ) ) {
return false;
}
return _handleMatchNoDedup();
_handleMatchNoDedup();
return true;
}

bool ReorderBuildStrategy::_handleMatchNoDedup() {
void ReorderBuildStrategy::_handleMatchNoDedup() {
DiskLoc loc = _cursor->currLoc();
_scanAndOrder->add( current( false ), _parsedQuery.showDiskLoc() ? &loc : 0 );
return false;
}

int ReorderBuildStrategy::rewriteMatches() {
Expand Down Expand Up @@ -412,18 +417,18 @@ namespace mongo {
_reorderedMatches() {
}

bool HybridBuildStrategy::handleMatch() {
bool HybridBuildStrategy::handleMatch( bool &orderedMatch ) {
if ( !_queryOptimizerCursor->currentPlanScanAndOrderRequired() ) {
return _orderedBuild.handleMatch();
return _orderedBuild.handleMatch( orderedMatch );
}
handleReorderMatch();
return false;
orderedMatch = false;
return handleReorderMatch();
}

void HybridBuildStrategy::handleReorderMatch() {
bool HybridBuildStrategy::handleReorderMatch() {
DiskLoc loc = _cursor->currLoc();
if ( _scanAndOrderDups.getsetdup( loc ) ) {
return;
return false;
}
try {
_reorderBuild._handleMatchNoDedup();
Expand All @@ -435,11 +440,12 @@ namespace mongo {
}
else if ( _queryOptimizerCursor->runningInitialInOrderPlan() ) {
_queryOptimizerCursor->abortOutOfOrderPlans();
return;
return true;
}
}
throw;
}
}
return true;
}

int HybridBuildStrategy::rewriteMatches() {
Expand Down Expand Up @@ -482,9 +488,10 @@ namespace mongo {
if ( !chunkMatches() ) {
return false;
}
bool orderedMatch = _builder->handleMatch();
_explain->noteIterate( orderedMatch, true, false );
return true;
bool orderedMatch = false;
bool match = _builder->handleMatch( orderedMatch );
_explain->noteIterate( match, orderedMatch, true, false );
return match;
}

void QueryResponseBuilder::noteYield() {
Expand All @@ -497,7 +504,7 @@ namespace mongo {

bool QueryResponseBuilder::enoughTotalResults() const {
if ( _parsedQuery.isExplain() ) {
return _parsedQuery.enoughForExplain( _explain->matches() );
return _parsedQuery.enoughForExplain( _explain->orderedMatches() );
}
return ( _parsedQuery.enough( _builder->bufferedMatches() ) ||
_buf.len() >= MaxBytesToReturnToClientAtOnce );
Expand Down Expand Up @@ -584,7 +591,7 @@ namespace mongo {
if ( _cursor->currentMatches( &details ) ) {
return true;
}
_explain->noteIterate( false, details._loadedObject, false );
_explain->noteIterate( false, false, details._loadedObject, false );
return false;
}

Expand All @@ -596,7 +603,7 @@ namespace mongo {
if ( _chunkManager->belongsToMe( _cursor->current() ) ) {
return true;
}
_explain->noteIterate( false, true, true );
_explain->noteIterate( false, false, true, true );
return false;
}

Expand Down
39 changes: 22 additions & 17 deletions src/mongo/db/ops/query.h
Expand Up @@ -54,11 +54,12 @@ namespace mongo {
/** Note information about a single query plan. */
virtual void notePlan( bool scanAndOrder, bool indexOnly ) {}
/** Note an iteration of the query. */
virtual void noteIterate( bool match, bool loadedObject, bool chunkSkip ) {}
virtual void noteIterate( bool match, bool orderedMatch, bool loadedObject,
bool chunkSkip ) {}
/** Note that the query yielded. */
virtual void noteYield() {}
/** @return number of matches noted. */
virtual long long matches() const { return 0; }
/** @return number of ordered matches noted. */
virtual long long orderedMatches() const { return 0; }
/** @return ExplainQueryInfo for a complete query. */
shared_ptr<ExplainQueryInfo> doneQueryInfo();
protected:
Expand All @@ -81,11 +82,13 @@ namespace mongo {
public:
MatchCountingExplainStrategy( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo );
protected:
virtual void _noteIterate( bool match, bool loadedObject, bool chunkSkip ) = 0;
virtual void _noteIterate( bool match, bool orderedMatch, bool loadedObject,
bool chunkSkip ) = 0;
private:
virtual void noteIterate( bool match, bool loadedObject, bool chunkSkip );
virtual long long matches() const { return _matches; }
long long _matches;
virtual void noteIterate( bool match, bool orderedMatch, bool loadedObject,
bool chunkSkip );
virtual long long orderedMatches() const { return _orderedMatches; }
long long _orderedMatches;
};

/** Record explain events for a simple cursor representing a single clause and plan. */
Expand All @@ -95,7 +98,8 @@ namespace mongo {
const shared_ptr<Cursor> &cursor );
private:
virtual void notePlan( bool scanAndOrder, bool indexOnly );
virtual void _noteIterate( bool match, bool loadedObject, bool chunkSkip );
virtual void _noteIterate( bool match, bool orderedMatch, bool loadedObject,
bool chunkSkip );
virtual void noteYield();
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
shared_ptr<Cursor> _cursor;
Expand All @@ -111,7 +115,8 @@ namespace mongo {
QueryOptimizerCursorExplainStrategy( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo,
const shared_ptr<QueryOptimizerCursor> &cursor );
private:
virtual void _noteIterate( bool match, bool loadedObject, bool chunkSkip );
virtual void _noteIterate( bool match, bool orderedMatch, bool loadedObject,
bool chunkSkip );
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
shared_ptr<QueryOptimizerCursor> _cursor;
};
Expand All @@ -128,9 +133,10 @@ namespace mongo {
virtual ~ResponseBuildStrategy() {}
/**
* Handle the current iterate of the supplied cursor as a (possibly duplicate) match.
* @return true if an ordered match is found.
* @return true if a match is found.
* @param orderedMatch set if it is an ordered match.
*/
virtual bool handleMatch() = 0;
virtual bool handleMatch( bool &orderedMatch ) = 0;
/**
* Write all matches into the buffer, overwriting existing data.
* @return number of matches written, or -1 if no op.
Expand Down Expand Up @@ -165,7 +171,7 @@ namespace mongo {
public:
OrderedBuildStrategy( const ParsedQuery &parsedQuery, const shared_ptr<Cursor> &cursor,
BufBuilder &buf, const QueryPlan::Summary &queryPlan );
virtual bool handleMatch();
virtual bool handleMatch( bool &orderedMatch );
virtual int bufferedMatches() const { return _bufferedMatches; }
private:
int _skip;
Expand All @@ -181,9 +187,9 @@ namespace mongo {
const shared_ptr<Cursor> &cursor,
BufBuilder &buf,
const QueryPlan::Summary &queryPlan );
virtual bool handleMatch();
virtual bool handleMatch( bool &orderedMatch );
/** Handle a match without performing deduping. */
bool _handleMatchNoDedup();
void _handleMatchNoDedup();
virtual int rewriteMatches();
virtual int bufferedMatches() const { return _bufferedMatches; }
private:
Expand All @@ -202,12 +208,11 @@ namespace mongo {
const shared_ptr<QueryOptimizerCursor> &cursor,
BufBuilder &buf );
private:
virtual bool handleMatch();
virtual bool handleMatch( bool &orderedMatch );
virtual int rewriteMatches();
virtual int bufferedMatches() const;
virtual void finishedFirstBatch();
void handleReorderMatch();
bool handleOrderedMatch();
bool handleReorderMatch();
DiskLocDupSet _scanAndOrderDups;
OrderedBuildStrategy _orderedBuild;
ReorderBuildStrategy _reorderBuild;
Expand Down

0 comments on commit 88ea9f1

Please sign in to comment.