Browse Source

Remove SoftReference from dfs.DeltaBaseCache

The Java GC doesn't always clear these before running out of memory
and failing allocations. In practice OpenJDK 7 is leaving these live,
removing any advantage of the SoftReference to attempt to shed memory
when the GC is unable to continue allocating.

Instead follow the pattern of the DfsBlockCache and use hard refs
to the object data. Require applications to configure the cache
size more accurately given expected memory usage.

Change-Id: I87586b3e71b1cba0308a6a278d42e971be4bccd3
stable-4.1
Shawn Pearce 10 years ago
parent
commit
2eb16aa6ca
  1. 85
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java

85
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java

@ -43,7 +43,6 @@
package org.eclipse.jgit.internal.storage.dfs; package org.eclipse.jgit.internal.storage.dfs;
import java.lang.ref.SoftReference;
/** /**
* Caches recently used objects for {@link DfsReader}. * Caches recently used objects for {@link DfsReader}.
@ -60,14 +59,12 @@ final class DeltaBaseCache {
} }
private int maxByteCount; private int maxByteCount;
private int curByteCount;
private final Slot[] table; private final Entry[] table;
private Slot lruHead;
private Slot lruTail; private Entry lruHead;
private Entry lruTail;
private int curByteCount;
DeltaBaseCache(DfsReader reader) { DeltaBaseCache(DfsReader reader) {
this(reader.getOptions().getDeltaBaseCacheLimit()); this(reader.getOptions().getDeltaBaseCacheLimit());
@ -75,19 +72,15 @@ final class DeltaBaseCache {
DeltaBaseCache(int maxBytes) { DeltaBaseCache(int maxBytes) {
maxByteCount = maxBytes; maxByteCount = maxBytes;
table = new Slot[1 << TABLE_BITS]; table = new Entry[1 << TABLE_BITS];
} }
Entry get(DfsPackKey key, long position) { Entry get(DfsPackKey key, long position) {
Slot e = table[hash(position)]; Entry e = table[hash(position)];
for (; e != null; e = e.tableNext) { for (; e != null; e = e.tableNext) {
if (e.offset == position && key.equals(e.pack)) { if (e.offset == position && key.equals(e.pack)) {
Entry buf = e.data.get(); moveToHead(e);
if (buf != null) { return e;
moveToHead(e);
return buf;
}
return null;
} }
} }
return null; return null;
@ -101,8 +94,7 @@ final class DeltaBaseCache {
releaseMemory(); releaseMemory();
int tableIdx = hash(offset); int tableIdx = hash(offset);
Slot e = new Slot(key, offset, data.length); Entry e = new Entry(key, offset, objectType, data);
e.data = new SoftReference<Entry>(new Entry(data, objectType));
e.tableNext = table[tableIdx]; e.tableNext = table[tableIdx];
table[tableIdx] = e; table[tableIdx] = e;
lruPushHead(e); lruPushHead(e);
@ -110,16 +102,16 @@ final class DeltaBaseCache {
private void releaseMemory() { private void releaseMemory() {
while (curByteCount > maxByteCount && lruTail != null) { while (curByteCount > maxByteCount && lruTail != null) {
Slot e = lruTail; Entry e = lruTail;
curByteCount -= e.size; curByteCount -= e.data.length;
lruRemove(e); lruRemove(e);
removeFromTable(e); removeFromTable(e);
} }
} }
private void removeFromTable(Slot e) { private void removeFromTable(Entry e) {
int tableIdx = hash(e.offset); int tableIdx = hash(e.offset);
Slot p = table[tableIdx]; Entry p = table[tableIdx];
if (p == e) { if (p == e) {
table[tableIdx] = e.tableNext; table[tableIdx] = e.tableNext;
@ -138,16 +130,16 @@ final class DeltaBaseCache {
e.pack, Long.valueOf(e.offset))); e.pack, Long.valueOf(e.offset)));
} }
private void moveToHead(final Slot e) { private void moveToHead(Entry e) {
if (e != lruHead) { if (e != lruHead) {
lruRemove(e); lruRemove(e);
lruPushHead(e); lruPushHead(e);
} }
} }
private void lruRemove(final Slot e) { private void lruRemove(Entry e) {
Slot p = e.lruPrev; Entry p = e.lruPrev;
Slot n = e.lruNext; Entry n = e.lruNext;
if (p != null) { if (p != null) {
p.lruNext = n; p.lruNext = n;
@ -162,8 +154,8 @@ final class DeltaBaseCache {
} }
} }
private void lruPushHead(final Slot e) { private void lruPushHead(Entry e) {
Slot n = lruHead; Entry n = lruHead;
e.lruNext = n; e.lruNext = n;
if (n != null) if (n != null)
n.lruPrev = e; n.lruPrev = e;
@ -180,8 +172,8 @@ final class DeltaBaseCache {
int getMemoryUsedByLruChainForTest() { int getMemoryUsedByLruChainForTest() {
int r = 0; int r = 0;
for (Slot e = lruHead; e != null; e = e.lruNext) { for (Entry e = lruHead; e != null; e = e.lruNext) {
r += e.size; r += e.data.length;
} }
return r; return r;
} }
@ -189,43 +181,28 @@ final class DeltaBaseCache {
int getMemoryUsedByTableForTest() { int getMemoryUsedByTableForTest() {
int r = 0; int r = 0;
for (int i = 0; i < table.length; i++) { for (int i = 0; i < table.length; i++) {
for (Slot e = table[i]; e != null; e = e.tableNext) { for (Entry e = table[i]; e != null; e = e.tableNext) {
r += e.size; r += e.data.length;
} }
} }
return r; return r;
} }
static class Entry { static class Entry {
final byte[] data;
final int type;
Entry(final byte[] aData, final int aType) {
data = aData;
type = aType;
}
}
private static class Slot {
final DfsPackKey pack; final DfsPackKey pack;
final long offset; final long offset;
final int type;
final byte[] data;
final int size; Entry tableNext;
Entry lruPrev;
Slot tableNext; Entry lruNext;
Slot lruPrev;
Slot lruNext;
SoftReference<Entry> data;
Slot(DfsPackKey key, long offset, int size) { Entry(DfsPackKey key, long offset, int type, byte[] data) {
this.pack = key; this.pack = key;
this.offset = offset; this.offset = offset;
this.size = size; this.type = type;
this.data = data;
} }
} }
} }

Loading…
Cancel
Save