diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2021-06-25 22:23:47 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2021-06-25 22:23:47 +0200 |
commit | bbb1c7f6451cef69bd98191bfdf4db04da003ecf (patch) | |
tree | 7a143bb41919ce49b95c05486eeda5547363114b /org.eclipse.jgit/src | |
parent | e2dc4b9c6445f91da73437e2ccc9729d86f776e2 (diff) | |
parent | 24d6d605388c82201092cf1699b51095299380a2 (diff) | |
download | jgit-bbb1c7f6451cef69bd98191bfdf4db04da003ecf.tar.gz jgit-bbb1c7f6451cef69bd98191bfdf4db04da003ecf.zip |
Merge branch 'stable-5.9' into stable-5.10
* stable-5.9:
Retry loose object read upon "Stale file handle" exception
Ignore missing javadoc in test bundles
Change-Id: I56fc2c47193a891285a705d44b3507f23982dc8a
Diffstat (limited to 'org.eclipse.jgit/src')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java | 1 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java | 84 |
2 files changed, 69 insertions, 16 deletions
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 d12a243a8e..66d54c0517 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -447,6 +447,7 @@ public class JGitText extends TranslationBundle { /***/ public String logLargerFiletimeDiff; /***/ public String logSmallerFiletime; /***/ public String logXDGConfigHomeInvalid; + /***/ public String looseObjectHandleIsStale; /***/ public String maxCountMustBeNonNegative; /***/ public String mergeConflictOnNonNoteEntries; /***/ public String mergeConflictOnNotes; 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 d32182864a..106cddd432 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 @@ -85,6 +85,10 @@ public class ObjectDirectory extends FileObjectDatabase { /** Maximum number of candidates offered as resolutions of abbreviation. */ private static final int RESOLVE_ABBREV_LIMIT = 256; + /** Maximum number of attempts to read a loose object for which a stale file + * handle exception is thrown */ + final static int MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS = 5; + private final AlternateHandle handle = new AlternateHandle(this); private final Config config; @@ -212,7 +216,7 @@ public class ObjectDirectory extends FileObjectDatabase { /** {@inheritDoc} */ @Override public void close() { - unpackedObjectCache.clear(); + unpackedObjectCache().clear(); final PackList packs = packList.get(); if (packs != NO_PACKS && packList.compareAndSet(packs, NO_PACKS)) { @@ -277,7 +281,7 @@ public class ObjectDirectory extends FileObjectDatabase { /** {@inheritDoc} */ @Override public boolean has(AnyObjectId objectId) { - return unpackedObjectCache.isUnpacked(objectId) + return unpackedObjectCache().isUnpacked(objectId) || hasPackedInSelfOrAlternate(objectId, null) || hasLooseInSelfOrAlternate(objectId, null); } @@ -395,7 +399,7 @@ public class ObjectDirectory extends FileObjectDatabase { @Override ObjectLoader openObject(WindowCursor curs, AnyObjectId objectId) throws IOException { - if (unpackedObjectCache.isUnpacked(objectId)) { + if (unpackedObjectCache().isUnpacked(objectId)) { ObjectLoader ldr = openLooseObject(curs, objectId); if (ldr != null) { return ldr; @@ -473,23 +477,71 @@ public class ObjectDirectory extends FileObjectDatabase { @Override ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id) throws IOException { - File path = fileFor(id); + int readAttempts = 0; + while (readAttempts < MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS) { + readAttempts++; + File path = fileFor(id); + try { + return getObjectLoader(curs, path, id); + } catch (FileNotFoundException noFile) { + if (path.exists()) { + throw noFile; + } + break; + } catch (IOException e) { + if (!FileUtils.isStaleFileHandleInCausalChain(e)) { + throw e; + } + if (LOG.isDebugEnabled()) { + LOG.debug(MessageFormat.format( + JGitText.get().looseObjectHandleIsStale, id.name(), + Integer.valueOf(readAttempts), Integer.valueOf( + MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS))); + } + } + } + unpackedObjectCache().remove(id); + return null; + } + + /** + * Provides a loader for an objectId + * + * @param curs + * cursor on the database + * @param path + * the path of the loose object + * @param id + * the object id + * @return a loader for the loose file object + * @throws IOException + * when file does not exist or it could not be opened + */ + ObjectLoader getObjectLoader(WindowCursor curs, File path, AnyObjectId id) + throws IOException { try (FileInputStream in = new FileInputStream(path)) { - unpackedObjectCache.add(id); + unpackedObjectCache().add(id); return UnpackedObject.open(in, path, id, curs); - } catch (FileNotFoundException noFile) { - if (path.exists()) { - throw noFile; - } - unpackedObjectCache.remove(id); - return null; } } + /** + * <p> + * Getter for the field <code>unpackedObjectCache</code>. + * </p> + * This accessor is particularly useful to allow mocking of this class for + * testing purposes. + * + * @return the cache of the objects currently unpacked. + */ + UnpackedObjectCache unpackedObjectCache() { + return unpackedObjectCache; + } + @Override long getObjectSize(WindowCursor curs, AnyObjectId id) throws IOException { - if (unpackedObjectCache.isUnpacked(id)) { + if (unpackedObjectCache().isUnpacked(id)) { long len = getLooseObjectSize(curs, id); if (0 <= len) { return len; @@ -567,13 +619,13 @@ public class ObjectDirectory extends FileObjectDatabase { throws IOException { File f = fileFor(id); try (FileInputStream in = new FileInputStream(f)) { - unpackedObjectCache.add(id); + unpackedObjectCache().add(id); return UnpackedObject.getSize(in, id, curs); } catch (FileNotFoundException noFile) { if (f.exists()) { throw noFile; } - unpackedObjectCache.remove(id); + unpackedObjectCache().remove(id); return -1; } } @@ -667,7 +719,7 @@ public class ObjectDirectory extends FileObjectDatabase { boolean createDuplicate) throws IOException { // If the object is already in the repository, remove temporary file. // - if (unpackedObjectCache.isUnpacked(id)) { + if (unpackedObjectCache().isUnpacked(id)) { FileUtils.delete(tmp, FileUtils.RETRY); return InsertLooseObjectResult.EXISTS_LOOSE; } @@ -723,7 +775,7 @@ public class ObjectDirectory extends FileObjectDatabase { Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst), StandardCopyOption.ATOMIC_MOVE); dst.setReadOnly(); - unpackedObjectCache.add(id); + unpackedObjectCache().add(id); return InsertLooseObjectResult.INSERTED; } |