Merge "Scan through all merged reftables for max/min update indices"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
index 2a2aeb5..a246ac9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
@@ -287,6 +287,123 @@
 	}
 
 	@Test
+	public void nonOverlappedUpdateIndices() throws IOException {
+		ByteArrayOutputStream buf = new ByteArrayOutputStream();
+		ReftableWriter writer = new ReftableWriter(buf)
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(2)
+				.begin();
+		writer.writeRef(ref("refs/heads/a", 1), 1);
+		writer.writeRef(ref("refs/heads/b", 2), 2);
+		writer.finish();
+		byte[] base = buf.toByteArray();
+
+		buf = new ByteArrayOutputStream();
+		writer = new ReftableWriter(buf)
+				.setMinUpdateIndex(3)
+				.setMaxUpdateIndex(4)
+				.begin();
+		writer.writeRef(ref("refs/heads/a", 10), 3);
+		writer.writeRef(ref("refs/heads/b", 20), 4);
+		writer.finish();
+		byte[] delta = buf.toByteArray();
+
+		MergedReftable mr = merge(base, delta);
+		assertEquals(1, mr.minUpdateIndex());
+		assertEquals(4, mr.maxUpdateIndex());
+
+		try (RefCursor rc = mr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals("refs/heads/a", rc.getRef().getName());
+			assertEquals(id(10), rc.getRef().getObjectId());
+			assertEquals(3, rc.getRef().getUpdateIndex());
+
+			assertTrue(rc.next());
+			assertEquals("refs/heads/b", rc.getRef().getName());
+			assertEquals(id(20), rc.getRef().getObjectId());
+			assertEquals(4, rc.getRef().getUpdateIndex());
+		}
+	}
+
+	@Test
+	public void overlappedUpdateIndices() throws IOException {
+		ByteArrayOutputStream buf = new ByteArrayOutputStream();
+		ReftableWriter writer = new ReftableWriter(buf)
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(3)
+				.begin();
+		writer.writeRef(ref("refs/heads/a", 1), 1);
+		writer.writeRef(ref("refs/heads/b", 2), 3);
+		writer.finish();
+		byte[] base = buf.toByteArray();
+
+		buf = new ByteArrayOutputStream();
+		writer = new ReftableWriter(buf)
+				.setMinUpdateIndex(2)
+				.setMaxUpdateIndex(4)
+				.begin();
+		writer.writeRef(ref("refs/heads/a", 10), 2);
+		writer.writeRef(ref("refs/heads/b", 20), 4);
+		writer.finish();
+		byte[] delta = buf.toByteArray();
+
+		MergedReftable mr = merge(base, delta);
+		assertEquals(1, mr.minUpdateIndex());
+		assertEquals(4, mr.maxUpdateIndex());
+
+		try (RefCursor rc = mr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals("refs/heads/a", rc.getRef().getName());
+			assertEquals(id(10), rc.getRef().getObjectId());
+			assertEquals(2, rc.getRef().getUpdateIndex());
+
+			assertTrue(rc.next());
+			assertEquals("refs/heads/b", rc.getRef().getName());
+			assertEquals(id(20), rc.getRef().getObjectId());
+			assertEquals(4, rc.getRef().getUpdateIndex());
+		}
+	}
+
+	@Test
+	public void enclosedUpdateIndices() throws IOException {
+		ByteArrayOutputStream buf = new ByteArrayOutputStream();
+		ReftableWriter writer = new ReftableWriter(buf)
+				.setMinUpdateIndex(1)
+				.setMaxUpdateIndex(4)
+				.begin();
+		writer.writeRef(ref("refs/heads/a", 1), 1);
+		writer.writeRef(ref("refs/heads/b", 20), 4);
+		writer.finish();
+		byte[] base = buf.toByteArray();
+
+		buf = new ByteArrayOutputStream();
+		writer = new ReftableWriter(buf)
+				.setMinUpdateIndex(2)
+				.setMaxUpdateIndex(3)
+				.begin();
+		writer.writeRef(ref("refs/heads/a", 10), 2);
+		writer.writeRef(ref("refs/heads/b", 2), 3);
+		writer.finish();
+		byte[] delta = buf.toByteArray();
+
+		MergedReftable mr = merge(base, delta);
+		assertEquals(1, mr.minUpdateIndex());
+		assertEquals(4, mr.maxUpdateIndex());
+
+		try (RefCursor rc = mr.allRefs()) {
+			assertTrue(rc.next());
+			assertEquals("refs/heads/a", rc.getRef().getName());
+			assertEquals(id(10), rc.getRef().getObjectId());
+			assertEquals(2, rc.getRef().getUpdateIndex());
+
+			assertTrue(rc.next());
+			assertEquals("refs/heads/b", rc.getRef().getName());
+			assertEquals(id(20), rc.getRef().getObjectId());
+			assertEquals(4, rc.getRef().getUpdateIndex());
+		}
+	}
+
+	@Test
 	public void compaction() throws IOException {
 		List<Ref> delta1 = Arrays.asList(
 				ref("refs/heads/next", 4),
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
index 18c013f..3633515 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
@@ -61,8 +61,16 @@
 	 */
 	@Override
 	public long maxUpdateIndex() throws IOException {
-		return tables.length > 0 ? tables[tables.length - 1].maxUpdateIndex()
-				: 0;
+		if (tables.length == 0) {
+			return 0;
+		}
+		long maxUpdateIndex = tables[tables.length - 1].maxUpdateIndex();
+		for (int i = tables.length - 2; i >= 0; i--) {
+			if (maxUpdateIndex < tables[i].maxUpdateIndex()) {
+				maxUpdateIndex = tables[i].maxUpdateIndex();
+			}
+		}
+		return maxUpdateIndex;
 	}
 
 	/**
@@ -70,8 +78,16 @@
 	 */
 	@Override
 	public long minUpdateIndex() throws IOException {
-		return tables.length > 0 ? tables[0].minUpdateIndex()
-			: 0;
+		if (tables.length == 0) {
+			return 0;
+		}
+		long minUpdateIndex = tables[0].minUpdateIndex();
+		for (int i = 0; i < tables.length - 1; i++) {
+			if (tables[i].minUpdateIndex() < minUpdateIndex) {
+				minUpdateIndex = tables[i].minUpdateIndex();
+			}
+		}
+		return minUpdateIndex;
 	}
 
 	/** {@inheritDoc} */