Skip to content

Commit 00c2d3f

Browse files
authored
Improve the git ratchet performance (memory and speed) (#1038)
2 parents 3f772a7 + 80afe4b commit 00c2d3f

File tree

8 files changed

+32
-20
lines changed

8 files changed

+32
-20
lines changed

Diff for: .circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ jobs:
109109
- *restore_cache_deps
110110
- run:
111111
name: gradlew npmTest
112-
command: ./gradlew npmTest --build-cache
112+
command: export SPOTLESS_EXCLUDE_MAVEN=true && ./gradlew npmTest --build-cache
113113
- store_test_results:
114114
path: testlib/build/test-results/NpmTest
115115
- store_test_results:

Diff for: CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ This document is intended for Spotless developers.
1010
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).
1111

1212
## [Unreleased]
13+
### Fixed
14+
* Performance improvements to GitRatchet ([#1038](https://github.com/diffplug/spotless/pull/1038)).
1315

1416
## [2.20.2] - 2021-12-05
1517
### Changed

Diff for: lib-extra/src/main/java/com/diffplug/spotless/extra/GitRatchet.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public boolean isClean(Project project, ObjectId treeSha, File file) throws IOEx
6363
return isClean(project, treeSha, relativePath);
6464
}
6565

66+
private Map<Repository, DirCache> dirCaches = new HashMap<>();
67+
6668
/**
6769
* This is the highest-level method, which all the others serve. Given the sha
6870
* of a git tree (not a commit!), and the file in question, this method returns
@@ -72,13 +74,16 @@ public boolean isClean(Project project, ObjectId treeSha, File file) throws IOEx
7274
public boolean isClean(Project project, ObjectId treeSha, String relativePathUnix) throws IOException {
7375
Repository repo = repositoryFor(project);
7476

75-
// TODO: should be cached-per-repo if it is thread-safe, or per-repo-per-thread if it is not
76-
DirCache dirCache = repo.readDirCache();
77-
77+
DirCacheIterator dirCacheIteratorInit;
78+
synchronized (this) {
79+
// each DirCache is thread-safe, and we compute them one-to-one based on `repositoryFor`
80+
DirCache dirCache = dirCaches.computeIfAbsent(repo, Errors.rethrow().wrap(Repository::readDirCache));
81+
dirCacheIteratorInit = new DirCacheIterator(dirCache);
82+
}
7883
try (TreeWalk treeWalk = new TreeWalk(repo)) {
7984
treeWalk.setRecursive(true);
8085
treeWalk.addTree(treeSha);
81-
treeWalk.addTree(new DirCacheIterator(dirCache));
86+
treeWalk.addTree(dirCacheIteratorInit);
8287
treeWalk.addTree(new FileTreeIterator(repo));
8388
treeWalk.setFilter(AndTreeFilter.create(
8489
PathFilter.create(relativePathUnix),
@@ -216,7 +221,7 @@ public synchronized ObjectId rootTreeShaOf(Project project, String reference) {
216221
RevCommit mergeBase = revWalk.next();
217222
treeSha = Optional.ofNullable(mergeBase).orElse(ratchetFrom).getTree();
218223
}
219-
rootTreeShaCache.put(repo, reference, treeSha);
224+
rootTreeShaCache.put(repo, reference, treeSha.copy());
220225
}
221226
return treeSha;
222227
} catch (IOException e) {
@@ -241,7 +246,7 @@ public synchronized ObjectId subtreeShaOf(Project project, ObjectId rootTreeSha)
241246
TreeWalk treeWalk = TreeWalk.forPath(repo, subpath, rootTreeSha);
242247
subtreeSha = treeWalk == null ? ObjectId.zeroId() : treeWalk.getObjectId(0);
243248
}
244-
subtreeShaCache.put(project, subtreeSha);
249+
subtreeShaCache.put(project, subtreeSha.copy());
245250
}
246251
return subtreeSha;
247252
} catch (IOException e) {

Diff for: plugin-gradle/CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`).
44

55
## [Unreleased]
6+
### Fixed
7+
* `ratchetFrom` is now faster and uses less memory ([#1038](https://github.com/diffplug/spotless/pull/1038)).
68

79
## [6.0.4] - 2021-12-07
810
### Fixed

Diff for: plugin-gradle/src/main/java/com/diffplug/gradle/spotless/IdeHook.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ static void performHook(SpotlessTaskImpl spotlessTask) {
4141
return;
4242
}
4343
if (spotlessTask.getTarget().contains(file)) {
44+
GitRatchetGradle ratchet = spotlessTask.getRatchet();
4445
try (Formatter formatter = spotlessTask.buildFormatter()) {
45-
if (spotlessTask.getRatchet() != null) {
46-
if (spotlessTask.getRatchet().isClean(spotlessTask.getProjectDir().get().getAsFile(), spotlessTask.getRootTreeSha(), file)) {
46+
if (ratchet != null) {
47+
if (ratchet.isClean(spotlessTask.getProjectDir().get().getAsFile(), spotlessTask.getRootTreeSha(), file)) {
4748
dumpIsClean();
4849
return;
4950
}

Diff for: plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java

+3-7
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
import java.util.Locale;
2424
import java.util.Objects;
2525

26-
import javax.annotation.Nullable;
27-
2826
import org.eclipse.jgit.lib.ObjectId;
2927
import org.gradle.api.DefaultTask;
3028
import org.gradle.api.file.DirectoryProperty;
@@ -44,6 +42,7 @@
4442
import com.diffplug.spotless.Formatter;
4543
import com.diffplug.spotless.FormatterStep;
4644
import com.diffplug.spotless.LineEnding;
45+
import com.diffplug.spotless.extra.GitRatchet;
4746

4847
public abstract class SpotlessTask extends DefaultTask {
4948
@Internal
@@ -76,9 +75,6 @@ public void setLineEndingsPolicy(LineEnding.Policy lineEndingsPolicy) {
7675
this.lineEndingsPolicy.set(lineEndingsPolicy);
7776
}
7877

79-
/*** API which performs git up-to-date tasks. */
80-
@Nullable
81-
private transient GitRatchetGradle ratchet;
8278
/** The sha of the tree at repository root, used for determining if an individual *file* is clean according to git. */
8379
private transient ObjectId rootTreeSha;
8480
/**
@@ -93,7 +89,7 @@ public void setLineEndingsPolicy(LineEnding.Policy lineEndingsPolicy) {
9389
public void setupRatchet(String ratchetFrom) {
9490
this.ratchetFrom = ratchetFrom;
9591
if (!ratchetFrom.isEmpty()) {
96-
ratchet = getTaskService().get().getRatchet();
92+
GitRatchet ratchet = getTaskService().get().getRatchet();
9793
File projectDir = getProjectDir().get().getAsFile();
9894
rootTreeSha = ratchet.rootTreeShaOf(projectDir, ratchetFrom);
9995
subtreeSha = ratchet.subtreeShaOf(projectDir, rootTreeSha);
@@ -107,7 +103,7 @@ public void setupRatchet(String ratchetFrom) {
107103

108104
@Internal
109105
GitRatchetGradle getRatchet() {
110-
return ratchet;
106+
return ObjectId.zeroId().equals(getRatchetSha()) ? null : getTaskService().get().getRatchet();
111107
}
112108

113109
@Internal

Diff for: plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTaskImpl.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.nio.file.Path;
2222
import java.nio.file.StandardCopyOption;
2323

24+
import javax.annotation.Nullable;
2425
import javax.inject.Inject;
2526

2627
import org.gradle.api.GradleException;
@@ -37,6 +38,7 @@
3738
import com.diffplug.common.base.StringPrinter;
3839
import com.diffplug.spotless.Formatter;
3940
import com.diffplug.spotless.PaddedCell;
41+
import com.diffplug.spotless.extra.GitRatchet;
4042

4143
@CacheableTask
4244
public abstract class SpotlessTaskImpl extends SpotlessTask {
@@ -53,7 +55,8 @@ void init(Provider<SpotlessTaskService> service) {
5355

5456
@TaskAction
5557
public void performAction(InputChanges inputs) throws Exception {
56-
getTaskService().get().registerSourceAlreadyRan(this);
58+
SpotlessTaskService taskService = getTaskService().get();
59+
taskService.registerSourceAlreadyRan(this);
5760
if (target == null) {
5861
throw new GradleException("You must specify 'Iterable<File> target'");
5962
}
@@ -65,24 +68,25 @@ public void performAction(InputChanges inputs) throws Exception {
6568
}
6669

6770
try (Formatter formatter = buildFormatter()) {
71+
GitRatchetGradle ratchet = getRatchet();
6872
for (FileChange fileChange : inputs.getFileChanges(target)) {
6973
File input = fileChange.getFile();
7074
if (fileChange.getChangeType() == ChangeType.REMOVED) {
7175
deletePreviousResult(input);
7276
} else {
7377
if (input.isFile()) {
74-
processInputFile(formatter, input);
78+
processInputFile(ratchet, formatter, input);
7579
}
7680
}
7781
}
7882
}
7983
}
8084

81-
private void processInputFile(Formatter formatter, File input) throws IOException {
85+
private void processInputFile(@Nullable GitRatchet ratchet, Formatter formatter, File input) throws IOException {
8286
File output = getOutputFile(input);
8387
getLogger().debug("Applying format to " + input + " and writing to " + output);
8488
PaddedCell.DirtyState dirtyState;
85-
if (getRatchet() != null && getRatchet().isClean(getProjectDir().get().getAsFile(), getRootTreeSha(), input)) {
89+
if (ratchet != null && ratchet.isClean(getProjectDir().get().getAsFile(), getRootTreeSha(), input)) {
8690
dirtyState = PaddedCell.isClean();
8791
} else {
8892
dirtyState = PaddedCell.calculateDirtyState(formatter, input);

Diff for: plugin-maven/CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).
44

55
## [Unreleased]
6+
### Fixed
7+
* `ratchetFrom` is now faster ([#1038](https://github.com/diffplug/spotless/pull/1038)).
68

79
## [2.17.6] - 2021-12-05
810
### Changed

0 commit comments

Comments
 (0)