diff options
author | Shawn Pearce <spearce@spearce.org> | 2014-02-03 18:05:39 -0500 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org <gerrit@eclipse.org> | 2014-02-03 18:05:39 -0500 |
commit | 8ae6295007f5247ba90e67bc86875cfecd082756 (patch) | |
tree | 4f346050038e65f0342d36aeff74f6cecf69f235 /org.eclipse.jgit/src | |
parent | 5404e70dc64201786cd6a21efb41310912860122 (diff) | |
parent | d1aacc415a3336144e4b3b55c402a025e920a031 (diff) | |
download | jgit-8ae6295007f5247ba90e67bc86875cfecd082756.tar.gz jgit-8ae6295007f5247ba90e67bc86875cfecd082756.zip |
Merge "Fix MissingObjectException race in ObjectDirectory"
Diffstat (limited to 'org.eclipse.jgit/src')
5 files changed, 290 insertions, 394 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java index eb4f01caca..a81d8ec0e9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java @@ -72,11 +72,11 @@ class CachedObjectDirectory extends FileObjectDatabase { * The set that contains unpacked objects identifiers, it is created when * the cached instance is created. */ - private final ObjectIdOwnerMap<UnpackedObjectId> unpackedObjects = new ObjectIdOwnerMap<UnpackedObjectId>(); + private ObjectIdOwnerMap<UnpackedObjectId> unpackedObjects; private final ObjectDirectory wrapped; - private AlternateHandle[] alts; + private CachedObjectDirectory[] alts; /** * The constructor @@ -86,11 +86,15 @@ class CachedObjectDirectory extends FileObjectDatabase { */ CachedObjectDirectory(ObjectDirectory wrapped) { this.wrapped = wrapped; + this.unpackedObjects = scanLoose(); + } + private ObjectIdOwnerMap<UnpackedObjectId> scanLoose() { + ObjectIdOwnerMap<UnpackedObjectId> m = new ObjectIdOwnerMap<UnpackedObjectId>(); File objects = wrapped.getDirectory(); String[] fanout = objects.list(); if (fanout == null) - fanout = new String[0]; + return m; for (String d : fanout) { if (d.length() != 2) continue; @@ -102,12 +106,13 @@ class CachedObjectDirectory extends FileObjectDatabase { continue; try { ObjectId id = ObjectId.fromString(d + e); - unpackedObjects.add(new UnpackedObjectId(id)); + m.add(new UnpackedObjectId(id)); } catch (IllegalArgumentException notAnObject) { // ignoring the file that does not represent loose object } } } + return m; } @Override @@ -121,13 +126,13 @@ class CachedObjectDirectory extends FileObjectDatabase { } @Override - FileObjectDatabase newCachedFileObjectDatabase() { - return this; + File getDirectory() { + return wrapped.getDirectory(); } @Override - File getDirectory() { - return wrapped.getDirectory(); + File fileFor(AnyObjectId id) { + return wrapped.fileFor(id); } @Override @@ -145,15 +150,12 @@ class CachedObjectDirectory extends FileObjectDatabase { return wrapped.getShallowCommits(); } - @Override - AlternateHandle[] myAlternates() { + private CachedObjectDirectory[] myAlternates() { if (alts == null) { - AlternateHandle[] src = wrapped.myAlternates(); - alts = new AlternateHandle[src.length]; - for (int i = 0; i < alts.length; i++) { - FileObjectDatabase s = src[i].db; - alts[i] = new AlternateHandle(s.newCachedFileObjectDatabase()); - } + ObjectDirectory.AlternateHandle[] src = wrapped.myAlternates(); + alts = new CachedObjectDirectory[src.length]; + for (int i = 0; i < alts.length; i++) + alts[i] = src[i].db.newCachedFileObjectDatabase(); } return alts; } @@ -170,61 +172,53 @@ class CachedObjectDirectory extends FileObjectDatabase { } @Override - boolean tryAgain1() { - return wrapped.tryAgain1(); - } - - @Override - public boolean has(final AnyObjectId objectId) { - return hasObjectImpl1(objectId); - } - - @Override - boolean hasObject1(AnyObjectId objectId) { - return unpackedObjects.contains(objectId) - || wrapped.hasObject1(objectId); + public boolean has(final AnyObjectId objectId) throws IOException { + if (unpackedObjects.contains(objectId)) + return true; + if (wrapped.hasPackedObject(objectId)) + return true; + for (CachedObjectDirectory alt : myAlternates()) { + if (alt.has(objectId)) + return true; + } + return false; } @Override ObjectLoader openObject(final WindowCursor curs, final AnyObjectId objectId) throws IOException { - return openObjectImpl1(curs, objectId); - } - - @Override - ObjectLoader openObject1(WindowCursor curs, AnyObjectId objectId) - throws IOException { - if (unpackedObjects.contains(objectId)) - return wrapped.openObject2(curs, objectId.name(), objectId); - return wrapped.openObject1(curs, objectId); - } - - @Override - boolean hasObject2(String objectId) { - return unpackedObjects.contains(ObjectId.fromString(objectId)); - } - - @Override - ObjectLoader openObject2(WindowCursor curs, String objectName, - AnyObjectId objectId) throws IOException { - if (unpackedObjects.contains(objectId)) - return wrapped.openObject2(curs, objectName, objectId); + ObjectLoader ldr = openLooseObject(curs, objectId); + if (ldr != null) + return ldr; + ldr = wrapped.openPackedObject(curs, objectId); + if (ldr != null) + return ldr; + for (CachedObjectDirectory alt : myAlternates()) { + ldr = alt.openObject(curs, objectId); + if (ldr != null) + return ldr; + } return null; } @Override - long getObjectSize1(WindowCursor curs, AnyObjectId objectId) throws IOException { - if (unpackedObjects.contains(objectId)) - return wrapped.getObjectSize2(curs, objectId.name(), objectId); - return wrapped.getObjectSize1(curs, objectId); + long getObjectSize(WindowCursor curs, AnyObjectId objectId) + throws IOException { + // Object size is unlikely to be requested from contexts using + // this type. Don't bother trying to accelerate the lookup. + return wrapped.getObjectSize(curs, objectId); } @Override - long getObjectSize2(WindowCursor curs, String objectName, AnyObjectId objectId) + ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id) throws IOException { - if (unpackedObjects.contains(objectId)) - return wrapped.getObjectSize2(curs, objectName, objectId); - return -1; + if (unpackedObjects.contains(id)) { + ObjectLoader ldr = wrapped.openLooseObject(curs, id); + if (ldr != null) + return ldr; + unpackedObjects = scanLoose(); + } + return null; } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java index ba45334bd3..3afc050ba6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileObjectDatabase.java @@ -74,61 +74,6 @@ abstract class FileObjectDatabase extends ObjectDatabase { return new ObjectDirectoryInserter(this, getConfig()); } - /** - * Does the requested object exist in this database? - * <p> - * Alternates (if present) are searched automatically. - * - * @param objectId - * identity of the object to test for existence of. - * @return true if the specified object is stored in this database, or any - * of the alternate databases. - */ - public boolean has(final AnyObjectId objectId) { - return hasObjectImpl1(objectId) || hasObjectImpl2(objectId.name()); - } - - /** - * Compute the location of a loose object file. - * - * @param objectId - * identity of the loose object to map to the directory. - * @return location of the object, if it were to exist as a loose object. - */ - File fileFor(final AnyObjectId objectId) { - return fileFor(objectId.name()); - } - - File fileFor(final String objectName) { - final String d = objectName.substring(0, 2); - final String f = objectName.substring(2); - return new File(new File(getDirectory(), d), f); - } - - final boolean hasObjectImpl1(final AnyObjectId objectId) { - if (hasObject1(objectId)) - return true; - - for (final AlternateHandle alt : myAlternates()) { - if (alt.db.hasObjectImpl1(objectId)) - return true; - } - - return tryAgain1() && hasObject1(objectId); - } - - final boolean hasObjectImpl2(final String objectId) { - if (hasObject2(objectId)) - return true; - - for (final AlternateHandle alt : myAlternates()) { - if (alt.db.hasObjectImpl2(objectId)) - return true; - } - - return false; - } - abstract void resolve(Set<ObjectId> matches, AbbreviatedObjectId id) throws IOException; @@ -138,180 +83,26 @@ abstract class FileObjectDatabase extends ObjectDatabase { abstract Set<ObjectId> getShallowCommits() throws IOException; - /** - * Open an object from this database. - * <p> - * Alternates (if present) are searched automatically. - * - * @param curs - * temporary working space associated with the calling thread. - * @param objectId - * identity of the object to open. - * @return a {@link ObjectLoader} for accessing the data of the named - * object, or null if the object does not exist. - * @throws IOException - */ - ObjectLoader openObject(final WindowCursor curs, final AnyObjectId objectId) - throws IOException { - ObjectLoader ldr; - - ldr = openObjectImpl1(curs, objectId); - if (ldr != null) - return ldr; - - ldr = openObjectImpl2(curs, objectId.name(), objectId); - if (ldr != null) - return ldr; - - return null; - } - - final ObjectLoader openObjectImpl1(final WindowCursor curs, - final AnyObjectId objectId) throws IOException { - ObjectLoader ldr; - - ldr = openObject1(curs, objectId); - if (ldr != null) - return ldr; - - for (final AlternateHandle alt : myAlternates()) { - ldr = alt.db.openObjectImpl1(curs, objectId); - if (ldr != null) - return ldr; - } - - if (tryAgain1()) { - ldr = openObject1(curs, objectId); - if (ldr != null) - return ldr; - } - - return null; - } - - final ObjectLoader openObjectImpl2(final WindowCursor curs, - final String objectName, final AnyObjectId objectId) - throws IOException { - ObjectLoader ldr; - - ldr = openObject2(curs, objectName, objectId); - if (ldr != null) - return ldr; - - for (final AlternateHandle alt : myAlternates()) { - ldr = alt.db.openObjectImpl2(curs, objectName, objectId); - if (ldr != null) - return ldr; - } - - return null; - } - - long getObjectSize(WindowCursor curs, AnyObjectId objectId) - throws IOException { - long sz = getObjectSizeImpl1(curs, objectId); - if (0 <= sz) - return sz; - return getObjectSizeImpl2(curs, objectId.name(), objectId); - } - - final long getObjectSizeImpl1(final WindowCursor curs, - final AnyObjectId objectId) throws IOException { - long sz; - - sz = getObjectSize1(curs, objectId); - if (0 <= sz) - return sz; - - for (final AlternateHandle alt : myAlternates()) { - sz = alt.db.getObjectSizeImpl1(curs, objectId); - if (0 <= sz) - return sz; - } - - if (tryAgain1()) { - sz = getObjectSize1(curs, objectId); - if (0 <= sz) - return sz; - } - - return -1; - } - - final long getObjectSizeImpl2(final WindowCursor curs, - final String objectName, final AnyObjectId objectId) - throws IOException { - long sz; - - sz = getObjectSize2(curs, objectName, objectId); - if (0 <= sz) - return sz; - - for (final AlternateHandle alt : myAlternates()) { - sz = alt.db.getObjectSizeImpl2(curs, objectName, objectId); - if (0 <= sz) - return sz; - } - - return -1; - } - abstract void selectObjectRepresentation(PackWriter packer, ObjectToPack otp, WindowCursor curs) throws IOException; abstract File getDirectory(); - abstract AlternateHandle[] myAlternates(); + abstract File fileFor(AnyObjectId id); - abstract boolean tryAgain1(); - - abstract boolean hasObject1(AnyObjectId objectId); - - abstract boolean hasObject2(String objectId); - - abstract ObjectLoader openObject1(WindowCursor curs, AnyObjectId objectId) + abstract ObjectLoader openObject(WindowCursor curs, AnyObjectId objectId) throws IOException; - abstract ObjectLoader openObject2(WindowCursor curs, String objectName, - AnyObjectId objectId) throws IOException; - - abstract long getObjectSize1(WindowCursor curs, AnyObjectId objectId) + abstract long getObjectSize(WindowCursor curs, AnyObjectId objectId) throws IOException; - abstract long getObjectSize2(WindowCursor curs, String objectName, - AnyObjectId objectId) throws IOException; + abstract ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id) + throws IOException; abstract InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id, boolean createDuplicate) throws IOException; abstract PackFile openPack(File pack) throws IOException; - abstract FileObjectDatabase newCachedFileObjectDatabase(); - abstract Collection<PackFile> getPacks(); - - static class AlternateHandle { - final FileObjectDatabase db; - - AlternateHandle(FileObjectDatabase db) { - this.db = db; - } - - void close() { - db.close(); - } - } - - static class AlternateRepository extends AlternateHandle { - final FileRepository repository; - - AlternateRepository(FileRepository r) { - super(r.getObjectDatabase()); - repository = r; - } - - void close() { - repository.close(); - } - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index 33026aad72..148781dfe9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java @@ -59,8 +59,8 @@ import org.eclipse.jgit.events.ConfigChangedEvent; import org.eclipse.jgit.events.ConfigChangedListener; import org.eclipse.jgit.events.IndexChangedEvent; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.internal.storage.file.FileObjectDatabase.AlternateHandle; -import org.eclipse.jgit.internal.storage.file.FileObjectDatabase.AlternateRepository; +import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateHandle; +import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateRepository; import org.eclipse.jgit.lib.BaseRepositoryBuilder; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; @@ -368,7 +368,7 @@ public class FileRepository extends Repository { */ public Set<ObjectId> getAdditionalHaves() { HashSet<ObjectId> r = new HashSet<ObjectId>(); - for (AlternateHandle d : objectDatabase. myAlternates()) { + for (AlternateHandle d : objectDatabase.myAlternates()) { if (d instanceof AlternateRepository) { Repository repo; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedDeltaObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedDeltaObject.java index f6bbae2b91..18f15b068c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedDeltaObject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LargePackedDeltaObject.java @@ -173,7 +173,7 @@ class LargePackedDeltaObject extends ObjectLoader { // final ObjectId myId = getObjectId(); final WindowCursor wc = new WindowCursor(db); - ObjectLoader ldr = db.openObject2(wc, myId.name(), myId); + ObjectLoader ldr = db.openLooseObject(wc, myId); if (ldr != null) return ldr.openStream(); 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 3b6901bd51..1795683aa8 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 @@ -200,32 +200,20 @@ public class ObjectDirectory extends FileObjectDatabase { unpackedObjectCache.clear(); final PackList packs = packList.get(); - packList.set(NO_PACKS); - for (final PackFile p : packs.packs) - p.close(); + if (packs != NO_PACKS && packList.compareAndSet(packs, NO_PACKS)) { + for (PackFile p : packs.packs) + p.close(); + } // Fully close all loaded alternates and clear the alternate list. AlternateHandle[] alt = alternates.get(); - if (alt != null) { - alternates.set(null); + if (alt != null && alternates.compareAndSet(alt, null)) { for(final AlternateHandle od : alt) od.close(); } } /** - * Compute the location of a loose object file. - * - * @param objectId - * identity of the loose object to map to the directory. - * @return location of the object, if it were to exist as a loose object. - */ - @Override - public File fileFor(final AnyObjectId objectId) { - return super.fileFor(objectId); - } - - /** * @return unmodifiable collection of all known pack files local to this * directory. Most recent packs are presented first. Packs most * likely to contain more recent objects appear before packs @@ -277,37 +265,64 @@ public class ObjectDirectory extends FileObjectDatabase { @Override public String toString() { - return "ObjectDirectory[" + getDirectory() + "]"; //$NON-NLS-1$ + return "ObjectDirectory[" + getDirectory() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public boolean has(AnyObjectId objectId) { + return unpackedObjectCache.isUnpacked(objectId) + || hasPackedInSelfOrAlternate(objectId) + || hasLooseInSelfOrAlternate(objectId); } - boolean hasObject1(final AnyObjectId objectId) { - if (unpackedObjectCache.isUnpacked(objectId)) + private boolean hasPackedInSelfOrAlternate(AnyObjectId objectId) { + if (hasPackedObject(objectId)) return true; - for (final PackFile p : packList.get().packs) { - try { - if (p.hasObject(objectId)) { - return true; + for (AlternateHandle alt : myAlternates()) { + if (alt.db.hasPackedInSelfOrAlternate(objectId)) + return true; + } + return false; + } + + private boolean hasLooseInSelfOrAlternate(AnyObjectId objectId) { + if (fileFor(objectId).exists()) + return true; + for (AlternateHandle alt : myAlternates()) { + if (alt.db.hasLooseInSelfOrAlternate(objectId)) + return true; + } + return false; + } + + boolean hasPackedObject(AnyObjectId objectId) { + PackList pList; + do { + pList = packList.get(); + for (PackFile p : pList.packs) { + try { + if (p.hasObject(objectId)) + return true; + } catch (IOException e) { + // 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. + removePack(p); } - } catch (IOException e) { - // 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. - // - removePack(p); - continue; } - } + } while (searchPacksAgain(pList)); return false; } + @Override void resolve(Set<ObjectId> matches, AbbreviatedObjectId id) throws IOException { // Go through the packs once. If we didn't find any resolutions // scan for new packs and check once more. - // int oldSize = matches.size(); - PackList pList = packList.get(); - for (;;) { + PackList pList; + do { + pList = packList.get(); for (PackFile p : pList.packs) { try { p.resolve(matches, id, RESOLVE_ABBREV_LIMIT); @@ -319,15 +334,7 @@ public class ObjectDirectory extends FileObjectDatabase { if (matches.size() > RESOLVE_ABBREV_LIMIT) return; } - if (matches.size() == oldSize) { - PackList nList = scanPacks(pList); - if (nList == pList || nList.packs.length == 0) - break; - pList = nList; - continue; - } - break; - } + } while (matches.size() == oldSize && searchPacksAgain(pList)); String fanOut = id.name().substring(0, 2); String[] entries = new File(getDirectory(), fanOut).list(); @@ -354,74 +361,164 @@ public class ObjectDirectory extends FileObjectDatabase { } } - ObjectLoader openObject1(final WindowCursor curs, - final AnyObjectId objectId) throws IOException { + @Override + ObjectLoader openObject(WindowCursor curs, AnyObjectId objectId) + throws IOException { if (unpackedObjectCache.isUnpacked(objectId)) { - ObjectLoader ldr = openObject2(curs, objectId.name(), objectId); + ObjectLoader ldr = openLooseObject(curs, objectId); if (ldr != null) return ldr; - else - unpackedObjectCache.remove(objectId); } + ObjectLoader ldr = openPackedFromSelfOrAlternate(curs, objectId); + if (ldr != null) + return ldr; + return openLooseFromSelfOrAlternate(curs, objectId); + } - PackList pList = packList.get(); - SEARCH: for (;;) { - for (final PackFile p : pList.packs) { - try { - final ObjectLoader ldr = p.get(curs, objectId); - if (ldr != null) - return ldr; - } catch (PackMismatchException e) { - // Pack was modified; refresh the entire pack list. - // - pList = scanPacks(pList); - continue SEARCH; - } catch (IOException e) { - // Assume the pack is corrupted. - // - removePack(p); + private ObjectLoader openPackedFromSelfOrAlternate(WindowCursor curs, + AnyObjectId objectId) { + ObjectLoader ldr = openPackedObject(curs, objectId); + if (ldr != null) + return ldr; + for (AlternateHandle alt : myAlternates()) { + ldr = alt.db.openPackedFromSelfOrAlternate(curs, objectId); + if (ldr != null) + return ldr; + } + return null; + } + + private ObjectLoader openLooseFromSelfOrAlternate(WindowCursor curs, + AnyObjectId objectId) throws IOException { + ObjectLoader ldr = openLooseObject(curs, objectId); + if (ldr != null) + return ldr; + for (AlternateHandle alt : myAlternates()) { + ldr = alt.db.openLooseFromSelfOrAlternate(curs, objectId); + if (ldr != null) + return ldr; + } + return null; + } + + ObjectLoader openPackedObject(WindowCursor curs, AnyObjectId objectId) { + PackList pList; + do { + SEARCH: for (;;) { + pList = packList.get(); + for (PackFile p : pList.packs) { + try { + ObjectLoader ldr = p.get(curs, objectId); + if (ldr != null) + return ldr; + } catch (PackMismatchException e) { + // Pack was modified; refresh the entire pack list. + if (searchPacksAgain(pList)) + continue SEARCH; + } catch (IOException e) { + // Assume the pack is corrupted. + removePack(p); + } } + break SEARCH; } + } while (searchPacksAgain(pList)); + return null; + } + + ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id) + throws IOException { + try { + File path = fileFor(id); + FileInputStream in = new FileInputStream(path); + try { + unpackedObjectCache.add(id); + return UnpackedObject.open(in, path, id, curs); + } finally { + in.close(); + } + } catch (FileNotFoundException noFile) { + unpackedObjectCache.remove(id); return null; } } - long getObjectSize1(final WindowCursor curs, final AnyObjectId objectId) + long getObjectSize(WindowCursor curs, AnyObjectId id) throws IOException { - PackList pList = packList.get(); - SEARCH: for (;;) { - for (final PackFile p : pList.packs) { - try { - long sz = p.getObjectSize(curs, objectId); - if (0 <= sz) - return sz; - } catch (PackMismatchException e) { - // Pack was modified; refresh the entire pack list. - // - pList = scanPacks(pList); - continue SEARCH; - } catch (IOException e) { - // Assume the pack is corrupted. - // - removePack(p); + if (unpackedObjectCache.isUnpacked(id)) { + long len = getLooseObjectSize(curs, id); + if (0 <= len) + return len; + } + long len = getPackedSizeFromSelfOrAlternate(curs, id); + if (0 <= len) + return len; + return getLooseSizeFromSelfOrAlternate(curs, id); + } + + private long getPackedSizeFromSelfOrAlternate(WindowCursor curs, + AnyObjectId id) { + long len = getPackedObjectSize(curs, id); + if (0 <= len) + return len; + for (AlternateHandle alt : myAlternates()) { + len = alt.db.getPackedSizeFromSelfOrAlternate(curs, id); + if (0 <= len) + return len; + } + return -1; + } + + private long getLooseSizeFromSelfOrAlternate(WindowCursor curs, + AnyObjectId id) throws IOException { + long len = getLooseObjectSize(curs, id); + if (0 <= len) + return len; + for (AlternateHandle alt : myAlternates()) { + len = alt.db.getLooseSizeFromSelfOrAlternate(curs, id); + if (0 <= len) + return len; + } + return -1; + } + + private long getPackedObjectSize(WindowCursor curs, AnyObjectId id) { + PackList pList; + do { + SEARCH: for (;;) { + pList = packList.get(); + for (PackFile p : pList.packs) { + try { + long len = p.getObjectSize(curs, id); + if (0 <= len) + return len; + } catch (PackMismatchException e) { + // Pack was modified; refresh the entire pack list. + if (searchPacksAgain(pList)) + continue SEARCH; + } catch (IOException e) { + // Assume the pack is corrupted. + removePack(p); + } } + break SEARCH; } - return -1; - } + } while (searchPacksAgain(pList)); + return -1; } - @Override - long getObjectSize2(WindowCursor curs, String objectName, - AnyObjectId objectId) throws IOException { + private long getLooseObjectSize(WindowCursor curs, AnyObjectId id) + throws IOException { try { - File path = fileFor(objectName); - FileInputStream in = new FileInputStream(path); + FileInputStream in = new FileInputStream(fileFor(id)); try { - return UnpackedObject.getSize(in, objectId, curs); + unpackedObjectCache.add(id); + return UnpackedObject.getSize(in, id, curs); } finally { in.close(); } } catch (FileNotFoundException noFile) { + unpackedObjectCache.remove(id); return -1; } } @@ -454,28 +551,6 @@ public class ObjectDirectory extends FileObjectDatabase { h.db.selectObjectRepresentation(packer, otp, curs); } - boolean hasObject2(final String objectName) { - return fileFor(objectName).exists(); - } - - ObjectLoader openObject2(final WindowCursor curs, - final String objectName, final AnyObjectId objectId) - throws IOException { - try { - File path = fileFor(objectName); - FileInputStream in = new FileInputStream(path); - try { - unpackedObjectCache.add(objectId); - return UnpackedObject.open(in, path, objectId, curs); - } finally { - in.close(); - } - } catch (FileNotFoundException noFile) { - unpackedObjectCache.remove(objectId); - return null; - } - } - @Override InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id, boolean createDuplicate) throws IOException { @@ -530,11 +605,8 @@ public class ObjectDirectory extends FileObjectDatabase { return InsertLooseObjectResult.FAILURE; } - boolean tryAgain1() { - final PackList old = packList.get(); - if (old.snapshot.isModified(packDirectory)) - return old != scanPacks(old); - return false; + private boolean searchPacksAgain(PackList old) { + return old.snapshot.isModified(packDirectory) && old != scanPacks(old); } Config getConfig() { @@ -794,6 +866,20 @@ public class ObjectDirectory extends FileObjectDatabase { return new AlternateHandle(db); } + /** + * Compute the location of a loose object file. + * + * @param objectId + * identity of the loose object to map to the directory. + * @return location of the object, if it were to exist as a loose object. + */ + public File fileFor(AnyObjectId objectId) { + String n = objectId.name(); + String d = n.substring(0, 2); + String f = n.substring(2); + return new File(new File(getDirectory(), d), f); + } + private static final class PackList { /** State just before reading the pack directory. */ final FileSnapshot snapshot; @@ -807,12 +893,37 @@ public class ObjectDirectory extends FileObjectDatabase { } } + static class AlternateHandle { + final ObjectDirectory db; + + AlternateHandle(ObjectDirectory db) { + this.db = db; + } + + void close() { + db.close(); + } + } + + static class AlternateRepository extends AlternateHandle { + final FileRepository repository; + + AlternateRepository(FileRepository r) { + super(r.getObjectDatabase()); + repository = r; + } + + void close() { + repository.close(); + } + } + @Override public ObjectDatabase newCachedDatabase() { return newCachedFileObjectDatabase(); } - FileObjectDatabase newCachedFileObjectDatabase() { + CachedObjectDirectory newCachedFileObjectDatabase() { return new CachedObjectDirectory(this); } } |