Merge "Reduce compares in Edit.getType"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/AbbreviationTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/AbbreviationTest.java
index 1a38a7d..25e7aa3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/AbbreviationTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/AbbreviationTest.java
@@ -144,7 +144,6 @@ public void testAbbreviatePackedBlob() throws Exception {
 		assertEquals(id, db.resolve(reader.abbreviate(id, 8).name()));
 	}
 
-	@SuppressWarnings("unchecked")
 	public void testAbbreviateIsActuallyUnique() throws Exception {
 		// This test is far more difficult. We have to manually craft
 		// an input that contains collisions at a particular prefix,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/pack/DeltaStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/pack/DeltaStreamTest.java
index 9b34ad5..3f3038b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/pack/DeltaStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/pack/DeltaStreamTest.java
@@ -249,12 +249,29 @@ private void assertValidState() throws IOException {
 		assertEquals(data.length, BinaryDelta.getResultSize(delta));
 		assertTrue(Arrays.equals(data, BinaryDelta.apply(base, delta)));
 
+		// Assert that a single bulk read produces the correct result.
+		//
 		byte[] act = new byte[data.length];
 		DeltaStream in = open();
 		assertEquals(data.length, in.getSize());
 		assertEquals(data.length, in.read(act));
 		assertEquals(-1, in.read());
-		assertTrue(Arrays.equals(data, act));
+		assertTrue("bulk read has same content", Arrays.equals(data, act));
+
+		// Assert that smaller tiny reads have the same result too.
+		//
+		act = new byte[data.length];
+		in = open();
+		int read = 0;
+		while (read < data.length) {
+			int n = in.read(act, read, 128);
+			if (n <= 0)
+				break;
+			read += n;
+		}
+		assertEquals(data.length, read);
+		assertEquals(-1, in.read());
+		assertTrue("small reads have same content", Arrays.equals(data, act));
 	}
 
 	private DeltaStream open() throws IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackRefFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackRefFilterTest.java
index edced2f..3483b9d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackRefFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackRefFilterTest.java
@@ -66,6 +66,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.storage.file.ObjectDirectory;
+import org.eclipse.jgit.storage.pack.BinaryDelta;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.TemporaryBuffer;
 
@@ -271,16 +272,24 @@ private void receive(final ReceivePack rp,
 	}
 
 	public void testUsingHiddenDeltaBaseFails() throws Exception {
+		byte[] delta = { 0x1, 0x1, 0x1, 'c' };
+		TestRepository<Repository> s = new TestRepository<Repository>(src);
+		RevCommit N = s.commit().parent(B).add("q",
+				s.blob(BinaryDelta.apply(dst.open(b).getCachedBytes(), delta)))
+				.create();
+
 		final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
-		packHeader(pack, 1);
+		packHeader(pack, 3);
+		copy(pack, src.open(N));
+		copy(pack, src.open(s.parseBody(N).getTree()));
 		pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
 		b.copyRawTo(pack);
-		deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
+		deflate(pack, delta);
 		digest(pack);
 
-		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256);
+		final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
 		final PacketLineOut inPckLine = new PacketLineOut(inBuf);
-		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + P.name() + ' '
+		inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
 				+ "refs/heads/s" + '\0'
 				+ BasePackPushConnection.CAPABILITY_REPORT_STATUS);
 		inPckLine.end();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
index d379737..249b95e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -47,7 +47,6 @@
 package org.eclipse.jgit.lib;
 
 import static java.util.zip.Deflater.DEFAULT_COMPRESSION;
-import static org.eclipse.jgit.lib.ObjectLoader.STREAM_THRESHOLD;
 
 import org.eclipse.jgit.lib.Config.SectionParser;
 
@@ -68,21 +67,12 @@ public CoreConfig parse(final Config cfg) {
 
 	private final boolean logAllRefUpdates;
 
-	private final int streamFileThreshold;
-
 	private final boolean autoCRLF;
 
 	private CoreConfig(final Config rc) {
 		compression = rc.getInt("core", "compression", DEFAULT_COMPRESSION);
 		packIndexVersion = rc.getInt("pack", "indexversion", 2);
 		logAllRefUpdates = rc.getBoolean("core", "logallrefupdates", true);
-
-		long maxMem = Runtime.getRuntime().maxMemory();
-		long sft = rc.getLong("core", null, "streamfilethreshold", STREAM_THRESHOLD);
-		sft = Math.min(sft, maxMem / 4); // don't use more than 1/4 of the heap
-		sft = Math.min(sft, Integer.MAX_VALUE); // cannot exceed array length
-		streamFileThreshold = (int) sft;
-
 		autoCRLF = rc.getBoolean("core", "autocrlf", false);
 	}
 
@@ -108,11 +98,6 @@ public boolean isLogAllRefUpdates() {
 		return logAllRefUpdates;
 	}
 
-	/** @return the size threshold beyond which objects must be streamed. */
-	public int getStreamFileThreshold() {
-		return streamFileThreshold;
-	}
-
 	/**
 	 * @return whether automatic CRLF conversion has been configured
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
index 0fc3bce..fe4a7fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectLoader.java
@@ -256,7 +256,7 @@ public void copyTo(OutputStream out) throws MissingObjectException,
 			ObjectStream in = openStream();
 			try {
 				final long sz = in.getSize();
-				byte[] tmp = new byte[1024];
+				byte[] tmp = new byte[8192];
 				long copied = 0;
 				while (copied < sz) {
 					int n = in.read(tmp);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index dd513d8..94eb621 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -61,7 +61,6 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.AsyncObjectLoaderQueue;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.CoreConfig;
 import org.eclipse.jgit.lib.MutableObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdSubclassMap;
@@ -96,6 +95,8 @@
  * {@link #next()} does not.
  */
 public class RevWalk implements Iterable<RevCommit> {
+	private static final int MB = 1 << 20;
+
 	/**
 	 * Set on objects whose important header data has been loaded.
 	 * <p>
@@ -171,9 +172,6 @@ public class RevWalk implements Iterable<RevCommit> {
 
 	private final ObjectIdSubclassMap<RevObject> objects;
 
-	/** Largest commit or annotated tag we are willing to touch. */
-	private final int bigFileThreshold;
-
 	private int freeFlags = APP_FLAGS;
 
 	private int delayFreeFlags;
@@ -230,13 +228,6 @@ private RevWalk(final Repository repo, final ObjectReader or) {
 		filter = RevFilter.ALL;
 		treeFilter = TreeFilter.ALL;
 		retainBody = true;
-
-		if (repo != null) {
-			CoreConfig cfg = repo.getConfig().get(CoreConfig.KEY);
-			bigFileThreshold = cfg.getStreamFileThreshold();
-		} else {
-			bigFileThreshold = 15 * 1024 * 1024;
-		}
 	}
 
 	/** @return the reader this walker is using to load objects. */
@@ -867,7 +858,7 @@ private RevObject parseNew(AnyObjectId id, ObjectLoader ldr)
 	byte[] getCachedBytes(RevObject obj, ObjectLoader ldr)
 			throws LargeObjectException, MissingObjectException, IOException {
 		try {
-			return ldr.getCachedBytes(bigFileThreshold);
+			return ldr.getCachedBytes(5 * MB);
 		} catch (LargeObjectException tooBig) {
 			tooBig.setObjectId(obj);
 			throw tooBig;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCache.java
index 523e084..68fa191 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCache.java
@@ -518,7 +518,6 @@ private void removeAll(final PackFile pack) {
 		gc();
 	}
 
-	@SuppressWarnings("unchecked")
 	private void gc() {
 		Ref r;
 		while ((r = (Ref) queue.poll()) != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaStream.java
index 6f479eb..72015d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/DeltaStream.java
@@ -215,7 +215,8 @@ public int read(byte[] buf, int off, int len) throws IOException {
 				if (n < 0)
 					throw new CorruptObjectException(
 							JGitText.get().baseLengthIncorrect);
-				baseOffset += n;
+				copyOffset += n;
+				baseOffset = copyOffset;
 				break;
 
 			case CMD_INSERT:
@@ -225,6 +226,7 @@ public int read(byte[] buf, int off, int len) throws IOException {
 
 			case CMD_EOF:
 				return 0 < act ? act : -1;
+
 			default:
 				throw new CorruptObjectException(
 						JGitText.get().unsupportedCommand0);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
index 2fb342d..20c4bb0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
@@ -994,7 +994,7 @@ private ObjectWalk setUpWalker(
 
 		final ObjectWalk walker = new ObjectWalk(reader);
 		walker.setRetainBody(false);
-		walker.sort(RevSort.COMMIT_TIME_DESC);
+		walker.sort(RevSort.TOPO);
 		if (thin && !not.isEmpty())
 			walker.sort(RevSort.BOUNDARY, true);
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 53a3841..4cc9ea5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -84,6 +84,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevFlag;
 import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevSort;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.storage.file.PackLock;
@@ -810,6 +811,13 @@ private void checkConnectivity() throws IOException {
 		ip = null;
 
 		final ObjectWalk ow = new ObjectWalk(db);
+		ow.setRetainBody(false);
+		if (checkReferencedIsReachable) {
+			ow.sort(RevSort.TOPO);
+			if (!baseObjects.isEmpty())
+				ow.sort(RevSort.BOUNDARY, true);
+		}
+
 		for (final ReceiveCommand cmd : commands) {
 			if (cmd.getResult() != Result.NOT_ATTEMPTED)
 				continue;
@@ -830,22 +838,19 @@ private void checkConnectivity() throws IOException {
 			}
 		}
 
-		if (checkReferencedIsReachable) {
-			for (ObjectId id : baseObjects) {
-				   RevObject b = ow.lookupAny(id, Constants.OBJ_BLOB);
-				   if (!b.has(RevFlag.UNINTERESTING))
-				     throw new MissingObjectException(b, b.getType());
-			}
-		}
-
 		RevCommit c;
 		while ((c = ow.next()) != null) {
-			if (checkReferencedIsReachable && !providedObjects.contains(c))
+			if (checkReferencedIsReachable //
+					&& !c.has(RevFlag.UNINTERESTING) //
+					&& !providedObjects.contains(c))
 				throw new MissingObjectException(c, Constants.TYPE_COMMIT);
 		}
 
 		RevObject o;
 		while ((o = ow.nextObject()) != null) {
+			if (o.has(RevFlag.UNINTERESTING))
+				continue;
+
 			if (checkReferencedIsReachable) {
 				if (providedObjects.contains(o))
 					continue;
@@ -856,6 +861,14 @@ private void checkConnectivity() throws IOException {
 			if (o instanceof RevBlob && !db.hasObject(o))
 				throw new MissingObjectException(o, Constants.TYPE_BLOB);
 		}
+
+		if (checkReferencedIsReachable) {
+			for (ObjectId id : baseObjects) {
+				o = ow.parseAny(id);
+				if (!o.has(RevFlag.UNINTERESTING))
+					throw new MissingObjectException(o, o.getType());
+			}
+		}
 	}
 
 	private void validateCommands() {