DfsMidxWriter: Use the input data instead of rereading the midx

Change-Id: I09c90fdd45286214a58dc9619b0b8bb96a6a6964
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
index 0c5cfe1..80a6864 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
@@ -13,6 +13,7 @@
 import static java.util.stream.Collectors.toMap;
 import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX;
+import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -26,13 +27,16 @@
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.internal.revwalk.RefAdvancerWalk;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndex;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter;
 import org.eclipse.jgit.internal.storage.midx.PackIndexMerger;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
 import org.eclipse.jgit.internal.storage.pack.PackBitmapCalculator;
 import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.storage.pack.PackConfig;
@@ -77,15 +81,18 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm,
 			}
 		}
 
+		PackIndexMerger data = dataBuilder.build();
+		byte[] checksum;
+
 		DfsPackDescription midxPackDesc = objdb.newPack(GC);
 		try (DfsOutputStream out = objdb.writeFile(midxPackDesc,
 				MULTI_PACK_INDEX)) {
 			MultiPackIndexWriter w = new MultiPackIndexWriter();
-			MultiPackIndexWriter.Result result = w.write(pm, out,
-					dataBuilder.build());
+			MultiPackIndexWriter.Result result = w.write(pm, out, data);
 			midxPackDesc.addFileExt(MULTI_PACK_INDEX);
 			midxPackDesc.setFileSize(MULTI_PACK_INDEX, result.bytesWritten());
 			midxPackDesc.setObjectCount(result.objectCount());
+			checksum = result.checksum();
 
 			Map<String, DfsPackDescription> byName = packs.stream()
 					.map(DfsPackFile::getPackDescription)
@@ -102,6 +109,7 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm,
 		// TODO(ifrade): At the moment we only support bitmaps on the base
 		if (base == null && packConfig != null) {
 			createAndAttachBitmaps(objdb.getRepository(), midxPackDesc,
+					checksum, data, packs,
 					packConfig);
 		}
 
@@ -109,12 +117,8 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm,
 	}
 
 	private static void createAndAttachBitmaps(DfsRepository db,
-			DfsPackDescription desc, PackConfig cfg) throws IOException {
-
-		DfsObjDatabase objdb = db.getObjectDatabase();
-		// We need a DfsPackFile to reread the contents
-		DfsPackFileMidx midxPack = db.getObjectDatabase().createDfsPackFileMidx(
-				DfsBlockCache.getInstance(), desc, new ArrayList<>());
+			DfsPackDescription desc, byte[] checksum, PackIndexMerger data,
+			List<DfsPackFile> packs, PackConfig cfg) throws IOException {
 
 		// TODO(ifrade): Verify we duplicate the behaviour about tags of regular
 		// bitmapping
@@ -125,14 +129,16 @@ private static void createAndAttachBitmaps(DfsRepository db,
 			return;
 		}
 
-		try (DfsReader ctx = objdb.newReader()) {
+		try (DfsReader ctx = db.getObjectDatabase().newReader()) {
+			ObjectIdOwnerMap<ObjectToPack> byId = new ObjectIdOwnerMap<>();
+			List<ObjectToPack> otps = asObjectsToPack(ctx, data, packs, byId);
+
 			RefAdvancerWalk adv = new RefAdvancerWalk(db,
-					c -> midxPack.hasObject(ctx, c));
+					c -> byId.contains(c));
 			Set<RevCommit> inPack = adv.advance(allHeads);
 
-			byte[] checksum = midxPack.getChecksum(ctx);
 			PackBitmapIndexBuilder writeBitmaps = new PackBitmapIndexBuilder(
-					midxPack.getLocalObjects(ctx));
+					otps);
 			int commitCount = writeBitmaps.getCommits().cardinality();
 
 			PackBitmapCalculator calculator = new PackBitmapCalculator(cfg);
@@ -145,4 +151,30 @@ private static void createAndAttachBitmaps(DfsRepository db,
 		}
 	}
 
+	private static List<ObjectToPack> asObjectsToPack(DfsReader ctx,
+			PackIndexMerger data, List<DfsPackFile> packs,
+			ObjectIdOwnerMap<ObjectToPack> byId) throws IOException {
+		long[] accPackSize = new long[packs.size()];
+		for (int i = 1; i < packs.size(); i++) {
+			long prevValue = accPackSize[i - 1];
+			accPackSize[i] = prevValue
+					+ packs.get(i - 1).getPackDescription().getFileSize(PACK);
+		}
+
+		List<ObjectToPack> result = new ArrayList<>(
+				data.getUniqueObjectCount());
+		MultiPackIndex.MidxIterator it = data.bySha1Iterator();
+		while (it.hasNext()) {
+			MultiPackIndex.MutableEntry entry = it.next();
+			int objectType = packs.get(entry.getPackId()).getObjectType(ctx,
+					entry.getOffset());
+			ObjectToPack o = new ObjectToPack(entry.getObjectId().toObjectId(),
+					objectType);
+			o.setOffset(accPackSize[entry.getPackId()] + entry.getOffset());
+			result.add(o);
+			byId.add(o);
+		}
+		return result;
+	}
+
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
index dad6d66..8584176 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
@@ -176,7 +176,7 @@ private PackIndexMerger(MidxIterator midxIterator, ProgressMonitor pm) {
 	 *
 	 * @return object count of the merged index
 	 */
-	int getUniqueObjectCount() {
+	public int getUniqueObjectCount() {
 		return uniqueObjectCount;
 	}
 
@@ -244,7 +244,7 @@ int getPackCount() {
 	 *
 	 * @return an iterator in sha1 order without duplicates.
 	 */
-	MidxIterator bySha1Iterator() {
+	public MidxIterator bySha1Iterator() {
 		midxIterator.reset();
 		return midxIterator;
 	}