Avoid looking up refs for all filtered changes When filtering a huge list of refs all the closed changes need to be identified and hidden; however, the mere lookup of the changes' SHA1s from the repository's ref-database can cause a considerable system load because of the high number of change refs. The initial list of refs to be filtered contains already all the '/meta' refs and their associated SHA1s hence it can be reused for looking up the change-id to their latest version instead of re-reading the same information from the repository on disk. Depends-On: https://gerrit-review.googlesource.com/c/gerrit/+/319756 Change-Id: I164addd6abc7c1dff1cfeedcec27415e6b88f3b3
diff --git a/src/main/java/com/googlesource/gerrit/modules/gitrefsfilter/ForProjectWrapper.java b/src/main/java/com/googlesource/gerrit/modules/gitrefsfilter/ForProjectWrapper.java index 0809840..3080694 100644 --- a/src/main/java/com/googlesource/gerrit/modules/gitrefsfilter/ForProjectWrapper.java +++ b/src/main/java/com/googlesource/gerrit/modules/gitrefsfilter/ForProjectWrapper.java
@@ -30,8 +30,10 @@ import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import java.util.Collection; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -79,6 +81,10 @@ @Override public Collection<Ref> filter(Collection<Ref> refs, Repository repo, RefFilterOptions opts) throws PermissionBackendException { + Map<Change.Id, ObjectId> changeRevisions = + refs.stream() + .filter(ref -> ref.getName().endsWith("/meta")) + .collect(Collectors.toMap(ForProjectWrapper::changeIdFromRef, Ref::getObjectId)); return defaultForProject .filter(refs, repo, opts) .parallelStream() @@ -87,13 +93,20 @@ .filter(config::isRefToShow) .filter( (ref) -> { + Change.Id changeId = changeIdFromRef(ref); String refName = ref.getName(); return (!isChangeRef(refName) - || (!isChangeMetaRef(refName) && isOpen(repo, refName))); + || (!isChangeMetaRef(refName) + && changeId != null + && isOpen(repo, changeId, changeRevisions.get(changeId)))); }) .collect(Collectors.toList()); } + private static Change.Id changeIdFromRef(Ref ref) { + return Change.Id.fromRef(ref.getName()); + } + private boolean isChangeRef(String changeKey) { return changeKey.startsWith("refs/changes"); } @@ -102,14 +115,14 @@ return isChangeRef(changeKey) && changeKey.endsWith("/meta"); } - private boolean isOpen(Repository repo, String refName) { + private boolean isOpen(Repository repo, Change.Id changeId, ObjectId changeRevision) { try { - Change.Id changeId = Change.Id.fromRef(refName); - ChangeNotes changeNotes = changeNotesFactory.create(repo, project, changeId); + ChangeNotes changeNotes = + changeNotesFactory.createChecked(repo, project, changeId, changeRevision); return changeNotes.getChange().getStatus().isOpen(); } catch (NoSuchChangeException e) { logger.atWarning().withCause(e).log( - "Ref %s refers to a non-existent change: hiding from the advertised refs", refName); + "Change %d does not exist: hiding from the advertised refs", changeId); return false; } }