]> source.dussan.org Git - jgit.git/commitdiff
Cache refreshed loose ref dirs in SnapshottingRefDirectory 41/205141/6
authorNasser Grainawi <quic_nasserg@quicinc.com>
Fri, 23 Feb 2024 17:34:37 +0000 (09:34 -0800)
committerMatthias Sohn <matthias.sohn@sap.com>
Tue, 19 Mar 2024 21:42:02 +0000 (21:42 +0000)
Update SnapshottingRefDirectory to have a cache of dirs refreshed for
loose refs. This should help improve performance when 'after_open'
setting is used for 'trustLooseRefStat' as duplicate refreshes are
avoided when a snapshot of the ref database is used in a request scope.

Change-Id: I8f66e7cee572e477d29abe2d9db69e97bca3ee4c
Signed-off-by: Nasser Grainawi <quic_nasserg@quicinc.com>
Co-authored-by: Martin Fick <quic_mfick@quicinc.com>
Co-authored-by: Kaushik Lingarkar <quic_kaushikl@quicinc.com>
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/SnapshottingRefDirectory.java

index 46607f60d955458b2ec894df42cb11505dca164b..1dc5776e06c913d3056cf07fba7df83d4c41b48f 100644 (file)
@@ -16,15 +16,21 @@ import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.revwalk.RevWalk;
 
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Snapshotting write-through cache of a {@link RefDirectory}.
  * <p>
  * This is intended to be short-term write-through snapshot based cache used in
- * a request scope to avoid re-reading packed-refs on each read. A future
- * improvement could also snapshot loose refs.
+ * a request scope to avoid re-reading packed-refs on each read and to avoid
+ * refreshing paths to a loose ref that has already been refreshed.
  * <p>
  * Only use this class when concurrent writes from other requests (not using the
  * same instance of SnapshottingRefDirectory) generally need not be visible to
@@ -34,6 +40,7 @@ import java.util.List;
  */
 class SnapshottingRefDirectory extends RefDirectory {
        final RefDirectory refDb;
+       private final Set<File> refreshedLooseRefDirs = ConcurrentHashMap.newKeySet();
 
        private volatile boolean isValid;
 
@@ -66,6 +73,22 @@ class SnapshottingRefDirectory extends RefDirectory {
                return packedRefs.get();
        }
 
+       @Override
+       void refreshPathToLooseRef(Path refPath) {
+               for (int i = 1; i < refPath.getNameCount(); i++) {
+                       File dir = fileFor(refPath.subpath(0, i).toString());
+                       if (!refreshedLooseRefDirs.contains(dir)) {
+                               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
+                               } finally {
+                                       refreshedLooseRefDirs.add(dir);
+                               }
+                       }
+               }
+       }
+
        @Override
        void delete(RefDirectoryUpdate update) throws IOException {
                refreshSnapshot();
@@ -107,6 +130,7 @@ class SnapshottingRefDirectory extends RefDirectory {
        }
 
        synchronized void invalidateSnapshot() {
+               refreshedLooseRefDirs.clear();
                isValid = false;
        }