diff options
author | Adi Zaimi <adizaimi@yahoo.com> | 2023-01-18 21:23:20 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-01-18 22:00:02 +0000 |
commit | 02502cf9ba7cafdfcbef7810991b3cdc8ba08c4c (patch) | |
tree | 0cb13bc8b317b04bcf6ebcbab0144a0695a44a9b | |
parent | a317c9b75dbd84687acc53af4f4c3c5afa6dcc7e (diff) | |
download | mongo-02502cf9ba7cafdfcbef7810991b3cdc8ba08c4c.tar.gz |
SERVER-67795: Add serverstatus counters for updateMany, deleteMany calls(v4.4)
-rw-r--r-- | jstests/sharding/server_status_crud_metrics.js | 22 | ||||
-rw-r--r-- | jstests/sharding/update_delete_many_metrics.js | 121 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/write_commands.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/stats/counters.h | 6 | ||||
-rw-r--r-- | src/mongo/s/write_ops/chunk_manager_targeter.cpp | 14 |
6 files changed, 166 insertions, 11 deletions
diff --git a/jstests/sharding/server_status_crud_metrics.js b/jstests/sharding/server_status_crud_metrics.js index 62a513242ca..7c30b6bd708 100644 --- a/jstests/sharding/server_status_crud_metrics.js +++ b/jstests/sharding/server_status_crud_metrics.js @@ -26,8 +26,8 @@ assert.commandWorked(unshardedColl.insert({x: 1, _id: 1})); // Verification for 'updateOneOpStyleBroadcastWithExactIDCount' metric. // Should increment the metric as the update cannot target single shard and are {multi:false}. -assert.commandWorked(testDB.coll.update({_id: "missing"}, {$set: {a: 1}}, {multi: false})); -assert.commandWorked(testDB.coll.update({_id: 1}, {$set: {a: 2}}, {multi: false})); +assert.commandWorked(testColl.update({_id: "missing"}, {$set: {a: 1}}, {multi: false})); +assert.commandWorked(testColl.update({_id: 1}, {$set: {a: 2}}, {multi: false})); // Should increment the metric because we broadcast by _id, even though the update subsequently // fails on the individual shard. @@ -42,21 +42,21 @@ let mongosServerStatus = testDB.adminCommand({serverStatus: 1}); assert.eq(4, mongosServerStatus.metrics.query.updateOneOpStyleBroadcastWithExactIDCount); // Shouldn't increment the metric when {multi:true}. -assert.commandWorked(testDB.coll.update({_id: 1}, {$set: {a: 3}}, {multi: true})); -assert.commandWorked(testDB.coll.update({}, {$set: {a: 3}}, {multi: true})); +assert.commandWorked(testColl.update({_id: 1}, {$set: {a: 3}}, {multi: true})); +assert.commandWorked(testColl.update({}, {$set: {a: 3}}, {multi: true})); // Shouldn't increment the metric when update can target single shard. -assert.commandWorked(testDB.coll.update({x: 11}, {$set: {a: 2}}, {multi: false})); -assert.commandWorked(testDB.coll.update({x: 1}, {$set: {a: 2}}, {multi: false})); +assert.commandWorked(testColl.update({x: 11}, {$set: {a: 2}}, {multi: false})); +assert.commandWorked(testColl.update({x: 1}, {$set: {a: 2}}, {multi: false})); // Shouldn't increment the metric for replacement style updates. -assert.commandWorked(testDB.coll.update({_id: 1}, {x: 1, a: 2})); -assert.commandWorked(testDB.coll.update({x: 1}, {x: 1, a: 1})); +assert.commandWorked(testColl.update({_id: 1}, {x: 1, a: 2})); +assert.commandWorked(testColl.update({x: 1}, {x: 1, a: 1})); // Shouldn't increment the metric when routing fails. -assert.commandFailedWithCode(testDB.coll.update({}, {$set: {x: 2}}, {multi: false}), +assert.commandFailedWithCode(testColl.update({}, {$set: {x: 2}}, {multi: false}), ErrorCodes.InvalidOptions); -assert.commandFailedWithCode(testDB.coll.update({_id: 1}, {$set: {x: 2}}, {upsert: true}), +assert.commandFailedWithCode(testColl.update({_id: 1}, {$set: {x: 2}}, {upsert: true}), ErrorCodes.ShardKeyNotFound); // Shouldn't increment the metrics for unsharded collection. @@ -65,7 +65,7 @@ assert.commandWorked(unshardedColl.update({_id: 1}, {$set: {a: 2}}, {multi: fals // Shouldn't incement the metrics when query had invalid operator. assert.commandFailedWithCode( - testDB.coll.update({_id: 1, $invalidOperator: 1}, {$set: {a: 2}}, {multi: false}), + testColl.update({_id: 1, $invalidOperator: 1}, {$set: {a: 2}}, {multi: false}), ErrorCodes.BadValue); mongosServerStatus = testDB.adminCommand({serverStatus: 1}); diff --git a/jstests/sharding/update_delete_many_metrics.js b/jstests/sharding/update_delete_many_metrics.js new file mode 100644 index 00000000000..bfa3dc86d09 --- /dev/null +++ b/jstests/sharding/update_delete_many_metrics.js @@ -0,0 +1,121 @@ +/** + * Tests for the 'metrics.query' section of the mongos and mongod serverStatus response verifying + * counters for updateMany and deleteMany + * @tags: [multiversion_incompatible] + */ + +(function() { +"use strict"; + +{ + const st = new ShardingTest({shards: 2, rs: {nodes: 2}}); + const mongodConns = []; + st.rs0.nodes.forEach(node => mongodConns.push(node)); + st.rs1.nodes.forEach(node => mongodConns.push(node)); + + const testDB = st.s.getDB("test"); + const testColl = testDB.coll; + const unshardedColl = testDB.unsharded; + + assert.commandWorked(st.s0.adminCommand({enableSharding: testDB.getName()})); + st.ensurePrimaryShard(testDB.getName(), st.shard0.shardName); + + // Shard testColl on {x:1}, split it at {x:0}, and move chunk {x:1} to shard1. + st.shardColl(testColl, {x: 1}, {x: 0}, {x: 1}); + + // Insert one document on each shard. + assert.commandWorked(testColl.insert({x: 1, _id: 1})); + assert.commandWorked(testColl.insert({x: -1, _id: 0})); + + assert.eq(2, testColl.countDocuments({})); + assert.commandWorked(unshardedColl.insert({x: 1, _id: 1})); + assert.eq(1, unshardedColl.countDocuments({})); + + let mongosServerStatus = testDB.adminCommand({serverStatus: 1}); + // Verification for 'updateManyCount' metric. + assert.eq(0, mongosServerStatus.metrics.query.updateManyCount); + // Verification for 'deleteManyCount' metric. + assert.eq(0, mongosServerStatus.metrics.query.deleteManyCount); + + assert.commandWorked(unshardedColl.update({_id: 1}, {$set: {a: 2}}, {multi: false})); + assert.commandWorked(testColl.update({_id: 1}, {$set: {a: 2}}, {multi: false})); + // 3 update with multi:true calls. + assert.commandWorked(unshardedColl.update({_id: 1}, {$set: {a: 2}}, {multi: true})); + assert.commandWorked(testColl.update({}, {$set: {a: 3}}, {multi: true})); + assert.commandWorked(testColl.update({_id: 1}, {$set: {a: 2}}, {multi: true})); + + // 2 updateMany calls. + assert.commandWorked(testColl.updateMany({}, {$set: {array: 'string', doc: 'string'}})); + assert.commandWorked(unshardedColl.updateMany({}, {$set: {array: 'string', doc: 'string'}})); + + // Use deleteMany to delete one of the documents. + const result = testColl.deleteMany({_id: 1}); + assert.commandWorked(result); + assert.eq(1, result.deletedCount); + assert.eq(1, testColl.countDocuments({})); + // Next call will not increase count. + assert.commandWorked(testColl.deleteOne({_id: 1})); + + // Use deleteMany to delete one document in the unsharded collection. + assert.commandWorked(unshardedColl.deleteMany({_id: 1})); + // Next call will not increase count. + assert.commandWorked(unshardedColl.deleteOne({_id: 1})); + + mongosServerStatus = testDB.adminCommand({serverStatus: 1}); + + // Verification for 'updateManyCount' metric. + assert.eq(5, mongosServerStatus.metrics.query.updateManyCount); + // Verification for 'deleteManyCount' metric. + assert.eq(2, mongosServerStatus.metrics.query.deleteManyCount); + + st.stop(); +} + +{ + const rst = new ReplSetTest({nodes: 2}); + rst.startSet(); + rst.initiate(); + + const primary = rst.getPrimary(); + const testDB = primary.getDB("test"); + const testColl = testDB.coll; + const unshardedColl = testDB.unsharded; + + // Insert one document on each shard. + assert.commandWorked(testColl.insert({x: 1, _id: 1})); + assert.commandWorked(testColl.insert({x: -1, _id: 0})); + assert.eq(2, testColl.countDocuments({})); + + let mongosServerStatus = testDB.adminCommand({serverStatus: 1}); + + // Verification for 'updateManyCount' metric. + assert.eq(0, mongosServerStatus.metrics.query.updateManyCount); + // Verification for 'deleteManyCount' metric. + assert.eq(0, mongosServerStatus.metrics.query.deleteManyCount); + + assert.commandWorked(testColl.update({_id: 1}, {$set: {a: 2}}, {multi: false})); + // 3 update with multi:true calls. + assert.commandWorked(testColl.update({}, {$set: {a: 3}}, {multi: true})); + assert.commandWorked(testColl.update({_id: 1}, {$set: {a: 2}}, {multi: true})); + + // 2 updateMany call. + assert.commandWorked(testColl.updateMany({}, {$set: {array: 'string', doc: 'string'}})); + + // Use deleteMany to delete one of the documents. + const result = testColl.deleteMany({_id: 1}); + assert.commandWorked(result); + assert.eq(1, result.deletedCount); + assert.eq(1, testColl.countDocuments({})); + // Next call will not increase count. + assert.commandWorked(testColl.deleteOne({_id: 1})); + + mongosServerStatus = testDB.adminCommand({serverStatus: 1}); + + // Verification for 'updateManyCount' metric. + assert.eq(3, mongosServerStatus.metrics.query.updateManyCount); + // Verification for 'deleteManyCount' metric. + assert.eq(1, mongosServerStatus.metrics.query.deleteManyCount); + + rst.stopSet(); +} +})(); diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index 14a6d491c71..6df6f7ad450 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -419,6 +419,9 @@ private: if (update.getArrayFilters()) { _updateMetrics->incrementExecutedWithArrayFilters(); } + if (update.getMulti()) { + updateManyCount.increment(1); + } } } @@ -514,6 +517,12 @@ private: _batch.getDeletes().size(), std::move(reply), &result); + // Collect metrics. + for (auto&& delOp : _batch.getDeletes()) { + if (delOp.getMulti()) { + deleteManyCount.increment(1); + } + } } void explain(OperationContext* opCtx, diff --git a/src/mongo/db/stats/counters.cpp b/src/mongo/db/stats/counters.cpp index 55b9cbeffb6..725741dde85 100644 --- a/src/mongo/db/stats/counters.cpp +++ b/src/mongo/db/stats/counters.cpp @@ -34,6 +34,7 @@ #include "mongo/db/stats/counters.h" #include "mongo/client/authenticate.h" +#include "mongo/db/commands/server_status_metric.h" #include "mongo/db/jsobj.h" #include "mongo/logv2/log.h" @@ -297,4 +298,8 @@ AuthCounter authCounter; AggStageCounters aggStageCounters; OperatorCountersAggExpressions operatorCountersAggExpressions; OperatorCountersMatchExpressions operatorCountersMatchExpressions; + +Counter64 updateManyCount; +Counter64 deleteManyCount; + } // namespace mongo diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h index aa11c84c2f1..2bb6870a7b0 100644 --- a/src/mongo/db/stats/counters.h +++ b/src/mongo/db/stats/counters.h @@ -315,4 +315,10 @@ private: }; extern OperatorCountersMatchExpressions operatorCountersMatchExpressions; + +// Track the number of {multi:true} updates. +extern Counter64 updateManyCount; +// Track the number of deleteMany calls. +extern Counter64 deleteManyCount; + } // namespace mongo diff --git a/src/mongo/s/write_ops/chunk_manager_targeter.cpp b/src/mongo/s/write_ops/chunk_manager_targeter.cpp index b8615e5282c..9e04c28a238 100644 --- a/src/mongo/s/write_ops/chunk_manager_targeter.cpp +++ b/src/mongo/s/write_ops/chunk_manager_targeter.cpp @@ -38,6 +38,7 @@ #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/collation/collation_index_key.h" +#include "mongo/db/stats/counters.h" #include "mongo/logv2/log.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_commands_helpers.h" @@ -63,6 +64,11 @@ Counter64 updateOneOpStyleBroadcastWithExactIDCount; ServerStatusMetricField<Counter64> updateOneOpStyleBroadcastWithExactIDStats( "query.updateOneOpStyleBroadcastWithExactIDCount", &updateOneOpStyleBroadcastWithExactIDCount); +ServerStatusMetricField<Counter64> displayUpdateManyCount("query.updateManyCount", + &updateManyCount); +ServerStatusMetricField<Counter64> displayDeleteManyCount("query.deleteManyCount", + &deleteManyCount); + /** * Update expressions are bucketed into one of two types for the purposes of shard targeting: * @@ -437,6 +443,10 @@ StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetUpdate( return updateType.getStatus(); } + if (updateDoc.getMulti()) { + updateManyCount.increment(1); + } + // If the collection is not sharded, forward the update to the primary shard. if (!_routingInfo->cm()) { if (!_routingInfo->db().primary()) { @@ -527,6 +537,10 @@ StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetDelete( OperationContext* opCtx, const write_ops::DeleteOpEntry& deleteDoc) const { BSONObj shardKey; + if (deleteDoc.getMulti()) { + deleteManyCount.increment(1); + } + if (_routingInfo->cm()) { // // Sharded collections have the following further requirements for targeting: |