aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorKaushik Lingarkar <quic_kaushikl@quicinc.com>2024-02-22 15:29:48 -0800
committerMatthias Sohn <matthias.sohn@sap.com>2024-03-05 00:17:47 +0100
commit21f7fdff79ce2863aba40bc2b676059884a3a8e9 (patch)
treebaab6bd9cfe000d524fd4fdb9dc18994c1a66c79 /org.eclipse.jgit
parent1a654d3db6e5bd667dd5218a55084545538519a2 (diff)
downloadjgit-21f7fdff79ce2863aba40bc2b676059884a3a8e9.tar.gz
jgit-21f7fdff79ce2863aba40bc2b676059884a3a8e9.zip
Introduce core.trustLooseRefStat config
With repositories on NFS, JGit can read an old value of a loose ref or miss the existence of a loose ref if file attributes of the loose ref or its parent directories are cached by NFS. Introduce a new config 'core.trustLooseRefStat' that will optionally refresh file attributes of the loose ref (at least on some NFS clients). Possible values for this new config are: * always: Trust loose ref file attributes (default) * after_open: Similar to 'always', but refresh the file attributes of the loose ref and its parent directories before trusting it The default is set to always trust the file attributes as after_open is known to degrade performance. In a subsequent change, SnapshottingRefDirectory will be updated to cache the directories that were refreshed to avoid duplicate work and thereby improve performance to some extent for the after_open setting. Change-Id: I9dfaeaf5307b2b51ce6ee4bfd9e0678786685fcf Signed-off-by: Kaushik Lingarkar <quic_kaushikl@quicinc.com>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java15
3 files changed, 59 insertions, 0 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index e27029798d..169dce1cc0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -37,6 +37,7 @@ import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.text.MessageFormat;
@@ -64,6 +65,7 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig.TrustPackedRefsStat;
+import org.eclipse.jgit.lib.CoreConfig.TrustLooseRefStat;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
@@ -181,6 +183,8 @@ public class RefDirectory extends RefDatabase {
private final TrustPackedRefsStat trustPackedRefsStat;
+ private final TrustLooseRefStat trustLooseRefStat;
+
RefDirectory(RefDirectory refDb) {
parent = refDb.parent;
gitDir = refDb.gitDir;
@@ -192,6 +196,7 @@ public class RefDirectory extends RefDatabase {
packedRefs.set(refDb.packedRefs.get());
trustFolderStat = refDb.trustFolderStat;
trustPackedRefsStat = refDb.trustPackedRefsStat;
+ trustLooseRefStat = refDb.trustLooseRefStat;
inProcessPackedRefsLock = refDb.inProcessPackedRefsLock;
}
@@ -213,6 +218,10 @@ public class RefDirectory extends RefDatabase {
.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT,
TrustPackedRefsStat.UNSET);
+ trustLooseRefStat = db.getConfig()
+ .getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_TRUST_LOOSE_REF_STAT,
+ TrustLooseRefStat.ALWAYS);
inProcessPackedRefsLock = new ReentrantLock(true);
}
@@ -1136,6 +1145,11 @@ public class RefDirectory extends RefDatabase {
LooseRef scanRef(LooseRef ref, String name) throws IOException {
final File path = fileFor(name);
+
+ if (trustLooseRefStat.equals(TrustLooseRefStat.AFTER_OPEN)) {
+ refreshPathToLooseRef(Paths.get(name));
+ }
+
FileSnapshot currentSnapshot = null;
if (ref != null) {
@@ -1221,6 +1235,29 @@ public class RefDirectory extends RefDatabase {
return new LooseUnpeeled(loose.snapshot, name, id);
}
+ /**
+ * Workaround for issues caused by NFS caching. Refresh directories starting
+ * from the repository root to a loose ref by opening an input stream. This
+ * refreshes file attributes of the loose ref (at least on some NFS
+ * clients).
+ *
+ * @param refPath
+ * path of a loose ref relative to the repository root
+ */
+ void refreshPathToLooseRef(Path refPath) {
+ for (int i = 1; i < refPath.getNameCount(); i++) {
+ File dir = fileFor(refPath.subpath(0, i).toString());
+ // Use Files.newInputStream(Path) as it is consistent with other
+ // code where a refresh is being done (see getPackedRefs()) and also
+ // it performs slightly better than Files.newDirectoryStream(Path)
+ try (InputStream stream = Files.newInputStream(dir.toPath())) {
+ // open the dir to refresh attributes (on some NFS clients)
+ } catch (IOException e) {
+ break; // loose ref may not exist
+ }
+ }
+ }
+
private static boolean isSymRef(byte[] buf, int n) {
if (n < 6)
return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 76b4d7195e..0edf3c5ad0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -972,6 +972,13 @@ public final class ConfigConstants {
public static final String CONFIG_KEY_TRUST_PACKED_REFS_STAT = "trustPackedRefsStat";
/**
+ * The "trustLooseRefStat" key
+ *
+ * @since 6.9
+ */
+ public static final String CONFIG_KEY_TRUST_LOOSE_REF_STAT = "trustLooseRefStat";
+
+ /**
* The "pack.preserveOldPacks" key
*
* @since 5.13.2
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
index 4de1801d04..9fa5d75a3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -144,6 +144,21 @@ public class CoreConfig {
UNSET
}
+ /**
+ * Permissible values for {@code core.trustLooseRefStat}.
+ *
+ * @since 6.9
+ */
+ public enum TrustLooseRefStat {
+
+ /** Trust file attributes of the loose ref. */
+ ALWAYS,
+
+ /** Open and close parent directories of the loose ref file until the
+ * repository root to refresh its file attributes and then trust it. */
+ AFTER_OPEN,
+ }
+
private final int compression;
private final int packIndexVersion;