package ru.yandex.market.graphouse.search.tree;
import ru.yandex.market.graphouse.MetricUtil;
import ru.yandex.market.graphouse.retention.RetentionProvider;
import ru.yandex.market.graphouse.search.MetricStatus;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Map;
/**
* @author Dmitry Andreev <a href="mailto:AndreevDm@yandex-team.ru"></a>
* @date 25/01/2017
*/
public abstract class MetricDir extends MetricBase {
public MetricDir(MetricDir parent, String name, MetricStatus status) {
super(parent, name, status);
}
@Override
public boolean isDir() {
return true;
}
@Override
public String getName() {
if (isRoot()) {
return "ROOT";
}
final String dirName = name + MetricUtil.LEVEL_SPLITTER;
return parent.isRoot() ? dirName : parent.toString() + dirName;
}
public abstract Map<String, MetricDir> getDirs();
public abstract Map<String, MetricName> getMetrics();
public abstract boolean hasDirs();
public abstract boolean hasMetrics();
public abstract int loadedMetricCount();
public abstract int loadedDirCount();
public abstract MetricDir maybeGetDir(String name);
public abstract MetricName maybeGetMetric(String name);
public MetricDir getOrCreateDir(String name, MetricStatus status, MetricDirFactory metricDirFactory) {
Map<String, MetricDir> dirs = getDirs();
MetricDir dir = dirs.get(name);
if (dir != null) {
return dir;
}
String internName = name.intern();
dir = dirs.computeIfAbsent(
internName,
s -> metricDirFactory.createMetricDir(MetricDir.this, internName, status)
);
notifyChildStatusChange(dir, null); //Can be false call, but its ok
return dir;
}
public MetricName getOrCreateMetric(String name, MetricStatus status, RetentionProvider retentionProvider) {
Map<String, MetricName> metrics = getMetrics();
MetricName metric = metrics.get(name);
if (metric != null) {
return metric;
}
String internName = name.intern();
metric = metrics.computeIfAbsent(
internName,
s -> new MetricName(this, internName, status, retentionProvider.getRetention(getName() + name))
);
notifyChildStatusChange(metric, null); //Can be false call, but its ok
return metric;
}
/**
* if all the metrics in the directory are hidden, then we try to hide it {@link MetricStatus#AUTO_HIDDEN}
* if there is at least one open metric for the directory, then we try to open it {@link MetricStatus#SIMPLE}
*/
public void notifyChildStatusChange(MetricBase metricBase, MetricStatus oldStatus) {
if (isRoot()) {
return;
}
MetricStatus newStatus = metricBase.getStatus();
// remove from the tree, it does not make sense to store it
if (newStatus == MetricStatus.AUTO_HIDDEN) {
if (metricBase.isDir()) {
getDirs().remove(metricBase.getName());
} else {
getMetrics().remove(metricBase.getName());
}
}
if (oldStatus != null && oldStatus.visible() == newStatus.visible()) {
return;
}
// if all the metrics in the directory are hidden, then we try to hide it {@link MetricStatus#AUTO_HIDDEN}
// if there is at least one open metric for the directory, then we try to open it {@link MetricStatus#SIMPLE}
if (newStatus.visible()) {
setStatus(MetricStatus.SIMPLE);
} else {
setStatus(hasVisibleChildren() ? MetricStatus.SIMPLE : MetricStatus.AUTO_HIDDEN);
}
}
private boolean hasVisibleChildren() {
if (hasDirs()) {
for (MetricDir metricDir : getDirs().values()) {
if (metricDir.visible()) {
return true;
}
}
}
if (hasMetrics()) {
for (MetricName metricName : getMetrics().values()) {
if (metricName.visible()) {
return true;
}
}
}
return false;
}
}