foundationdb/flow/TDMetric.cpp

232 lines
7.0 KiB
C++
Raw Normal View History

2017-05-26 04:48:44 +08:00
/*
* TDMetric.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
*
2017-05-26 04:48:44 +08:00
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
2017-05-26 04:48:44 +08:00
* http://www.apache.org/licenses/LICENSE-2.0
*
2017-05-26 04:48:44 +08:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flow/TDMetric.actor.h"
#include "flow/flow.h"
2017-05-26 04:48:44 +08:00
const StringRef BaseEventMetric::metricType = LiteralStringRef("Event");
template <>
const StringRef Int64Metric::metricType = LiteralStringRef("Int64");
template <>
const StringRef DoubleMetric::metricType = LiteralStringRef("Double");
template <>
const StringRef BoolMetric::metricType = LiteralStringRef("Bool");
template <>
const StringRef StringMetric::metricType = LiteralStringRef("String");
std::string reduceFilename(std::string const& filename) {
2017-05-26 04:48:44 +08:00
std::string r = filename;
2017-05-26 04:48:44 +08:00
// Remove any path prefix
size_t trunc = r.find_last_of("/\\");
if (trunc != r.npos)
2017-05-26 04:48:44 +08:00
r = r.substr(trunc + 1);
2017-05-26 04:48:44 +08:00
// Look for sequences of 8 or more hex chars and remove them if found
size_t pos = 0;
static const char* hexchars = "0123456789abcdef";
while (pos < r.size()) {
2017-05-26 04:48:44 +08:00
size_t first = r.find_first_of(hexchars, pos);
if (first == r.npos)
2017-05-26 04:48:44 +08:00
break;
size_t last = r.find_first_not_of(hexchars, first);
if (last == r.npos)
2017-05-26 04:48:44 +08:00
last = r.size();
int runLen = last - first;
if (runLen >= 8)
2017-05-26 04:48:44 +08:00
r.erase(first, runLen);
else
pos = last + 1;
}
return r;
}
void MetricKeyRef::writeField(BinaryWriter& wr) const {
wr.serializeBytes(LiteralStringRef("\x01"));
wr.serializeBytes(fieldName);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(fieldType);
wr.serializeBytes(LiteralStringRef("\x00"));
2017-05-26 04:48:44 +08:00
}
void MetricKeyRef::writeMetricName(BinaryWriter& wr) const {
wr.serializeBytes(LiteralStringRef("\x01"));
wr.serializeBytes(name.name);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(name.type);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(address);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(name.id);
wr.serializeBytes(LiteralStringRef("\x00"));
2017-05-26 04:48:44 +08:00
}
const Standalone<StringRef> MetricKeyRef::packLatestKey() const {
BinaryWriter wr(Unversioned());
wr.serializeBytes(prefix);
wr.serializeBytes(LiteralStringRef("\x01TDMetricsLastValue\x00"));
2017-05-26 04:48:44 +08:00
writeMetricName(wr);
return wr.toValue();
2017-05-26 04:48:44 +08:00
}
const Standalone<StringRef> MetricKeyRef::packDataKey(int64_t time) const {
BinaryWriter wr(Unversioned());
wr.serializeBytes(prefix);
if (isField())
wr.serializeBytes(LiteralStringRef("\x01TDFieldData\x00"));
2017-05-26 04:48:44 +08:00
else
wr.serializeBytes(LiteralStringRef("\x01TDMetricData\x00"));
2017-05-26 04:48:44 +08:00
writeMetricName(wr);
if (isField())
2017-05-26 04:48:44 +08:00
writeField(wr);
wr.serializeAsTuple(level);
if (time >= 0)
2017-05-26 04:48:44 +08:00
wr.serializeAsTuple(time);
return wr.toValue();
2017-05-26 04:48:44 +08:00
}
const Standalone<StringRef> MetricKeyRef::packFieldRegKey() const {
ASSERT(isField());
BinaryWriter wr(Unversioned());
wr.serializeBytes(prefix);
wr.serializeBytes(LiteralStringRef("\x01TDFields\x00\x01"));
wr.serializeBytes(name.name);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(name.type);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(fieldName);
wr.serializeBytes(LiteralStringRef("\x00\x01"));
wr.serializeBytes(fieldType);
wr.serializeBytes(LiteralStringRef("\x00"));
return wr.toValue();
2017-05-26 04:48:44 +08:00
}
2020-11-24 04:20:37 +08:00
bool TDMetricCollection::canLog(int level) const {
2017-05-26 04:48:44 +08:00
// Whether a given level can be logged or not depends on the length of the rollTimes queue.
// No restriction until queue size reaches METRIC_LIMIT_START_QUEUE_SIZE
if (rollTimes.size() < FLOW_KNOBS->METRIC_LIMIT_START_QUEUE_SIZE)
2017-05-26 04:48:44 +08:00
return true;
2017-05-26 04:48:44 +08:00
int extraQueueItems = rollTimes.size() - FLOW_KNOBS->METRIC_LIMIT_START_QUEUE_SIZE;
// Level must be greater than the number of responseFactor-sized groups of additional items in the queue.
return level > extraQueueItems / FLOW_KNOBS->METRIC_LIMIT_RESPONSE_FACTOR;
}
void TDMetricCollection::checkRoll(uint64_t t, int64_t usedBytes) {
currentTimeBytes += usedBytes;
if (currentTimeBytes > 1e6) {
TEST(true); // metrics were rolled
2017-05-26 04:48:44 +08:00
currentTimeBytes = 0;
rollTimes.push_back(t);
for (auto& it : metricMap)
2017-05-26 04:48:44 +08:00
it.value->rollMetric(t);
metricEnabled.trigger();
}
}
DynamicEventMetric::DynamicEventMetric(MetricNameRef const& name, Void)
: BaseEventMetric(name), newFields(false), latestRecorded(false) {}
2017-05-26 04:48:44 +08:00
uint64_t DynamicEventMetric::log(uint64_t explicitTime) {
if (!enabled)
2017-05-26 04:48:44 +08:00
return 0;
uint64_t t = explicitTime ? explicitTime : timer_int();
double x = deterministicRandom()->random01();
2017-05-26 04:48:44 +08:00
int64_t l = 0;
if (x == 0.0)
l = FLOW_KNOBS->MAX_METRIC_LEVEL - 1;
2017-05-26 04:48:44 +08:00
else
l = std::min(FLOW_KNOBS->MAX_METRIC_LEVEL - 1, (int64_t)(::log(1.0 / x) / FLOW_KNOBS->METRIC_LEVEL_DIVISOR));
2017-05-26 04:48:44 +08:00
if (!TDMetricCollection::getTDMetrics()->canLog(l))
2017-05-26 04:48:44 +08:00
return 0;
// fprintf(stderr, "Logging %s with %d fields (other than Time)\n", name.name.toString().c_str(), fields.size());
2017-05-26 04:48:44 +08:00
if (newFields) {
// New fields were added so go to new key for all fields (at all levels) so the field parallel data series line
// up correctly.
2017-05-26 04:48:44 +08:00
time.nextKeyAllLevels(t);
for (auto& [name, field] : fields)
field->nextKeyAllLevels(t);
2017-05-26 04:48:44 +08:00
newFields = false;
}
bool overflow = false;
int64_t bytes = 0;
2017-05-26 04:48:44 +08:00
time.log(t, t, l, overflow, bytes);
for (auto& [name, field] : fields)
field->log(t, l, overflow, bytes);
if (overflow) {
time.nextKey(t, l);
for (auto& [name, field] : fields)
field->nextKey(t, l);
2017-05-26 04:48:44 +08:00
}
latestRecorded = false;
TDMetricCollection::getTDMetrics()->checkRoll(t, bytes);
clearFields();
return t;
}
void DynamicEventMetric::flushData(MetricKeyRef const& mk, uint64_t rollTime, MetricUpdateBatch& batch) {
time.flushField(mk, rollTime, batch);
for (auto& [name, field] : fields)
field->flushField(mk, rollTime, batch);
if (!latestRecorded) {
batch.updates.emplace_back(mk.packLatestKey(), StringRef());
2017-05-26 04:48:44 +08:00
latestRecorded = true;
}
}
void DynamicEventMetric::rollMetric(uint64_t t) {
2017-05-26 04:48:44 +08:00
time.rollMetric(t);
for (auto& f : fields)
f.second->rollMetric(t);
2017-05-26 04:48:44 +08:00
}
void DynamicEventMetric::registerFields(MetricKeyRef const& mk, std::vector<Standalone<StringRef>>& fieldKeys) {
2017-05-26 04:48:44 +08:00
// This is actually redundant on update registrations but it's not a big deal
time.registerField(mk, fieldKeys);
// Register the new fields
for (auto& f : fieldsToRegister)
fields[f]->registerField(mk, fieldKeys);
2017-05-26 04:48:44 +08:00
// Clear the to-register set.
fieldsToRegister.clear();
}
2020-12-27 10:35:28 +08:00
std::string MetricData::toString() const {
return format("MetricData(addr=%p start=%llu appendStart=%llu rollTime=%llu writerLen=%d)",
this,
start,
appendStart,
rollTime,
writer.getLength());
2017-05-26 04:48:44 +08:00
}