Browse Source

Strongly reference indices in DfsPackFile

DfsBlockCache.Ref might get cleared out if the JVM is running out of
memory. As a result, the index is not persisted for the request and
will be reloaded unnecessarily.

Change-Id: I3b57ad5e6673f77f2dc66177a649ac412a97fe20
Signed-off-by: Minh Thai <mthai@google.com>
stable-5.4
Minh Thai 6 years ago
parent
commit
01f084f5d9
  1. 241
      org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java

241
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java

@ -98,13 +98,13 @@ public final class DfsPackFile extends BlockBasedFile {
private final Object initLock = new Object(); private final Object initLock = new Object();
/** Index mapping {@link ObjectId} to position within the pack stream. */ /** Index mapping {@link ObjectId} to position within the pack stream. */
private volatile DfsBlockCache.Ref<PackIndex> index; private volatile PackIndex index;
/** Reverse version of {@link #index} mapping position to {@link ObjectId}. */ /** Reverse version of {@link #index} mapping position to {@link ObjectId}. */
private volatile DfsBlockCache.Ref<PackReverseIndex> reverseIndex; private volatile PackReverseIndex reverseIndex;
/** Index of compressed bitmap mapping entire object graph. */ /** Index of compressed bitmap mapping entire object graph. */
private volatile DfsBlockCache.Ref<PackBitmapIndex> bitmapIndex; private volatile PackBitmapIndex bitmapIndex;
/** /**
* Objects we have tried to read, and discovered to be corrupt. * Objects we have tried to read, and discovered to be corrupt.
@ -150,15 +150,15 @@ public final class DfsPackFile extends BlockBasedFile {
* @return whether the pack index file is loaded and cached in memory. * @return whether the pack index file is loaded and cached in memory.
*/ */
public boolean isIndexLoaded() { public boolean isIndexLoaded() {
DfsBlockCache.Ref<PackIndex> idxref = index; return index != null;
return idxref != null && idxref.has();
} }
void setPackIndex(PackIndex idx) { void setPackIndex(PackIndex idx) {
long objCnt = idx.getObjectCount(); long objCnt = idx.getObjectCount();
int recSize = Constants.OBJECT_ID_LENGTH + 8; int recSize = Constants.OBJECT_ID_LENGTH + 8;
long sz = objCnt * recSize; long sz = objCnt * recSize;
index = cache.putRef(desc.getStreamKey(INDEX), sz, idx); cache.putRef(desc.getStreamKey(INDEX), sz, idx);
index = idx;
} }
/** /**
@ -176,12 +176,8 @@ public final class DfsPackFile extends BlockBasedFile {
} }
private PackIndex idx(DfsReader ctx) throws IOException { private PackIndex idx(DfsReader ctx) throws IOException {
DfsBlockCache.Ref<PackIndex> idxref = index; if (index != null) {
if (idxref != null) { return index;
PackIndex idx = idxref.get();
if (idx != null) {
return idx;
}
} }
if (invalid) { if (invalid) {
@ -192,59 +188,60 @@ public final class DfsPackFile extends BlockBasedFile {
.dispatch(new BeforeDfsPackIndexLoadedEvent(this)); .dispatch(new BeforeDfsPackIndexLoadedEvent(this));
synchronized (initLock) { synchronized (initLock) {
idxref = index; if (index != null) {
if (idxref != null) { return index;
PackIndex idx = idxref.get();
if (idx != null) {
return idx;
}
} }
DfsStreamKey idxKey = desc.getStreamKey(INDEX);
try { try {
idxref = cache.getOrLoadRef(idxKey, () -> { DfsStreamKey idxKey = desc.getStreamKey(INDEX);
try { DfsBlockCache.Ref<PackIndex> idxref = cache.getOrLoadRef(idxKey,
ctx.stats.readIdx++; () -> {
long start = System.nanoTime(); try {
try (ReadableChannel rc = ctx.db.openFile(desc, ctx.stats.readIdx++;
INDEX)) { long start = System.nanoTime();
InputStream in = Channels.newInputStream(rc); try (ReadableChannel rc = ctx.db.openFile(desc,
int wantSize = 8192; INDEX)) {
int bs = rc.blockSize(); InputStream in = Channels
if (0 < bs && bs < wantSize) { .newInputStream(rc);
bs = (wantSize / bs) * bs; int wantSize = 8192;
} else if (bs <= 0) { int bs = rc.blockSize();
bs = wantSize; if (0 < bs && bs < wantSize) {
bs = (wantSize / bs) * bs;
} else if (bs <= 0) {
bs = wantSize;
}
PackIndex idx = PackIndex.read(
new BufferedInputStream(in, bs));
int sz = (int) Math.min(
idx.getObjectCount() * REC_SIZE,
Integer.MAX_VALUE);
ctx.stats.readIdxBytes += rc.position();
index = idx;
return new DfsBlockCache.Ref<>(idxKey, 0,
sz, idx);
} finally {
ctx.stats.readIdxMicros += elapsedMicros(
start);
}
} catch (EOFException e) {
throw new IOException(MessageFormat.format(
DfsText.get().shortReadOfIndex,
desc.getFileName(INDEX)), e);
} catch (IOException e) {
throw new IOException(MessageFormat.format(
DfsText.get().cannotReadIndex,
desc.getFileName(INDEX)), e);
} }
PackIndex idx = PackIndex });
.read(new BufferedInputStream(in, bs)); PackIndex idx = idxref.get();
int sz = (int) Math.min( if (index == null && idx != null) {
idx.getObjectCount() * REC_SIZE, index = idx;
Integer.MAX_VALUE); }
ctx.stats.readIdxBytes += rc.position(); return index;
return new DfsBlockCache.Ref<>(idxKey, 0, sz, idx);
} finally {
ctx.stats.readIdxMicros += elapsedMicros(start);
}
} catch (EOFException e) {
throw new IOException(MessageFormat.format(
DfsText.get().shortReadOfIndex,
desc.getFileName(INDEX)), e);
} catch (IOException e) {
throw new IOException(MessageFormat.format(
DfsText.get().cannotReadIndex,
desc.getFileName(INDEX)), e);
}
});
} catch (IOException e) { } catch (IOException e) {
invalid = true; invalid = true;
throw e; throw e;
} }
PackIndex idx = idxref.get();
if (idx != null) {
index = idxref;
}
return idx;
} }
} }
@ -257,102 +254,90 @@ public final class DfsPackFile extends BlockBasedFile {
return null; return null;
} }
DfsBlockCache.Ref<PackBitmapIndex> idxref = bitmapIndex; if (bitmapIndex != null) {
if (idxref != null) { return bitmapIndex;
PackBitmapIndex bmidx = idxref.get();
if (bmidx != null) {
return bmidx;
}
} }
synchronized (initLock) { synchronized (initLock) {
idxref = bitmapIndex; if (bitmapIndex != null) {
if (idxref != null) { return bitmapIndex;
PackBitmapIndex bmidx = idxref.get();
if (bmidx != null) {
return bmidx;
}
} }
PackIndex idx = idx(ctx); PackIndex idx = idx(ctx);
PackReverseIndex revidx = getReverseIdx(ctx); PackReverseIndex revidx = getReverseIdx(ctx);
DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX); DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX);
idxref = cache.getOrLoadRef(bitmapKey, () -> { DfsBlockCache.Ref<PackBitmapIndex> idxref = cache
ctx.stats.readBitmap++; .getOrLoadRef(bitmapKey, () -> {
long start = System.nanoTime(); ctx.stats.readBitmap++;
try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) { long start = System.nanoTime();
long size; try (ReadableChannel rc = ctx.db.openFile(desc,
PackBitmapIndex bmidx; BITMAP_INDEX)) {
try { long size;
InputStream in = Channels.newInputStream(rc); PackBitmapIndex bmidx;
int wantSize = 8192; try {
int bs = rc.blockSize(); InputStream in = Channels.newInputStream(rc);
if (0 < bs && bs < wantSize) { int wantSize = 8192;
bs = (wantSize / bs) * bs; int bs = rc.blockSize();
} else if (bs <= 0) { if (0 < bs && bs < wantSize) {
bs = wantSize; bs = (wantSize / bs) * bs;
} else if (bs <= 0) {
bs = wantSize;
}
in = new BufferedInputStream(in, bs);
bmidx = PackBitmapIndex.read(in, idx, revidx);
} finally {
size = rc.position();
ctx.stats.readIdxBytes += size;
ctx.stats.readIdxMicros += elapsedMicros(start);
}
int sz = (int) Math.min(size, Integer.MAX_VALUE);
bitmapIndex = bmidx;
return new DfsBlockCache.Ref<>(bitmapKey, 0, sz,
bmidx);
} catch (EOFException e) {
throw new IOException(MessageFormat.format(
DfsText.get().shortReadOfIndex,
desc.getFileName(BITMAP_INDEX)), e);
} catch (IOException e) {
throw new IOException(MessageFormat.format(
DfsText.get().cannotReadIndex,
desc.getFileName(BITMAP_INDEX)), e);
} }
in = new BufferedInputStream(in, bs); });
bmidx = PackBitmapIndex.read(in, idx, revidx);
} finally {
size = rc.position();
ctx.stats.readIdxBytes += size;
ctx.stats.readIdxMicros += elapsedMicros(start);
}
int sz = (int) Math.min(size, Integer.MAX_VALUE);
return new DfsBlockCache.Ref<>(bitmapKey, 0, sz, bmidx);
} catch (EOFException e) {
throw new IOException(
MessageFormat.format(DfsText.get().shortReadOfIndex,
desc.getFileName(BITMAP_INDEX)),
e);
} catch (IOException e) {
throw new IOException(
MessageFormat.format(DfsText.get().cannotReadIndex,
desc.getFileName(BITMAP_INDEX)),
e);
}
});
PackBitmapIndex bmidx = idxref.get(); PackBitmapIndex bmidx = idxref.get();
if (bmidx != null) { if (bitmapIndex == null && bmidx != null) {
bitmapIndex = idxref; bitmapIndex = bmidx;
} }
return bmidx; return bitmapIndex;
} }
} }
PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException { PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
DfsBlockCache.Ref<PackReverseIndex> revref = reverseIndex; if (reverseIndex != null) {
if (revref != null) { return reverseIndex;
PackReverseIndex revidx = revref.get();
if (revidx != null) {
return revidx;
}
} }
synchronized (initLock) { synchronized (initLock) {
revref = reverseIndex; if (reverseIndex != null) {
if (revref != null) { return reverseIndex;
PackReverseIndex revidx = revref.get();
if (revidx != null) {
return revidx;
}
} }
PackIndex idx = idx(ctx); PackIndex idx = idx(ctx);
DfsStreamKey revKey = new DfsStreamKey.ForReverseIndex( DfsStreamKey revKey = new DfsStreamKey.ForReverseIndex(
desc.getStreamKey(INDEX)); desc.getStreamKey(INDEX));
revref = cache.getOrLoadRef(revKey, () -> { DfsBlockCache.Ref<PackReverseIndex> revref = cache
PackReverseIndex revidx = new PackReverseIndex(idx); .getOrLoadRef(revKey, () -> {
int sz = (int) Math.min(idx.getObjectCount() * 8, PackReverseIndex revidx = new PackReverseIndex(idx);
Integer.MAX_VALUE); int sz = (int) Math.min(idx.getObjectCount() * 8,
return new DfsBlockCache.Ref<>(revKey, 0, sz, revidx); Integer.MAX_VALUE);
}); reverseIndex = revidx;
return new DfsBlockCache.Ref<>(revKey, 0, sz, revidx);
});
PackReverseIndex revidx = revref.get(); PackReverseIndex revidx = revref.get();
if (revidx != null) { if (reverseIndex == null && revidx != null) {
reverseIndex = revref; reverseIndex = revidx;
} }
return revidx; return reverseIndex;
} }
} }

Loading…
Cancel
Save