
com.yahoo.metrics.simple.DimensionCache Maven / Gradle / Ivy
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.metrics.simple;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* The persistence layer for metrics. Both CPU and memory hungry, but
* it runs in its own little world.
*
* @author Steinar Knutsen
*/
class DimensionCache {
private static class TimeStampedMetric {
public final long millis;
public final UntypedMetric metric;
public TimeStampedMetric(long millis, UntypedMetric metric) {
this.millis = millis;
this.metric = metric;
}
}
private final Map> persistentData = new HashMap<>();
private final int pointsToKeep;
public DimensionCache(int pointsToKeep) {
this.pointsToKeep = pointsToKeep;
}
void updateDimensionPersistence(Bucket toDelete, Bucket toPresent) {
updatePersistentData(toDelete);
padPresentation(toPresent);
}
private void padPresentation(Bucket toPresent) {
Map>> currentMetricNames = toPresent.getValuesByMetricName();
for (Map.Entry>> metric : currentMetricNames.entrySet()) {
final int currentDataPoints = metric.getValue().size();
if (currentDataPoints < pointsToKeep) {
padMetric(metric.getKey(), toPresent, currentDataPoints);
}
}
Set keysMissingFromPresentation = new HashSet<>(persistentData.keySet());
keysMissingFromPresentation.removeAll(currentMetricNames.keySet());
for (String cachedMetric : keysMissingFromPresentation) {
padMetric(cachedMetric, toPresent, 0);
}
}
private void updatePersistentData(Bucket toDelete) {
if (toDelete == null) {
return;
}
long millis = toDelete.gotTimeStamps ? toDelete.toMillis : System.currentTimeMillis();
for (Map.Entry>> metric : toDelete.getValuesByMetricName().entrySet()) {
LinkedHashMap cachedPoints = getCachedMetric(metric.getKey());
for (Entry newestInterval : metric.getValue()) {
// overwriting an existing entry does not update the order
// in the map
cachedPoints.remove(newestInterval.getKey());
TimeStampedMetric toInsert = new TimeStampedMetric(millis, newestInterval.getValue());
cachedPoints.put(newestInterval.getKey(), toInsert);
}
}
}
private static final long MAX_AGE_MILLIS = 4 * 3600 * 1000;
private void padMetric(String metric, Bucket toPresent, int currentDataPoints) {
LinkedHashMap cachedPoints = getCachedMetric(metric);
int toAdd = pointsToKeep - currentDataPoints;
@SuppressWarnings({"unchecked","rawtypes"})
Entry[] cachedEntries = cachedPoints.entrySet().toArray(new Entry[0]);
long nowMillis = System.currentTimeMillis();
for (int i = cachedEntries.length - 1; i >= 0 && toAdd > 0; --i) {
Entry leastOld = cachedEntries[i];
if (leastOld.getValue().millis + MAX_AGE_MILLIS < nowMillis) {
continue;
}
Identifier id = new Identifier(metric, leastOld.getKey());
if ( ! toPresent.hasIdentifier(id)) {
toPresent.put(id, leastOld.getValue().metric.pruneData());
--toAdd;
}
}
}
@SuppressWarnings("serial")
private LinkedHashMap getCachedMetric(String metricName) {
LinkedHashMap points = persistentData.get(metricName);
if (points == null) {
points = new LinkedHashMap<>(16, 0.75f, false) {
protected @Override boolean removeEldestEntry(Map.Entry eldest) {
return size() > pointsToKeep;
}
};
persistentData.put(metricName, points);
}
return points;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy