1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Bug 514708 - Performance improvement indexer by caching Strings.

Change-Id: If07961701bd568f674918c484cad16699bfa1cdf
Signed-off-by: Patrick Koenemann <patrick.koenemann@itemis.de>
This commit is contained in:
Patrick Koenemann 2017-04-05 11:19:53 +02:00 committed by Nathan Ridge
parent 8286a3e2d4
commit 3a57ea79ab
3 changed files with 80 additions and 5 deletions

View file

@ -18,11 +18,16 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.core.runtime.CoreException;
@ -110,6 +115,22 @@ public class Database {
private long cacheHits;
private long cacheMisses;
/** Soft reference wrapper to keep track of the record for disposed strings. */
private static class SoftStringRef extends SoftReference<IString> {
private final long record;
public SoftStringRef(IString referent, ReferenceQueue<? super IString> q) {
super(referent, q);
record = referent.getRecord();
}
public long getRecord() {
return record;
}
}
// a cache for strings which is used for btree lookups; soft refs ensure garbage collection
private final Map<Long, Reference<IString>> stringCache = new HashMap<>();
private final ReferenceQueue<IString> stringDisposal = new ReferenceQueue<>();
/**
* Construct a new Database object, creating a backing file if necessary.
* @param location the local file path for the database
@ -243,6 +264,8 @@ public class Database {
createNewChunks((int) setasideChunks);
flush();
}
// clear cache for strings which are used for btree searches
clearStringCache();
}
private void removeChunksFromCache() {
@ -463,6 +486,7 @@ public class Database {
}
addBlock(chunk, blocksize, block);
freed += blocksize;
stringCache.remove(offset); // also remove record from string cache (if it exists)
}
public void putByte(long offset, byte value) throws CoreException {
@ -564,9 +588,9 @@ public class Database {
}
if (bytelen > ShortString.MAX_BYTE_LENGTH) {
return new LongString(this, chars, useBytes);
return addStringToCache(new LongString(this, chars, useBytes));
} else {
return new ShortString(this, chars, useBytes);
return addStringToCache(new ShortString(this, chars, useBytes));
}
}
@ -579,12 +603,33 @@ public class Database {
}
public IString getString(long offset) throws CoreException {
final Reference<IString> cachedStringReference = stringCache.get(offset);
if (cachedStringReference != null) {
final IString cachedString = cachedStringReference.get();
if (cachedString != null) {
return cachedString; // string already cached, no need to re-retrieve it :-)
}
}
final int l = getInt(offset);
int bytelen= l < 0 ? -l : 2 * l;
if (bytelen > ShortString.MAX_BYTE_LENGTH) {
return new LongString(this, offset);
return addStringToCache(new LongString(this, offset));
}
return new ShortString(this, offset);
return addStringToCache(new ShortString(this, offset));
}
private IString addStringToCache(IString string) {
// add string to cache
stringCache.put(string.getRecord(), new SoftStringRef(string, stringDisposal));
// also remove keys from cache list upon garbage collection
if (stringDisposal != null) {
Reference<? extends IString> disposedRef = stringDisposal.poll();
while (disposedRef instanceof SoftStringRef) {
stringCache.remove(((SoftStringRef) disposedRef).getRecord());
disposedRef = stringDisposal.poll();
}
}
return string;
}
/**
@ -629,6 +674,7 @@ public class Database {
} catch (IOException e) {
throw new CoreException(new DBStatus(e));
}
clearStringCache();
}
/**
@ -731,6 +777,15 @@ public class Database {
// Also handles header chunk.
flushAndUnlockChunks(dirtyChunks, true);
// And clear string cache
clearStringCache();
}
private void clearStringCache() {
stringCache.clear();
while (stringDisposal.poll() != null) {
}
}
private void flushAndUnlockChunks(final ArrayList<Chunk> dirtyChunks, boolean isComplete) throws CoreException {

View file

@ -27,6 +27,9 @@ public class LongString implements IString {
private final long record;
private int hash;
// this string is immutable, so we can cache the actual char array
private char[] cachedChars;
// Additional fields of first record.
private static final int LENGTH = 0; // Must be first to match ShortString.
private static final int NEXT1 = 4;
@ -89,6 +92,9 @@ public class LongString implements IString {
} else {
chunk.putChars(nextRecord + CHARSN, chars, start, remaining);
}
// There is currently no need to store char[] in cachedChars because all
// callers are currently only interested in the record.
}
@Override
@ -98,6 +104,9 @@ public class LongString implements IString {
@Override
public char[] getChars() throws CoreException {
if (cachedChars != null) {
return cachedChars; // no need to re-retrieve array if it is already cached
}
int length = db.getInt(record + LENGTH);
final boolean useBytes = length < 0;
int numChars1 = NUM_CHARS1;
@ -135,6 +144,7 @@ public class LongString implements IString {
start += partLen;
p= p + NEXTN;
}
cachedChars = chars; // cache the array
return chars;
}

View file

@ -26,6 +26,9 @@ public class ShortString implements IString {
private final long record;
private int hash;
// this string is immutable, so we can cache the actual char array
private char[] cachedChars;
private static final int LENGTH = 0;
private static final int CHARS = 4;
@ -49,6 +52,9 @@ public class ShortString implements IString {
} else {
chunk.putChars(p, chars, 0, n);
}
// There is currently no need to store char[] in cachedChars because all
// callers are currently only interested in the record.
}
@Override
@ -63,6 +69,9 @@ public class ShortString implements IString {
@Override
public char[] getChars() throws CoreException {
if (cachedChars != null) {
return cachedChars; // no need to re-retrieve array if it is already cached
}
final Chunk chunk = db.getChunk(record);
final int l = chunk.getInt(record + LENGTH);
final int length = Math.abs(l);
@ -72,6 +81,7 @@ public class ShortString implements IString {
} else {
chunk.getChars(record + CHARS, chars, 0, length);
}
cachedChars = chars; // cache the array
return chars;
}