aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2019-04-17 17:42:50 +0200
committerSonarTech <sonartech@sonarsource.com>2019-04-24 20:21:04 +0200
commitca672c1a71098c93f0e7f1b64d73b21c7e6706a9 (patch)
tree6fed59e5798c4a2172105816ee56bbcfb60d0a0a /server/sonar-server
parentb48765ede74a653404ae98f0a0255f4c2e31ea19 (diff)
downloadsonarqube-ca672c1a71098c93f0e7f1b64d73b21c7e6706a9.tar.gz
sonarqube-ca672c1a71098c93f0e7f1b64d73b21c7e6706a9.zip
SONARCLOUD-582 split loading of profiles in rule activation
Diffstat (limited to 'server/sonar-server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java55
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java45
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java46
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));