Merge branch 'stable-5.6'

* stable-5.6:
  reftable: don't check deadline on the first try
  reftable: clarify comment
  reftable: clear cache on full compaction
  reftable: remove outdated comment
  reftable: clarify that LogCursor may return a null ReflogEntry

Change-Id: I9458a746311984fa687b3da964805e2568ed37f3
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java
index 9da3507..b13cdb9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -510,6 +511,43 @@
 	}
 
 	@Test
+	public void compactFully() throws Exception {
+		FileReftableDatabase refDb = (FileReftableDatabase) db.getRefDatabase();
+		PersonIdent person = new PersonIdent("jane", "jane@invalid");
+
+		ObjectId aId  = db.exactRef("refs/heads/a").getObjectId();
+		ObjectId bId  = db.exactRef("refs/heads/b").getObjectId();
+
+		SecureRandom random = new SecureRandom();
+		List<String> strs = new ArrayList<>();
+		for (int i = 0; i < 1024; i++) {
+			strs.add(String.format("%02x",
+					Integer.valueOf(random.nextInt(256))));
+		}
+
+		String randomStr = String.join("", strs);
+		String refName = "branch";
+		for (long i = 0; i < 2; i++) {
+			RefUpdate ru = refDb.newUpdate(refName, false);
+			ru.setNewObjectId(i % 2 == 0 ? aId : bId);
+			ru.setForceUpdate(true);
+			// Only write a large string in the first table, so it becomes much larger
+			// than the second, and the result is not autocompacted.
+			ru.setRefLogMessage(i == 0 ? randomStr : "short", false);
+			ru.setRefLogIdent(person);
+
+			RefUpdate.Result res = ru.update();
+			assertTrue(res == Result.NEW || res == FORCED);
+		}
+
+		assertEquals(refDb.exactRef(refName).getObjectId(), bId);
+		assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment()));
+		refDb.compactFully();
+		assertEquals(refDb.exactRef(refName).getObjectId(), bId);
+		assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment()));
+	}
+
+	@Test
 	public void reftableRefsStorageClass() throws IOException {
 		Ref b = db.exactRef("refs/heads/b");
 		assertEquals(Ref.Storage.PACKED, b.getStorage());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
index dc9c28c..aea14de 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
@@ -106,6 +106,7 @@
 		reftableDatabase.getLock().lock();
 		try {
 			reftableStack.compactFully();
+			reftableDatabase.clearCache();
 		} finally {
 			reftableDatabase.getLock().unlock();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
index 5b540bd..4cb0bd3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
@@ -237,8 +237,13 @@
 		long max = 1000;
 		long delay = 0;
 		boolean success = false;
-		while (System.currentTimeMillis() < deadline) {
+
+		// Don't check deadline for the first 3 retries, so we can step with a
+		// debugger without worrying about deadlines.
+		int tries = 0;
+		while (tries < 3 || System.currentTimeMillis() < deadline) {
 			List<String> names = readTableNames();
+			tries++;
 			try {
 				reloadOnce(names);
 				success = true;
@@ -260,9 +265,6 @@
 		}
 
 		if (!success) {
-			// TODO: should reexamine the 'refs' file to see if it was the same
-			// if it didn't change, then we must have corruption. If it did,
-			// retry.
 			throw new LockFailedException(stackPath);
 		}
 
@@ -374,7 +376,7 @@
 	 *
 	 * @param w
 	 *            writer to write data to a reftable under construction
-	 * @return true if the transaction.
+	 * @return true if the transaction was successful.
 	 * @throws IOException
 	 *             on I/O problems
 	 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java
index 9d410ae..f78975a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/LogCursor.java
@@ -12,6 +12,7 @@
 
 import java.io.IOException;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.lib.ReflogEntry;
 
 /**
@@ -45,8 +46,9 @@
 	/**
 	 * Get current log entry.
 	 *
-	 * @return current log entry.
+	 * @return current log entry. Maybe null if we are producing deletions.
 	 */
+	@Nullable
 	public abstract ReflogEntry getReflogEntry();
 
 	/** {@inheritDoc} */