Allow to discover bitmap on disk created after the packfile

When the bitmap file was created *after* a packfile had been
loaded into the memory, JGit was unable to discover them.

That happed because of two problems:

1. The PackDirectory.getPacks() does not implement the usual
   while loop that is scanning through the packs directory
   as in the other parts of JGit.

2. The scan packs does not look for newly created bitmap files
   if the packfile is already loaded in memory.

Implement the normal packfiles scanning whenever the PackDirectory
needs to return a list of packs, and make sure that any reused
Pack object would have its associated bitmap properly refreshed
from disk.

Adapt the assertions in GcConcurrentTest with the rescanned list
of Pack from the objects/packs directory.

Bug: jgit-15
Change-Id: I2ed576cefd78a0e128b175228a59c9af51523d7b
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 1519873..96a0649 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
@@ -186,13 +186,12 @@ public void repackAndCheckBitmapUsage() throws Exception {
 		// make sure gc() has caused creation of a new packfile
 		assertNotEquals(oldPackName, newPackName);
 
-		// Even when asking again for the set of packfiles outdated data
-		// will be returned. As long as the repository can work on cached data
-		// it will do so and not detect that a new packfile exists.
-		assertNotEquals(getSinglePack(repository).getPackName(), newPackName);
+		// When asking again for the set of packfiles the new updated data
+		// will be returned because of the rescan of the pack directory.
+		assertEquals(getSinglePack(repository).getPackName(), newPackName);
 
-		// Only when accessing object content it is required to rescan the pack
-		// directory and the new packfile will be detected.
+		// When accessing object content the new packfile refreshed from
+		// the rescan triggered from the list of packs.
 		repository.getObjectDatabase().open(b).getSize();
 		assertEquals(getSinglePack(repository).getPackName(), newPackName);
 		assertNotNull(getSinglePack(repository).getBitmapIndex());
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 45a6794..eabb0c6 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -64,6 +64,8 @@
 binaryHunkInvalidLength=Binary hunk, line {0}: input corrupt; expected length byte, got 0x{1}
 binaryHunkLineTooShort=Binary hunk, line {0}: input ended prematurely
 binaryHunkMissingNewline=Binary hunk, line {0}: input line not terminated by newline
+bitmapAccessErrorForPackfile=Error whilst trying to access bitmap file for {}
+bitmapFailedToGet=Failed to get bitmap index file {}
 bitmapMissingObject=Bitmap at {0} is missing {1}.
 bitmapsMustBePrepared=Bitmaps must be prepared before they may be written.
 blameNotCommittedYet=Not Committed Yet
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 c7cad43..1d5a2e1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -93,6 +93,8 @@ public static JGitText get() {
 	/***/ public String binaryHunkInvalidLength;
 	/***/ public String binaryHunkLineTooShort;
 	/***/ public String binaryHunkMissingNewline;
+	/***/ public String bitmapAccessErrorForPackfile;
+	/***/ public String bitmapFailedToGet;
 	/***/ public String bitmapMissingObject;
 	/***/ public String bitmapsMustBePrepared;
 	/***/ public String blameNotCommittedYet;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
index d6c25b2..7d39b1f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -1160,6 +1160,19 @@ synchronized PackBitmapIndex getBitmapIndex() throws IOException {
 		return bitmapIdx;
 	}
 
+	synchronized void refreshBitmapIndex(PackFile bitmapIndexFile) {
+		this.bitmapIdx = null;
+		this.invalid = false;
+		this.bitmapIdxFile = bitmapIndexFile;
+		try {
+			getBitmapIndex();
+		} catch (IOException e) {
+			LOG.warn(JGitText.get().bitmapFailedToGet, bitmapIdxFile, e);
+			this.bitmapIdx = null;
+			this.bitmapIdxFile = null;
+		}
+	}
+
 	private synchronized PackReverseIndex getReverseIdx() throws IOException {
 		if (reverseIdx == null)
 			reverseIdx = new PackReverseIndex(idx());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
index 6a99cb3..1676d8b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -115,10 +115,13 @@ void close() {
 	}
 
 	Collection<Pack> getPacks() {
-		PackList list = packList.get();
-		if (list == NO_PACKS) {
-			list = scanPacks(list);
-		}
+		PackList list;
+		do {
+			list = packList.get();
+			if (list == NO_PACKS) {
+				list = scanPacks(list);
+			}
+		} while (searchPacksAgain(list));
 		Pack[] packs = list.packs;
 		return Collections.unmodifiableCollection(Arrays.asList(packs));
 	}
@@ -455,6 +458,13 @@ private PackList scanPacksImpl(PackList old) {
 					&& !oldPack.getFileSnapshot().isModified(packFile)) {
 				forReuse.remove(packFile.getName());
 				list.add(oldPack);
+				try {
+					if(oldPack.getBitmapIndex() == null) {
+						oldPack.refreshBitmapIndex(packFilesByExt.get(BITMAP_INDEX));
+					}
+				} catch (IOException e) {
+					LOG.warn(JGitText.get().bitmapAccessErrorForPackfile, oldPack.getPackName(), e);
+				}
 				continue;
 			}