diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java index 68fee612f..42851498b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java @@ -436,6 +436,19 @@ public abstract class ObjectReader { // Do nothing by default, most readers don't want or need advice. } + /** + * Advise the reader to avoid unreachable objects. + *

+ * While enabled the reader will skip over anything previously proven to be + * unreachable. This may be dangerous in the face of concurrent writes. + * + * @param avoid + * true to avoid unreachable objects. + */ + public void setAvoidUnreachableObjects(boolean avoid) { + // Do nothing by default. + } + /** * An index that can be used to speed up ObjectWalks. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackFile.java index 80cced84e..707488b03 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackFile.java @@ -45,9 +45,10 @@ package org.eclipse.jgit.storage.dfs; +import static org.eclipse.jgit.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.storage.pack.PackExt.BITMAP_INDEX; -import static org.eclipse.jgit.storage.pack.PackExt.PACK; import static org.eclipse.jgit.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.storage.pack.PackExt.PACK; import java.io.BufferedInputStream; import java.io.EOFException; @@ -276,8 +277,12 @@ public final class DfsPackFile { } } + final boolean isGarbage() { + return packDesc.getPackSource() == UNREACHABLE_GARBAGE; + } + PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException { - if (invalid) + if (invalid || isGarbage()) return null; DfsBlockCache.Ref idxref = bitmapIndex; if (idxref != null) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsReader.java index 7d5fb5b2a..401c483d4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsReader.java @@ -118,6 +118,8 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { private boolean wantReadAhead; + private boolean avoidUnreachable; + private List pendingReadAhead; DfsReader(DfsObjDatabase db) { @@ -143,6 +145,11 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { return new DfsReader(db); } + @Override + public void setAvoidUnreachableObjects(boolean avoid) { + avoidUnreachable = avoid; + } + @Override public BitmapIndex getBitmapIndex() throws IOException { for (DfsPackFile pack : db.getPacks()) { @@ -169,8 +176,11 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { throws IOException { if (id.isComplete()) return Collections.singleton(id.toObjectId()); + boolean noGarbage = avoidUnreachable; HashSet matches = new HashSet(4); for (DfsPackFile pack : db.getPacks()) { + if (noGarbage && pack.isGarbage()) + continue; pack.resolve(this, matches, id, 256); if (256 <= matches.size()) break; @@ -182,8 +192,9 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { public boolean has(AnyObjectId objectId) throws IOException { if (last != null && last.hasObject(this, objectId)) return true; + boolean noGarbage = avoidUnreachable; for (DfsPackFile pack : db.getPacks()) { - if (last == pack) + if (pack == last || (noGarbage && pack.isGarbage())) continue; if (pack.hasObject(this, objectId)) { last = pack; @@ -203,8 +214,9 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { return ldr; } + boolean noGarbage = avoidUnreachable; for (DfsPackFile pack : db.getPacks()) { - if (pack == last) + if (pack == last || (noGarbage && pack.isGarbage())) continue; ObjectLoader ldr = pack.get(this, objectId); if (ldr != null) { @@ -265,6 +277,7 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { int lastIdx = 0; DfsPackFile lastPack = packList[lastIdx]; + boolean noGarbage = avoidUnreachable; OBJECT_SCAN: for (T t : objectIds) { try { @@ -281,6 +294,8 @@ public final class DfsReader extends ObjectReader implements ObjectReuseAsIs { if (i == lastIdx) continue; DfsPackFile pack = packList[i]; + if (noGarbage && pack.isGarbage()) + continue; try { long p = pack.findOffset(this, t); if (0 < p) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index f0ba0cdc5..12f688658 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -792,6 +792,7 @@ public class UploadPack { sentReady = false; int haveCnt = 0; + walk.getObjectReader().setAvoidUnreachableObjects(true); AsyncRevObjectQueue q = walk.parseAny(peerHas, false); try { for (;;) { @@ -838,6 +839,7 @@ public class UploadPack { } } finally { q.release(); + walk.getObjectReader().setAvoidUnreachableObjects(false); } int missCnt = peerHas.size() - haveCnt;