summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Pearce <spearce@spearce.org>2013-03-12 17:55:47 -0400
committerGerrit Code Review @ Eclipse.org <gerrit@eclipse.org>2013-03-12 17:55:47 -0400
commit7e229c75c168dbff5f2b5470ddfcce86467fe6c5 (patch)
tree6d4246244b52aa0262a0df708f22043c923216e7
parentc017d7ef4524d6132043229f024689b567548360 (diff)
parentbb002c619bc373059c4f2494da7870f5679ba845 (diff)
downloadjgit-7e229c75c168dbff5f2b5470ddfcce86467fe6c5.tar.gz
jgit-7e229c75c168dbff5f2b5470ddfcce86467fe6c5.zip
Merge "Avoid repacking unreachable garbage in DfsGarbageCollector"
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsGarbageCollector.java57
1 files changed, 52 insertions, 5 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsGarbageCollector.java
index 6027eadc42..76b36a416a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsGarbageCollector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsGarbageCollector.java
@@ -46,12 +46,11 @@ package org.eclipse.jgit.storage.dfs;
import static org.eclipse.jgit.storage.dfs.DfsObjDatabase.PackSource.GC;
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.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -69,6 +68,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.storage.file.PackIndex;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackExt;
import org.eclipse.jgit.storage.pack.PackWriter;
import org.eclipse.jgit.util.io.CountingOutputStream;
@@ -90,6 +90,8 @@ public class DfsGarbageCollector {
private PackConfig packConfig;
+ private long coalesceGarbageLimit = 50 << 20;
+
private Map<String, Ref> refsBefore;
private List<DfsPackFile> packsBefore;
@@ -139,6 +141,38 @@ public class DfsGarbageCollector {
return this;
}
+ /** @return garbage packs smaller than this size will be repacked. */
+ public long getCoalesceGarbageLimit() {
+ return coalesceGarbageLimit;
+ }
+
+ /**
+ * Set the byte size limit for garbage packs to be repacked.
+ * <p>
+ * Any UNREACHABLE_GARBAGE pack smaller than this limit will be repacked at
+ * the end of the run. This allows the garbage collector to coalesce
+ * unreachable objects into a single file.
+ * <p>
+ * If an UNREACHABLE_GARBAGE pack is already larger than this limit it will
+ * be left alone by the garbage collector. This avoids unnecessary disk IO
+ * reading and copying the objects.
+ * <p>
+ * If limit is set to 0 the UNREACHABLE_GARBAGE coalesce is disabled.<br>
+ * If limit is set to {@link Long#MAX_VALUE}, everything is coalesced.
+ * <p>
+ * Keeping unreachable garbage prevents race conditions with repository
+ * changes that may suddenly need an object whose only copy was stored in
+ * the UNREACHABLE_GARBAGE pack.
+ *
+ * @param limit
+ * size in bytes.
+ * @return {@code this}
+ */
+ public DfsGarbageCollector setCoalesceGarbageLimit(long limit) {
+ coalesceGarbageLimit = limit;
+ return this;
+ }
+
/**
* Create a single new pack file containing all of the live objects.
* <p>
@@ -167,7 +201,7 @@ public class DfsGarbageCollector {
objdb.clearCache();
refsBefore = repo.getAllRefs();
- packsBefore = Arrays.asList(objdb.getPacks());
+ packsBefore = packsToRebuild();
if (packsBefore.isEmpty())
return true;
@@ -203,6 +237,19 @@ public class DfsGarbageCollector {
}
}
+ private List<DfsPackFile> packsToRebuild() throws IOException {
+ DfsPackFile[] packs = objdb.getPacks();
+ List<DfsPackFile> out = new ArrayList<DfsPackFile>(packs.length);
+ for (DfsPackFile p : packs) {
+ DfsPackDescription d = p.getPackDescription();
+ if (d.getPackSource() != UNREACHABLE_GARBAGE)
+ out.add(p);
+ else if (d.getFileSize(PackExt.PACK) < coalesceGarbageLimit)
+ out.add(p);
+ }
+ return out;
+ }
+
/** @return all of the source packs that fed into this compaction. */
public List<DfsPackDescription> getSourcePacks() {
return toPrune();
@@ -264,9 +311,9 @@ public class DfsGarbageCollector {
PackWriter pw = newPackWriter();
try {
RevWalk pool = new RevWalk(ctx);
+ pm.beginTask("Finding garbage", (int) getObjectsBefore());
for (DfsPackFile oldPack : packsBefore) {
PackIndex oldIdx = oldPack.getPackIndex(ctx);
- pm.beginTask("Finding garbage", (int) oldIdx.getObjectCount());
for (PackIndex.MutableEntry ent : oldIdx) {
pm.update(1);
ObjectId id = ent.toObjectId();
@@ -276,8 +323,8 @@ public class DfsGarbageCollector {
int type = oldPack.getObjectType(ctx, ent.getOffset());
pw.addObject(pool.lookupAny(id, type));
}
- pm.endTask();
}
+ pm.endTask();
if (0 < pw.getObjectCount())
writePack(UNREACHABLE_GARBAGE, pw, pm);
} finally {