From 1287dbc981d8091ba8ff71a588afa1352624f375 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 28 Jun 2012 21:21:15 +0400 Subject: [PATCH] memory backed, limited recent strings interner for stubs --- .../psi/stubs/StubSerializationHelper.java | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java b/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java index b9097c322e03..ed2305ffa586 100644 --- a/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java +++ b/platform/core-api/src/com/intellij/psi/stubs/StubSerializationHelper.java @@ -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> myIdToSerializer = new TIntObjectHashMap>(); @@ -47,6 +48,7 @@ public class StubSerializationHelper { public StubSerializationHelper(AbstractStringEnumerator nameStorage) { myNameStorage = nameStorage; } + public void assignId(@NotNull final StubSerializer 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[] 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(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;