diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.corrupt.rev b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.corrupt.rev new file mode 100644 index 000000000..74283a2f9 Binary files /dev/null and b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.corrupt.rev differ diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.rev b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.rev new file mode 100644 index 000000000..6ac7d65f6 Binary files /dev/null and b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.rev differ diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java index 84fc58e05..f8fb4c15e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexTest.java @@ -10,13 +10,52 @@ package org.eclipse.jgit.internal.storage.file; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.IOException; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.junit.JGitTestUtil; import org.junit.Test; public class PackReverseIndexTest { + + @Test + public void open_fallbackToComputed() throws IOException { + String noRevFilePrefix = "pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12."; + PackReverseIndex computed = PackReverseIndexFactory.openOrCompute( + getResourceFileFor(noRevFilePrefix, PackExt.REVERSE_INDEX), 7, + () -> PackIndex.open( + getResourceFileFor(noRevFilePrefix, PackExt.INDEX))); + + assertTrue(computed instanceof PackReverseIndexComputed); + } + + @Test + public void open_readGoodFile() throws IOException { + String hasRevFilePrefix = "pack-cbdeda40019ae0e6e789088ea0f51f164f489d14."; + PackReverseIndex version1 = PackReverseIndexFactory.openOrCompute( + getResourceFileFor(hasRevFilePrefix, PackExt.REVERSE_INDEX), 6, + () -> PackIndex.open( + getResourceFileFor(hasRevFilePrefix, PackExt.INDEX))); + + assertTrue(version1 instanceof PackReverseIndexV1); + } + + @Test + public void open_readCorruptFile() { + String hasRevFilePrefix = "pack-cbdeda40019ae0e6e789088ea0f51f164f489d14."; + + assertThrows(IOException.class, + () -> PackReverseIndexFactory.openOrCompute( + getResourceFileFor(hasRevFilePrefix + "corrupt.", + PackExt.REVERSE_INDEX), + 6, () -> PackIndex.open(getResourceFileFor( + hasRevFilePrefix, PackExt.INDEX)))); + } + @Test public void read_badMagic() { byte[] badMagic = new byte[] { 'R', 'B', 'A', 'D', // magic @@ -53,4 +92,9 @@ public void read_unsupportedVersion2() { assertThrows(IOException.class, () -> PackReverseIndexFactory.readFromFile(in, 0, () -> null)); } + + private File getResourceFileFor(String packFilePrefix, PackExt ext) { + return JGitTestUtil + .getTestResourceFile(packFilePrefix + ext.getExtension()); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java index b16da5ae8..32830c3cf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java @@ -14,6 +14,8 @@ import static org.eclipse.jgit.internal.storage.file.PackReverseIndex.VERSION_1; import java.io.DataInput; +import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.DigestInputStream; @@ -23,11 +25,42 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.io.SilentFileInputStream; /** * Factory for creating instances of {@link PackReverseIndex}. */ public final class PackReverseIndexFactory { + /** + * Create an in-memory pack reverse index by reading it from the given file + * if the file exists, or computing it from the given pack index if the file + * doesn't exist. + * + * @param idxFile + * the file to read the pack file from, if it exists + * @param objectCount + * the number of objects in the corresponding pack + * @param packIndexSupplier + * a function to lazily get the corresponding forward index + * @return the reverse index instance + * @throws IOException + * if reading from the file fails + */ + static PackReverseIndex openOrCompute(File idxFile, long objectCount, + PackBitmapIndex.SupplierWithIOException packIndexSupplier) + throws IOException { + try (SilentFileInputStream fd = new SilentFileInputStream(idxFile)) { + return readFromFile(fd, objectCount, packIndexSupplier); + } catch (FileNotFoundException e) { + return computeFromIndex(packIndexSupplier.get()); + } catch (IOException e) { + throw new IOException( + MessageFormat.format(JGitText.get().unreadablePackIndex, + idxFile.getAbsolutePath()), + e); + } + } + /** * Compute an in-memory pack reverse index from the in-memory pack forward * index. This computation uses insertion sort, which has a quadratic