diff options
-rw-r--r-- | src/mongo/db/commands/count_cmd.cpp | 85 | ||||
-rw-r--r-- | src/mongo/db/exec/count.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/exec/count.h | 28 | ||||
-rw-r--r-- | src/mongo/db/query/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/query/count_request.cpp | 131 | ||||
-rw-r--r-- | src/mongo/db/query/count_request.h | 94 | ||||
-rw-r--r-- | src/mongo/db/query/count_request_test.cpp | 133 | ||||
-rw-r--r-- | src/mongo/db/query/find_and_modify_request.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/find_and_modify_request.h | 6 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.h | 2 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_request.h | 2 | ||||
-rw-r--r-- | src/mongo/dbtests/query_stage_count.cpp | 38 |
13 files changed, 416 insertions, 146 deletions
diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index 00d5b4ac731..7f4e0bf3a65 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -77,14 +77,13 @@ namespace { ExplainCommon::Verbosity verbosity, BSONObjBuilder* out) const { - CountRequest request; - Status parseStatus = parseRequest(dbname, cmdObj, &request); - if (!parseStatus.isOK()) { - return parseStatus; + auto request = CountRequest::parseFromBSON(dbname, cmdObj); + if (!request.isOK()) { + return request.getStatus(); } // Acquire the db read lock. - AutoGetCollectionForRead ctx(txn, request.ns); + AutoGetCollectionForRead ctx(txn, request.getValue().getNs()); Collection* collection = ctx.getCollection(); // Prevent chunks from being cleaned up during yields - this allows us to only check the @@ -94,7 +93,7 @@ namespace { PlanExecutor* rawExec; Status getExecStatus = getExecutorCount(txn, collection, - request, + request.getValue(), true, // explain PlanExecutor::YIELD_AUTO, &rawExec); @@ -114,13 +113,12 @@ namespace { int, string& errmsg, BSONObjBuilder& result) { - CountRequest request; - Status parseStatus = parseRequest(dbname, cmdObj, &request); - if (!parseStatus.isOK()) { - return appendCommandStatus(result, parseStatus); + auto request = CountRequest::parseFromBSON(dbname, cmdObj); + if (!request.isOK()) { + return appendCommandStatus(result, request.getStatus()); } - AutoGetCollectionForRead ctx(txn, request.ns); + AutoGetCollectionForRead ctx(txn, request.getValue().getNs()); Collection* collection = ctx.getCollection(); // Prevent chunks from being cleaned up during yields - this allows us to only check the @@ -130,7 +128,7 @@ namespace { PlanExecutor* rawExec; Status getExecStatus = getExecutorCount(txn, collection, - request, + request.getValue(), false, // !explain PlanExecutor::YIELD_AUTO, &rawExec); @@ -160,69 +158,6 @@ namespace { return true; } - /** - * Parses a count command object, 'cmdObj'. - * - * On success, fills in the out-parameter 'request' and returns an OK status. - * - * Returns a failure status if 'cmdObj' is not well formed. - */ - Status parseRequest(const std::string& dbname, - const BSONObj& cmdObj, - CountRequest* request) const { - - long long skip = 0; - if (cmdObj["skip"].isNumber()) { - skip = cmdObj["skip"].numberLong(); - if (skip < 0) { - return Status(ErrorCodes::BadValue, "skip value is negative in count query"); - } - } - else if (cmdObj["skip"].ok()) { - return Status(ErrorCodes::BadValue, "skip value is not a valid number"); - } - - long long limit = 0; - if (cmdObj["limit"].isNumber()) { - limit = cmdObj["limit"].numberLong(); - } - else if (cmdObj["limit"].ok()) { - return Status(ErrorCodes::BadValue, "limit value is not a valid number"); - } - - // For counts, limit and -limit mean the same thing. - if (limit < 0) { - limit = -limit; - } - - // We don't validate that "query" is a nested object due to SERVER-15456. - BSONObj query = cmdObj.getObjectField("query"); - - BSONObj hintObj; - if (Object == cmdObj["hint"].type()) { - hintObj = cmdObj["hint"].Obj(); - } - else if (String == cmdObj["hint"].type()) { - const std::string hint = cmdObj.getStringField("hint"); - hintObj = BSON("$hint" << hint); - } - - std::string ns = parseNs(dbname, cmdObj); - - if (!nsIsFull(ns)) { - return Status(ErrorCodes::BadValue, "collection name missing"); - } - - // Parsed correctly. Fill out 'request' with the results. - request->ns = ns; - request->query = query; - request->hint = hintObj; - request->limit = limit; - request->skip = skip; - - return Status::OK(); - } - } cmdCount; } // namespace diff --git a/src/mongo/db/exec/count.cpp b/src/mongo/db/exec/count.cpp index 9d747c31aca..7534f7e1e44 100644 --- a/src/mongo/db/exec/count.cpp +++ b/src/mongo/db/exec/count.cpp @@ -50,7 +50,7 @@ namespace mongo { : _txn(txn), _collection(collection), _request(request), - _leftToSkip(request.skip), + _leftToSkip(request.getSkip()), _ws(ws), _child(child), _commonStats(kStageType) { } @@ -62,7 +62,7 @@ namespace mongo { return true; } - if (_request.limit > 0 && _specificStats.nCounted >= _request.limit) { + if (_request.getLimit() > 0 && _specificStats.nCounted >= _request.getLimit()) { return true; } @@ -73,14 +73,14 @@ namespace mongo { invariant(_collection); long long nCounted = _collection->numRecords(_txn); - if (0 != _request.skip) { - nCounted -= _request.skip; + if (0 != _request.getSkip()) { + nCounted -= _request.getSkip(); if (nCounted < 0) { nCounted = 0; } } - long long limit = _request.limit; + long long limit = _request.getLimit(); if (limit < 0) { limit = -limit; } @@ -90,7 +90,7 @@ namespace mongo { } _specificStats.nCounted = nCounted; - _specificStats.nSkipped = _request.skip; + _specificStats.nSkipped = _request.getSkip(); _specificStats.trivialCount = true; } @@ -105,7 +105,7 @@ namespace mongo { // If we don't have a query and we have a non-NULL collection, then we can execute this // as a trivial count (just ask the collection for how many records it has). - if (_request.query.isEmpty() && NULL != _collection) { + if (_request.getQuery().isEmpty() && NULL != _collection) { trivialCount(); return PlanStage::IS_EOF; } diff --git a/src/mongo/db/exec/count.h b/src/mongo/db/exec/count.h index ff70f3b2170..05bce99ac66 100644 --- a/src/mongo/db/exec/count.h +++ b/src/mongo/db/exec/count.h @@ -30,37 +30,11 @@ #include "mongo/db/exec/plan_stage.h" +#include "mongo/db/query/count_request.h" namespace mongo { /** - * A description of a request for a count operation. Copyable. - */ - struct CountRequest { - // Namespace to operate on (e.g. "foo.bar"). - std::string ns; - - // A predicate describing the set of documents to count. - // - // NOTE: - // Parsing the raw BSON to our AST is left for later so that the parse method does not - // have to look at the catalog. Specifically, creating a CanonicalQuery requires a - // Collection* due to the WhereCallback, and we'd rather not have the parse method require - // a Collection*. - BSONObj query; - - // Indicates to the query planner that it should generate a count plan using a - // particular index. - BSONObj hint; - - // An integer limiting the number of documents to count. - long long limit; - - // An integer indicating to not include the first n documents in the count. - long long skip; - }; - - /** * Stage used by the count command. This stage sits at the root of a plan tree * and counts the number of results returned by its child stage. * diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index 66f00e9696c..bb209a8ae47 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -101,6 +101,7 @@ env.Library( env.Library( target='command_request_response', source=[ + 'count_request.cpp', 'cursor_responses.cpp', 'find_and_modify_request.cpp', 'getmore_request.cpp', @@ -115,6 +116,7 @@ env.Library( env.CppUnitTest( target='command_request_response_test', source=[ + 'count_request_test.cpp', 'find_and_modify_request_test.cpp', 'getmore_request_test.cpp', ], diff --git a/src/mongo/db/query/count_request.cpp b/src/mongo/db/query/count_request.cpp new file mode 100644 index 00000000000..a587586590f --- /dev/null +++ b/src/mongo/db/query/count_request.cpp @@ -0,0 +1,131 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/query/count_request.h" + +#include "mongo/db/namespace_string.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { +namespace { + + const char kCmdName[] = "count"; + const char kQueryField[] = "query"; + const char kLimitField[] = "limit"; + const char kSkipField[] = "skip"; + const char kHintField[] = "hint"; + +} // namespace + + CountRequest::CountRequest(const std::string& fullNs, BSONObj query) + : _fullNs(fullNs), + _query(query.getOwned()) { + } + + void CountRequest::setHint(BSONObj hint) { + _hint = hint.getOwned(); + } + + BSONObj CountRequest::toBSON() const { + BSONObjBuilder builder; + + builder.append(kCmdName, _fullNs); + builder.append(kQueryField, _query); + + if (_limit) { + builder.append(kLimitField, _limit.get()); + } + + if (_skip) { + builder.append(kSkipField, _skip.get()); + } + + if (_hint) { + builder.append(kHintField, _hint.get()); + } + + return builder.obj(); + } + + StatusWith<CountRequest> CountRequest::parseFromBSON(const std::string& dbname, + const BSONObj& cmdObj) { + + BSONElement firstElt = cmdObj.firstElement(); + const std::string coll = (firstElt.type() == BSONType::String) ? firstElt.str() : ""; + + const std::string ns = str::stream() << dbname << "." << coll; + if (!nsIsFull(ns)) { + return Status(ErrorCodes::BadValue, "invalid collection name"); + } + + // We don't validate that "query" is a nested object due to SERVER-15456. + CountRequest request(ns, cmdObj.getObjectField(kQueryField)); + + // Limit + if (cmdObj[kLimitField].isNumber()) { + long long limit = cmdObj[kLimitField].numberLong(); + + // For counts, limit and -limit mean the same thing. + if (limit < 0) { + limit = -limit; + } + + request.setLimit(limit); + } + else if (cmdObj[kLimitField].ok()) { + return Status(ErrorCodes::BadValue, "limit value is not a valid number"); + } + + // Skip + if (cmdObj[kSkipField].isNumber()) { + long long skip = cmdObj[kSkipField].numberLong(); + if (skip < 0) { + return Status(ErrorCodes::BadValue, "skip value is negative in count query"); + } + + request.setSkip(skip); + } + else if (cmdObj[kSkipField].ok()) { + return Status(ErrorCodes::BadValue, "skip value is not a valid number"); + } + + // Hint + if (Object == cmdObj[kHintField].type()) { + request.setHint(cmdObj[kHintField].Obj()); + } + else if (String == cmdObj[kHintField].type()) { + const std::string hint = cmdObj.getStringField(kHintField); + request.setHint(BSON("$hint" << hint)); + } + + return request; + } + +} // namespace mongo diff --git a/src/mongo/db/query/count_request.h b/src/mongo/db/query/count_request.h new file mode 100644 index 00000000000..0e9eb25ee30 --- /dev/null +++ b/src/mongo/db/query/count_request.h @@ -0,0 +1,94 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <string> + +#include "mongo/db/jsobj.h" + +namespace mongo { + + + template<typename T> class StatusWith; + + /** + * A description of a request for a count operation. Copyable. + */ + class CountRequest { + public: + + /** + * Construct an empty request. + */ + CountRequest(const std::string& fullNs, BSONObj query); + + const std::string& getNs() const { return _fullNs; } + const BSONObj getQuery() const { return _query; } + + long long getLimit() const { return _limit.value_or(0); } + void setLimit(long long limit) { _limit = limit; } + + long long getSkip() const { return _skip.value_or(0); } + void setSkip(long long skip) { _skip = skip; } + + const BSONObj getHint() const { return _hint.value_or(BSONObj()); } + void setHint(BSONObj hint); + + /** + * Constructs a BSON representation of this request, which can be used for sending it in + * commands. + */ + BSONObj toBSON() const; + + /** + * Construct a CountRequest from the command specification and db name. + */ + static StatusWith<CountRequest> parseFromBSON(const std::string& dbname, + const BSONObj& cmdObj); + + private: + // Namespace to operate on (e.g. "foo.bar"). + const std::string _fullNs; + + // A predicate describing the set of documents to count. + const BSONObj _query; + + // Optional. An integer limiting the number of documents to count. + boost::optional<long long> _limit; + + // Optional. An integer indicating to not include the first n documents in the count. + boost::optional<long long> _skip; + + // Optional. Indicates to the query planner that it should generate a count plan using a + // particular index. + boost::optional<BSONObj> _hint; + }; + +} // namespace mongo diff --git a/src/mongo/db/query/count_request_test.cpp b/src/mongo/db/query/count_request_test.cpp new file mode 100644 index 00000000000..4f0546b4180 --- /dev/null +++ b/src/mongo/db/query/count_request_test.cpp @@ -0,0 +1,133 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/bson/json.h" +#include "mongo/db/query/count_request.h" +#include "mongo/util/mongoutils/str.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace { + + TEST(CountRequest, ParseDefaults) { + const auto countRequestStatus = + CountRequest::parseFromBSON("TestDB", + BSON("count" << "TestColl" << + "query" << BSON("a" << BSON("$lte" << 10)))); + + ASSERT_OK(countRequestStatus.getStatus()); + + const CountRequest& countRequest = countRequestStatus.getValue(); + + ASSERT_EQUALS(countRequest.getNs(), "TestDB.TestColl"); + ASSERT_EQUALS(countRequest.getQuery(), fromjson("{ a : { '$lte' : 10 } }")); + + // Defaults + ASSERT_EQUALS(countRequest.getLimit(), 0); + ASSERT_EQUALS(countRequest.getSkip(), 0); + ASSERT(countRequest.getHint().isEmpty()); + } + + TEST(CountRequest, ParseComplete) { + const auto countRequestStatus = + CountRequest::parseFromBSON("TestDB", + BSON("count" << "TestColl" << + "query" << BSON("a" << BSON("$gte" << 11)) << + "limit" << 100 << + "skip" << 1000 << + "hint" << BSON("b" << 5))); + + ASSERT_OK(countRequestStatus.getStatus()); + + const CountRequest& countRequest = countRequestStatus.getValue(); + + ASSERT_EQUALS(countRequest.getNs(), "TestDB.TestColl"); + ASSERT_EQUALS(countRequest.getQuery(), fromjson("{ a : { '$gte' : 11 } }")); + ASSERT_EQUALS(countRequest.getLimit(), 100); + ASSERT_EQUALS(countRequest.getSkip(), 1000); + ASSERT_EQUALS(countRequest.getHint(), fromjson("{ b : 5 }")); + } + + TEST(CountRequest, ParseNegativeLimit) { + const auto countRequestStatus = + CountRequest::parseFromBSON("TestDB", + BSON("count" << "TestColl" << + "query" << BSON("a" << BSON("$gte" << 11)) << + "limit" << -100 << + "skip" << 1000 << + "hint" << BSON("b" << 5))); + + ASSERT_OK(countRequestStatus.getStatus()); + + const CountRequest& countRequest = countRequestStatus.getValue(); + + ASSERT_EQUALS(countRequest.getNs(), "TestDB.TestColl"); + ASSERT_EQUALS(countRequest.getQuery(), fromjson("{ a : { '$gte' : 11 } }")); + ASSERT_EQUALS(countRequest.getLimit(), 100); + ASSERT_EQUALS(countRequest.getSkip(), 1000); + ASSERT_EQUALS(countRequest.getHint(), fromjson("{ b : 5 }")); + } + + TEST(CountRequest, FailParseMissingNS) { + const auto countRequestStatus = + CountRequest::parseFromBSON("TestDB", + BSON("query" << BSON("a" << BSON("$gte" << 11)))); + + ASSERT_EQUALS(countRequestStatus.getStatus(), ErrorCodes::BadValue); + } + + TEST(CountRequest, FailParseBadSkipValue) { + const auto countRequestStatus = + CountRequest::parseFromBSON("TestDB", + BSON("count" << "TestColl" << + "query" << BSON("a" << BSON("$gte" << 11)) << + "skip" << -1000)); + + ASSERT_EQUALS(countRequestStatus.getStatus(), ErrorCodes::BadValue); + } + + TEST(CountRequest, ToBSON) { + CountRequest countRequest("TestDB.TestColl", BSON("a" << BSON("$gte" << 11))); + countRequest.setLimit(100); + countRequest.setSkip(1000); + countRequest.setHint(BSON("b" << 5)); + + BSONObj actualObj = countRequest.toBSON(); + BSONObj expectedObj(fromjson("{ count : 'TestDB.TestColl'," + " query : { a : { '$gte' : 11 } }," + " limit : 100," + " skip : 1000," + " hint : { b : 5 } }")); + + ASSERT_EQUALS(actualObj, expectedObj); + } + +} // namespace +} // namespace mongo diff --git a/src/mongo/db/query/find_and_modify_request.cpp b/src/mongo/db/query/find_and_modify_request.cpp index 013baeb5079..1b960198d1a 100644 --- a/src/mongo/db/query/find_and_modify_request.cpp +++ b/src/mongo/db/query/find_and_modify_request.cpp @@ -49,8 +49,6 @@ namespace { } // unnamed namespace - FindAndModifyRequest::FindAndModifyRequest() = default; - FindAndModifyRequest::FindAndModifyRequest(NamespaceString fullNs, BSONObj query, BSONObj updateObj): diff --git a/src/mongo/db/query/find_and_modify_request.h b/src/mongo/db/query/find_and_modify_request.h index 569f1c66aaf..353869abee6 100644 --- a/src/mongo/db/query/find_and_modify_request.h +++ b/src/mongo/db/query/find_and_modify_request.h @@ -50,12 +50,6 @@ namespace mongo { public: /** - * Do not use! This constructor is available only because StatusWith requires the - * type to have one. - */ - FindAndModifyRequest(); // TODO: SERVER-18007 - - /** * Creates a new instance of an 'update' type findAndModify request. */ static FindAndModifyRequest makeUpdate(NamespaceString fullNs, diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 2b7f0980b4b..0f5044273ba 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -1216,6 +1216,7 @@ namespace { bool explain, PlanExecutor::YieldPolicy yieldPolicy, PlanExecutor** execOut) { + unique_ptr<WorkingSet> ws(new WorkingSet()); PlanStage* root; QuerySolution* querySolution; @@ -1226,24 +1227,29 @@ namespace { // to create a child for the count stage in this case. // // If there is a hint, then we can't use a trival count plan as described above. - if (collection && request.query.isEmpty() && request.hint.isEmpty()) { + if (collection && request.getQuery().isEmpty() && request.getHint().isEmpty()) { root = new CountStage(txn, collection, request, ws.get(), NULL); - return PlanExecutor::make(txn, ws.release(), root, request.ns, yieldPolicy, execOut); + return PlanExecutor::make(txn, + ws.release(), + root, + request.getNs(), + yieldPolicy, + execOut); } unique_ptr<CanonicalQuery> cq; - if (!request.query.isEmpty() || !request.hint.isEmpty()) { + if (!request.getQuery().isEmpty() || !request.getHint().isEmpty()) { // If query or hint is not empty, canonicalize the query before working with collection. typedef MatchExpressionParser::WhereCallback WhereCallback; CanonicalQuery* rawCq = NULL; Status canonStatus = CanonicalQuery::canonicalize( - request.ns, - request.query, + request.getNs(), + request.getQuery(), BSONObj(), // sort BSONObj(), // projection 0, // skip 0, // limit - request.hint, + request.getHint(), BSONObj(), // min BSONObj(), // max false, // snapshot @@ -1264,7 +1270,12 @@ namespace { // reporting machinery always assumes that the root stage for a count operation is // a CountStage, so in this case we put a CountStage on top of an EOFStage. root = new CountStage(txn, collection, request, ws.get(), new EOFStage()); - return PlanExecutor::make(txn, ws.release(), root, request.ns, yieldPolicy, execOut); + return PlanExecutor::make(txn, + ws.release(), + root, + request.getNs(), + yieldPolicy, + execOut); } invariant(cq.get()); diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h index 221bef800fc..c92f67a00ca 100644 --- a/src/mongo/db/query/get_executor.h +++ b/src/mongo/db/query/get_executor.h @@ -40,7 +40,7 @@ namespace mongo { class Collection; - struct CountRequest; + class CountRequest; struct GroupRequest; diff --git a/src/mongo/db/query/getmore_request.h b/src/mongo/db/query/getmore_request.h index 197125ecfcf..2d30f96ed75 100644 --- a/src/mongo/db/query/getmore_request.h +++ b/src/mongo/db/query/getmore_request.h @@ -45,7 +45,7 @@ namespace mongo { GetMoreRequest(); /** - * Construct a GetMoreRequesst from the command specification and db name. + * Construct a GetMoreRequest from the command specification and db name. */ static StatusWith<GetMoreRequest> parseFromBSON(const std::string& dbname, const BSONObj& cmdObj); diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index 09f64990bda..3a8ea2dcb8b 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -148,7 +148,7 @@ namespace QueryStageCount { unique_ptr<WorkingSet> ws(new WorkingSet); - StatusWithMatchExpression swme = MatchExpressionParser::parse(request.query); + StatusWithMatchExpression swme = MatchExpressionParser::parse(request.getQuery()); unique_ptr<MatchExpression> expression(swme.getValue()); PlanStage* scan; @@ -164,7 +164,7 @@ namespace QueryStageCount { ASSERT_FALSE(stats->trivialCount); ASSERT_EQUALS(stats->nCounted, expected_n); - ASSERT_EQUALS(stats->nSkipped, request.skip); + ASSERT_EQUALS(stats->nSkipped, request.getSkip()); } // Performs a test using a count stage whereby each unit of work is interjected @@ -220,16 +220,6 @@ namespace QueryStageCount { return new CollectionScan(&_txn, params, ws, expr); } - CountRequest createCountRequest(const BSONObj& filter, size_t skip=0, size_t limit=0) { - CountRequest request; - request.ns = ns(); - request.query = filter; - request.limit = limit; - request.skip = skip; - request.hint = BSONObj(); - return request; - } - static const char* ns() { return "unittest.QueryStageCount"; } protected: @@ -244,8 +234,8 @@ namespace QueryStageCount { class QueryStageCountNoChangeDuringYield : public CountStageTest { public: void run() { - BSONObj filter = BSON("x" << LT << kDocuments/2); - CountRequest request = createCountRequest(filter); + CountRequest request(ns(), BSON("x" << LT << kDocuments / 2)); + testCount(request, kDocuments/2); testCount(request, kDocuments/2, true); } @@ -254,7 +244,9 @@ namespace QueryStageCount { class QueryStageCountYieldWithSkip : public CountStageTest { public: void run() { - CountRequest request = createCountRequest(BSON("x" << GTE << 0), 2); + CountRequest request(ns(), BSON("x" << GTE << 0)); + request.setSkip(2); + testCount(request, kDocuments-2); testCount(request, kDocuments-2, true); } @@ -263,7 +255,10 @@ namespace QueryStageCount { class QueryStageCountYieldWithLimit : public CountStageTest { public: void run() { - CountRequest request = createCountRequest(BSON("x" << GTE << 0), 0, 2); + CountRequest request(ns(), BSON("x" << GTE << 0)); + request.setSkip(0); + request.setLimit(2); + testCount(request, 2); testCount(request, 2, true); } @@ -273,7 +268,8 @@ namespace QueryStageCount { class QueryStageCountInsertDuringYield : public CountStageTest { public: void run() { - CountRequest request = createCountRequest(BSON("x" << 1)); + CountRequest request(ns(), BSON("x" << 1)); + testCount(request, kInterjections+1); testCount(request, kInterjections+1, true); } @@ -289,7 +285,8 @@ namespace QueryStageCount { void run() { // expected count would be 99 but we delete the second record // after doing the first unit of work - CountRequest request = createCountRequest(BSON("x" << GTE << 1)); + CountRequest request(ns(), BSON("x" << GTE << 1)); + testCount(request, kDocuments-2); testCount(request, kDocuments-2, true); } @@ -313,7 +310,8 @@ namespace QueryStageCount { void run() { // expected count would be kDocuments-2 but we update the first and second records // after doing the first unit of work so they wind up getting counted later on - CountRequest request = createCountRequest(BSON("x" << GTE << 2)); + CountRequest request(ns(), BSON("x" << GTE << 2)); + testCount(request, kDocuments); testCount(request, kDocuments, true); } @@ -335,7 +333,7 @@ namespace QueryStageCount { class QueryStageCountMultiKeyDuringYield : public CountStageTest { public: void run() { - CountRequest request = createCountRequest(BSON("x" << 1)); + CountRequest request(ns(), BSON("x" << 1)); testCount(request, kDocuments+1, true); // only applies to indexed case } |