summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp65
-rw-r--r--src/mongo/db/commands/plan_cache_commands.h35
-rw-r--r--src/mongo/db/commands/plan_cache_commands_test.cpp32
3 files changed, 62 insertions, 70 deletions
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index da280a7c172..2728fc322e8 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -94,7 +94,6 @@ namespace {
// the ActionType construction will be completed first.
new PlanCacheListQueryShapes();
new PlanCacheClear();
- new PlanCacheDrop();
new PlanCacheListPlans();
return Status::OK();
@@ -244,7 +243,7 @@ namespace mongo {
}
PlanCacheClear::PlanCacheClear() : PlanCacheCommand("planCacheClear",
- "Drops all cached queries in a collection.",
+ "Drops one or all cached queries in a collection.",
ActionType::planCacheWrite) { }
Status PlanCacheClear::runPlanCacheCommand(const string& ns, BSONObj& cmdObj,
@@ -257,53 +256,47 @@ namespace mongo {
if (!status.isOK()) {
return status;
}
- return clear(ns, planCache);
+ return clear(planCache, ns, cmdObj);
}
// static
- Status PlanCacheClear::clear(const std::string& ns, PlanCache* planCache) {
+ Status PlanCacheClear::clear(PlanCache* planCache, const string& ns, const BSONObj& cmdObj) {
invariant(planCache);
- planCache->clear();
-
- LOG(1) << ns << ": cleared plan cache";
+ // According to the specification, the planCacheClear command runs in two modes:
+ // - clear all query shapes; or
+ // - clear plans for single query shape when a query shape is described in the
+ // command arguments.
+ if (cmdObj.hasField("query")) {
+ CanonicalQuery* cqRaw;
+ Status status = PlanCacheCommand::canonicalize(ns, cmdObj, &cqRaw);
+ if (!status.isOK()) {
+ return status;
+ }
- return Status::OK();
- }
+ scoped_ptr<CanonicalQuery> cq(cqRaw);
+ Status result = planCache->remove(*cq);
+ if (!result.isOK()) {
+ return result;
+ }
- PlanCacheDrop::PlanCacheDrop() : PlanCacheCommand("planCacheDrop",
- "Drops query shape from plan cache.",
- ActionType::planCacheWrite) { }
+ LOG(1) << ns << ": removed plan cache entry - " << cq->getQueryObj().toString()
+ << "(sort: " << cq->getParsed().getSort()
+ << "; projection: " << cq->getParsed().getProj() << ")";
- Status PlanCacheDrop::runPlanCacheCommand(const string& ns, BSONObj& cmdObj,
- BSONObjBuilder* bob) {
- Client::ReadContext readCtx(ns);
- Client::Context& ctx = readCtx.ctx();
- PlanCache* planCache;
- Status status = getPlanCache(ctx.db(), ns, &planCache);
- if (!status.isOK()) {
- return status;
+ return Status::OK();
}
- return drop(planCache, ns, cmdObj);
- }
- // static
- Status PlanCacheDrop::drop(PlanCache* planCache, const string& ns, const BSONObj& cmdObj) {
- CanonicalQuery* cqRaw;
- Status status = canonicalize(ns, cmdObj, &cqRaw);
- if (!status.isOK()) {
- return status;
+ // If query is not provided, make sure sort and projection are not in arguments.
+ // We do not want to clear the entire cache inadvertently when the user
+ // forgets to provide a value for "query".
+ if (cmdObj.hasField("sort") || cmdObj.hasField("projection")) {
+ return Status(ErrorCodes::BadValue, "sort or projection provided without query");
}
- scoped_ptr<CanonicalQuery> cq(cqRaw);
- Status result = planCache->remove(*cq);
- if (!result.isOK()) {
- return result;
- }
+ planCache->clear();
- LOG(1) << ns << ": removed plan cache entry - " << cq->getQueryObj().toString()
- << "(sort: " << cq->getParsed().getSort()
- << "; projection: " << cq->getParsed().getProj() << ")";
+ LOG(1) << ns << ": cleared plan cache";
return Status::OK();
}
diff --git a/src/mongo/db/commands/plan_cache_commands.h b/src/mongo/db/commands/plan_cache_commands.h
index fd3c0832089..6cf666bce36 100644
--- a/src/mongo/db/commands/plan_cache_commands.h
+++ b/src/mongo/db/commands/plan_cache_commands.h
@@ -120,7 +120,12 @@ namespace mongo {
/**
* planCacheClear
*
- * { planCacheClear: <collection> }
+ * {
+ * planCacheClear: <collection>,
+ * query: <query>,
+ * sort: <sort>,
+ * projection: <projection>
+ * }
*
*/
class PlanCacheClear : public PlanCacheCommand {
@@ -130,32 +135,20 @@ namespace mongo {
/**
* Clears collection's plan cache.
+ * If query shape is provided, clears plans for that single query shape only.
*/
- static Status clear(const std::string& ns, PlanCache* planCache);
- };
-
- /**
- * planCacheDrop
- *
- * { planCacheDrop: <collection>, key: <key> } }
- *
- */
- class PlanCacheDrop : public PlanCacheCommand {
- public:
- PlanCacheDrop();
- virtual Status runPlanCacheCommand(const std::string& ns, BSONObj& cmdObj,
- BSONObjBuilder* bob);
-
- /**
- * Drops using a cache key.
- */
- static Status drop(PlanCache* planCache,const std::string& ns, const BSONObj& cmdObj);
+ static Status clear(PlanCache* planCache, const std::string& ns, const BSONObj& cmdObj);
};
/**
* planCacheListPlans
*
- * { planCacheListPlans: <collection>, key: <key> } }
+ * {
+ * planCacheListPlans: <collection>,
+ * query: <query>,
+ * sort: <sort>,
+ * projection: <projection>
+ * }
*
*/
class PlanCacheListPlans : public PlanCacheCommand {
diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp
index 66d8a3c9c29..0fdfad7da19 100644
--- a/src/mongo/db/commands/plan_cache_commands_test.cpp
+++ b/src/mongo/db/commands/plan_cache_commands_test.cpp
@@ -144,7 +144,7 @@ namespace {
* Tests for planCacheClear
*/
- TEST(PlanCacheCommandsTest, planCacheClearOneKey) {
+ TEST(PlanCacheCommandsTest, planCacheClearAllShapes) {
// Create a canonical query
CanonicalQuery* cqRaw;
ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw));
@@ -160,7 +160,7 @@ namespace {
ASSERT_EQUALS(getShapes(planCache).size(), 1U);
// Clear cache and confirm number of keys afterwards.
- ASSERT_OK(PlanCacheClear::clear(ns, &planCache));
+ ASSERT_OK(PlanCacheClear::clear(&planCache, ns, BSONObj()));
ASSERT_EQUALS(getShapes(planCache).size(), 0U);
}
@@ -207,24 +207,30 @@ namespace {
}
/**
- * Tests for planCacheDrop
+ * Tests for planCacheClear (single query shape)
*/
- TEST(PlanCacheCommandsTest, planCacheDropInvalidParameter) {
+ TEST(PlanCacheCommandsTest, planCacheClearInvalidParameter) {
PlanCache planCache;
- // Missing query field is not ok.
- ASSERT_NOT_OK(PlanCacheDrop::drop(&planCache, ns, BSONObj()));
- // Query field type must be PlanCacheKey.
- ASSERT_NOT_OK(PlanCacheDrop::drop(&planCache, ns, fromjson("{query: 12345}")));
- ASSERT_NOT_OK(PlanCacheDrop::drop(&planCache, ns, fromjson("{query: /keyisnotregex/}")));
+ // Query field type must be BSON object.
+ ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{query: 12345}")));
+ ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{query: /keyisnotregex/}")));
+ // Query must pass canonicalization.
+ ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns,
+ fromjson("{query: {a: {$no_such_op: 1}}}")));
+ // Sort present without query is an error.
+ ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{sort: {a: 1}}")));
+ // Projection present without query is an error.
+ ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns,
+ fromjson("{projection: {_id: 0, a: 1}}")));
}
- TEST(PlanCacheCommandsTest, planCacheDropUnknownKey) {
+ TEST(PlanCacheCommandsTest, planCacheClearUnknownKey) {
PlanCache planCache;
- ASSERT_NOT_OK(PlanCacheDrop::drop(&planCache, ns, fromjson("{query: {a: 1}}")));
+ ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{query: {a: 1}}")));
}
- TEST(PlanCacheCommandsTest, planCacheDropOneKey) {
+ TEST(PlanCacheCommandsTest, planCacheClearOneKey) {
// Create 2 canonical queries.
CanonicalQuery* cqRaw;
ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw));
@@ -253,7 +259,7 @@ namespace {
// Drop {b: 1} from cache. Make sure {a: 1} is still in cache afterwards.
BSONObjBuilder bob;
- ASSERT_OK(PlanCacheDrop::drop(&planCache, ns, BSON("query" << cqB->getQueryObj())));
+ ASSERT_OK(PlanCacheClear::clear(&planCache, ns, BSON("query" << cqB->getQueryObj())));
vector<BSONObj> shapesAfter = getShapes(planCache);
ASSERT_EQUALS(shapesAfter.size(), 1U);
ASSERT_EQUALS(shapesAfter[0], shapeA);