diff options
author | Dan Larkin-York <dan.larkin-york@mongodb.com> | 2022-08-29 22:32:52 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-08-29 23:12:36 +0000 |
commit | be2effed55930ecd2b9efc06057ab45dbb4163d0 (patch) | |
tree | a2da49851184afe549b7456ae9a6cd4eed2f50f9 | |
parent | ccb0d93033900be8cead29d3cdd414d8a85f2b03 (diff) | |
download | mongo-be2effed55930ecd2b9efc06057ab45dbb4163d0.tar.gz |
SERVER-66699 Add statistics about bucket state management to serverStatus
-rw-r--r-- | jstests/noPassthrough/timeseries_server_status_state_management.js | 102 | ||||
-rw-r--r-- | src/mongo/db/timeseries/bucket_catalog.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/timeseries/bucket_catalog.h | 11 |
3 files changed, 133 insertions, 0 deletions
diff --git a/jstests/noPassthrough/timeseries_server_status_state_management.js b/jstests/noPassthrough/timeseries_server_status_state_management.js new file mode 100644 index 00000000000..31f18ae52ba --- /dev/null +++ b/jstests/noPassthrough/timeseries_server_status_state_management.js @@ -0,0 +1,102 @@ +/** + * Tests that BucketCatalog bucket state management statistics are reported correctly in server + * status. + * + * @tags: [ + * # State management statistics added as part of scalability improvements project. + * featureFlagTimeseriesScalabilityImprovements, + * ] + */ +(function() { +"use strict"; + +const conn = MongoRunner.runMongod(); + +const dbName = jsTestName(); +const db = conn.getDB(dbName); +assert.commandWorked(db.dropDatabase()); + +const coll = db.getCollection(jsTestName()); + +const timeFieldName = "tt"; +const metaFieldName = "mm"; + +const resetCollection = () => { + coll.drop(); + assert.commandWorked(db.createCollection( + jsTestName(), {timeseries: {timeField: timeFieldName, metaField: metaFieldName}})); +}; + +const dropUnrelatedCollection = () => { + const unrelated = db.getCollection(jsTestName() + "_foo"); + assert.commandWorked(db.createCollection( + unrelated.getName(), {timeseries: {timeField: timeFieldName, metaField: metaFieldName}})); + unrelated.drop(); +}; + +const expected = { + bucketsManaged: 0, + currentEra: 0, + erasWithRemainingBuckets: 0, + trackedClearOperations: 0 +}; +const checkServerStatus = function() { + const actual = + assert.commandWorked(db.runCommand({serverStatus: 1})).bucketCatalog.stateManagement; + assert.eq(expected.bucketsManaged, actual.bucketsManaged); + assert.eq(expected.currentEra, actual.currentEra); + assert.eq(expected.erasWithRemainingBuckets, actual.erasWithRemainingBuckets); + assert.eq(expected.trackedClearOperations, actual.trackedClearOperations); +}; + +resetCollection(); +assert.commandWorked(coll.insert({[metaFieldName]: 1, [timeFieldName]: ISODate()})); +expected.bucketsManaged++; +expected.erasWithRemainingBuckets++; +checkServerStatus(); + +dropUnrelatedCollection(); +expected.currentEra++; +expected.trackedClearOperations++; +checkServerStatus(); + +// Inserting into the existing bucket will update its era, which has no net effect on +// erasWithRemainingBuckets, but the previously tracked clear will get cleaned up. +assert.commandWorked(coll.insert({[metaFieldName]: 1, [timeFieldName]: ISODate()})); +expected.trackedClearOperations--; +checkServerStatus(); + +assert.commandWorked(coll.insert({[metaFieldName]: 2, [timeFieldName]: ISODate()})); +expected.bucketsManaged++; +checkServerStatus(); + +// Clearing the collection will not immediately remove the old bucket states. +resetCollection(); +expected.currentEra++; +expected.trackedClearOperations++; +checkServerStatus(); + +// Inserting more measurements will check and remove the old bucket for that meta, and open a new +// one. The other meta value still has an old bucket. +assert.commandWorked(coll.insert({[metaFieldName]: 1, [timeFieldName]: ISODate()})); +expected.erasWithRemainingBuckets++; +checkServerStatus(); + +// If we clear an unrelated collection and add a third metadata value, we'll get a bucket in a third +// era. +dropUnrelatedCollection(); +assert.commandWorked(coll.insert({[metaFieldName]: 3, [timeFieldName]: ISODate()})); +expected.bucketsManaged++; +expected.currentEra++; +expected.erasWithRemainingBuckets++; +expected.trackedClearOperations++; +checkServerStatus(); + +// If we access the oldest bucket, we'll clear it and garbage collect a tracked clear. +assert.commandWorked(coll.insert({[metaFieldName]: 2, [timeFieldName]: ISODate()})); +expected.erasWithRemainingBuckets--; +expected.trackedClearOperations--; +checkServerStatus(); + +MongoRunner.stopMongod(conn); +}()); diff --git a/src/mongo/db/timeseries/bucket_catalog.cpp b/src/mongo/db/timeseries/bucket_catalog.cpp index 10ce10848cf..e7df8f04471 100644 --- a/src/mongo/db/timeseries/bucket_catalog.cpp +++ b/src/mongo/db/timeseries/bucket_catalog.cpp @@ -27,6 +27,8 @@ * it in the license file. */ +#include "mongo/bson/bsonobj.h" +#include "mongo/bson/bsonobjbuilder.h" #include "mongo/platform/basic.h" #include "mongo/db/timeseries/bucket_catalog.h" @@ -431,6 +433,17 @@ boost::optional<BucketCatalog::BucketState> BucketCatalog::BucketStateManager::s return _setBucketStateHelper(catalogLock, id, target); } +void BucketCatalog::BucketStateManager::appendStats(BSONObjBuilder* base) const { + stdx::lock_guard catalogLock{*_mutex}; + + BSONObjBuilder builder{base->subobjStart("stateManagement")}; + + builder.appendNumber("bucketsManaged", static_cast<long long>(_bucketStates.size())); + builder.appendNumber("currentEra", static_cast<long long>(_era)); + builder.appendNumber("erasWithRemainingBuckets", static_cast<long long>(_countMap.size())); + builder.appendNumber("trackedClearOperations", static_cast<long long>(_clearRegistry.size())); +} + boost::optional<BucketCatalog::BucketState> BucketCatalog::BucketStateManager::_setBucketStateHelper(WithLock catalogLock, const OID& id, @@ -1027,6 +1040,10 @@ void BucketCatalog::appendGlobalExecutionStats(BSONObjBuilder* builder) const { _appendExecutionStatsToBuilder(&_globalExecutionStats, builder); } +void BucketCatalog::appendStateManagementStats(BSONObjBuilder* builder) const { + _bucketStateManager.appendStats(builder); +} + BucketCatalog::BucketMetadata::BucketMetadata(BSONElement elem, const StringData::ComparatorInterface* comparator) : _metadataElement(elem), _comparator(comparator) { @@ -1865,6 +1882,9 @@ public: // Append the global execution stats for all namespaces. bucketCatalog.appendGlobalExecutionStats(&builder); + // Append the global state management stats for all namespaces. + bucketCatalog.appendStateManagementStats(&builder); + return builder.obj(); } } bucketCatalogServerStatus; diff --git a/src/mongo/db/timeseries/bucket_catalog.h b/src/mongo/db/timeseries/bucket_catalog.h index 921cc330a4d..a6cd1169a11 100644 --- a/src/mongo/db/timeseries/bucket_catalog.h +++ b/src/mongo/db/timeseries/bucket_catalog.h @@ -29,6 +29,7 @@ #pragma once +#include "mongo/bson/bsonobjbuilder.h" #include <boost/container/small_vector.hpp> #include <boost/container/static_vector.hpp> #include <queue> @@ -377,6 +378,11 @@ public: */ void appendGlobalExecutionStats(BSONObjBuilder* builder) const; + /** + * Appends the global bucket state management stats for all namespaces to the builder. + */ + void appendStateManagementStats(BSONObjBuilder* builder) const; + protected: enum class BucketState { // Bucket can be inserted into, and does not have an outstanding prepared commit @@ -589,6 +595,11 @@ protected: */ boost::optional<BucketState> setBucketState(const OID& id, BucketState target); + /** + * Appends statistics for observability. + */ + void appendStats(BSONObjBuilder* builder) const; + protected: void _decrementEraCountHelper(uint64_t era); void _incrementEraCountHelper(uint64_t era); |