Skip to content

Commit cf2bd09

Browse files
louiswilliamsMongoDB Bot
authored andcommitted
SERVER-103741 Profiler collection metrics (#40142)
GitOrigin-RevId: feff19d43493819b330bed1844768299e8ae6b89
1 parent f4159b4 commit cf2bd09

File tree

6 files changed

+155
-37
lines changed

6 files changed

+155
-37
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Tests for serverStatus profiler stats.
3+
*/
4+
const conn = MongoRunner.runMongod();
5+
assert.neq(null, conn, "mongod was unable to start up");
6+
const db = conn.getDB(jsTest.name());
7+
const coll = db[jsTest.name()];
8+
9+
const nDocs = 32;
10+
coll.drop();
11+
assert.commandWorked(db.createCollection(jsTest.name()));
12+
13+
for (let i = 0; i < nDocs; i++) {
14+
assert.commandWorked(coll.insert({a: i}));
15+
}
16+
17+
// Enable profiling and run a query that implicitly creates the profile collection.
18+
assert.commandWorked(db.setProfilingLevel(2, 0));
19+
assert.eq(nDocs, coll.find({}).itcount());
20+
21+
// Turn off the profiler to avoid incrementing the stats further.
22+
assert.commandWorked(db.setProfilingLevel(0, 0));
23+
24+
let profilerEntries = db.system.profile.find({}).itcount();
25+
assert.eq(1, profilerEntries);
26+
27+
let profilerWriteStats = db.serverStatus().profiler;
28+
assert.eq(0, profilerWriteStats.activeWriters);
29+
assert.eq(profilerWriteStats.totalWrites, profilerEntries);
30+
31+
MongoRunner.stopMongod(conn);

jstests/noPassthrough/server_status_catalog_stats.js

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@
88
(function() {
99
"use strict";
1010

11-
const replSet = new ReplSetTest({nodes: 2});
11+
// Construct a replica set where the same node remains primary across restarts, because the
12+
// system.profile collection is not replicated.
13+
const replSet = new ReplSetTest({
14+
nodes: [
15+
{},
16+
{rsConfig: {priority: 0}},
17+
]
18+
});
1219
replSet.startSet();
1320
replSet.initiate();
1421

@@ -26,6 +33,7 @@ assertCatalogStats(db1, (stats) => {
2633
assert.eq(0, stats.capped);
2734
assert.eq(0, stats.clustered);
2835
assert.eq(0, stats.collections);
36+
assert.eq(0, stats.systemProfile);
2937
assert.eq(0, stats.timeseries);
3038
assert.eq(0, stats.views);
3139
internalCollectionsAtStart = stats.internalCollections;
@@ -39,14 +47,25 @@ assert.commandWorked(
3947
assert.commandWorked(db1.createCollection('view', {viewOn: 'coll', pipeline: []}));
4048
assert.commandWorked(db1.createCollection('ts', {timeseries: {timeField: 't'}}));
4149

50+
// A system.views and system.buckets collection should have been created.
51+
let internalCollectionsCreated = 2;
52+
53+
// Create the profile collection.
54+
assert.commandWorked(db1.setProfilingLevel(2, 0));
55+
assert.eq(1, db1.coll.find({}).itcount());
56+
internalCollectionsCreated += 1;
57+
58+
// Turn off profiler to avoid creating extra collections.
59+
assert.commandWorked(db1.setProfilingLevel(0, 100));
60+
4261
assertCatalogStats(db1, (stats) => {
4362
assert.eq(1, stats.capped);
4463
assert.eq(1, stats.clustered);
4564
assert.eq(3, stats.collections);
65+
assert.eq(1, stats.systemProfile);
4666
assert.eq(1, stats.timeseries);
4767
assert.eq(1, stats.views);
48-
// A system.views and system.buckets collection should have been created.
49-
assert.eq(internalCollectionsAtStart + 2, stats.internalCollections);
68+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
5069
assert.eq(internalViewsAtStart, stats.internalViews);
5170
});
5271

@@ -56,10 +75,11 @@ assertCatalogStats(db1, (stats) => {
5675
assert.eq(1, stats.capped);
5776
assert.eq(1, stats.clustered);
5877
assert.eq(3, stats.collections);
78+
assert.eq(1, stats.systemProfile);
5979
assert.eq(1, stats.timeseries);
6080
assert.eq(1, stats.views);
6181
// An system.views and system.buckets collection should have been created.
62-
assert.eq(internalCollectionsAtStart + 2, stats.internalCollections);
82+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
6383
assert.eq(internalViewsAtStart, stats.internalViews);
6484
});
6585

@@ -70,14 +90,17 @@ assert.commandWorked(
7090
assert.commandWorked(db2.createCollection('view', {viewOn: 'coll', pipeline: []}));
7191
assert.commandWorked(db2.createCollection('ts', {timeseries: {timeField: 't'}}));
7292

93+
// An system.views and system.buckets collection should have been created.
94+
internalCollectionsCreated += 2;
95+
7396
assertCatalogStats(db1, (stats) => {
7497
assert.eq(2, stats.capped);
7598
assert.eq(2, stats.clustered);
7699
assert.eq(6, stats.collections);
100+
assert.eq(1, stats.systemProfile);
77101
assert.eq(2, stats.timeseries);
78102
assert.eq(2, stats.views);
79-
// An system.views and system.buckets collection should have been created.
80-
assert.eq(internalCollectionsAtStart + 4, stats.internalCollections);
103+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
81104
assert.eq(internalViewsAtStart, stats.internalViews);
82105
});
83106

@@ -92,9 +115,10 @@ assertCatalogStats(db1, (stats) => {
92115
assert.eq(2, stats.capped);
93116
assert.eq(2, stats.clustered);
94117
assert.eq(6, stats.collections);
118+
assert.eq(1, stats.systemProfile);
95119
assert.eq(2, stats.timeseries);
96120
assert.eq(2, stats.views);
97-
assert.eq(internalCollectionsAtStart + 4, stats.internalCollections);
121+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
98122
assert.eq(internalViewsAtStart, stats.internalViews);
99123
});
100124

@@ -104,39 +128,49 @@ assert(db1.clustered.drop());
104128
assert(db1.view.drop());
105129
assert(db1.ts.drop());
106130

131+
// The system.buckets collection will be dropped, but not system.views.
132+
internalCollectionsCreated -= 1;
133+
107134
assertCatalogStats(db1, (stats) => {
108135
assert.eq(1, stats.capped);
109136
assert.eq(1, stats.clustered);
110137
assert.eq(3, stats.collections);
138+
assert.eq(1, stats.systemProfile);
111139
assert.eq(1, stats.timeseries);
112140
assert.eq(1, stats.views);
113-
// The system.views collection will stick around
114-
assert.eq(internalCollectionsAtStart + 3, stats.internalCollections);
141+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
115142
assert.eq(internalViewsAtStart, stats.internalViews);
116143
});
117144

118145
db1.dropDatabase();
119146

147+
// The system.views and system.profile collections should be dropped.
148+
internalCollectionsCreated -= 2;
149+
120150
assertCatalogStats(db1, (stats) => {
121151
assert.eq(1, stats.capped);
122152
assert.eq(3, stats.collections);
153+
// The system.profile collection should be dropped.
154+
assert.eq(0, stats.systemProfile);
123155
assert.eq(1, stats.timeseries);
124156
assert.eq(1, stats.views);
125-
// The system.views collection should be dropped
126-
assert.eq(internalCollectionsAtStart + 2, stats.internalCollections);
157+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
127158
assert.eq(internalViewsAtStart, stats.internalViews);
128159
});
129160

130161
db2.dropDatabase();
131162

163+
// The system.views and system.buckets collections should be dropped.
164+
internalCollectionsCreated -= 2;
165+
132166
assertCatalogStats(db1, (stats) => {
133167
assert.eq(0, stats.capped);
134168
assert.eq(0, stats.clustered);
135169
assert.eq(0, stats.collections);
170+
assert.eq(0, stats.systemProfile);
136171
assert.eq(0, stats.timeseries);
137172
assert.eq(0, stats.views);
138-
// The system.views collection should be dropped
139-
assert.eq(internalCollectionsAtStart, stats.internalCollections);
173+
assert.eq(internalCollectionsAtStart + internalCollectionsCreated, stats.internalCollections);
140174
assert.eq(internalViewsAtStart, stats.internalViews);
141175
});
142176

src/mongo/db/catalog/catalog_stats.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class CatalogStatsSSS : public ServerStatusSection {
6565
int timeseriesExtendedRange = 0;
6666
int csfle = 0;
6767
int queryableEncryption = 0;
68+
int systemProfile = 0;
6869

6970
void toBson(BSONObjBuilder* builder) const {
7071
builder->append("collections", collections);
@@ -79,6 +80,7 @@ class CatalogStatsSSS : public ServerStatusSection {
7980
}
8081
builder->append("csfle", csfle);
8182
builder->append("queryableEncryption", queryableEncryption);
83+
builder->append("systemProfile", systemProfile);
8284
}
8385
};
8486

@@ -95,6 +97,7 @@ class CatalogStatsSSS : public ServerStatusSection {
9597
stats.timeseriesExtendedRange = requiresTimeseriesExtendedRangeSupport.load();
9698
stats.csfle = catalogStats.csfle;
9799
stats.queryableEncryption = catalogStats.queryableEncryption;
100+
stats.systemProfile = catalogStats.systemProfile;
98101

99102
const auto viewCatalogDbNames = catalog->getViewCatalogDbNames(opCtx);
100103
for (const auto& dbName : viewCatalogDbNames) {

src/mongo/db/catalog/collection_catalog.cpp

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2256,19 +2256,27 @@ void CollectionCatalog::_registerCollection(OperationContext* opCtx,
22562256
}
22572257

22582258

2259-
if (!nss.isOnInternalDb() && !nss.isSystem()) {
2260-
_stats.userCollections += 1;
2261-
if (coll->isCapped()) {
2262-
_stats.userCapped += 1;
2263-
}
2264-
if (coll->isClustered()) {
2265-
_stats.userClustered += 1;
2266-
}
2267-
if (coll->getCollectionOptions().encryptedFieldConfig) {
2268-
_stats.queryableEncryption += 1;
2259+
if (!nss.isOnInternalDb()) {
2260+
if (!nss.isSystem()) {
2261+
_stats.userCollections += 1;
2262+
if (coll->isCapped()) {
2263+
_stats.userCapped += 1;
2264+
}
2265+
if (coll->isClustered()) {
2266+
_stats.userClustered += 1;
2267+
}
2268+
if (coll->getCollectionOptions().encryptedFieldConfig) {
2269+
_stats.queryableEncryption += 1;
2270+
}
2271+
if (isCSFLE1Validator(coll->getValidatorDoc())) {
2272+
_stats.csfle += 1;
2273+
}
2274+
} else {
2275+
_stats.internal += 1;
22692276
}
2270-
if (isCSFLE1Validator(coll->getValidatorDoc())) {
2271-
_stats.csfle += 1;
2277+
2278+
if (nss.isSystemDotProfile()) {
2279+
_stats.systemProfile += 1;
22722280
}
22732281
} else {
22742282
_stats.internal += 1;
@@ -2327,19 +2335,27 @@ std::shared_ptr<Collection> CollectionCatalog::deregisterCollection(
23272335
_pushCatalogIdForNSSAndUUID(ns, uuid, boost::none, commitTime);
23282336
}
23292337

2330-
if (!ns.isOnInternalDb() && !ns.isSystem()) {
2331-
_stats.userCollections -= 1;
2332-
if (coll->isCapped()) {
2333-
_stats.userCapped -= 1;
2334-
}
2335-
if (coll->isClustered()) {
2336-
_stats.userClustered -= 1;
2337-
}
2338-
if (coll->getCollectionOptions().encryptedFieldConfig) {
2339-
_stats.queryableEncryption -= 1;
2338+
if (!ns.isOnInternalDb()) {
2339+
if (!ns.isSystem()) {
2340+
_stats.userCollections -= 1;
2341+
if (coll->isCapped()) {
2342+
_stats.userCapped -= 1;
2343+
}
2344+
if (coll->isClustered()) {
2345+
_stats.userClustered -= 1;
2346+
}
2347+
if (coll->getCollectionOptions().encryptedFieldConfig) {
2348+
_stats.queryableEncryption -= 1;
2349+
}
2350+
if (isCSFLE1Validator(coll->getValidatorDoc())) {
2351+
_stats.csfle -= 1;
2352+
}
2353+
} else {
2354+
_stats.internal -= 1;
23402355
}
2341-
if (isCSFLE1Validator(coll->getValidatorDoc())) {
2342-
_stats.csfle -= 1;
2356+
2357+
if (ns.isSystemDotProfile()) {
2358+
_stats.systemProfile -= 1;
23432359
}
23442360
} else {
23452361
_stats.internal -= 1;

src/mongo/db/catalog/collection_catalog.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ class CollectionCatalog {
670670
int csfle = 0;
671671
// Queryable Encryption collections on non-internal databases
672672
int queryableEncryption = 0;
673+
// <>.system.profile collections on non-internal databases. Counted as `internal`.
674+
int systemProfile = 0;
673675
};
674676

675677
/**

src/mongo/db/introspect.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "mongo/db/auth/authorization_session.h"
3535
#include "mongo/db/catalog/collection_write_path.h"
3636
#include "mongo/db/client.h"
37+
#include "mongo/db/commands/server_status.h"
3738
#include "mongo/db/concurrency/exception_util.h"
3839
#include "mongo/db/concurrency/lock_state.h"
3940
#include "mongo/db/curop.h"
@@ -52,6 +53,32 @@ using std::endl;
5253
using std::string;
5354
using std::unique_ptr;
5455

56+
namespace {
57+
58+
AtomicWord<int64_t> profilerWritesTotal{0};
59+
AtomicWord<int64_t> profilerWritesActive{0};
60+
61+
class ProfilerSection : public ServerStatusSection {
62+
public:
63+
ProfilerSection() : ServerStatusSection("profiler") {}
64+
65+
~ProfilerSection() override = default;
66+
67+
bool includeByDefault() const override {
68+
return true;
69+
}
70+
71+
BSONObj generateSection(OperationContext* opCtx,
72+
const BSONElement& configElement) const override {
73+
BSONObjBuilder bob;
74+
bob.append("totalWrites", profilerWritesTotal.loadRelaxed());
75+
bob.append("activeWriters", profilerWritesActive.loadRelaxed());
76+
return bob.obj();
77+
}
78+
} profilerSection;
79+
80+
} // namespace
81+
5582
void profile(OperationContext* opCtx, NetworkOp op) {
5683
// Initialize with 1kb at start in order to avoid realloc later
5784
BufBuilder profileBufBuilder(1024);
@@ -106,6 +133,10 @@ void profile(OperationContext* opCtx, NetworkOp op) {
106133
});
107134
AlternativeClientRegion acr(newClient);
108135
const auto dbProfilingNS = NamespaceString::makeSystemDotProfileNamespace(ns.dbName());
136+
137+
profilerWritesActive.fetchAndAddRelaxed(1);
138+
ON_BLOCK_EXIT([&] { profilerWritesActive.fetchAndAddRelaxed(-1); });
139+
109140
AutoGetCollection autoColl(newCtx.get(), dbProfilingNS, MODE_IX);
110141
Database* const db = autoColl.getDb();
111142
if (!db) {
@@ -126,6 +157,7 @@ void profile(OperationContext* opCtx, NetworkOp op) {
126157
uassertStatusOK(collection_internal::insertDocument(
127158
newCtx.get(), coll, InsertStatement(p), nullOpDebug, false));
128159
wuow.commit();
160+
profilerWritesTotal.fetchAndAddRelaxed(1);
129161
} catch (const AssertionException& assertionEx) {
130162
LOGV2_WARNING(20703,
131163
"Caught Assertion while trying to profile {operation} against "

0 commit comments

Comments
 (0)