Skip to content

Commit 052c411

Browse files
committed
Merge branch 'stable-7.0' into stable-7.1
* stable-7.0: Do not always refresh packed-refs during ref updates Change-Id: I6f249ceb085105ae3309c6d1312ffa9482569fb6
2 parents 274d177 + 4eb0802 commit 052c411

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
@@ -56,7 +56,7 @@ For details on native git options see also the official [git config documentatio
5656
| `core.supportsAtomicFileCreation` | `true` | ⃞ | Whether the filesystem supports atomic file creation. |
5757
| `core.symlinks` | Auto detect if filesystem supports symlinks| ✅ | If false, symbolic links are checked out as small plain files that contain the link text. |
5858
| `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. |
59-
| `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`. |
59+
| `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.|
6060
| `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. |
6161
| `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. |
6262

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
@@ -731,7 +731,7 @@ void delete(RefDirectoryUpdate update) throws IOException {
731731
PackedRefList packed = getPackedRefs();
732732
if (packed.contains(name)) {
733733
// Force update our packed-refs snapshot before writing
734-
packed = refreshPackedRefs();
734+
packed = getLockedPackedRefs(lck);
735735
int idx = packed.find(name);
736736
if (0 <= idx) {
737737
commitPackedRefs(lck, packed.remove(idx), packed, true);
@@ -799,7 +799,7 @@ private void pack(Collection<String> refs,
799799
try {
800800
LockFile lck = lockPackedRefsOrThrow();
801801
try {
802-
PackedRefList oldPacked = refreshPackedRefs();
802+
PackedRefList oldPacked = getLockedPackedRefs(lck);
803803
RefList<Ref> newPacked = oldPacked;
804804

805805
// Iterate over all refs to be packed
@@ -982,6 +982,15 @@ else if (0 <= (idx = packed.find(dst.getName())))
982982
}
983983

984984
PackedRefList getPackedRefs() throws IOException {
985+
return refreshPackedRefsIfNeeded();
986+
}
987+
988+
PackedRefList getLockedPackedRefs(LockFile packedRefsFileLock) throws IOException {
989+
packedRefsFileLock.requireLock();
990+
return refreshPackedRefsIfNeeded();
991+
}
992+
993+
PackedRefList refreshPackedRefsIfNeeded() throws IOException {
985994
PackedRefList curList = packedRefs.get();
986995
if (!curList.shouldRefresh()) {
987996
return curList;
@@ -996,23 +1005,29 @@ private PackedRefsRefresher getPackedRefsRefresher(PackedRefList curList)
9961005
return refresher;
9971006
}
9981007
// This synchronized is NOT needed for correctness. Instead it is used
999-
// as a throttling mechanism to ensure that only one "read" thread does
1000-
// the work to refresh the file. In order to avoid stalling writes which
1001-
// must already be serialized and tend to be a bottleneck,
1002-
// the refreshPackedRefs() need not be synchronized.
1008+
// as a mechanism to try to avoid parallel reads of the same file content
1009+
// since repeating work, even in parallel, hurts performance.
1010+
// Unfortunately, this approach can still lead to some unnecessary re-reads
1011+
// during the "racy" window of the snapshot timestamp.
10031012
synchronized (this) {
10041013
if (packedRefsRefresher.get() != refresher) {
10051014
refresher = packedRefsRefresher.get();
10061015
if (refresher != null) {
1007-
// Refresher now guaranteed to have been created after the
1008-
// current thread entered getPackedRefsRefresher(), even if
1009-
// it's currently out of date.
1016+
// Refresher now guaranteed to have not started refreshing until
1017+
// after the current thread entered getPackedRefsRefresher(),
1018+
// even if it's currently out of date. And if the packed-refs
1019+
// lock is held before calling this method, then it is also
1020+
// guaranteed to not be out-of date even during the "racy"
1021+
// window of the snapshot timestamp.
10101022
return refresher;
10111023
}
10121024
}
1013-
refresher = createPackedRefsRefresherAsLatest(curList);
1025+
refresher = new PackedRefsRefresher(curList);
1026+
packedRefsRefresher.set(refresher);
10141027
}
1015-
return runAndClear(refresher);
1028+
refresher.run();
1029+
packedRefsRefresher.compareAndSet(refresher, null);
1030+
return refresher;
10161031
}
10171032

10181033
private boolean shouldRefreshPackedRefs(FileSnapshot snapshot) throws IOException {
@@ -1041,23 +1056,6 @@ private boolean shouldRefreshPackedRefs(FileSnapshot snapshot) throws IOExceptio
10411056
return true;
10421057
}
10431058

1044-
PackedRefList refreshPackedRefs() throws IOException {
1045-
return runAndClear(createPackedRefsRefresherAsLatest(packedRefs.get()))
1046-
.getOrThrowIOException();
1047-
}
1048-
1049-
private PackedRefsRefresher createPackedRefsRefresherAsLatest(PackedRefList curList) {
1050-
PackedRefsRefresher refresher = new PackedRefsRefresher(curList);
1051-
packedRefsRefresher.set(refresher);
1052-
return refresher;
1053-
}
1054-
1055-
private PackedRefsRefresher runAndClear(PackedRefsRefresher refresher) {
1056-
refresher.run();
1057-
packedRefsRefresher.compareAndSet(refresher, null);
1058-
return refresher;
1059-
}
1060-
10611059
private PackedRefList refreshPackedRefs(PackedRefList curList)
10621060
throws IOException {
10631061
final PackedRefList newList = readPackedRefs();

0 commit comments

Comments
 (0)