diff options
Diffstat (limited to 'jstests/sharding/libs')
| -rw-r--r-- | jstests/sharding/libs/defragmentation_util.js | 26 | ||||
| -rw-r--r-- | jstests/sharding/libs/last_lts_mongod_commands.js | 4 | ||||
| -rw-r--r-- | jstests/sharding/libs/last_lts_mongos_commands.js | 5 | ||||
| -rw-r--r-- | jstests/sharding/libs/mongos_api_params_util.js | 7 | ||||
| -rw-r--r-- | jstests/sharding/libs/resharding_test_fixture.js | 100 | ||||
| -rw-r--r-- | jstests/sharding/libs/with_partial_shard_key_util.js | 28 |
6 files changed, 128 insertions, 42 deletions
diff --git a/jstests/sharding/libs/defragmentation_util.js b/jstests/sharding/libs/defragmentation_util.js index 52ac1333ef7..943f2eb462d 100644 --- a/jstests/sharding/libs/defragmentation_util.js +++ b/jstests/sharding/libs/defragmentation_util.js @@ -21,7 +21,9 @@ var defragmentationUtil = (function() { } createAndDistributeChunks(mongos, ns, numChunks, chunkSpacing); - createRandomZones(mongos, ns, numZones, chunkSpacing); + // Created zones will line up exactly with existing chunks so as not to trigger zone + // violations in the balancer. + createRandomZones(mongos, ns, numZones); fillChunksToRandomSize(mongos, ns, docSizeBytes, maxChunkFillMB); const beginningNumberChunks = findChunksUtil.countChunksForNs(mongos.getDB('config'), ns); @@ -49,19 +51,18 @@ var defragmentationUtil = (function() { } }; - let createRandomZones = function(mongos, ns, numZones, chunkSpacing) { - for (let i = -Math.floor(numZones / 2); i < Math.ceil(numZones / 2); i++) { + let createRandomZones = function(mongos, ns, numZones) { + let existingChunks = findChunksUtil.findChunksByNs(mongos.getDB('config'), ns); + existingChunks = Array.shuffle(existingChunks.toArray()); + for (let i = 0; i < numZones; i++) { let zoneName = "Zone" + i; - let shardForZone = - findChunksUtil - .findOneChunkByNs(mongos.getDB('config'), ns, {min: {key: i * chunkSpacing}}) - .shard; + let shardForZone = existingChunks[i].shard; assert.commandWorked( mongos.adminCommand({addShardToZone: shardForZone, zone: zoneName})); assert.commandWorked(mongos.adminCommand({ updateZoneKeyRange: ns, - min: {key: i * chunkSpacing}, - max: {key: i * chunkSpacing + chunkSpacing}, + min: existingChunks[i].min, + max: existingChunks[i].max, zone: zoneName })); } @@ -202,6 +203,13 @@ var defragmentationUtil = (function() { assert.soon(function() { let balancerStatus = assert.commandWorked(mongos.adminCommand({balancerCollectionStatus: ns})); + + if (balancerStatus.balancerCompliant) { + // As we can't rely on `balancerCompliant` due to orphan counter non atomic update, + // we need to ensure the collection is balanced by some extra checks + sh.awaitCollectionBalance(mongos.getCollection(ns)); + } + return balancerStatus.balancerCompliant || balancerStatus.firstComplianceViolation !== 'defragmentingChunks'; }); diff --git a/jstests/sharding/libs/last_lts_mongod_commands.js b/jstests/sharding/libs/last_lts_mongod_commands.js index c25af3a8275..f8c0802af04 100644 --- a/jstests/sharding/libs/last_lts_mongod_commands.js +++ b/jstests/sharding/libs/last_lts_mongod_commands.js @@ -20,8 +20,12 @@ const commandsAddedToMongodSinceLastLTS = [ "clusterGetMore", "clusterInsert", "clusterUpdate", + "createSearchIndexes", + "dropSearchIndex", "getClusterParameter", + "listSearchIndexes", "rotateCertificates", "setClusterParameter", "setUserWriteBlockMode", + "updateSearchIndex", ]; diff --git a/jstests/sharding/libs/last_lts_mongos_commands.js b/jstests/sharding/libs/last_lts_mongos_commands.js index f7a72743e6b..c2d8308e5f4 100644 --- a/jstests/sharding/libs/last_lts_mongos_commands.js +++ b/jstests/sharding/libs/last_lts_mongos_commands.js @@ -18,12 +18,16 @@ const commandsAddedToMongosSinceLastLTS = [ "commitReshardCollection", "compactStructuredEncryptionData", "configureCollectionBalancing", + "createSearchIndexes", + "dropSearchIndex", "getClusterParameter", + "listSearchIndexes", "moveRange", "reshardCollection", "rotateCertificates", "setAllowMigrations", "setClusterParameter", + "setProfilingFilterGlobally", // TODO SERVER-73305 "setUserWriteBlockMode", "testDeprecation", "testDeprecationInVersion2", @@ -31,4 +35,5 @@ const commandsAddedToMongosSinceLastLTS = [ "testRemoval", "testVersions1And2", "testVersion2", + "updateSearchIndex", ]; diff --git a/jstests/sharding/libs/mongos_api_params_util.js b/jstests/sharding/libs/mongos_api_params_util.js index e1ca18df3e6..8289582d9ee 100644 --- a/jstests/sharding/libs/mongos_api_params_util.js +++ b/jstests/sharding/libs/mongos_api_params_util.js @@ -75,7 +75,7 @@ let MongosAPIParametersUtil = (function() { function awaitRemoveShard(shardName) { assert.commandWorked(st.startBalancer()); - st.waitForBalancer(true, 60000); + st.awaitBalancerRound(); assert.soon(() => { const res = st.s.adminCommand({removeShard: shardName}); jsTestLog(`removeShard result: ${tojson(res)}`); @@ -1215,9 +1215,8 @@ let MongosAPIParametersUtil = (function() { } }, { - commandName: "setFreeMonitoring", - skip: "explicitly fails for mongos, primary mongod only", - conditional: true + commandName: "setProfilingFilterGlobally", + skip: "executes locally on mongos (not sent to any remote node)", }, { commandName: "setParameter", diff --git a/jstests/sharding/libs/resharding_test_fixture.js b/jstests/sharding/libs/resharding_test_fixture.js index 13d39674f0f..cd658ae9508 100644 --- a/jstests/sharding/libs/resharding_test_fixture.js +++ b/jstests/sharding/libs/resharding_test_fixture.js @@ -85,11 +85,11 @@ var ReshardingTest = class { /** @private */ this._newShardKey = undefined; /** @private */ - this._pauseCoordinatorBeforeBlockingWrites = undefined; + this._pauseCoordinatorBeforeBlockingWritesFailpoints = []; /** @private */ - this._pauseCoordinatorBeforeDecisionPersistedFailpoint = undefined; + this._pauseCoordinatorBeforeDecisionPersistedFailpoints = []; /** @private */ - this._pauseCoordinatorBeforeCompletionFailpoint = undefined; + this._pauseCoordinatorBeforeCompletionFailpoints = []; /** @private */ this._reshardingThread = undefined; /** @private */ @@ -283,6 +283,11 @@ var ReshardingTest = class { return sourceCollection; } + get tempNs() { + assert.neq(undefined, this._tempNs, "createShardedCollection must be called first"); + return this._tempNs; + } + /** * Reshards an existing collection using the specified new shard key and new chunk ranges. * @@ -316,13 +321,19 @@ var ReshardingTest = class { this._newShardKey = Object.assign({}, newShardKeyPattern); - const configPrimary = this._st.configRS.getPrimary(); - this._pauseCoordinatorBeforeBlockingWrites = - configureFailPoint(configPrimary, "reshardingPauseCoordinatorBeforeBlockingWrites"); - this._pauseCoordinatorBeforeDecisionPersistedFailpoint = - configureFailPoint(configPrimary, "reshardingPauseCoordinatorBeforeDecisionPersisted"); - this._pauseCoordinatorBeforeCompletionFailpoint = configureFailPoint( - configPrimary, "reshardingPauseCoordinatorBeforeCompletion", {}, {times: 1}); + this._pauseCoordinatorBeforeBlockingWritesFailpoints = []; + this._pauseCoordinatorBeforeDecisionPersistedFailpoints = []; + this._pauseCoordinatorBeforeCompletionFailpoints = []; + this._st.forEachConfigServer((configServer) => { + this._pauseCoordinatorBeforeBlockingWritesFailpoints.push( + configureFailPoint(configServer, "reshardingPauseCoordinatorBeforeBlockingWrites")); + this._pauseCoordinatorBeforeDecisionPersistedFailpoints.push(configureFailPoint( + configServer, "reshardingPauseCoordinatorBeforeDecisionPersisted")); + this._pauseCoordinatorBeforeCompletionFailpoints.push( + configureFailPoint(configServer, + "reshardingPauseCoordinatorBeforeCompletion", + {"sourceNamespace": this._ns})); + }); this._commandDoneSignal = new CountDownLatch(1); @@ -452,9 +463,9 @@ var ReshardingTest = class { try { fn(); } catch (duringReshardingError) { - for (const fp of [this._pauseCoordinatorBeforeBlockingWrites, - this._pauseCoordinatorBeforeDecisionPersistedFailpoint, - this._pauseCoordinatorBeforeCompletionFailpoint]) { + for (const fp of [...this._pauseCoordinatorBeforeBlockingWritesFailpoints, + ...this._pauseCoordinatorBeforeDecisionPersistedFailpoints, + ...this._pauseCoordinatorBeforeCompletionFailpoints]) { try { fp.off(); } catch (disableFailpointError) { @@ -503,7 +514,9 @@ var ReshardingTest = class { * proceeding to the next stage. This helper returns after either: * * 1) The node's waitForFailPoint returns successfully or - * 2) The `reshardCollection` command has returned a response. + * 2) The `reshardCollection` command has returned a response or + * 3) The ReshardingCoordinator is blocked on the reshardingPauseCoordinatorBeforeCompletion + * failpoint and won't ever satisfy the supplied failpoint. * * The function returns true when we returned because the server reached the failpoint. The * function returns false when the `reshardCollection` command is no longer running. @@ -512,9 +525,20 @@ var ReshardingTest = class { * @private */ _waitForFailPoint(fp) { + const completionFailpoint = this._pauseCoordinatorBeforeCompletionFailpoints.find( + completionFailpoint => completionFailpoint.conn.host === fp.conn.host); + assert.soon( () => { - return this._commandDoneSignal.getCount() === 0 || fp.waitWithTimeout(1000); + if (this._commandDoneSignal.getCount() === 0 || fp.waitWithTimeout(1000)) { + return true; + } + + if (completionFailpoint !== fp && completionFailpoint.waitWithTimeout(1000)) { + completionFailpoint.off(); + } + + return false; }, "Timed out waiting for failpoint to be hit. Failpoint: " + fp.failPointName, undefined, @@ -529,6 +553,19 @@ var ReshardingTest = class { postCheckConsistencyFn = () => {}, postDecisionPersistedFn = () => {}, afterReshardingFn = () => {}) { + // The CSRS primary may have changed as a result of running the duringReshardingFn() + // callback function. The failpoints will only be triggered on the new CSRS primary so we + // detect which node that is here. + const configPrimary = this._st.configRS.getPrimary(); + const primaryIdx = this._pauseCoordinatorBeforeBlockingWritesFailpoints.findIndex( + fp => fp.conn.host === configPrimary.host); + // The CSRS secondaries may be going through replication rollback which closes their + // connections to the test client. We wait for any replication rollbacks to complete and for + // the test client to have reconnected so the failpoints can be turned off on all of the + // nodes later on. + this._st.configRS.awaitSecondaryNodes(); + this._st.configRS.awaitReplication(); + let performCorrectnessChecks = true; if (expectedErrorCode === ErrorCodes.OK) { this._callFunctionSafely(() => { @@ -539,17 +576,18 @@ var ReshardingTest = class { // reshardingPauseCoordinatorBeforeDecisionPersisted failpoint to wait for all of // the recipient shards to have applied through all of the oplog entries from all of // the donor shards. - if (!this._waitForFailPoint(this._pauseCoordinatorBeforeBlockingWrites)) { + if (!this._waitForFailPoint( + this._pauseCoordinatorBeforeBlockingWritesFailpoints[primaryIdx])) { performCorrectnessChecks = false; } - this._pauseCoordinatorBeforeBlockingWrites.off(); + this._pauseCoordinatorBeforeBlockingWritesFailpoints.forEach(fp => fp.off()); // A resharding command that returned a failure will not hit the "Decision // Persisted" failpoint. If the command has returned, don't require that the // failpoint was entered. This ensures that following up by joining the // `_reshardingThread` will succeed. if (!this._waitForFailPoint( - this._pauseCoordinatorBeforeDecisionPersistedFailpoint)) { + this._pauseCoordinatorBeforeDecisionPersistedFailpoints[primaryIdx])) { performCorrectnessChecks = false; } @@ -562,22 +600,21 @@ var ReshardingTest = class { postCheckConsistencyFn(); } - this._pauseCoordinatorBeforeDecisionPersistedFailpoint.off(); + this._pauseCoordinatorBeforeDecisionPersistedFailpoints.forEach(fp => fp.off()); postDecisionPersistedFn(); - this._pauseCoordinatorBeforeCompletionFailpoint.off(); + this._pauseCoordinatorBeforeCompletionFailpoints.forEach(fp => fp.off()); }); } else { this._callFunctionSafely(() => { - this.retryOnceOnNetworkError( // - () => this._pauseCoordinatorBeforeBlockingWrites.off()); - + this._pauseCoordinatorBeforeBlockingWritesFailpoints.forEach( + fp => this.retryOnceOnNetworkError(fp.off)); postCheckConsistencyFn(); - this.retryOnceOnNetworkError( - () => this._pauseCoordinatorBeforeDecisionPersistedFailpoint.off()); + this._pauseCoordinatorBeforeDecisionPersistedFailpoints.forEach( + fp => this.retryOnceOnNetworkError(fp.off)); postDecisionPersistedFn(); - this.retryOnceOnNetworkError( - () => this._pauseCoordinatorBeforeCompletionFailpoint.off()); + this._pauseCoordinatorBeforeCompletionFailpoints.forEach( + fp => this.retryOnceOnNetworkError(fp.off)); }); } @@ -600,7 +637,11 @@ var ReshardingTest = class { /** @private */ _checkConsistency() { - const nsCursor = this._st.s.getCollection(this._ns).find().sort({_id: 1}); + // The "available" read concern level won't block this find cmd behind the critical section. + // Tests for resharding are not expected to have unowned documents in the collection being + // resharded. + const nsCursor = + this._st.s.getCollection(this._ns).find().readConcern("available").sort({_id: 1}); const tempNsCursor = this._st.s.getCollection(this._tempNs).find().sort({_id: 1}); const diff = ((diff) => { @@ -618,7 +659,8 @@ var ReshardingTest = class { docsExtraAfterResharding: [], docsMissingAfterResharding: [], }, - "existing sharded collection and temporary resharding collection had different" + + "existing sharded collection " + this._ns + + " and temporary resharding collection " + this._tempNs + " had different" + " contents"); } diff --git a/jstests/sharding/libs/with_partial_shard_key_util.js b/jstests/sharding/libs/with_partial_shard_key_util.js new file mode 100644 index 00000000000..bcfeae08926 --- /dev/null +++ b/jstests/sharding/libs/with_partial_shard_key_util.js @@ -0,0 +1,28 @@ +/** + * Utilities for the find_and_modify_with_partial_shard_key.js and delete_with_partial_shard_key.js + * tests. + */ +"use strict"; + +/** + * Runs an explain on the `cmdObj` and checks that the explain targets the shard given be + * `expectedShardName`. + */ +function assertExplainTargetsCorrectShard(db, cmdObj, expectedShardName) { + var res = db.runCommand({explain: cmdObj}); + assert.eq(res.queryPlanner.winningPlan.shards.length, 1); + assert.eq(res.queryPlanner.winningPlan.shards[0].shardName, expectedShardName); +} + +/** + * Performs a split given by the `splitDoc`, and then moves the chunk containg `moveShard0Doc` to + * shard0 and the chunk containing `moveShard1Doc` to shard1. + */ +function splitAndMoveChunks(st, splitDoc, moveShard0Doc, moveShard1Doc) { + assert.commandWorked(st.s0.adminCommand({split: "test.sharded_coll", middle: splitDoc})); + + assert.commandWorked(st.s0.adminCommand( + {moveChunk: "test.sharded_coll", find: moveShard0Doc, to: st.shard0.shardName})); + assert.commandWorked(st.s0.adminCommand( + {moveChunk: "test.sharded_coll", find: moveShard1Doc, to: st.shard1.shardName})); +} |
