mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 14:42: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:
parent
8286a3e2d4
commit
3a57ea79ab
3 changed files with 80 additions and 5 deletions
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ public class ShortString implements IString {
|
|||
private final Database db;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue