| Steps To Reproduce: |
jstests/concurrency/fsm_workloads/CRUD_and_commands.js
|
diff --git a/jstests/concurrency/fsm_workloads/CRUD_and_commands.js b/jstests/concurrency/fsm_workloads/CRUD_and_commands.js
|
new file mode 100644
|
index 0000000000..6fc472dd93
|
--- /dev/null
|
+++ b/jstests/concurrency/fsm_workloads/CRUD_and_commands.js
|
@@ -0,0 +1,223 @@
|
+'use strict';
|
+
|
+/**
|
+ * Perform CRUD operations, some of which may implicitly create collections. Also perform index
|
+ * creations which may implicitly create collections.
|
+ */
|
+
|
+var $config = (function() {
|
+ const data = {numIds: 10, numDocsToInsertPerThread: 5, valueToBeInserted: 1, batchSize: 50};
|
+
|
+ const states = {
|
+ init: function init(db, collName) {
|
+ this.session = db.getMongo().startSession({causalConsistency: true});
|
+ this.sessionDb = this.session.getDatabase(db.getName());
|
+ this.docValue = "mydoc";
|
+ },
|
+
|
+ insertDocs: function insertDocs(db, collName) {
|
+ for (let i = 0; i < 5; i++) {
|
+ const res = db[collName].insert({value: this.docValue, num: 1});
|
+ assertWhenOwnColl.commandWorked(res);
|
+ assertWhenOwnColl.eq(1, res.nInserted);
|
+ }
|
+ },
|
+
|
+ updateDocs: function updateDocs(db, collName) {
|
+ for (let i = 0; i < 5; ++i) {
|
+ let indexToUpdate = Math.floor(Math.random() * this.numIds);
|
+ try {
|
+ assertWhenOwnColl.commandWorked(db[collName].update(
|
+ {_id: indexToUpdate}, {$inc: {num: 1}}, {upsert: true}));
|
+ } catch (e) {
|
+ // We propagate TransientTransactionErrors to allow the state function to
|
+ // automatically be retried when TestData.runInsideTransaction=true
|
+ if (e.hasOwnProperty('errorLabels') &&
|
+ e.errorLabels.includes('TransientTransactionError')) {
|
+ throw e;
|
+ }
|
+ // dropIndex can cause queries to throw if these queries yield.
|
+ assertAlways.contains(e.code,
|
+ [ErrorCodes.QueryPlanKilled, ErrorCodes.OperationFailed],
|
+ 'unexpected error code: ' + e.code + ': ' + e.message);
|
+ }
|
+ }
|
+ },
|
+
|
+ readDocs: function readDocs(db, collName) {
|
+ for (let i = 0; i < 5; ++i) {
|
+ try {
|
+ let res = db[collName].findOne({value: this.docValue});
|
+ if (res !== null) {
|
+ assertAlways.eq(this.docValue, res.value);
|
+ }
|
+ } catch (e) {
|
+ // We propagate TransientTransactionErrors to allow the state function to
|
+ // automatically be retried when TestData.runInsideTransaction=true
|
+ if (e.hasOwnProperty('errorLabels') &&
|
+ e.errorLabels.includes('TransientTransactionError')) {
|
+ throw e;
|
+ }
|
+ // dropIndex can cause queries to throw if these queries yield.
|
+ assertAlways.contains(e.code,
|
+ [ErrorCodes.QueryPlanKilled, ErrorCodes.OperationFailed],
|
+ 'unexpected error code: ' + e.code + ': ' + e.message);
|
+ }
|
+ }
|
+ },
|
+
|
+ deleteDocs: function deleteDocs(db, collName) {
|
+ let indexToDelete = Math.floor(Math.random() * this.numIds);
|
+ try {
|
+ db[collName].deleteOne({_id: indexToDelete});
|
+ } catch (e) {
|
+ // We propagate TransientTransactionErrors to allow the state function to
|
+ // automatically be retried when TestData.runInsideTransaction=true
|
+ if (e.hasOwnProperty('errorLabels') &&
|
+ e.errorLabels.includes('TransientTransactionError')) {
|
+ throw e;
|
+ }
|
+ // dropIndex can cause queries to throw if these queries yield.
|
+ assertAlways.contains(e.code,
|
+ [ErrorCodes.QueryPlanKilled, ErrorCodes.OperationFailed],
|
+ 'unexpected error code: ' + e.code + ': ' + e.message);
|
+ }
|
+ },
|
+
|
+ createIndex: function createIndex(db, collName) {
|
+ db[collName].createIndex({value: 1});
|
+ },
|
+
|
+ createIdIndex: function createIdIndex(db, collName) {
|
+ assertWhenOwnColl.commandWorked(db[collName].createIndex({_id: 1}));
|
+ },
|
+
|
+ dropIndex: function dropIndex(db, collName) {
|
+ db[collName].dropIndex({value: 1});
|
+ },
|
+
|
+ dropCollection: function dropCollection(db, collName) {
|
+ db[collName].drop();
|
+ /*
|
+ // The above drop forces this state to be run outside of a transaction, so it is fine to
|
+ // ignore DuplicateKey errors here.
|
+ for (let i = 0; i < this.numIds; i++) {
|
+ const res = db[collName].insert({_id: i, value: this.docValue, num: 1});
|
+ assertAlways.commandWorkedOrFailedWithCode(res, ErrorCodes.DuplicateKey);
|
+ }*/
|
+ }
|
+
|
+ };
|
+
|
+ const transitions = {
|
+ init: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.10
|
+ },
|
+ insertDocs: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ updateDocs: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ readDocs: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ deleteDocs: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ createIndex: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ createIdIndex: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ dropIndex: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.30
|
+ },
|
+ dropCollection: {
|
+ insertDocs: 0.10,
|
+ updateDocs: 0.10,
|
+ readDocs: 0.10,
|
+ deleteDocs: 0.10,
|
+ createIndex: 0.10,
|
+ createIdIndex: 0.10,
|
+ dropIndex: 0.10,
|
+ dropCollection: 0.10
|
+ }
|
+ };
|
+
|
+ function setup(db, collName, cluster) {
|
+ assertAlways.commandWorked(db.runCommand({create: collName}));
|
+ for (let i = 0; i < this.numIds; i++) {
|
+ const res = db[collName].insert({_id: i, value: this.docValue, num: 1});
|
+ assertAlways.commandWorked(res);
|
+ assert.eq(1, res.nInserted);
|
+ }
|
+ }
|
+
|
+ return {
|
+ threadCount: 5,
|
+ iterations: 10,
|
+ startState: 'init',
|
+ states: states,
|
+ transitions: transitions,
|
+ setup: setup,
|
+ data: data,
|
+ };
|
+})();
|
|