diff options
author | Daniel Gottlieb <daniel.gottlieb@10gen.com> | 2017-01-13 13:28:29 -0500 |
---|---|---|
committer | Daniel Gottlieb <daniel.gottlieb@10gen.com> | 2017-01-13 13:28:29 -0500 |
commit | 5a4686591b4d7b4f85cf87a913b6f17ae5941ce5 (patch) | |
tree | c398300b806d56c79d5e36790be7afbcd2eb2691 /jstests/concurrency | |
parent | 5313582dae3fc0fe11d91dbbc3d2a8154de3b038 (diff) | |
download | mongo-5a4686591b4d7b4f85cf87a913b6f17ae5941ce5.tar.gz |
SERVER-24563 Fix race in check for DB names that differ in case only
(cherry picked from commit dceaf6bf28fb879eb23f3c022647ee3e8f15c370)
Modifications for backport:
src/mongo/db/catalog/database_holder.h
src/mongo/db/catalog/database_holder.cpp
jstests/concurrency/fsm_all_sharded_replication.js
jstests/concurrency/fsm_all_sharded_replication_with_balancer.js
jstests/concurrency/fsm_workloads/create_database.js
Diffstat (limited to 'jstests/concurrency')
3 files changed, 142 insertions, 0 deletions
diff --git a/jstests/concurrency/fsm_all_sharded_replication.js b/jstests/concurrency/fsm_all_sharded_replication.js index d4068148d47..435277a2a47 100644 --- a/jstests/concurrency/fsm_all_sharded_replication.js +++ b/jstests/concurrency/fsm_all_sharded_replication.js @@ -9,6 +9,7 @@ var blacklist = [ 'distinct.js', // SERVER-13116 distinct isn't sharding aware 'distinct_noindex.js', // SERVER-13116 distinct isn't sharding aware 'distinct_projection.js', // SERVER-13116 distinct isn't sharding aware + 'create_database.js', // SERVER-17397 Drops of sharded namespaces may not fully succeed 'drop_database.js', // SERVER-17397 Drops of sharded namespaces may not fully succeed // Disabled due to SERVER-3645, '.count() can be wrong on sharded collections'. diff --git a/jstests/concurrency/fsm_all_sharded_replication_with_balancer.js b/jstests/concurrency/fsm_all_sharded_replication_with_balancer.js index 444f7eab3cb..59d6e0f4a61 100644 --- a/jstests/concurrency/fsm_all_sharded_replication_with_balancer.js +++ b/jstests/concurrency/fsm_all_sharded_replication_with_balancer.js @@ -9,6 +9,7 @@ var blacklist = [ 'distinct.js', // SERVER-13116 distinct isn't sharding aware 'distinct_noindex.js', // SERVER-13116 distinct isn't sharding aware 'distinct_projection.js', // SERVER-13116 distinct isn't sharding aware + 'create_database.js', // SERVER-17397 Drops of sharded namespaces may not fully succeed 'drop_database.js', // SERVER-17397 Drops of sharded namespaces may not fully succeed 'remove_where.js', // SERVER-14669 Multi-removes that use $where miscount removed documents diff --git a/jstests/concurrency/fsm_workloads/create_database.js b/jstests/concurrency/fsm_workloads/create_database.js new file mode 100644 index 00000000000..10b619454b4 --- /dev/null +++ b/jstests/concurrency/fsm_workloads/create_database.js @@ -0,0 +1,140 @@ +'use strict'; + +/** + * create_database.js + * + * Repeatedly creates and drops a database, with the focus on creation using different name casing. + * Create using all different methods, implicitly by inserting, creating views/indexes etc. + * + * Each thread uses its own database, though sometimes threads may try to create databases with + * names that only differ in case, expecting the appriopriate error code. + */ +var $config = (function() { + + var data = { + checkCommandResult: function checkCommandResult(mayFailWithDatabaseDifferCase, res) { + if (mayFailWithDatabaseDifferCase && !res.ok) + assertAlways.commandFailedWithCode(res, ErrorCodes.DatabaseDifferCase); + else + assertAlways.commandWorked(res); + return res; + }, + + checkWriteResult: function checkWriteResult(mayFailWithDatabaseDifferCase, res) { + if (mayFailWithDatabaseDifferCase && res.hasWriteError()) { + assertAlways.eq(res.getWriteError().code, ErrorCodes.DatabaseDifferCase); + } else + assertAlways.writeOK(res); + return res; + } + }; + + var states = (function() { + function init(db, collName) { + var uniqueNr = this.tid; + var semiUniqueNr = Math.floor(uniqueNr / 2); + + // The semiUniqueDBName may clash and result in a DatabaseDifferCas error on + // creation, + // while the uniqueDBName does not clash. The unique and created variables track + // this. + this.semiUniqueDBName = + (this.tid % 2 ? 'create_database' : 'CREATE_DATABASE') + semiUniqueNr; + this.uniqueDBName = 'CreateDatabase' + uniqueNr; + this.myDB = db.getSiblingDB(this.uniqueDBName); + this.created = false; + this.unique = true; + } + + function useSemiUniqueDBName(db, collName) { + this.myDB = db.getSiblingDB(this.semiUniqueDBName); + this.unique = false; + } + + function createCollection(db, collName) { + this.created = + this.checkCommandResult(!this.unique, this.myDB.createCollection(collName)).ok; + } + + function createIndex(db, collName) { + var background = Math.random > 0.5; + var res = this.myDB.getCollection(collName).createIndex({x: 1}, {background}); + this.created |= + this.checkCommandResult(!this.unique, res).createdCollectionAutomatically; + } + + function insert(db, collName) { + this.created |= this.checkWriteResult(!this.created && !this.unique, + this.myDB.getCollection(collName).insert({x: 1})) + .nInserted == 1; + } + + function upsert(db, collName) { + this.created |= this.checkWriteResult(!this.created && !this.unique, + this.myDB.getCollection(collName).update( + {x: 1}, {x: 2}, {upsert: 1})).nUpserted == 1; + } + + function drop(db, collName) { + if (this.created) + assertAlways(this.myDB.getCollection(collName).drop()); + } + + function dropDatabase(db, collName) { + if (this.created) + assertAlways.commandWorked(this.myDB.dropDatabase()); + } + + function listDatabases(db, collName) { + for (var database of db.adminCommand({listDatabases: 1}).databases) { + var res = db.getSiblingDB(database.name).runCommand({listCollections: 1}); + assertAlways.commandWorked(res); + assertAlways.neq(database.name, this.myDB.toString(), "this DB shouldn't exist"); + } + } + + return { + init: init, + useSemiUniqueDBName: useSemiUniqueDBName, + createCollection: createCollection, + createIndex: createIndex, + insert: insert, + upsert: upsert, + drop: drop, + dropDatabase: dropDatabase, + listDatabases: listDatabases, + }; + })(); + + var transitions = { + init: { + useSemiUniqueDBName: 0.25, + createCollection: 0.375, + createIndex: 0.125, + insert: 0.125, + upsert: 0.125 + }, + useSemiUniqueDBName: {createCollection: 1.00}, + createCollection: {dropDatabase: 0.25, createIndex: 0.25, insert: 0.25, upsert: 0.25}, + createIndex: {insert: 0.25, upsert: 0.25, dropDatabase: 0.5}, + insert: {dropDatabase: 0.2, drop: 0.05, insert: 0.5, upsert: 0.25}, + upsert: {dropDatabase: 0.2, drop: 0.05, insert: 0.25, upsert: 0.5}, + drop: {dropDatabase: 0.75, init: 0.25}, // OK to leave the empty database behind sometimes + dropDatabase: {init: 0.75, listDatabases: 0.25}, + listDatabases: {init: 0.75, listDatabases: 0.25}, + }; + + return { + data: data, + // We only run a few iterations to reduce the amount of data cumulatively + // written to disk by mmapv1. For example, setting 10 threads and 180 + // iterations (with an expected 6 transitions per create/drop roundtrip) + // causes this workload to write at least 32MB (.ns and .0 files) * 10 threads + // * 30 iterations worth of data to disk, or about 10GB, which can be slow on + // test hosts. + threadCount: 10, + iterations: 180, + states: states, + transitions: transitions, + }; +})(); |