Metrics.java

190 lines | 5.953 kB Blame History Raw Download
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufrgs.inf.prosoft.tfcache;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * @author romulo
 */
public class Metrics implements Comparable<Metrics> {

    private long ttl;
    private long hits;
    private long timeInCache;
    private long stales;
    private long savedTime;
    private BigDecimal savedTimePerTimeInCache;

    public Metrics() {
        this.savedTimePerTimeInCache = new BigDecimal(BigInteger.ZERO);
    }

    public Metrics(long ttl, long hits, long timeInCache, long stales, long savedTime) {
        if (ttl < 0 || hits < 0 || timeInCache < 0 || stales < 0 || savedTime < 0) {
            throw new RuntimeException("Metrics cannot be under zero");
        }
        if (timeInCache == 0) {
            throw new RuntimeException("timeInCache should not be zero");
        }
        this.ttl = ttl;
        this.hits = hits;
        this.timeInCache = timeInCache;
        this.stales = stales;
        this.savedTime = savedTime;
        this.savedTimePerTimeInCache = new BigDecimal(this.savedTime).divide(new BigDecimal(this.timeInCache), MathContext.DECIMAL128);
    }

    public long getTtl() {
        return this.ttl;
    }

    public long getHits() {
        return this.hits;
    }

    public long getTimeInCache() {
        return timeInCache;
    }

    public long getStales() {
        return this.stales;
    }

    public long getSavedTime() {
        return this.savedTime;
    }

    public BigDecimal getSavedTimePerTimeInCache() {
        return this.savedTimePerTimeInCache;
    }

    public synchronized void keepBestMetrics(Metrics metrics) {
        keepBestMetrics(metrics.ttl, metrics.hits, metrics.timeInCache, metrics.stales, metrics.savedTime);
    }

    public synchronized void keepBestMetrics(long ttl, long hits, long timeInCache, long stales, long savedTime) {
        if (ttl < 0 || hits < 0 || timeInCache < 0 || stales < 0 || savedTime < 0) {
            throw new RuntimeException("Metrics cannot be under zero. TTL: " + ttl
                    + " hits: " + hits
                    + " timeInCache: " + timeInCache
                    + " stales: " + stales
                    + " savedTime: " + savedTime);
        }
        if (ttl == 0 || hits == 0 || savedTime == 0) {
            return;
        }
        if (timeInCache == 0) {
            throw new RuntimeException("timeInCache should not be zero");
        }
        BigDecimal savedTimePerTimeInCache = new BigDecimal(savedTime).divide(new BigDecimal(timeInCache), MathContext.DECIMAL128);
        if (this.ttl == 0 || compareTo(ttl, hits, timeInCache, stales, savedTime, savedTimePerTimeInCache) == -1) {
            this.ttl = ttl;
            this.hits = hits;
            this.timeInCache = timeInCache;
            this.stales = stales;
            this.savedTime = savedTime;
            this.savedTimePerTimeInCache = savedTimePerTimeInCache;
        }
    }

    public static void removeDominatedMetrics(Collection<Metrics> allMetrics) {
        Map<Long, List<Metrics>> groupBySavedTime = allMetrics.stream().collect(Collectors.groupingBy(Metrics::getSavedTime));
        groupBySavedTime.remove(0L);
        groupBySavedTime.forEach((savedTime, value) -> {
            Metrics max = value.stream().max(Metrics::compareTo).get();
            value.removeIf(metric -> metric.getSavedTimePerTimeInCache().compareTo(max.getSavedTimePerTimeInCache()) == -1);
        });

        List<Metrics> localMaxima = groupBySavedTime.entrySet().stream()
                .map(entry -> entry.getValue().stream())
                .reduce(Stream::concat)
                .orElse(Stream.empty())
                .collect(Collectors.toList());

        allMetrics.removeIf(metrics -> !localMaxima.contains(metrics));
    }

    @Override
    public int compareTo(Metrics other) {
        return compareTo(other.ttl, other.hits, other.timeInCache, other.stales, other.savedTime, other.savedTimePerTimeInCache);
    }

    private int compareTo(long ttl, long hits, long timeInCache, long stales, long savedTime, BigDecimal savedTimePerTimeInCache) {
        if (getSavedTimePerTimeInCache().compareTo(savedTimePerTimeInCache) == 1) {
            return 1;
        }
        if (getSavedTimePerTimeInCache().compareTo(savedTimePerTimeInCache) == -1) {
            return -1;
        }
        if (this.stales < stales) {
            return 1;
        }
        if (this.stales > stales) {
            return -1;
        }
        if (this.savedTime > savedTime) {
            return 1;
        }
        if (this.savedTime < savedTime) {
            return -1;
        }
        if (this.hits > hits) {
            return 1;
        }
        if (this.hits < hits) {
            return -1;
        }
        if (this.ttl < ttl) {
            return 1;
        }
        if (this.ttl > ttl) {
            return -1;
        }
        if (this.timeInCache < timeInCache) {
            return 1;
        }
        if (this.timeInCache > timeInCache) {
            return -1;
        }
        return 0;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + (int) (this.ttl ^ (this.ttl >>> 32));
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Metrics)) {
            return false;
        }
        return compareTo((Metrics) obj) == 0;
    }

    @Override
    public String toString() {
        return "TTL: " + this.ttl
                + " STpTiC: " + getSavedTimePerTimeInCache()
                + " Stales: " + this.stales
                + " Hits: " + this.hits
                + " SavedTime: " + this.savedTime
                + " TimeInCache: " + this.timeInCache;
    }

}