diff options
author | Kaushik Lingarkar <quic_kaushikl@quicinc.com> | 2024-02-22 15:29:48 -0800 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2024-03-05 00:17:47 +0100 |
commit | 21f7fdff79ce2863aba40bc2b676059884a3a8e9 (patch) | |
tree | baab6bd9cfe000d524fd4fdb9dc18994c1a66c79 /org.eclipse.jgit | |
parent | 1a654d3db6e5bd667dd5218a55084545538519a2 (diff) | |
download | jgit-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')
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; |