summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Noma <gregory.noma@gmail.com>2021-02-03 23:09:05 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-02-04 10:57:47 +0000
commitc61595630908224faa65856222ae7186b72e54cf (patch)
treef8c3dbce79a1131bd54c5af11bd34da13c917c9c
parentc7c16d3c6fdcb24bde8a014b0ca2c0d4650ce9d2 (diff)
downloadmongo-c61595630908224faa65856222ae7186b72e54cf.tar.gz
SERVER-54106 Use DecimalCounter for time-series inserts
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp34
-rw-r--r--src/mongo/db/timeseries/bucket_catalog.cpp24
-rw-r--r--src/mongo/db/timeseries/bucket_catalog.h10
-rw-r--r--src/mongo/util/decimal_counter.h17
-rw-r--r--src/mongo/util/decimal_counter_bm.cpp19
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