diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2021-02-03 23:09:05 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-04 10:57:47 +0000 |
commit | c61595630908224faa65856222ae7186b72e54cf (patch) | |
tree | f8c3dbce79a1131bd54c5af11bd34da13c917c9c | |
parent | c7c16d3c6fdcb24bde8a014b0ca2c0d4650ce9d2 (diff) | |
download | mongo-c61595630908224faa65856222ae7186b72e54cf.tar.gz |
SERVER-54106 Use DecimalCounter for time-series inserts
-rw-r--r-- | src/mongo/db/commands/write_commands/write_commands.cpp | 34 | ||||
-rw-r--r-- | src/mongo/db/timeseries/bucket_catalog.cpp | 24 | ||||
-rw-r--r-- | src/mongo/db/timeseries/bucket_catalog.h | 10 | ||||
-rw-r--r-- | src/mongo/util/decimal_counter.h | 17 | ||||
-rw-r--r-- | src/mongo/util/decimal_counter_bm.cpp | 19 |
5 files changed, 55 insertions, 49 deletions
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index 302b6a69a1d..305236c2099 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -122,28 +122,6 @@ bool isTimeseries(OperationContext* opCtx, const NamespaceString& ns) { const int kTimeseriesControlVersion = 1; /** - * Returns $set expressions for the bucket's data field. - * If 'metadataElem' is not empty, the time-series collection was created with a metadata field. - * All measurements in a bucket share the same value in the 'meta' field, so there is no need to add - * the metadata to the data field. - */ -void appendTimeseriesDataFields(const std::vector<BSONObj>& docs, - BSONElement metadataElem, - uint16_t count, - BSONObjBuilder* builder) { - for (const auto& doc : docs) { - for (const auto& elem : doc) { - auto key = elem.fieldNameStringData(); - if (metadataElem && key == metadataElem.fieldNameStringData()) { - continue; - } - builder->appendAs(elem, str::stream() << "data." << key << "." << count); - } - count++; - } -} - -/** * Transforms a single time-series insert to an update request on an existing bucket. */ write_ops::UpdateOpEntry makeTimeseriesUpdateOpEntry(const OID& bucketId, @@ -168,7 +146,7 @@ write_ops::UpdateOpEntry makeTimeseriesUpdateOpEntry(const OID& bucketId, // doc_diff::kSubDiffSectionFieldPrefix + <field name> => {<index_0>: ..., <index_1>: ...} StringDataMap<BSONObjBuilder> dataFieldBuilders; auto metadataElem = metadata.firstElement(); - auto count = data.numCommittedMeasurements; + DecimalCounter<uint32_t> count(data.numCommittedMeasurements); for (const auto& doc : data.docs) { for (const auto& elem : doc) { auto key = elem.fieldNameStringData(); @@ -176,9 +154,9 @@ write_ops::UpdateOpEntry makeTimeseriesUpdateOpEntry(const OID& bucketId, continue; } auto& builder = dataFieldBuilders[key]; - builder.appendAs(elem, std::to_string(count)); + builder.appendAs(elem, count); } - count++; + ++count; } // doc_diff::kSubDiffSectionFieldPrefix + <field name> @@ -220,16 +198,16 @@ BSONArray makeTimeseriesInsertDocument(const OID& bucketId, auto metadataElem = metadata.firstElement(); StringDataMap<BSONObjBuilder> dataBuilders; - uint16_t count = 0; + DecimalCounter<uint32_t> count; for (const auto& doc : data.docs) { - auto countFieldName = std::to_string(count++); for (const auto& elem : doc) { auto key = elem.fieldNameStringData(); if (metadataElem && key == metadataElem.fieldNameStringData()) { continue; } - dataBuilders[key].appendAs(elem, countFieldName); + dataBuilders[key].appendAs(elem, count); } + ++count; } BSONArrayBuilder builder; diff --git a/src/mongo/db/timeseries/bucket_catalog.cpp b/src/mongo/db/timeseries/bucket_catalog.cpp index 39da80a5a2b..ccdd0f54b39 100644 --- a/src/mongo/db/timeseries/bucket_catalog.cpp +++ b/src/mongo/db/timeseries/bucket_catalog.cpp @@ -39,6 +39,15 @@ namespace mongo { namespace { const auto getBucketCatalog = ServiceContext::declareDecoration<BucketCatalog>(); + +uint8_t numDigits(uint32_t num) { + uint8_t numDigits = 0; + while (num) { + num /= 10; + ++numDigits; + } + return numDigits; +} } // namespace BSONObj BucketCatalog::CommitData::toBSON() const { @@ -222,7 +231,7 @@ BucketCatalog::CommitData BucketCatalog::commit(const OID& bucketId, stats.numMeasurementsCommitted += measurements.size(); // Inform waiters that their measurements have been committed. - for (uint16_t i = 1; i < bucket.numPendingCommitMeasurements; i++) { + for (uint32_t i = 1; i < bucket.numPendingCommitMeasurements; i++) { bucket.promises.front().emplaceValue(*previousCommitInfo); bucket.promises.pop(); } @@ -390,7 +399,7 @@ void BucketCatalog::Bucket::calculateBucketFieldsAndSizeChange( newFieldNamesToBeInserted->clear(); *newFieldNamesSize = 0; *sizeToBeAdded = 0; - auto numMeasurementsFieldLength = std::to_string(numMeasurements).size(); + auto numMeasurementsFieldLength = numDigits(numMeasurements); for (const auto& elem : doc) { if (elem.fieldNameStringData() == metaField) { // Ignore the metadata field since it will not be inserted. @@ -583,11 +592,12 @@ bool BucketCatalog::MinMax::_appendUpdates(BSONObjBuilder* builder) { } } else { builder->append(doc_diff::kArrayHeader, true); - for (size_t i = 0; i < _array.size(); i++) { - auto& minMax = _array[i]; + DecimalCounter<size_t> count; + for (auto& minMax : _array) { invariant(minMax._type != Type::kUnset); if (minMax._updated) { - auto updateFieldName = doc_diff::kUpdateSectionFieldName + std::to_string(i); + std::string updateFieldName = str::stream() + << doc_diff::kUpdateSectionFieldName << StringData(count); if (minMax._type == Type::kObject) { BSONObjBuilder subObj(builder->subobjStart(updateFieldName)); minMax._append(&subObj); @@ -603,11 +613,13 @@ bool BucketCatalog::MinMax::_appendUpdates(BSONObjBuilder* builder) { BSONObjBuilder subDiff; if (minMax._appendUpdates(&subDiff)) { // An update occurred at a lower level, so append the sub diff. - builder->append(doc_diff::kSubDiffSectionFieldPrefix + std::to_string(i), + builder->append(str::stream() << doc_diff::kSubDiffSectionFieldPrefix + << StringData(count), subDiff.done()); appended = true; } } + ++count; } } diff --git a/src/mongo/db/timeseries/bucket_catalog.h b/src/mongo/db/timeseries/bucket_catalog.h index ef9feba4811..68d2a24f2cc 100644 --- a/src/mongo/db/timeseries/bucket_catalog.h +++ b/src/mongo/db/timeseries/bucket_catalog.h @@ -60,7 +60,7 @@ public: std::vector<BSONObj> docs; BSONObj bucketMin; // The full min/max if this is the bucket's first commit, or the updates BSONObj bucketMax; // since the previous commit if not. - uint16_t numCommittedMeasurements; + uint32_t numCommittedMeasurements; StringSet newFieldNamesToBeInserted; BSONObj toBSON() const; @@ -226,17 +226,17 @@ private: // The total size in bytes of the bucket's BSON serialization, including measurements to be // inserted. - uint32_t size = 0; + uint64_t size = 0; // The total number of measurements in the bucket, including uncommitted measurements and // measurements to be inserted. - uint16_t numMeasurements = 0; + uint32_t numMeasurements = 0; // The number of measurements that were most recently returned from a call to commit(). - uint16_t numPendingCommitMeasurements = 0; + uint32_t numPendingCommitMeasurements = 0; // The number of committed measurements in the bucket. - uint16_t numCommittedMeasurements = 0; + uint32_t numCommittedMeasurements = 0; // The number of current writers for the bucket. uint32_t numWriters = 0; diff --git a/src/mongo/util/decimal_counter.h b/src/mongo/util/decimal_counter.h index b090989792f..9fe0124ccba 100644 --- a/src/mongo/util/decimal_counter.h +++ b/src/mongo/util/decimal_counter.h @@ -33,6 +33,7 @@ #include <limits> #include "mongo/base/string_data.h" +#include "mongo/util/itoa.h" namespace mongo { /** @@ -44,6 +45,9 @@ template <typename T> class DecimalCounter { public: static_assert(std::is_unsigned<T>::value, "DecimalCounter requires an unsigned type"); + + DecimalCounter<T>(T start = 0) : _lastDigitIndex(_getLastDigitIndex(start)), _counter(start) {} + constexpr operator StringData() const { return {_digits, static_cast<size_t>(_lastDigitIndex + 1)}; } @@ -95,10 +99,19 @@ public: } private: + uint8_t _getLastDigitIndex(T start) { + if (!start) { + return 0; + } + StringData startStr = ItoA(start); + std::memcpy(_digits, startStr.rawData(), startStr.size()); + return startStr.size() - 1; + } + // Add 1, because digit10 is 1 less than the maximum number of digits, and 1 for the final '\0'. static constexpr size_t kBufSize = std::numeric_limits<T>::digits10 + 2; char _digits[kBufSize] = {'0'}; // Remainder is zero-initialized. - uint8_t _lastDigitIndex = 0; // Indicates the last digit in _digits. - T _counter = 0; + uint8_t _lastDigitIndex; // Indicates the last digit in _digits. + T _counter; }; } // namespace mongo diff --git a/src/mongo/util/decimal_counter_bm.cpp b/src/mongo/util/decimal_counter_bm.cpp index fb0f0cc601e..8c7a4be538a 100644 --- a/src/mongo/util/decimal_counter_bm.cpp +++ b/src/mongo/util/decimal_counter_bm.cpp @@ -35,11 +35,14 @@ #include "mongo/util/itoa.h" namespace mongo { +namespace { +auto nonzeroStart = std::numeric_limits<uint32_t>::max() / 2; +} // namespace void BM_decimalCounterPreInc(benchmark::State& state) { uint64_t items = 0; for (auto _ : state) { - DecimalCounter<uint32_t> count; + DecimalCounter<uint32_t> count(state.range(1)); for (int i = state.range(0); i--;) { benchmark::ClobberMemory(); benchmark::DoNotOptimize(StringData(++count)); @@ -52,7 +55,7 @@ void BM_decimalCounterPreInc(benchmark::State& state) { void BM_decimalCounterPostInc(benchmark::State& state) { uint64_t items = 0; for (auto _ : state) { - DecimalCounter<uint32_t> count; + DecimalCounter<uint32_t> count(state.range(1)); for (int i = state.range(0); i--;) { benchmark::ClobberMemory(); benchmark::DoNotOptimize(StringData(count++)); @@ -65,7 +68,7 @@ void BM_decimalCounterPostInc(benchmark::State& state) { void BM_ItoACounter(benchmark::State& state) { uint64_t items = 0; for (auto _ : state) { - uint32_t count = 0; + uint32_t count = state.range(1); for (int i = state.range(0); i--;) { benchmark::ClobberMemory(); benchmark::DoNotOptimize(StringData(ItoA(++count))); @@ -78,7 +81,7 @@ void BM_ItoACounter(benchmark::State& state) { void BM_to_stringCounter(benchmark::State& state) { uint64_t items = 0; for (auto _ : state) { - uint32_t count = 0; + uint32_t count = state.range(1); for (int i = state.range(0); i--;) { benchmark::ClobberMemory(); benchmark::DoNotOptimize(std::to_string(++count)); @@ -88,9 +91,9 @@ void BM_to_stringCounter(benchmark::State& state) { state.SetItemsProcessed(items); } -BENCHMARK(BM_decimalCounterPreInc)->Arg(10000); -BENCHMARK(BM_decimalCounterPostInc)->Arg(10000); -BENCHMARK(BM_ItoACounter)->Arg(10000); -BENCHMARK(BM_to_stringCounter)->Arg(10000); +BENCHMARK(BM_decimalCounterPreInc)->Args({10000, 0})->Args({{10, nonzeroStart}}); +BENCHMARK(BM_decimalCounterPostInc)->Args({10000, 0})->Args({{10, nonzeroStart}}); +BENCHMARK(BM_ItoACounter)->Args({10000, 0})->Args({{10, nonzeroStart}}); +BENCHMARK(BM_to_stringCounter)->Args({10000, 0})->Args({{10, nonzeroStart}}); } // namespace mongo |