Merge branch 'stable-4.9' into stable-4.10

* stable-4.9:
  Fix error log message in ObjectDirectory.handlePackError()
  Properly format pack checksums in PackFile.idx()
  Cancel gc if thread was interrupted
  PackFile: report correct message for checksum mismatch
  ObjectDirectory: Clean up logging
  Bazel: Stop using native.git_repository
  ObjectDirectory: extra logging on packfile exceptions

Change-Id: I0847251eb010616a705e0b91df4bdebc225fa95d
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
index 643bb49..c60c357 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcConcurrentTest.java
@@ -47,27 +47,35 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jgit.errors.CancelledException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.pack.PackWriter;
 import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.EmptyProgressMonitor;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Sets;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
 import org.junit.Test;
 
 public class GcConcurrentTest extends GcTestCase {
@@ -221,4 +229,48 @@
 		assertEquals(getSinglePack(repository).getPackName(), newPackName);
 		assertNotNull(getSinglePack(repository).getBitmapIndex());
 	}
+
+	@Test
+	public void testInterruptGc() throws Exception {
+		FileBasedConfig c = repo.getConfig();
+		c.setInt(ConfigConstants.CONFIG_GC_SECTION, null,
+				ConfigConstants.CONFIG_KEY_AUTOPACKLIMIT, 1);
+		c.save();
+		SampleDataRepositoryTestCase.copyCGitTestPacks(repo);
+		ExecutorService executor = Executors.newSingleThreadExecutor();
+		final CountDownLatch latch = new CountDownLatch(1);
+		Future<Collection<PackFile>> result = executor
+				.submit(new Callable<Collection<PackFile>>() {
+
+					@Override
+					public Collection<PackFile> call() throws Exception {
+						long start = System.currentTimeMillis();
+						System.out.println("starting gc");
+						latch.countDown();
+						Collection<PackFile> r = gc.gc();
+						System.out.println("gc took "
+								+ (System.currentTimeMillis() - start) + " ms");
+						return r;
+					}
+				});
+		try {
+			latch.await();
+			Thread.sleep(5);
+			executor.shutdownNow();
+			result.get();
+			fail("thread wasn't interrupted");
+		} catch (ExecutionException e) {
+			Throwable cause = e.getCause();
+			if (cause instanceof CancelledException) {
+				assertEquals(JGitText.get().operationCanceled,
+						cause.getMessage());
+			} else if (cause instanceof IOException) {
+				Throwable cause2 = cause.getCause();
+				assertTrue(cause2 instanceof InterruptedException
+						|| cause2 instanceof ExecutionException);
+			} else {
+				fail("unexpected exception " + e);
+			}
+		}
+	}
 }
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 699783b..d505420 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -284,7 +284,7 @@
 exceptionHookExecutionInterrupted=Execution of "{0}" hook interrupted.
 exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command
 exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1}
-exceptionWhileReadingPack=ERROR: Exception caught while accessing pack file {0}, the pack file might be corrupt, {1}. Caught {2} consecutive errors while trying to read this pack.
+exceptionWhileReadingPack=Exception caught while accessing pack file {0}, the pack file might be corrupt. Caught {1} consecutive errors while trying to read this pack.
 expectedACKNAKFoundEOF=Expected ACK/NAK, found EOF
 expectedACKNAKGot=Expected ACK/NAK, got: {0}
 expectedBooleanStringValue=Expected boolean string value
@@ -497,7 +497,7 @@
 operationCanceled=Operation {0} was canceled
 outputHasAlreadyBeenStarted=Output has already been started.
 overflowedReftableBlock=Overflowed reftable block
-packChecksumMismatch=Pack checksum mismatch detected for pack file {0}
+packChecksumMismatch=Pack checksum mismatch detected for pack file {0}: .pack has {1} whilst .idx has {2}
 packCorruptedWhileWritingToFilesystem=Pack corrupted while writing to filesystem
 packDoesNotMatchIndex=Pack {0} does not match index
 packedRefsHandleIsStale=packed-refs handle is stale, {0}. retry
@@ -697,6 +697,7 @@
 tSizeMustBeGreaterOrEqual1=tSize must be >= 1
 unableToCheckConnectivity=Unable to check connectivity.
 unableToCreateNewObject=Unable to create new object: {0}
+unableToReadPackfile=Unable to read packfile {0}
 unableToRemovePath=Unable to remove path ''{0}''
 unableToStore=Unable to store {0}.
 unableToWrite=Unable to write {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index bd5a39b..a471228 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -758,6 +758,7 @@
 	/***/ public String tSizeMustBeGreaterOrEqual1;
 	/***/ public String unableToCheckConnectivity;
 	/***/ public String unableToCreateNewObject;
+	/***/ public String unableToReadPackfile;
 	/***/ public String unableToRemovePath;
 	/***/ public String unableToStore;
 	/***/ public String unableToWrite;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index a69485a..45089fe 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -1281,7 +1281,7 @@
 	}
 
 	private void checkCancelled() throws CancelledException {
-		if (pm.isCancelled()) {
+		if (pm.isCancelled() || Thread.currentThread().isInterrupted()) {
 			throw new CancelledException(JGitText.get().operationCanceled);
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 3e2fd82..e210a68 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -360,6 +360,9 @@
 					// The hasObject call should have only touched the index,
 					// so any failure here indicates the index is unreadable
 					// by this process, and the pack is likewise not readable.
+					LOG.warn(MessageFormat.format(
+							JGitText.get().unableToReadPackfile,
+							p.getPackFile().getAbsolutePath()), e);
 					removePack(p);
 				}
 			}
@@ -652,6 +655,8 @@
 		if ((e instanceof CorruptObjectException)
 				|| (e instanceof PackInvalidException)) {
 			warnTmpl = JGitText.get().corruptPack;
+			LOG.warn(MessageFormat.format(warnTmpl,
+					p.getPackFile().getAbsolutePath()), e);
 			// Assume the pack is corrupted, and remove it from the list.
 			removePack(p);
 		} else if (e instanceof FileNotFoundException) {
@@ -681,8 +686,8 @@
 				// Don't remove the pack from the list, as the error may be
 				// transient.
 				LOG.error(MessageFormat.format(errTmpl,
-						p.getPackFile().getAbsolutePath()),
-						Integer.valueOf(transientErrorCount), e);
+						p.getPackFile().getAbsolutePath(),
+						Integer.valueOf(transientErrorCount)), e);
 			}
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index d5219c7..b41ba9b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -187,7 +187,9 @@
 				} else if (!Arrays.equals(packChecksum, idx.packChecksum)) {
 					throw new PackMismatchException(MessageFormat.format(
 							JGitText.get().packChecksumMismatch,
-							packFile.getPath()));
+							packFile.getPath(),
+							ObjectId.fromRaw(packChecksum).name(),
+							ObjectId.fromRaw(idx.packChecksum).name()));
 				}
 				loadedIdx = idx;
 			} catch (InterruptedIOException e) {
@@ -753,10 +755,10 @@
 		fd.readFully(buf, 0, 20);
 		if (!Arrays.equals(buf, packChecksum)) {
 			throw new PackMismatchException(MessageFormat.format(
-					JGitText.get().packObjectCountMismatch
-					, ObjectId.fromRaw(buf).name()
-					, ObjectId.fromRaw(idx.packChecksum).name()
-					, getPackFile()));
+					JGitText.get().packChecksumMismatch,
+					getPackFile(),
+					ObjectId.fromRaw(buf).name(),
+					ObjectId.fromRaw(idx.packChecksum).name()));
 		}
 	}
 
diff --git a/tools/bazlets.bzl b/tools/bazlets.bzl
index f97b72c..f089af4 100644
--- a/tools/bazlets.bzl
+++ b/tools/bazlets.bzl
@@ -1,10 +1,12 @@
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
 NAME = "com_googlesource_gerrit_bazlets"
 
 def load_bazlets(
         commit,
         local_path = None):
     if not local_path:
-        native.git_repository(
+        git_repository(
             name = NAME,
             remote = "https://gerrit.googlesource.com/bazlets",
             commit = commit,