Skip to content

Commit 4eb0802

Browse files
committed
Merge branch 'stable-6.10' into stable-7.0
* stable-6.10: Do not always refresh packed-refs during ref updates Change-Id: I4cdc1b80841481f83b64b800ef54da0b8ef8753a
2 parents 02c8c75 + d0a5242 commit 4eb0802

File tree

3 files changed

+28
-30
lines changed

3 files changed

+28
-30
lines changed

Documentation/config-options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ For details on native git options see also the official [git config documentatio
5555
| `core.supportsAtomicFileCreation` | `true` | ⃞ | Whether the filesystem supports atomic file creation. |
5656
| `core.symlinks` | Auto detect if filesystem supports symlinks| ✅ | If false, symbolic links are checked out as small plain files that contain the link text. |
5757
| `core.trustFolderStat` | `true` | ⃞ | Whether to trust the pack folder's, packed-refs file's and loose-objects folder's file attributes (Java equivalent of stat command on *nix). When looking for pack files, if `false` JGit will always scan the `.git/objects/pack` folder and if set to `true` it assumes that pack files are unchanged if the file attributes of the pack folder are unchanged. When getting the list of packed refs, if `false` JGit will always read the packed-refs file and if set to `true` it uses the file attributes of the packed-refs file and will only read it if a file attribute has changed. When looking for loose objects, if `false` and if a loose object is not found, JGit will open and close a stream to `.git/objects` folder (which can refresh its directory listing, at least on some NFS clients) and retry looking for that loose object. Setting this option to `false` can help to workaround caching issues on NFS, but reduces performance. |
58-
| `core.trustPackedRefsStat` | `unset` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the packed-refs file. If `never` JGit will ignore the file attributes of the packed-refs file and always read it. If `always` JGit will trust the file attributes of the packed-refs file and will only read it if a file attribute has changed. `after_open` behaves the same as `always`, except that the packed-refs file is opened and closed before its file attributes are considered. An open/close of the packed-refs file is known to refresh its file attributes, at least on some NFS clients. If `unset`, JGit will use the behavior described in `trustFolderStat`. |
58+
| `core.trustPackedRefsStat` | `unset` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the packed-refs file. If `never` JGit will ignore the file attributes of the packed-refs file and always read it. If `always` JGit will trust the file attributes of the packed-refs file and will only read it if a file attribute has changed. `after_open` behaves the same as `always`, except that the packed-refs file is opened and closed before its file attributes are considered. An open/close of the packed-refs file is known to refresh its file attributes, at least on some NFS clients. If `unset`, JGit will use the behavior described in `trustFolderStat`. Note: since 6.10.2, this setting applies during both ref reads and ref updates, but previously only applied during reads.|
5959
| `core.trustLooseRefStat` | `always` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the loose ref. If `always` JGit will trust the file attributes of the loose ref and its parent directories. `after_open` behaves similar to `always`, except that all parent directories of the loose ref up to the repository root are opened and closed before its file attributes are considered. An open/close of these parent directories is known to refresh the file attributes, at least on some NFS clients. |
6060
| `core.worktree` | Root directory of the working tree if it is not the parent directory of the `.git` directory | ✅ | The path to the root of the working tree. |
6161

org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public void execute(RevWalk walk, ProgressMonitor monitor,
172172
}
173173

174174
packedRefsLock = refdb.lockPackedRefsOrThrow();
175-
PackedRefList oldPackedList = refdb.refreshPackedRefs();
175+
PackedRefList oldPackedList = refdb.getLockedPackedRefs(packedRefsLock);
176176
RefList<Ref> newRefs = applyUpdates(walk, oldPackedList, pending);
177177
if (newRefs == null) {
178178
return;

org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ void delete(RefDirectoryUpdate update) throws IOException {
702702
PackedRefList packed = getPackedRefs();
703703
if (packed.contains(name)) {
704704
// Force update our packed-refs snapshot before writing
705-
packed = refreshPackedRefs();
705+
packed = getLockedPackedRefs(lck);
706706
int idx = packed.find(name);
707707
if (0 <= idx) {
708708
commitPackedRefs(lck, packed.remove(idx), packed, true);
@@ -770,7 +770,7 @@ private void pack(Collection<String> refs,
770770
try {
771771
LockFile lck = lockPackedRefsOrThrow();
772772
try {
773-
PackedRefList oldPacked = refreshPackedRefs();
773+
PackedRefList oldPacked = getLockedPackedRefs(lck);
774774
RefList<Ref> newPacked = oldPacked;
775775

776776
// Iterate over all refs to be packed
@@ -953,6 +953,15 @@ else if (0 <= (idx = packed.find(dst.getName())))
953953
}
954954

955955
PackedRefList getPackedRefs() throws IOException {
956+
return refreshPackedRefsIfNeeded();
957+
}
958+
959+
PackedRefList getLockedPackedRefs(LockFile packedRefsFileLock) throws IOException {
960+
packedRefsFileLock.requireLock();
961+
return refreshPackedRefsIfNeeded();
962+
}
963+
964+
PackedRefList refreshPackedRefsIfNeeded() throws IOException {
956965
PackedRefList curList = packedRefs.get();
957966
if (!curList.shouldRefresh()) {
958967
return curList;
@@ -967,23 +976,29 @@ private PackedRefsRefresher getPackedRefsRefresher(PackedRefList curList)
967976
return refresher;
968977
}
969978
// This synchronized is NOT needed for correctness. Instead it is used
970-
// as a throttling mechanism to ensure that only one "read" thread does
971-
// the work to refresh the file. In order to avoid stalling writes which
972-
// must already be serialized and tend to be a bottleneck,
973-
// the refreshPackedRefs() need not be synchronized.
979+
// as a mechanism to try to avoid parallel reads of the same file content
980+
// since repeating work, even in parallel, hurts performance.
981+
// Unfortunately, this approach can still lead to some unnecessary re-reads
982+
// during the "racy" window of the snapshot timestamp.
974983
synchronized (this) {
975984
if (packedRefsRefresher.get() != refresher) {
976985
refresher = packedRefsRefresher.get();
977986
if (refresher != null) {
978-
// Refresher now guaranteed to have been created after the
979-
// current thread entered getPackedRefsRefresher(), even if
980-
// it's currently out of date.
987+
// Refresher now guaranteed to have not started refreshing until
988+
// after the current thread entered getPackedRefsRefresher(),
989+
// even if it's currently out of date. And if the packed-refs
990+
// lock is held before calling this method, then it is also
991+
// guaranteed to not be out-of date even during the "racy"
992+
// window of the snapshot timestamp.
981993
return refresher;
982994
}
983995
}
984-
refresher = createPackedRefsRefresherAsLatest(curList);
996+
refresher = new PackedRefsRefresher(curList);
997+
packedRefsRefresher.set(refresher);
985998
}
986-
return runAndClear(refresher);
999+
refresher.run();
1000+
packedRefsRefresher.compareAndSet(refresher, null);
1001+
return refresher;
9871002
}
9881003

9891004
private boolean shouldRefreshPackedRefs(FileSnapshot snapshot) throws IOException {
@@ -1012,23 +1027,6 @@ private boolean shouldRefreshPackedRefs(FileSnapshot snapshot) throws IOExceptio
10121027
return true;
10131028
}
10141029

1015-
PackedRefList refreshPackedRefs() throws IOException {
1016-
return runAndClear(createPackedRefsRefresherAsLatest(packedRefs.get()))
1017-
.getOrThrowIOException();
1018-
}
1019-
1020-
private PackedRefsRefresher createPackedRefsRefresherAsLatest(PackedRefList curList) {
1021-
PackedRefsRefresher refresher = new PackedRefsRefresher(curList);
1022-
packedRefsRefresher.set(refresher);
1023-
return refresher;
1024-
}
1025-
1026-
private PackedRefsRefresher runAndClear(PackedRefsRefresher refresher) {
1027-
refresher.run();
1028-
packedRefsRefresher.compareAndSet(refresher, null);
1029-
return refresher;
1030-
}
1031-
10321030
private PackedRefList refreshPackedRefs(PackedRefList curList)
10331031
throws IOException {
10341032
final PackedRefList newList = readPackedRefs();

0 commit comments

Comments
 (0)