diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0004_PackReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0004_PackReaderTest.java index 67861f677..d14cc212a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0004_PackReaderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0004_PackReaderTest.java @@ -46,6 +46,8 @@ package org.eclipse.jgit.storage.file; +import static org.eclipse.jgit.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.storage.pack.PackExt.PACK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -70,7 +72,7 @@ public void test003_lookupCompressedObject() throws IOException { final ObjectLoader or; id = ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"); - pr = new PackFile(TEST_PACK); + pr = new PackFile(TEST_PACK, PACK.getBit() | INDEX.getBit()); or = pr.get(new WindowCursor(null), id); assertNotNull(or); assertEquals(Constants.OBJ_TREE, or.getType()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectory.java index 22ef45df6..7574f2aa8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/ObjectDirectory.java @@ -43,6 +43,9 @@ package org.eclipse.jgit.storage.file; +import static org.eclipse.jgit.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.storage.pack.PackExt.PACK; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -74,6 +77,7 @@ import org.eclipse.jgit.lib.RepositoryCache.FileKey; import org.eclipse.jgit.storage.pack.CachedPack; import org.eclipse.jgit.storage.pack.ObjectToPack; +import org.eclipse.jgit.storage.pack.PackExt; import org.eclipse.jgit.storage.pack.PackWriter; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; @@ -335,10 +339,23 @@ private CachedPackList scanCachedPacks(CachedPackList old) public PackFile openPack(final File pack) throws IOException { final String p = pack.getName(); - if (p.length() != 50 || !p.startsWith("pack-") || !p.endsWith(".pack")) //$NON-NLS-1$ + if (p.length() != 50 || !p.startsWith("pack-") || !p.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$ throw new IOException(MessageFormat.format(JGitText.get().notAValidPack, pack)); - PackFile res = new PackFile(pack); + // The pack and index are assumed to exist. The existence of other + // extensions needs to be explicitly checked. + // + int extensions = PACK.getBit() | INDEX.getBit(); + final String base = p.substring(0, p.length() - 4); + for (PackExt ext : PackExt.values()) { + if ((extensions & ext.getBit()) == 0) { + final String name = base + ext.getExtension(); + if (new File(pack.getParentFile(), name).exists()) + extensions |= ext.getBit(); + } + } + + PackFile res = new PackFile(pack, extensions); insertPack(res); return res; } @@ -720,9 +737,14 @@ private PackList scanPacksImpl(final PackList old) { if (indexName.length() != 49 || !indexName.endsWith(".idx")) //$NON-NLS-1$ continue; - final String base = indexName.substring(0, indexName.length() - 4); - final String packName = base + ".pack"; //$NON-NLS-1$ - if (!names.contains(packName)) { + final String base = indexName.substring(0, indexName.length() - 3); + int extensions = 0; + for (PackExt ext : PackExt.values()) { + if (names.contains(base + ext.getExtension())) + extensions |= ext.getBit(); + } + + if ((extensions & PACK.getBit()) == 0) { // Sometimes C Git's HTTP fetch transport leaves a // .idx file behind and does not download the .pack. // We have to skip over such useless indexes. @@ -730,6 +752,7 @@ private PackList scanPacksImpl(final PackList old) { continue; } + final String packName = base + PACK.getExtension(); final PackFile oldPack = forReuse.remove(packName); if (oldPack != null) { list.add(oldPack); @@ -737,7 +760,7 @@ private PackList scanPacksImpl(final PackList old) { } final File packFile = new File(packDirectory, packName); - list.add(new PackFile(packFile)); + list.add(new PackFile(packFile, extensions)); foundNew = true; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackFile.java index 666df58be..6c24a3fef 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackFile.java @@ -97,6 +97,8 @@ public int compare(final PackFile a, final PackFile b) { private final File packFile; + private final int extensions; + private File keepFile; private volatile String packName; @@ -138,10 +140,13 @@ public int compare(final PackFile a, final PackFile b) { * * @param packFile * path of the .pack file holding the data. + * @param extensions + * additional pack file extensions with the same base as the pack */ - public PackFile(final File packFile) { + public PackFile(final File packFile, int extensions) { this.packFile = packFile; this.packLastModified = (int) (packFile.lastModified() >> 10); + this.extensions = extensions; // Multiply by 31 here so we can more directly combine with another // value in WindowCache.hash(), without doing the multiply there. @@ -1085,4 +1090,8 @@ private File extFile(PackExt ext) { String b = (dot < 0) ? p : p.substring(0, dot); return new File(packFile.getParentFile(), b + '.' + ext.getExtension()); } + + private boolean hasExt(PackExt ext) { + return (extensions & ext.getBit()) != 0; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackExt.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackExt.java index cb33308c6..61a660930 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackExt.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackExt.java @@ -45,21 +45,52 @@ /** A pack file extension. */ public class PackExt { + private static volatile PackExt[] VALUES = new PackExt[] {}; /** A pack file extension. */ - public static final PackExt PACK = new PackExt("pack"); //$NON-NLS-1$ + public static final PackExt PACK = newPackExt("pack"); //$NON-NLS-1$ /** A pack index file extension. */ - public static final PackExt INDEX = new PackExt("idx"); //$NON-NLS-1$ + public static final PackExt INDEX = newPackExt("idx"); //$NON-NLS-1$ + + /** @return all of the PackExt values. */ + public static PackExt[] values() { + return VALUES; + } + + /** + * Returns a PackExt for the file extension and registers it in the values + * array. + * + * @param ext + * the file extension. + * @return the PackExt for the ext + */ + public synchronized static PackExt newPackExt(String ext) { + PackExt[] dst = new PackExt[VALUES.length + 1]; + for (int i = 0; i < VALUES.length; i++) { + PackExt packExt = VALUES[i]; + if (packExt.getExtension().equals(ext)) + return packExt; + dst[i] = packExt; + } + if (VALUES.length >= 32) + throw new IllegalStateException( + "maximum number of pack extensions exceeded"); //$NON-NLS-1$ + + PackExt value = new PackExt(ext, VALUES.length); + dst[VALUES.length] = value; + VALUES = dst; + return value; + } private final String ext; - /** - * @param ext - * the file extension. - */ - public PackExt(String ext) { + private final int pos; + + private PackExt(String ext, int pos) { this.ext = ext; + this.pos = pos; } /** @return the file extension. */ @@ -67,21 +98,19 @@ public String getExtension() { return ext; } - @Override - public boolean equals(Object obj) { - if (obj instanceof PackExt) { - return ((PackExt) obj).getExtension().equals(getExtension()); - } - return false; + /** @return the position of the extension in the values array. */ + public int getPosition() { + return pos; } - @Override - public int hashCode() { - return getExtension().hashCode(); + /** @return the bit mask of the extension e.g {@code 1 << getPosition()}. */ + public int getBit() { + return 1 << getPosition(); } @Override public String toString() { - return String.format("PackExt[%s]", getExtension()); //$NON-NLS-1$ + return String.format("PackExt[%s, bit=0x%s]", getExtension(), //$NON-NLS-1$ + Integer.toHexString(getBit())); } }