Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Sohn2021-06-26 14:37:59 +0000
committerMatthias Sohn2021-06-26 14:37:59 +0000
commitd46af8c69d598b63301900758e49b6b260168c16 (patch)
tree3e7fe3fc41152817e21dab0c7c4b43abc3a282cf /org.eclipse.jgit/src/org
parent6976a30f443ece4815a977b0a5a897c0236018f7 (diff)
parent8bd0161c83c54911be59bbfdee00eeb9c1f6adb9 (diff)
downloadjgit-d46af8c69d598b63301900758e49b6b260168c16.tar.gz
jgit-d46af8c69d598b63301900758e49b6b260168c16.tar.xz
jgit-d46af8c69d598b63301900758e49b6b260168c16.zip
Merge branch 'stable-5.12'
* stable-5.12: Retry loose object read upon "Stale file handle" exception Ignore missing javadoc in test bundles Change-Id: I67c613c066a3252f9b0d0a3dcc026b57e10bfe1d
Diffstat (limited to 'org.eclipse.jgit/src/org')
-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/LooseObjects.java82
2 files changed, 70 insertions, 13 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 46d96df9c3..8622e0a1a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -470,6 +470,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/LooseObjects.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
index e7cb285c34..33621a1e9f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
@@ -17,8 +17,10 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.StandardCopyOption;
+import java.text.MessageFormat;
import java.util.Set;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.FileObjectDatabase.InsertLooseObjectResult;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
@@ -40,6 +42,12 @@ class LooseObjects {
private static final Logger LOG = LoggerFactory
.getLogger(LooseObjects.class);
+ /**
+ * Maximum number of attempts to read a loose object for which a stale file
+ * handle exception is thrown
+ */
+ private final static int MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS = 5;
+
private final File directory;
private final UnpackedObjectCache unpackedObjectCache;
@@ -69,7 +77,7 @@ class LooseObjects {
}
void close() {
- unpackedObjectCache.clear();
+ unpackedObjectCache().clear();
}
/** {@inheritDoc} */
@@ -79,7 +87,7 @@ class LooseObjects {
}
boolean hasCached(AnyObjectId id) {
- return unpackedObjectCache.isUnpacked(id);
+ return unpackedObjectCache().isUnpacked(id);
}
/**
@@ -133,29 +141,77 @@ class LooseObjects {
}
ObjectLoader open(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;
+ }
+
long getSize(WindowCursor curs, AnyObjectId id) 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;
}
}
@@ -207,7 +263,7 @@ class LooseObjects {
Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst),
StandardCopyOption.ATOMIC_MOVE);
dst.setReadOnly();
- unpackedObjectCache.add(id);
+ unpackedObjectCache().add(id);
return InsertLooseObjectResult.INSERTED;
}

Back to the top