memory backed, limited recent strings interner for stubs

This commit is contained in:
Maxim.Mossienko
2012-06-28 21:24:39 +04:00
parent 0c9b3b4d4d
commit 1287dbc981
@@ -16,13 +16,15 @@
package com.intellij.psi.stubs;
import com.intellij.openapi.diagnostic.LogUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.LowMemoryWatcher;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.util.containers.SLRUCache;
import com.intellij.util.io.AbstractStringEnumerator;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.io.IOUtil;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TObjectIntHashMap;
import jsr166e.SequenceLock;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,13 +34,12 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
/**
* Author: dmitrylomov
*/
public class StubSerializationHelper {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubSerializationHelper");
private AbstractStringEnumerator myNameStorage;
protected final TIntObjectHashMap<StubSerializer<? extends StubElement>> myIdToSerializer = new TIntObjectHashMap<StubSerializer<? extends StubElement>>();
@@ -47,6 +48,7 @@ public class StubSerializationHelper {
public StubSerializationHelper(AbstractStringEnumerator nameStorage) {
myNameStorage = nameStorage;
}
public void assignId(@NotNull final StubSerializer<? extends StubElement> serializer) throws IOException {
final int id = persistentId(serializer);
final StubSerializer old = myIdToSerializer.put(id, serializer);
@@ -98,6 +100,58 @@ public class StubSerializationHelper {
return idValue;
}
private static class RecentStringInterner {
private final int myStripeMask;
private final SLRUCache<String, String>[] myInterns;
private final Lock[] myStripeLocks;
private final LowMemoryWatcher myClearingCallback;
private RecentStringInterner(int capacity) {
final int stripes = 16;
myInterns = new SLRUCache[stripes];
myStripeLocks = new Lock[myInterns.length];
for(int i = 0; i < myInterns.length; ++i) {
myInterns[i] = new SLRUCache<String, String>(capacity / stripes, capacity / stripes) {
@NotNull
@Override
public String createValue(String key) {
return key;
}
};
myStripeLocks[i] = new SequenceLock();
}
assert Integer.highestOneBit(stripes) == stripes;
myStripeMask = stripes - 1;
myClearingCallback = LowMemoryWatcher.register(new Runnable() {
@Override
public void run() {
clear();
};
});
}
String get(String s) {
final int stripe = Math.abs(s.hashCode()) & myStripeMask;
try {
myStripeLocks[stripe].lock();
return myInterns[stripe].get(s);
} finally {
myStripeLocks[stripe].unlock();
}
}
void clear() {
for(int i = 0; i < myInterns.length; ++i) {
myStripeLocks[i].lock();
myInterns[i].clear();
myStripeLocks[i].unlock();
}
}
}
private final RecentStringInterner myStringInterner = new RecentStringInterner(8192);
public StubElement deserialize(InputStream stream) throws IOException {
FileLocalStringEnumerator storage = new FileLocalStringEnumerator();
StubInputStream inputStream = new StubInputStream(stream, storage);
@@ -106,7 +160,7 @@ public class StubSerializationHelper {
int i = 1;
while(i <= size) {
String s = IOUtil.readUTFFast(buffer, inputStream);
String s = myStringInterner.get(IOUtil.readUTFFast(buffer, inputStream));
storage.myStrings.add(s);
storage.myEnumerates.put(s, i);
++i;