Adds rate limit to checking byte size.
Since there is a separate guardrail for memory used by uid map, we
no longer add the memory from uid map with the memory per each
config's metrics. We also prevent the byte size check from happening
too frequently. In order to mock the MetricsManager, we refactor
some of the existing methods.
Test: Added unit-tests and verified they all pass on marlin.
Change-Id: I15cf105f7d95f4016fdb0443b0a33eebe862cafb
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index c291647..2df0c90 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -86,9 +86,7 @@
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(msg);
- // TODO: THIS CHECK FAILS BECAUSE ONCE UIDMAP SIZE EXCEEDS LIMIT, DROPPING METRICS DATA
- // DOESN'T HELP. FIX THIS.
- // flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
+ flushIfNecessary(msg.GetTimestampNs(), pair.first, *(pair.second));
}
// Hard-coded logic to update the isolated uid's in the uid-map.
@@ -217,23 +215,32 @@
mLastBroadcastTimes.erase(key);
}
-void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs,
- const ConfigKey& key,
- const unique_ptr<MetricsManager>& metricsManager) {
+void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, const ConfigKey& key,
+ MetricsManager& metricsManager) {
std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
- size_t totalBytes = metricsManager->byteSize() + mUidMap->getBytesUsed();
- // TODO: Find a way to test that the dropping and broadcasts are sent when memory is exceeded.
- if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data.
+ auto lastCheckTime = mLastByteSizeTimes.find(key);
+ if (lastCheckTime != mLastByteSizeTimes.end()) {
+ if (timestampNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
+ return;
+ }
+ }
+
+ // We suspect that the byteSize() computation is expensive, so we set a rate limit.
+ size_t totalBytes = metricsManager.byteSize();
+ mLastByteSizeTimes[key] = timestampNs;
+ if (totalBytes >
+ StatsdStats::kMaxMetricsBytesPerConfig) { // Too late. We need to start clearing data.
// We ignore the return value so we force each metric producer to clear its contents.
- metricsManager->onDumpReport();
+ metricsManager.onDumpReport();
StatsdStats::getInstance().noteDataDropped(key);
VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
- } else if (totalBytes >
- .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
- auto lastFlushNs = mLastBroadcastTimes.find(key);
- if (lastFlushNs != mLastBroadcastTimes.end()) {
- if (timestampNs - lastFlushNs->second < kMinBroadcastPeriod) {
+ } else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
+ // Send broadcast so that receivers can pull data.
+ auto lastBroadcastTime = mLastBroadcastTimes.find(key);
+ if (lastBroadcastTime != mLastBroadcastTimes.end()) {
+ if (timestampNs - lastBroadcastTime->second < StatsdStats::kMinBroadcastPeriodNs) {
+ VLOG("StatsD would've sent a broadcast but the rate limit stopped us.");
return;
}
}