package diskCacheV111.pools;
import javax.annotation.Nonnull;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.dcache.pool.assumption.Assumption;
import static com.google.common.base.Preconditions.checkNotNull;
public class PoolCostInfo implements Serializable
{
private static final long serialVersionUID = 5181562551679185500L;
private PoolQueueInfo _store;
private PoolQueueInfo _restore;
private PoolQueueInfo _p2p;
private PoolQueueInfo _p2pClient;
private final Map<String, NamedPoolQueueInfo> _extendedMoverHash;
private final String _defaultQueueName;
private PoolSpaceInfo _space;
private final String _poolName;
private double _moverCostFactor;
public PoolCostInfo(String poolName, String defaultQueue)
{
_poolName = poolName;
_defaultQueueName = checkNotNull(defaultQueue);
_space = new PoolSpaceInfo(0, 0, 0, 0);
_extendedMoverHash = new HashMap<>();
}
public PoolCostInfo(String defaultQueue, Assumption.Pool info)
{
_poolName = info.name();
_defaultQueueName = checkNotNull(defaultQueue);
_space = info.space();
_extendedMoverHash = info.movers().stream().collect(Collectors.toMap(q -> q.getName(), q -> q));
_p2pClient = info.p2PClient();
_p2p = info.p2pServer();
_restore = info.restore();
_store = info.store();
_moverCostFactor = info.moverCostFactor();
}
public String getPoolName()
{
return _poolName;
}
public static class NamedPoolQueueInfo extends PoolQueueInfo
{
private static final long serialVersionUID = -7097362707394583875L;
private final String _name;
public NamedPoolQueueInfo(String name,
int active, int maxActive, int queued,
int readers, int writers)
{
super(active, maxActive, queued, readers, writers);
_name = name;
}
public String getName()
{
return _name;
}
@Override
public String toString()
{
return _name + "={" + super.toString() + '}';
}
}
public static class PoolQueueInfo implements Serializable
{
private static final long serialVersionUID = 1304697767284208011L;
private int _active;
private final int _maxActive;
private int _queued;
private final int _readers;
private final int _writers;
public PoolQueueInfo(int active, int maxActive, int queued, int readers, int writers)
{
_active = active;
_maxActive = maxActive;
_queued = queued;
_readers = readers;
_writers = writers;
}
@Override
public String toString()
{
return "a=" + _active + ";m=" + _maxActive + ";q=" + _queued + ";r=" + _readers + ";w=" + _writers;
}
public int getActive()
{
return _active;
}
public int getMaxActive()
{
return _maxActive;
}
public int getQueued()
{
return _queued;
}
public int getReaders()
{
return _readers;
}
public int getWriters()
{
return _writers;
}
public void modifyQueue(int diff)
{
int total = Math.max(0, _active + _queued + diff);
_active = Math.min(total, _maxActive);
_queued = Math.max(0, total - _maxActive);
}
}
public PoolQueueInfo getStoreQueue()
{
return _store;
}
public PoolQueueInfo getRestoreQueue()
{
return _restore;
}
public PoolQueueInfo getP2pQueue()
{
return _p2p;
}
public PoolQueueInfo getP2pClientQueue()
{
return _p2pClient;
}
public PoolQueueInfo getMoverQueue()
{
int moverActive = 0, moverMaxActive = 0, queued = 0, readers = 0, writers = 0;
for (NamedPoolQueueInfo queue : _extendedMoverHash.values()) {
moverActive += queue.getActive();
moverMaxActive += queue.getMaxActive();
queued += queue.getQueued();
readers += queue.getReaders();
writers += queue.getWriters();
}
return new PoolQueueInfo(moverActive, moverMaxActive, queued, readers, writers);
}
public PoolSpaceInfo getSpaceInfo()
{
return _space;
}
public static class PoolSpaceInfo implements Serializable
{
private static final long serialVersionUID = -8966065301943351970L;
private final long _total;
private long _free;
private final long _precious;
private final long _removable;
private final long _lru;
private long _gap;
private double _breakEven;
public PoolSpaceInfo(long total, long free, long precious, long removable)
{
this(total, free, precious, removable, 0);
}
public PoolSpaceInfo(long total, long free, long precious, long removable, long lru)
{
if (total < free) {
throw new IllegalArgumentException("total >= free");
}
if (total < precious) {
throw new IllegalArgumentException("total >= precious");
}
if (total < removable) {
throw new IllegalArgumentException("total >= removable");
}
_total = total;
_free = free;
_precious = precious;
_removable = removable;
_lru = lru;
}
public PoolSpaceInfo(long totalSpace, long freeSpace, long preciousSpace, long removableSpace, long lru,
double breakEven, long gap)
{
this(totalSpace, freeSpace, preciousSpace, removableSpace, lru);
_breakEven = breakEven;
_gap = gap;
}
public void setParameter(double breakEven, long gap)
{
_breakEven = breakEven;
_gap = gap;
}
@Override
public String toString()
{
return "t=" + _total +
";f=" + _free +
";p=" + _precious +
";r=" + _removable +
";lru=" + _lru +
";{g=" + _gap + ";b=" + _breakEven + '}';
}
public long getFreeSpace()
{
return _free;
}
public long getTotalSpace()
{
return _total;
}
public long getPreciousSpace()
{
return _precious;
}
public long getRemovableSpace()
{
return _removable;
}
public long getUsedSpace()
{
return _total - _free;
}
public long getGap()
{
return _gap;
}
public double getBreakEven()
{
return _breakEven;
}
public long getLRUSeconds()
{
return _lru;
}
public void modifyPinnedSpace(long diff)
{
_free = Math.max(0, Math.min(_free - diff, _total - _removable - _precious));
}
}
//
/// the setters
//
public void setSpaceUsage(long total, long free, long precious, long removable)
{
_space = new PoolSpaceInfo(total, free, precious, removable);
}
public void setSpaceUsage(long total, long free, long precious, long removable, long lru)
{
_space = new PoolSpaceInfo(total, free, precious, removable, lru);
}
public void
setQueueSizes(int restoreActive, int restoreMaxActive, int restoreQueued,
int storeActive, int storeMaxActive, int storeQueued)
{
_restore = new PoolQueueInfo(restoreActive, restoreMaxActive,
restoreQueued, 0,
restoreActive + restoreQueued);
_store = new PoolQueueInfo(storeActive, storeMaxActive, storeQueued,
storeActive + storeQueued, 0);
}
public void addExtendedMoverQueueSizes(String name, int moverActive,
int moverMaxActive, int moverQueued,
int moverReaders, int moverWriters)
{
NamedPoolQueueInfo info =
new NamedPoolQueueInfo(name, moverActive, moverMaxActive,
moverQueued, moverReaders, moverWriters);
_extendedMoverHash.put(name, info);
}
@Nonnull
public Map<String, NamedPoolQueueInfo> getExtendedMoverHash()
{
return _extendedMoverHash;
}
@Nonnull
public String getDefaultQueueName()
{
return _defaultQueueName;
}
public void setP2pServerQueueSizes(int p2pActive, int p2pMaxActive, int p2pQueued)
{
_p2p = new PoolQueueInfo(p2pActive, p2pMaxActive, p2pQueued,
p2pActive + p2pQueued, 0);
}
public void setP2pClientQueueSizes(int p2pClientActive, int p2pClientMaxActive, int p2pClientQueued)
{
_p2pClient = new PoolQueueInfo(p2pClientActive, p2pClientMaxActive,
p2pClientQueued, 0,
p2pClientActive + p2pClientQueued);
}
public void setMoverCostFactor(double moverCostFactor)
{
_moverCostFactor = moverCostFactor;
}
public double getMoverCostFactor()
{
return _moverCostFactor;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(_poolName).append("={");
if (_restore != null) {
sb.append("R={").append(_restore).append("};");
}
if (_store != null) {
sb.append("S={").append(_store).append("};");
}
if (_p2p != null) {
sb.append("PS={").append(_p2p).append("};");
}
if (_p2pClient != null) {
sb.append("PC={").append(_p2pClient).append("};");
}
sb.append("SP={").append(_space.toString()).append("};");
sb.append("XM={");
for (PoolQueueInfo namedPoolQueueInfo : _extendedMoverHash.values()) {
sb.append(namedPoolQueueInfo.toString()).append(';');
}
sb.append("};");
sb.append('}');
return sb.toString();
}
public double getPerformanceCost()
{
return getPerformanceCost(_store, _extendedMoverHash.values());
}
public static double getPerformanceCost(PoolQueueInfo storeQueue, Collection<NamedPoolQueueInfo> moverQueues)
{
double cost = 0.0;
double div = 0.0;
if (storeQueue != null) {
if (storeQueue.getQueued() > 0) {
cost += 1.0;
} else {
cost += (1.0 - Math.pow(0.75, storeQueue.getActive()));
}
div += 1.0;
}
for (PoolCostInfo.NamedPoolQueueInfo queue : moverQueues) {
if (queue.getMaxActive() > 0) {
cost += ((double) queue.getQueued() +
(double) queue.getActive()) /
(double) queue.getMaxActive();
} else if (queue.getQueued() > 0) {
cost += 1.0;
}
div += 1.0;
}
return div > 0.0 ? cost / div : 1000000.0;
}
}