package com.sun.solaris.domain.pools;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
import com.sun.solaris.service.logging.*;
import com.sun.solaris.service.pools.*;
public final class DecisionHistory implements Serializable {
public static final int DECISION_LIFETIME = 256;
private HashMap decisions = new HashMap();
private transient HashMap resourcesAwaitingImprovement = new HashMap();
private transient LinkedList decisionList = new LinkedList();
public DecisionHistory()
{
}
public void recordProcessorMove(ComponentMove move,
double startingUtilization, int sampleCount) throws PoolsException
{
Decision decision = Decision.forMove(move, startingUtilization);
decision.setStartingSampleCount(sampleCount);
Object o = decisions.put(decision.getKey(), decision);
Poold.OPT_LOG.log(Severity.DEBUG, "recorded decision (" +
decision + ")" + (o == null ? "" : " (displaced " + o +
")"));
resourcesAwaitingImprovement.put(move.getTo(),
decision.getKey());
decisionList.add(decision);
}
private void recordImprovementWithUtilization(Resource resource,
double utilization)
{
String decisionKey = (String)resourcesAwaitingImprovement.get(
resource);
if (decisionKey != null) {
Decision decision = (Decision)decisions.get(
decisionKey);
if (decision != null) {
decision.setImprovementWithNewUtilization(
utilization);
Poold.OPT_LOG.log(Severity.DEBUG, resource +
" improvement measured for decision " +
decision.describe());
}
}
}
private static abstract class Decision implements Serializable {
private double startingUtilization = 0.0;
private double improvement = 0.0;
private int usage = 0;
private int startingSampleCount;
private Date date;
public abstract String getKey();
public static final Decision forMove(Move move,
double startingUtilization)
{
if (move instanceof ComponentMove)
return (new ComponentMoveDecision(
(ComponentMove)move, startingUtilization));
else
return (null);
}
private Decision()
{
date = new Date();
}
public final void setStartingUtilization(
double startingUtilization)
{
this.startingUtilization = startingUtilization;
}
public void setStartingSampleCount(int sampleCount)
{
this.startingSampleCount = sampleCount;
}
public int getStartingSampleCount()
{
return (startingSampleCount);
}
abstract public void setImprovementWithNewUtilization(
double newUtilization);
protected void setImprovement(double improvement)
{
this.improvement = improvement;
}
public final double getImprovement()
{
return (improvement);
}
public final double getStartingUtilization()
{
return (startingUtilization);
}
public abstract int hashCode();
public abstract boolean equals(Object o);
public abstract String toString();
private static final long serialVersionUID = 0x7860687;
public final int getUsage()
{
return (usage);
}
private final void incrementUsage()
{
usage++;
}
public final Date getDate()
{
return date;
}
private static SimpleDateFormat dateFormatter;
private final static String dateFormat = "MMM d kk:mm:ss";
public final String describe()
{
if (dateFormatter == null)
dateFormatter = new SimpleDateFormat(
dateFormat);
return (toString() + " made at " +
dateFormatter.format(getDate()) +
" with improvement " + getImprovement() +
" used " + getUsage() + " times");
}
}
private static final class ComponentMoveDecision extends Decision {
private String cpuid;
private String fromPsetName;
private String toPsetName;
private String fromPsetComposition;
private String toPsetComposition;
private int toPsetSize;
private String utilizationClass;
public ComponentMoveDecision(ComponentMove move,
double startingUtilization) throws IllegalArgumentException
{
try {
cpuid = move.getComponents().toString();
fromPsetName = move.getFrom().toString();
toPsetName = move.getTo().toString();
fromPsetComposition = move.getFrom()
.getComponents(null).toString();
toPsetComposition = move.getTo()
.getComponents(null).toString();
toPsetSize = move.getTo().getComponents(null)
.size();
utilizationClass = computeUtilizationClass(
startingUtilization);
setStartingUtilization(startingUtilization);
} catch (PoolsException pe) {
throw(IllegalArgumentException)(
new IllegalArgumentException().initCause(
pe));
}
}
public String getKey()
{
StringBuffer sb = new StringBuffer();
sb.append(cpuid);
sb.append(", ");
sb.append(fromPsetName);
sb.append(", ");
sb.append(toPsetName);
return (sb.toString());
}
public void setImprovementWithNewUtilization(
double newUtilization)
{
double sizeRatio = (double)(toPsetSize - 1) /
toPsetSize;
double expectedUtilization = sizeRatio *
getStartingUtilization();
Poold.OPT_LOG.log(Severity.DEBUG,
"pset improvement calculation expected " +
expectedUtilization + ", got " + newUtilization);
setImprovement(newUtilization - expectedUtilization);
}
public int hashCode() {
return (((((cpuid.hashCode() ^
fromPsetName.hashCode()) ^ toPsetName.hashCode()) ^
fromPsetComposition.hashCode()) ^
toPsetComposition.hashCode()) ^
utilizationClass.hashCode());
}
public boolean equals(Object o) {
if (!(o instanceof ComponentMoveDecision))
return false;
else {
ComponentMoveDecision cmd =
(ComponentMoveDecision)o;
return (cpuid.equals(cmd.cpuid) &&
fromPsetName.equals(cmd.fromPsetName) &&
toPsetName.equals(cmd.toPsetName) &&
fromPsetComposition.equals(
cmd.fromPsetComposition) &&
toPsetComposition.equals(
cmd.toPsetComposition) &&
utilizationClass.equals(
cmd.utilizationClass));
}
}
private String computeUtilizationClass(
double startingUtilization)
{
return "I";
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(cpuid.toString());
sb.append(", ");
sb.append(fromPsetName.toString());
sb.append(", ");
sb.append(toPsetName.toString());
sb.append(", ");
sb.append(fromPsetComposition.toString());
sb.append(", ");
sb.append(toPsetComposition.toString());
sb.append(", ");
sb.append(utilizationClass.toString());
return (sb.toString());
}
private static final long serialVersionUID = 0xf7860687;
}
public boolean veto(Move m, double utilization)
{
Decision current = Decision.forMove(m, utilization);
Decision past;
if (current != null) {
past = (Decision)decisions.get(current.getKey());
if (past != null)
past.incrementUsage();
if (past != null && past.getImprovement() < 0.0) {
Poold.OPT_LOG.log(Severity.DEBUG, m +
" vetoed by decision " + past.describe());
return true;
}
}
return false;
}
private static final long serialVersionUID = 0xf7860687;
public static DecisionHistory loadFromFile(String path)
throws IOException, ClassNotFoundException
{
return (load(new FileInputStream(path)));
}
public void syncToFile(String path) throws IOException
{
FileOutputStream fos = new FileOutputStream(path);
sync(fos);
fos.close();
}
public static DecisionHistory load(InputStream is)
throws IOException, ClassNotFoundException
{
ObjectInputStream ois = new ObjectInputStream(is);
DecisionHistory dh = (DecisionHistory)ois.readObject();
return (dh);
}
public void sync(OutputStream os) throws IOException
{
new ObjectOutputStream(os).writeObject(this);
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(decisions.keySet().size() + " decisions {");
Iterator it = decisions.keySet().iterator();
while (it.hasNext()) {
String dk = (String)it.next();
Decision d = (Decision)decisions.get(dk);
sb.append("\t(");
sb.append(d.describe());
sb.append(")\n");
}
sb.append("}");
return (sb.toString());
}
public void expireAndMeasureImprovements(Monitor mon)
{
if (mon.isValid()) {
for (Iterator it = resourcesAwaitingImprovement.
keySet().iterator(); it.hasNext(); ) {
Resource res = (Resource)it.next();
try {
double utilization = mon.
getUtilization(res);
recordImprovementWithUtilization(res,
utilization);
} catch (StaleMonitorException sme) {
String decisionKey = (String)
resourcesAwaitingImprovement.
get(res);
if (decisionKey != null)
decisions.remove(decisionKey);
}
it.remove();
}
}
int cutoff = mon.getSampleCount() - DECISION_LIFETIME;
if (cutoff > 0) {
Decision decision;
ListIterator it = decisionList.listIterator(0);
while (it.hasNext()) {
decision = (Decision)it.next();
int sc = decision.getStartingSampleCount();
if (sc < cutoff) {
if (sc > 0) {
Poold.OPT_LOG.log(
Severity.DEBUG,
"expiring decision (" +
decision + ")");
it.remove();
decisions.remove(
decision.getKey());
}
} else
break;
}
}
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
resourcesAwaitingImprovement = new HashMap();
decisionList = new LinkedList();
for (Iterator it = decisions.keySet().iterator();
it.hasNext(); ) {
String decisionKey = (String)it.next();
Decision decision = (Decision)decisions.get(
decisionKey);
decision.setStartingSampleCount(0);
decisionList.add(decision);
}
}
}