/*
* Copyright 2016 Ben Manes. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.benmanes.caffeine.cache.simulator.policy.sketch.climbing;
import static com.github.benmanes.caffeine.cache.simulator.policy.sketch.climbing.HillClimber.Adaptation.Type.DECREASE_WINDOW;
import static com.github.benmanes.caffeine.cache.simulator.policy.sketch.climbing.HillClimber.Adaptation.Type.INCREASE_WINDOW;
import com.github.benmanes.caffeine.cache.simulator.BasicSettings;
import com.typesafe.config.Config;
/**
* A naive, simple hill climber.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
final class SimpleClimber implements HillClimber {
private final int pivot;
private int sample;
private final int sampleSize;
private int hitsInSample;
private int missesInSample;
private double previousHitRate;
private final double tolerance;
private boolean increaseWindow;
public SimpleClimber(Config config) {
SimpleClimberSettings settings = new SimpleClimberSettings(config);
this.sampleSize = (int) (settings.percentSample() * settings.maximumSize());
this.pivot = (int) (settings.percentPivot() * settings.maximumSize());
this.tolerance = 100d * settings.tolerance();
}
@Override
public void onMiss(long key) {
missesInSample++;
sample++;
}
@Override
public void onHit(long key, QueueType queueType) {
hitsInSample++;
sample++;
}
@Override
public Adaptation adapt(int windowSize, int protectedSize) {
Adaptation adaption = Adaptation.HOLD;
if (sample >= sampleSize) {
double hitRate = (100d * hitsInSample) / (hitsInSample + missesInSample);
if (!Double.isNaN(hitRate) && !Double.isInfinite(hitRate) && (previousHitRate != 0.0)) {
adaption = adjust(hitRate);
}
previousHitRate = hitRate;
missesInSample = 0;
hitsInSample = 0;
sample = 0;
}
return adaption;
}
private Adaptation adjust(double hitRate) {
if (hitRate < (previousHitRate + tolerance)) {
increaseWindow = !increaseWindow;
}
Adaptation.Type adaptionType = increaseWindow ? INCREASE_WINDOW : DECREASE_WINDOW;
return new Adaptation(adaptionType, pivot);
}
static final class SimpleClimberSettings extends BasicSettings {
static final String BASE_PATH = "hill-climber-window-tiny-lfu.simple.";
public SimpleClimberSettings(Config config) {
super(config);
}
public double percentPivot() {
return config().getDouble(BASE_PATH + "percent-pivot");
}
public double percentSample() {
return config().getDouble(BASE_PATH + "percent-sample");
}
public double tolerance() {
return config().getInt(BASE_PATH + "tolerance");
}
}
}