]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6315 cache rules and query active rules per profile
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 13 Mar 2017 17:05:53 +0000 (18:05 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 23 Mar 2017 16:38:34 +0000 (17:38 +0100)
rather than 1 by 1

server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/CachingRuleActivator.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/CachingRuleActivatorContextFactory.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java

index 07797e41e324aff30cc23d8ba018f923f3a35e20..4b65e4d69e55028fb3f372c69233fcb154deb901 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.server.platform.ServerLifecycleNotifier;
 import org.sonar.server.platform.web.RegisterServletFilters;
 import org.sonar.server.qualitygate.RegisterQualityGates;
 import org.sonar.server.qualityprofile.CachingRuleActivator;
+import org.sonar.server.qualityprofile.CachingRuleActivatorContextFactory;
 import org.sonar.server.qualityprofile.RegisterQualityProfiles;
 import org.sonar.server.rule.RegisterRules;
 import org.sonar.server.startup.ClearRulesOverloadedDebt;
@@ -53,8 +54,9 @@ public class PlatformLevelStartup extends PlatformLevel {
       IndexerStartupTask.class,
       RegisterMetrics.class,
       RegisterQualityGates.class,
-      CachingRuleActivator.class,
       RegisterRules.class,
+      CachingRuleActivatorContextFactory.class,
+      CachingRuleActivator.class,
       RegisterQualityProfiles.class,
       RegisterPermissionTemplates.class,
       RenameDeprecatedPropertyKeys.class,
index 478136c9dfe535b492225089372ceb5d7c2f2ad8..452ef1fb31f97f9b636692babc9d7eaced4430fe 100644 (file)
@@ -36,7 +36,7 @@ public class CachingRuleActivator extends RuleActivator {
       .maximumSize(10_000)
       .build();
 
-  public CachingRuleActivator(System2 system2, DbClient db, RuleIndex ruleIndex, RuleActivatorContextFactory contextFactory, TypeValidations typeValidations,
+  public CachingRuleActivator(System2 system2, DbClient db, RuleIndex ruleIndex, CachingRuleActivatorContextFactory contextFactory, TypeValidations typeValidations,
     ActiveRuleIndexer activeRuleIndexer, UserSession userSession) {
     super(system2, db, ruleIndex, contextFactory, typeValidations, activeRuleIndexer, userSession);
   }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/CachingRuleActivatorContextFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/CachingRuleActivatorContextFactory.java
new file mode 100644 (file)
index 0000000..d038eae
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.picocontainer.Startable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.util.stream.Collectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.ActiveRuleDto;
+import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.db.qualityprofile.ActiveRuleParamDto;
+import org.sonar.db.rule.RuleDto;
+
+public class CachingRuleActivatorContextFactory extends RuleActivatorContextFactory implements Startable {
+  private final DbClient dbClient;
+  private final Map<RuleKey, RuleDto> rulesByRuleKey = new HashMap<>();
+  private final Cache<String, Map<RuleKey, ActiveRuleDto>> childrenByParentKey = CacheBuilder.newBuilder()
+    .maximumSize(10)
+    .build();
+
+  public CachingRuleActivatorContextFactory(DbClient db) {
+    super(db);
+    this.dbClient = db;
+  }
+
+  @Override
+  public void start() {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      dbClient.ruleDao().selectAll(dbSession).forEach(rule -> rulesByRuleKey.put(rule.getKey(), rule));
+    }
+  }
+
+  @Override
+  public void stop() {
+    // nothing to do
+  }
+
+  @Override
+  Optional<RuleDto> getRule(DbSession dbSession, RuleKey ruleKey) {
+    return Optional.ofNullable(rulesByRuleKey.get(ruleKey));
+  }
+
+  @Override
+  Optional<ActiveRuleDto> getActiveRule(DbSession session, ActiveRuleKey key) {
+    try {
+      String profileKey = key.qProfile();
+      Map<RuleKey, ActiveRuleDto> profileActiveRulesByRuleKey = childrenByParentKey.get(
+        profileKey,
+        () -> loadActiveRulesOfQualityProfile(session, profileKey));
+      return Optional.ofNullable(profileActiveRulesByRuleKey.get(key.ruleKey()));
+    } catch (ExecutionException e) {
+      throw new IllegalStateException(e.getCause());
+    }
+  }
+
+  private Map<RuleKey, ActiveRuleDto> loadActiveRulesOfQualityProfile(DbSession session, String profileKey) {
+    return dbClient.activeRuleDao().selectByProfileKey(session, profileKey).stream()
+      .collect(Collectors.uniqueIndex(dto -> dto.getKey().ruleKey()));
+  }
+
+  @Override
+  List<ActiveRuleParamDto> getActiveRuleParams(DbSession session, ActiveRuleDto activeRuleDto) {
+    return super.getActiveRuleParams(session, activeRuleDto);
+  }
+}
index 26eb457277bccbe6b69ad82712c88d7e4a99c2a7..cc05119462f468b5f0ef22dc2de25542662cd1af 100644 (file)
@@ -19,8 +19,9 @@
  */
 package org.sonar.server.qualityprofile;
 
-import com.google.common.base.Optional;
 import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.ServerSide;
 import org.sonar.db.DbClient;
@@ -65,7 +66,7 @@ public class RuleActivatorContextFactory {
   }
 
   private RuleDto initRule(RuleKey ruleKey, RuleActivatorContext context, DbSession dbSession) {
-    Optional<RuleDto> rule = db.ruleDao().selectByKey(dbSession, ruleKey);
+    Optional<RuleDto> rule = getRule(dbSession, ruleKey);
     checkRequest(rule.isPresent(), "Rule not found: %s", ruleKey);
     context.setRule(rule.get());
     context.setRuleParams(db.ruleDao().selectRuleParamsByRuleKey(dbSession, rule.get().getKey()));
@@ -74,17 +75,29 @@ public class RuleActivatorContextFactory {
 
   private void initActiveRules(String profileKey, RuleKey ruleKey, RuleActivatorContext context, DbSession session, boolean parent) {
     ActiveRuleKey key = ActiveRuleKey.of(profileKey, ruleKey);
-    Optional<ActiveRuleDto> activeRule = db.activeRuleDao().selectByKey(session, key);
+    Optional<ActiveRuleDto> activeRule = getActiveRule(session, key);
     Collection<ActiveRuleParamDto> activeRuleParams = null;
     if (activeRule.isPresent()) {
-      activeRuleParams = db.activeRuleDao().selectParamsByActiveRuleId(session, activeRule.get().getId());
+      activeRuleParams = getActiveRuleParams(session, activeRule.get());
     }
     if (parent) {
-      context.setParentActiveRule(activeRule.orNull());
+      context.setParentActiveRule(activeRule.orElse(null));
       context.setParentActiveRuleParams(activeRuleParams);
     } else {
-      context.setActiveRule(activeRule.orNull());
+      context.setActiveRule(activeRule.orElse(null));
       context.setActiveRuleParams(activeRuleParams);
     }
   }
+
+  Optional<RuleDto> getRule(DbSession dbSession, RuleKey ruleKey) {
+    return Optional.ofNullable(db.ruleDao().selectByKey(dbSession, ruleKey).orNull());
+  }
+
+  Optional<ActiveRuleDto> getActiveRule(DbSession session, ActiveRuleKey key) {
+    return Optional.ofNullable(db.activeRuleDao().selectByKey(session, key).orNull());
+  }
+
+  List<ActiveRuleParamDto> getActiveRuleParams(DbSession session, ActiveRuleDto activeRuleDto) {
+    return db.activeRuleDao().selectParamsByActiveRuleId(session, activeRuleDto.getId());
+  }
 }
index a7ab0d05aa0c6e26c187358ba0705205c316c059..6c61a05c8a7f7280ca1567e15183ab8cf7bd94c7 100644 (file)
@@ -40,6 +40,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.loadedtemplate.LoadedTemplateDto;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.qualityprofile.QualityProfileDto;
+import org.sonar.server.language.LanguageTesting;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
 import org.sonar.server.tester.UserSessionRule;
 
@@ -54,8 +55,8 @@ import static org.mockito.Mockito.when;
 import static org.sonar.core.util.UtcDateUtils.formatDateTime;
 
 public class RegisterQualityProfilesTest {
-  private static final DummyLanguage FOO_LANGUAGE = new DummyLanguage("foo");
-  private static final DummyLanguage BAR_LANGUAGE = new DummyLanguage("bar");
+  private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo", "foo", "foo");
+  private static final Language BAR_LANGUAGE = LanguageTesting.newLanguage("bar", "bar", "bar");
   private static final String TABLE_RULES_PROFILES = "RULES_PROFILES";
   private static final String TYPE_QUALITY_PROFILE = "QUALITY_PROFILE";
   private static final String SONAR_WAY_QP_NAME = "Sonar way";
@@ -374,7 +375,7 @@ public class RegisterQualityProfilesTest {
     return new RegisterQualityProfiles(
       dbClient,
       new QProfileFactory(dbClient, mockedUuidFactory, mockedSystem2),
-      new CachingRuleActivator(mockedSystem2, dbClient, null, new RuleActivatorContextFactory(dbClient), null, null, userSessionRule),
+      new CachingRuleActivator(mockedSystem2, dbClient, null, new CachingRuleActivatorContextFactory(dbClient), null, null, userSessionRule),
       definitions,
       languages,
       mockedActiveRuleIndexer);
@@ -411,29 +412,6 @@ public class RegisterQualityProfilesTest {
     }
   }
 
-  private static class DummyLanguage implements Language {
-    private final String key;
-
-    private DummyLanguage(String key) {
-      this.key = key;
-    }
-
-    @Override
-    public String getKey() {
-      return key;
-    }
-
-    @Override
-    public String getName() {
-      return key;
-    }
-
-    @Override
-    public String[] getFileSuffixes() {
-      return new String[] {key};
-    }
-  }
-
   private String computeLoadedTemplateType(DummyProfileDefinition qpDefinition) {
     String qpIdentifier = lowerCase(qpDefinition.getLanguage()) + ":" + qpDefinition.getName();
     return format("%s.%s", TYPE_QUALITY_PROFILE, DigestUtils.md5Hex(qpIdentifier.getBytes(UTF_8)));