summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorMax Hirschhorn <max.hirschhorn@mongodb.com>2016-07-15 09:25:47 -0400
committerMax Hirschhorn <max.hirschhorn@mongodb.com>2016-07-15 09:25:47 -0400
commit25c4706ca406196a76dc325b3836f5553148203f (patch)
treec7b6b9de1f403da72c94ee7eced8cb1007537518 /jstests
parentc3d0144eba384f8d33d49f571810b921312a41c0 (diff)
downloadmongo-25c4706ca406196a76dc325b3836f5553148203f.tar.gz
SERVER-24761 Abort entire query plan when a catalog operation occurs.
Plan execution cannot proceed if the collection or a candidate index was dropped during a yield. This prevents the subplanner from trying to build plan stages when the collection and indexes no longer exist. (cherry picked from commit a7e0e028e73c0b4f543c1ded1f4af0673630617a)
Diffstat (limited to 'jstests')
-rw-r--r--jstests/concurrency/fsm_workloads/kill_rooted_or.js81
1 files changed, 81 insertions, 0 deletions
diff --git a/jstests/concurrency/fsm_workloads/kill_rooted_or.js b/jstests/concurrency/fsm_workloads/kill_rooted_or.js
new file mode 100644
index 00000000000..01383e05411
--- /dev/null
+++ b/jstests/concurrency/fsm_workloads/kill_rooted_or.js
@@ -0,0 +1,81 @@
+'use strict';
+
+/**
+ * kill_rooted_or.js
+ *
+ * Queries using a rooted $or predicate to cause plan selection to use the subplanner. Tests that
+ * the subplanner correctly halts plan execution when the collection is dropped or a candidate index
+ * is dropped.
+ *
+ * This workload was designed to reproduce SERVER-24761.
+ */
+var $config = (function() {
+
+ // Use the workload name as the collection name, since the workload name is assumed to be
+ // unique.
+ var uniqueCollectionName = 'kill_rooted_or';
+
+ var data = {
+ collName: uniqueCollectionName,
+ indexSpecs: [
+ {a: 1},
+ {a: 1, c: 1},
+ {b: 1},
+ {b: 1, c: 1},
+ ]
+ };
+
+ var states = {
+ query: function query(db, collName) {
+ var cursor = db[this.collName].find({$or: [{a: 0}, {b: 0}]});
+ try {
+ assert.eq(0, cursor.itcount());
+ } catch (e) {
+ // Ignore errors due to the plan executor being killed.
+ }
+ },
+
+ dropCollection: function dropCollection(db, collName) {
+ db[this.collName].drop();
+
+ // Recreate all of the indexes on the collection.
+ this.indexSpecs.forEach(indexSpec => {
+ assertAlways.commandWorked(db[this.collName].createIndex(indexSpec));
+ });
+ },
+
+ dropIndex: function dropIndex(db, collName) {
+ var indexSpec = this.indexSpecs[Random.randInt(this.indexSpecs.length)];
+
+ // We don't assert that the command succeeded when dropping an index because it's
+ // possible another thread has already dropped this index.
+ db[this.collName].dropIndex(indexSpec);
+
+ // Recreate the index that was dropped.
+ assertAlways.commandWorked(db[this.collName].createIndex(indexSpec));
+ }
+ };
+
+ var transitions = {
+ query: {query: 0.8, dropCollection: 0.1, dropIndex: 0.1},
+ dropCollection: {query: 1},
+ dropIndex: {query: 1}
+ };
+
+ function setup(db, collName, cluster) {
+ this.indexSpecs.forEach(indexSpec => {
+ assertAlways.commandWorked(db[this.collName].createIndex(indexSpec));
+ });
+ }
+
+ return {
+ threadCount: 10,
+ iterations: 50,
+ data: data,
+ states: states,
+ startState: 'query',
+ transitions: transitions,
+ setup: setup
+ };
+
+})();