diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2019-04-17 17:42:50 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-04-24 20:21:04 +0200 |
commit | ca672c1a71098c93f0e7f1b64d73b21c7e6706a9 (patch) | |
tree | 6fed59e5798c4a2172105816ee56bbcfb60d0a0a /server/sonar-server | |
parent | b48765ede74a653404ae98f0a0255f4c2e31ea19 (diff) | |
download | sonarqube-ca672c1a71098c93f0e7f1b64d73b21c7e6706a9.tar.gz sonarqube-ca672c1a71098c93f0e7f1b64d73b21c7e6706a9.zip |
SONARCLOUD-582 split loading of profiles in rule activation
Diffstat (limited to 'server/sonar-server')
3 files changed, 121 insertions, 25 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java new file mode 100644 index 00000000000..ef073340e7a --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.qualityprofile; + +import java.util.Collection; +import org.sonar.db.qualityprofile.ActiveRuleDto; +import org.sonar.db.qualityprofile.ActiveRuleParamDto; +import org.sonar.db.qualityprofile.QProfileDto; + +@FunctionalInterface +public interface DescendantProfilesSupplier { + + Result get(Collection<QProfileDto> profiles, Collection<Integer> ruleIds); + + final class Result { + private final Collection<QProfileDto> profiles; + private final Collection<ActiveRuleDto> activeRules; + private final Collection<ActiveRuleParamDto> activeRuleParams; + + public Result(Collection<QProfileDto> profiles, Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) { + this.profiles = profiles; + this.activeRules = activeRules; + this.activeRuleParams = activeRuleParams; + } + + public Collection<QProfileDto> getProfiles() { + return profiles; + } + + public Collection<ActiveRuleDto> getActiveRules() { + return activeRules; + } + + public Collection<ActiveRuleParamDto> getActiveRuleParams() { + return activeRuleParams; + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java index 3cf258cfcd9..c96a3c75ac4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java @@ -21,7 +21,6 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; -import com.google.common.collect.Maps; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -41,6 +40,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static java.util.Objects.requireNonNull; import static org.sonar.core.util.stream.MoreCollectors.index; +import static org.sonar.core.util.stream.MoreCollectors.toArrayList; import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; import static org.sonar.server.ws.WsUtils.checkRequest; @@ -61,8 +61,8 @@ class RuleActivationContext { private final ListMultimap<String, QProfileDto> profilesByParentUuid = ArrayListMultimap.create(); // The rules/active rules involved in the group of activations/de-activations - private final Map<Integer, RuleWrapper> rulesById; - private final Map<ActiveRuleKey, ActiveRuleWrapper> activeRulesByKey; + private final Map<Integer, RuleWrapper> rulesById = new HashMap<>(); + private final Map<ActiveRuleKey, ActiveRuleWrapper> activeRulesByKey = new HashMap<>(); // Cursors used to move in the rules and in the tree of profiles. @@ -74,10 +74,13 @@ class RuleActivationContext { private ActiveRuleWrapper currentActiveRule; private ActiveRuleWrapper currentParentActiveRule; + private boolean descendantsLoaded = false; + private final DescendantProfilesSupplier descendantProfilesSupplier; + private RuleActivationContext(Builder builder) { this.date = builder.date; + this.descendantProfilesSupplier = builder.descendantProfilesSupplier; - this.rulesById = Maps.newHashMapWithExpectedSize(builder.rules.size()); ListMultimap<Integer, RuleParamDto> paramsByRuleId = builder.ruleParams.stream().collect(index(RuleParamDto::getRuleId)); for (RuleDefinitionDto rule : builder.rules) { RuleWrapper wrapper = new RuleWrapper(rule, paramsByRuleId.get(rule.getId())); @@ -85,16 +88,22 @@ class RuleActivationContext { } this.baseRulesProfile = builder.baseRulesProfile; - for (QProfileDto profile : builder.profiles) { + register(builder.profiles); + register(builder.activeRules, builder.activeRuleParams); + } + + private void register(Collection<QProfileDto> profiles) { + for (QProfileDto profile : profiles) { profilesByUuid.put(profile.getKee(), profile); if (profile.getParentKee() != null) { profilesByParentUuid.put(profile.getParentKee(), profile); } } + } - this.activeRulesByKey = Maps.newHashMapWithExpectedSize(builder.activeRules.size()); - ListMultimap<Integer, ActiveRuleParamDto> paramsByActiveRuleId = builder.activeRuleParams.stream().collect(index(ActiveRuleParamDto::getActiveRuleId)); - for (ActiveRuleDto activeRule : builder.activeRules) { + private void register(Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) { + ListMultimap<Integer, ActiveRuleParamDto> paramsByActiveRuleId = activeRuleParams.stream().collect(index(ActiveRuleParamDto::getActiveRuleId)); + for (ActiveRuleDto activeRule : activeRules) { ActiveRuleWrapper wrapper = new ActiveRuleWrapper(activeRule, paramsByActiveRuleId.get(activeRule.getId())); this.activeRulesByKey.put(activeRule.getKey(), wrapper); } @@ -173,11 +182,25 @@ class RuleActivationContext { * The children of {@link #getProfiles()} */ Collection<QProfileDto> getChildProfiles() { + loadDescendants(); return getProfiles().stream() .flatMap(p -> profilesByParentUuid.get(p.getKee()).stream()) .collect(Collectors.toList()); } + private void loadDescendants() { + if (descendantsLoaded) { + return; + } + Collection<QProfileDto> baseProfiles = profilesByUuid.values().stream() + .filter(p -> p.getRulesProfileUuid().equals(baseRulesProfile.getKee())) + .collect(toArrayList(profilesByUuid.size())); + DescendantProfilesSupplier.Result result = descendantProfilesSupplier.get(baseProfiles, rulesById.keySet()); + register(result.getProfiles()); + register(result.getActiveRules(), result.getActiveRuleParams()); + descendantsLoaded = true; + } + /** * Move the cursor to the given rule and back to the base profile. */ @@ -226,6 +249,7 @@ class RuleActivationContext { private Collection<QProfileDto> profiles; private Collection<ActiveRuleDto> activeRules; private Collection<ActiveRuleParamDto> activeRuleParams; + private DescendantProfilesSupplier descendantProfilesSupplier; Builder setDate(long l) { this.date = l; @@ -266,6 +290,11 @@ class RuleActivationContext { return this; } + Builder setDescendantProfilesSupplier(DescendantProfilesSupplier d) { + this.descendantProfilesSupplier = d; + return this; + } + RuleActivationContext build() { checkArgument(date > 0, "date is not set"); requireNonNull(baseRulesProfile, "baseRulesProfile is null"); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java index 8bef04772dd..835f4153227 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Stream; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -51,7 +52,6 @@ import org.sonar.server.user.UserSession; import org.sonar.server.util.TypeValidations; import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Collections.singleton; import static org.sonar.server.ws.WsUtils.checkRequest; /** @@ -198,16 +198,16 @@ public class RuleActivator { String parentValue = parentActiveRule != null ? parentActiveRule.getParamValue(paramKey) : null; String activeRuleValue = activeRule == null ? null : activeRule.getParamValue(paramKey); paramValue = context.hasRequestedParamValue(request, paramKey) ? - // If the request contains the parameter then we're using either value from request, or parent value, or default value + // If the request contains the parameter then we're using either value from request, or parent value, or default value firstNonNull( context.getRequestedParamValue(request, paramKey), parentValue, rule.getParamDefaultValue(paramKey)) // If the request doesn't contain the parameter, then we're using either value in DB, or parent value, or default value : firstNonNull( - activeRuleValue, - parentValue, - rule.getParamDefaultValue(paramKey)); + activeRuleValue, + parentValue, + rule.getParamDefaultValue(paramKey)); } change.setParameter(paramKey, validateParam(ruleParamDto, paramValue)); @@ -356,14 +356,13 @@ public class RuleActivator { checkArgument(builtInProfile.isBuiltIn(), "Rules profile with UUID %s is not built-in", builtInProfile.getKee()); RuleActivationContext.Builder builder = new RuleActivationContext.Builder(); + builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession)); // load rules List<RuleDefinitionDto> rules = completeWithRules(dbSession, builder, ruleIds); - // load org profiles - List<QProfileDto> aliasedBuiltInProfiles = db.qualityProfileDao().selectQProfilesByRuleProfile(dbSession, builtInProfile); - List<QProfileDto> profiles = new ArrayList<>(aliasedBuiltInProfiles); - profiles.addAll(db.qualityProfileDao().selectDescendants(dbSession, aliasedBuiltInProfiles)); + // load org profiles. Their parents are null by nature. + List<QProfileDto> profiles = db.qualityProfileDao().selectQProfilesByRuleProfile(dbSession, builtInProfile); builder.setProfiles(profiles); builder.setBaseProfile(builtInProfile); @@ -371,20 +370,20 @@ public class RuleActivator { Collection<String> ruleProfileUuids = Stream .concat(Stream.of(builtInProfile.getKee()), profiles.stream().map(QProfileDto::getRulesProfileUuid)) .collect(MoreCollectors.toHashSet(profiles.size() + 1)); - completeWithActiveRules(dbSession, builder, rules, ruleProfileUuids); - + completeWithActiveRules(dbSession, builder, ruleIds, ruleProfileUuids); return builder.build(); } public RuleActivationContext createContextForUserProfile(DbSession dbSession, QProfileDto profile, Collection<Integer> ruleIds) { checkArgument(!profile.isBuiltIn(), "Profile with UUID %s is built-in", profile.getKee()); RuleActivationContext.Builder builder = new RuleActivationContext.Builder(); + builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession)); // load rules - List<RuleDefinitionDto> rules = completeWithRules(dbSession, builder, ruleIds); + completeWithRules(dbSession, builder, ruleIds); - // load descendant profiles - List<QProfileDto> profiles = new ArrayList<>(db.qualityProfileDao().selectDescendants(dbSession, singleton(profile))); + // load profiles + List<QProfileDto> profiles = new ArrayList<>(); profiles.add(profile); if (profile.getParentKee() != null) { profiles.add(db.qualityProfileDao().selectByUuid(dbSession, profile.getParentKee())); @@ -396,11 +395,24 @@ public class RuleActivator { Collection<String> ruleProfileUuids = profiles.stream() .map(QProfileDto::getRulesProfileUuid) .collect(MoreCollectors.toHashSet(profiles.size())); - completeWithActiveRules(dbSession, builder, rules, ruleProfileUuids); + completeWithActiveRules(dbSession, builder, ruleIds, ruleProfileUuids); return builder.build(); } + private DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) { + return (parents, ruleIds) -> { + Collection<QProfileDto> profiles = db.qualityProfileDao().selectDescendants(dbSession, parents); + Set<String> ruleProfileUuids = profiles.stream() + .map(QProfileDto::getRulesProfileUuid) + .collect(MoreCollectors.toHashSet()); + Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleIds, ruleProfileUuids); + List<Integer> activeRuleIds = activeRules.stream().map(ActiveRuleDto::getId).collect(MoreCollectors.toArrayList(activeRules.size())); + List<ActiveRuleParamDto> activeRuleParams = db.activeRuleDao().selectParamsByActiveRuleIds(dbSession, activeRuleIds); + return new DescendantProfilesSupplier.Result(profiles, activeRules, activeRuleParams); + }; + } + private List<RuleDefinitionDto> completeWithRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<Integer> ruleIds) { List<RuleDefinitionDto> rules = db.ruleDao().selectDefinitionByIds(dbSession, ruleIds); builder.setRules(rules); @@ -408,8 +420,8 @@ public class RuleActivator { return rules; } - private void completeWithActiveRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<RuleDefinitionDto> rules, Collection<String> ruleProfileUuids) { - Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, rules, ruleProfileUuids); + private void completeWithActiveRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<Integer> ruleIds, Collection<String> ruleProfileUuids) { + Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleIds, ruleProfileUuids); builder.setActiveRules(activeRules); List<Integer> activeRuleIds = activeRules.stream().map(ActiveRuleDto::getId).collect(MoreCollectors.toArrayList(activeRules.size())); builder.setActiveRuleParams(db.activeRuleDao().selectParamsByActiveRuleIds(dbSession, activeRuleIds)); |