summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2021-06-25 22:23:47 +0200
committerMatthias Sohn <matthias.sohn@sap.com>2021-06-25 22:23:47 +0200
commitbbb1c7f6451cef69bd98191bfdf4db04da003ecf (patch)
tree7a143bb41919ce49b95c05486eeda5547363114b /org.eclipse.jgit/src
parente2dc4b9c6445f91da73437e2ccc9729d86f776e2 (diff)
parent24d6d605388c82201092cf1699b51095299380a2 (diff)
downloadjgit-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.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java84
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;
}