org.eclipse.mat.parser.internal.snapshot.ObjectCache Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2008 SAP AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.mat.parser.internal.snapshot;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.mat.collect.HashMapIntObject;
abstract public class ObjectCache {
static class Entry {
E object;
int key;
int numUsages;
}
private int maxSize;
private final HashMapIntObject> map;
private final List>> lfus;
private int maxLfuBuckets = 0;
private int lowestNonEmptyLfu = 0;
public ObjectCache(int maxSize) {
this.maxSize = maxSize;
this.map = new HashMapIntObject>(maxSize);
this.lfus = new ArrayList>>(5);
this.maxLfuBuckets = maxSize / 3;
}
public synchronized E get(int objectId) {
Entry e = map.get(objectId);
if (e != null) {
revalueEntry(e);
} else {
e = new Entry();
e.object = load(objectId);
e.key = objectId;
doInsert(e);
while (map.size() > maxSize)
removeLeastValuableNode();
}
return e.object;
}
public synchronized void clear() {
this.map.clear();
this.lfus.clear();
}
protected abstract E load(int key);
protected synchronized void doInsert(final Entry e) {
lfu(e.numUsages).addFirst(e);
Entry> p = map.put(e.key, e);
lowestNonEmptyLfu = 0;
if (p != null)
lfu(p.numUsages).remove(p);
}
protected final LinkedList> lfu(int numUsageIndex) {
int lfuIndex = Math.min(maxLfuBuckets, numUsageIndex);
if (lfuIndex >= lfus.size()) {
LinkedList> lfu = new LinkedList>();
lfus.add(lfuIndex, lfu);
return lfu;
} else {
return lfus.get(lfuIndex);
}
}
protected void revalueEntry(Entry entry) {
LinkedList> currBucket = lfu(entry.numUsages);
LinkedList> nextBucket = lfu(++entry.numUsages);
currBucket.remove(entry);
nextBucket.addFirst(entry);
}
protected LinkedList> getLowestNonEmptyLfu() {
LinkedList> lfu = null;
for (int i = lowestNonEmptyLfu; i < lfus.size(); i++) {
lfu = lfu(i);
if (lfu.size() != 0) {
lowestNonEmptyLfu = i;
return lfu;
}
}
return lfu;
}
protected void removeLeastValuableNode() {
LinkedList> lfu = getLowestNonEmptyLfu();
Entry> lln = lfu.remove(lfu.size() - 1);
map.remove(lln.key);
}
}