org.apache.flink.runtime.state.gemini.engine.vm.HitRecord Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.flink.runtime.state.gemini.engine.vm;
import org.apache.flink.annotation.VisibleForTesting;
import java.util.Arrays;
/**
* record page's request num.
* No Thread safe.
*/
public class HitRecord {
private long currentAgeTimeTick;
//age1,age2,age3,currentAge
//TODO change to short to reduce memory
private int[] ages;
private byte currentAgeCusor;
public HitRecord() {
//now hard code
ages = new int[4];
for (int i = 0; i < ages.length; i++) {
//-1 is to examine whether to start just in a short time.
ages[i] = -1;
}
currentAgeCusor = 3;
currentAgeTimeTick = -1;
}
/**
* the bigger size and less chain index will get lower score, which means the page is more probable to be evicted.
*/
public float score(long curAgeTimeTick, int size, int chainIndex) {
//align the ages
if (currentAgeTimeTick < curAgeTimeTick) {
addRequestCount(curAgeTimeTick, 0);
}
//last 3 ages count
byte ageCusor = prevCusor(currentAgeCusor);
int a3 = ages[ageCusor];
ageCusor = prevCusor(ageCusor);
int a2 = ages[ageCusor];
ageCusor = prevCusor(ageCusor);
int a1 = ages[ageCusor];
if (a1 == -1 && a2 == -1 && a3 == -1) {
return (Float.MAX_VALUE / size) * (1 + chainIndex);
} else if (a1 == -1 && a2 == -1) {
return (((float) a3 * 100) / size) * (1 + chainIndex);
} else if (a1 == -1) {
return (((float) (a3 * 60 + a2 * 40)) / size) * (1 + chainIndex);
}
return (((float) (a3 * 50 + a2 * 30 + a1 * 20)) / size) * (1 + chainIndex);
}
public void addRequestCount(long curAgeTimeTick, int requestCount) {
if (this.currentAgeTimeTick == -1) {
//starting
currentAgeTimeTick = curAgeTimeTick;
ages[currentAgeCusor] = requestCount;
} else if (this.currentAgeTimeTick == curAgeTimeTick) {
//current Age
ages[currentAgeCusor] += requestCount;
} else if (curAgeTimeTick <= this.currentAgeTimeTick + (ages.length - 1)) {
//Next Age or pass less ages
while (this.currentAgeTimeTick < curAgeTimeTick - 1) {
currentAgeCusor = nextCusor(currentAgeCusor);
ages[currentAgeCusor] = 0;
this.currentAgeTimeTick++;
}
this.currentAgeTimeTick = curAgeTimeTick;
currentAgeCusor = nextCusor(currentAgeCusor);
ages[currentAgeCusor] = requestCount;
} else {
//pass too much Ages
for (int i = 0; i < ages.length - 1; i++) {
ages[i] = 0;
}
this.currentAgeTimeTick = curAgeTimeTick;
currentAgeCusor = (byte) (ages.length - 1);
ages[currentAgeCusor] = requestCount;
}
}
@VisibleForTesting
public byte nextCusor(byte currentAgeCusor) {
return currentAgeCusor + 1 == ages.length ? (byte) 0 : (byte) (currentAgeCusor + 1);
}
@VisibleForTesting
public byte prevCusor(byte currentAgeCusor) {
return currentAgeCusor == 0 ? (byte) (ages.length - 1) : (byte) (currentAgeCusor - 1);
}
public long getRequestCount(long curAgeTimeTick) {
//align the ages
if (currentAgeTimeTick < curAgeTimeTick) {
addRequestCount(curAgeTimeTick, 0);
}
return Arrays.stream(ages).filter(value -> value != -1).sum();
}
@VisibleForTesting
public long getCurrentAgeTimeTick() {
return currentAgeTimeTick;
}
@VisibleForTesting
public byte getCurrentAgeCusor() {
return currentAgeCusor;
}
@VisibleForTesting
public int[] getAges() {
return ages;
}
}