From 80d90858ad98c4e274439a6fe628a4260a28cfdf Mon Sep 17 00:00:00 2001 From: Patrick Hiesel Date: Fri, 28 Jan 2022 10:40:52 +0100 Subject: Memoize compiled RefPattern in ProjectCache Compiling regular expressions is known to be expensive. If the access section contains a regular expression, we pre compile and memoize it. Release-Notes: Memoize reg-ex compilation in projects cache Change-Id: I84f50323e9f08e69ab6414203927c7d2eacb23e4 (cherry picked from commit e235c42b099138f713ceef034923bfd7731f75ad) --- java/com/google/gerrit/entities/AccessSection.java | 16 ++++++++++++++++ .../google/gerrit/server/project/RefPatternMatcher.java | 12 ++++++++++++ .../com/google/gerrit/server/project/SectionMatcher.java | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/java/com/google/gerrit/entities/AccessSection.java b/java/com/google/gerrit/entities/AccessSection.java index 69a234a5c4..8ae0a5dbed 100644 --- a/java/com/google/gerrit/entities/AccessSection.java +++ b/java/com/google/gerrit/entities/AccessSection.java @@ -18,12 +18,14 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static java.util.Objects.requireNonNull; import com.google.auto.value.AutoValue; +import com.google.auto.value.extension.memoized.Memoized; import com.google.common.collect.ImmutableList; import com.google.gerrit.common.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import java.util.regex.Pattern; /** Portion of a {@link Project} describing access rules. */ @AutoValue @@ -42,6 +44,20 @@ public abstract class AccessSection implements Comparable { /** Name of the access section. It could be a ref pattern or something else. */ public abstract String getName(); + /** + * A compiled regular expression in case {@link #getName()} is a regular expression. This is + * memoized to save callers from compiling patterns for every use. + */ + @Memoized + public Optional getNamePattern() { + if (isValidRefSectionName(getName()) + && getName().startsWith(REGEX_PREFIX) + && !getName().contains("${")) { + return Optional.of(Pattern.compile(getName())); + } + return Optional.empty(); + } + public abstract ImmutableList getPermissions(); public static AccessSection create(String name) { diff --git a/java/com/google/gerrit/server/project/RefPatternMatcher.java b/java/com/google/gerrit/server/project/RefPatternMatcher.java index b9076b3db6..be840b5b23 100644 --- a/java/com/google/gerrit/server/project/RefPatternMatcher.java +++ b/java/com/google/gerrit/server/project/RefPatternMatcher.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; import com.google.gerrit.common.data.ParameterizedString; +import com.google.gerrit.entities.AccessSection; import com.google.gerrit.entities.Account; import com.google.gerrit.entities.RefNames; import com.google.gerrit.server.CurrentUser; @@ -32,6 +33,13 @@ import java.util.regex.Pattern; import java.util.stream.Stream; public abstract class RefPatternMatcher { + public static RefPatternMatcher getMatcher(AccessSection section) { + if (section.getNamePattern().isPresent()) { + return new Regexp(section.getNamePattern().get()); + } + return getMatcher(section.getName()); + } + public static RefPatternMatcher getMatcher(String pattern) { if (containsParameters(pattern)) { return new ExpandParameters(pattern); @@ -79,6 +87,10 @@ public abstract class RefPatternMatcher { pattern = Pattern.compile(re); } + Regexp(Pattern re) { + pattern = re; + } + @Override public boolean match(String ref, CurrentUser user) { return pattern.matcher(ref).matches() || (isRE(ref) && pattern.pattern().equals(ref)); diff --git a/java/com/google/gerrit/server/project/SectionMatcher.java b/java/com/google/gerrit/server/project/SectionMatcher.java index 763957e03e..3d7175fa61 100644 --- a/java/com/google/gerrit/server/project/SectionMatcher.java +++ b/java/com/google/gerrit/server/project/SectionMatcher.java @@ -28,7 +28,7 @@ public class SectionMatcher extends RefPatternMatcher { static SectionMatcher wrap(Project.NameKey project, AccessSection section) { String ref = section.getName(); if (AccessSection.isValidRefSectionName(ref)) { - return new SectionMatcher(project, section, getMatcher(ref)); + return new SectionMatcher(project, section, getMatcher(section)); } return null; } -- cgit v1.2.3