PackWriter: support excluding objects already in other packs

This can be useful when implementing garbage collection and there
are packs that should not be copied, such as huge packs that have
a sibling ".keep" file alongside of them.

Callers driving PackWriter need to initialize the list of packs not
to include objects from by passing each index to excludeObjects().

Change-Id: Id7f34df69df97be406bcae184308e92b0e8690fd
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
This commit is contained in:
Shawn O. Pearce 2011-08-16 12:32:10 -07:00 committed by Chris Aniszczyk
parent c580c56c4d
commit a1a8c6d77e
1 changed files with 49 additions and 1 deletions

View File

@ -99,6 +99,7 @@
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.storage.file.PackIndex;
import org.eclipse.jgit.storage.file.PackIndexWriter;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.TemporaryBuffer;
@ -157,6 +158,10 @@ public class PackWriter {
private Set<ObjectId> tagTargets = Collections.emptySet();
private PackIndex[] excludeInPacks;
private PackIndex excludeInPackLast;
private Deflater myDeflater;
private final ObjectReader reader;
@ -425,6 +430,25 @@ public long getObjectCount() throws IOException {
return stats.totalObjects;
}
/**
* Add a pack index whose contents should be excluded from the result.
*
* @param idx
* objects in this index will not be in the output pack.
*/
public void excludeObjects(PackIndex idx) {
if (excludeInPacks == null) {
excludeInPacks = new PackIndex[] { idx };
excludeInPackLast = idx;
} else {
int cnt = excludeInPacks.length;
PackIndex[] newList = new PackIndex[cnt + 1];
System.arraycopy(excludeInPacks, 0, newList, 0, cnt);
newList[cnt] = idx;
excludeInPacks = newList;
}
}
/**
* Prepare the list of objects to be written to the pack stream.
* <p>
@ -721,6 +745,9 @@ public void writePack(ProgressMonitor compressMonitor,
if (writeMonitor == null)
writeMonitor = NullProgressMonitor.INSTANCE;
excludeInPacks = null;
excludeInPackLast = null;
boolean needSearchForReuse = reuseSupport != null && (
reuseDeltas
|| config.isReuseObjects()
@ -1459,6 +1486,8 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
BlockList<RevCommit> commits = new BlockList<RevCommit>();
RevCommit c;
while ((c = walker.next()) != null) {
if (exclude(c))
continue;
if (c.has(inCachedPack)) {
CachedPack pack = tipToPack.get(c);
if (includesAllTips(pack, include, walker)) {
@ -1524,6 +1553,8 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
while ((o = walker.nextObject()) != null) {
if (o.has(RevFlag.UNINTERESTING))
continue;
if (exclude(o))
continue;
int pathHash = walker.getPathHashCode();
byte[] pathBuf = walker.getPathBuffer();
@ -1537,6 +1568,8 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
while ((o = walker.nextObject()) != null) {
if (o.has(RevFlag.UNINTERESTING))
continue;
if (exclude(o))
continue;
addObject(o, walker.getPathHashCode());
countingMonitor.update(1);
}
@ -1608,7 +1641,8 @@ private static boolean includesAllTips(CachedPack pack, RevFlag include,
*/
public void addObject(final RevObject object)
throws IncorrectObjectTypeException {
addObject(object, 0);
if (!exclude(object))
addObject(object, 0);
}
private void addObject(final RevObject object, final int pathHashCode) {
@ -1622,6 +1656,20 @@ private void addObject(final RevObject object, final int pathHashCode) {
objectsMap.add(otp);
}
private boolean exclude(AnyObjectId objectId) {
if (excludeInPacks == null)
return false;
if (excludeInPackLast.hasObject(objectId))
return true;
for (PackIndex idx : excludeInPacks) {
if (idx.hasObject(objectId)) {
excludeInPackLast = idx;
return true;
}
}
return false;
}
/**
* Select an object representation for this writer.
* <p>