Avoid computing file diffs when evalution code owner approvals
To evaluate code owner approvals on a change we need to know which files
have been changed. So far we retrieved the changed files from the diff
cache, which means file diffs are being computed when they are not
cached yet (or when their cache entry has expired). Computing files diff
for changes that touch many files (e.g. > 70k files) can take > 15min.
Since the code owner approval evaluation only needs to know which files
have changed, computing the file diffs seems unnecessary. DiffOperations
has a new method that allows to get the modified files without computing
the file diffs and with this change we are using it to get the changed
files instead of getting them from the diff cache. For the evalution of
code owner approvals detecting renames is important (because renamed
files require an approval on the old and the new path), hence the
rename detection must be enabled.
Bug: Google b/461456634
Change-Id: I45c7e61832be45676ef0ceae5044990cfdf469e0
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java b/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
index 07b42bc..f0723bc 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
@@ -32,12 +32,12 @@
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.DiffOperationsForCommitValidation;
-import com.google.gerrit.server.patch.DiffOptions;
-import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.patch.gitdiff.ModifiedFile;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.eclipse.jgit.lib.ObjectId;
@@ -91,7 +91,7 @@
requireNonNull(mergeCommitStrategy, "mergeCommitStrategy");
try (Timer0.Context ctx = codeOwnerMetrics.getChangedFiles.start()) {
- Map<String, FileDiffOutput> fileDiffOutputs;
+ List<ModifiedFile> modifiedFiles;
if (mergeCommitStrategy.equals(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION)
|| isInitialCommit(project, revision)) {
// Use parentNum=0 to do the comparison against the default base.
@@ -99,9 +99,9 @@
// Initial commits are supported when using parentNum=0.
// For merge commits the default base is the auto-merge commit which should be used as base
// if the merge commit strategy is FILES_WITH_CONFLICT_RESOLUTION.
- fileDiffOutputs =
- diffOperations.listModifiedFilesAgainstParent(
- project, revision, /* parentNum= */ 0, DiffOptions.DEFAULTS);
+ modifiedFiles =
+ diffOperations.getModifiedFiles(
+ project, revision, /* parentNum= */ 0, /* enableRenameDetection= */ true);
} else {
checkState(mergeCommitStrategy.equals(MergeCommitStrategy.ALL_CHANGED_FILES));
// Always use parent 1 to do the comparison.
@@ -109,13 +109,12 @@
// handled above).
// For merge commits also the first parent should be used if the merge commit strategy is
// ALL_CHANGED_FILES.
- fileDiffOutputs =
- diffOperations.listModifiedFilesAgainstParent(
- project, revision, 1, DiffOptions.DEFAULTS);
+ modifiedFiles =
+ diffOperations.getModifiedFiles(
+ project, revision, /* parentNum= */ 1, /* enableRenameDetection= */ true);
}
- return fileDiffOutputToChangedFiles(
- filterOutMagicFilesFromFileDiffOutputAndSort(fileDiffOutputs))
+ return modifiedFilesToChangedFiles(filterOutMagicFilesFromModifiedFilesAndSort(modifiedFiles))
.collect(toImmutableList());
}
}
@@ -209,7 +208,8 @@
project, revision, 1, /* enableRenameDetection= */ true);
}
- return modifiedFilesToChangedFiles(filterOutMagicFilesFromModifiedFilesAndSort(modifiedFiles))
+ return modifiedFilesToChangedFiles(
+ filterOutMagicFilesFromModifiedFilesAndSort(modifiedFiles.values()))
.collect(toImmutableList());
}
}
@@ -221,27 +221,14 @@
}
}
- private Stream<Map.Entry<String, FileDiffOutput>> filterOutMagicFilesFromFileDiffOutputAndSort(
- Map<String, FileDiffOutput> fileDiffOutputs) {
- return fileDiffOutputs.entrySet().stream()
- .filter(e -> !Patch.isMagic(e.getKey()))
- .sorted(comparing(Map.Entry::getKey));
+ private Stream<ModifiedFile> filterOutMagicFilesFromModifiedFilesAndSort(
+ Collection<ModifiedFile> modifiedFiles) {
+ return modifiedFiles.stream()
+ .filter(modifiedFile -> !Patch.isMagic(modifiedFile.getDefaultPath()))
+ .sorted(comparing(ModifiedFile::getDefaultPath));
}
- private Stream<ChangedFile> fileDiffOutputToChangedFiles(
- Stream<Map.Entry<String, FileDiffOutput>> fileDiffOutputs) {
- return fileDiffOutputs.map(Map.Entry::getValue).map(ChangedFile::create);
- }
-
- private Stream<Map.Entry<String, ModifiedFile>> filterOutMagicFilesFromModifiedFilesAndSort(
- Map<String, ModifiedFile> modifiedFiles) {
- return modifiedFiles.entrySet().stream()
- .filter(e -> !Patch.isMagic(e.getKey()))
- .sorted(comparing(Map.Entry::getKey));
- }
-
- private Stream<ChangedFile> modifiedFilesToChangedFiles(
- Stream<Map.Entry<String, ModifiedFile>> modifiedFiles) {
- return modifiedFiles.map(Map.Entry::getValue).map(ChangedFile::create);
+ private Stream<ChangedFile> modifiedFilesToChangedFiles(Stream<ModifiedFile> modifiedFiles) {
+ return modifiedFiles.map(ChangedFile::create);
}
}