Skip to content

Commit

Permalink
SONAR-10313 Do not retrieve rules in request twice
Browse files Browse the repository at this point in the history
When building IssueQuery and loading SearchResponseData
  • Loading branch information
sns-seb committed Feb 8, 2018
1 parent d91a7d9 commit 682c8c5
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 69 deletions.
Expand Up @@ -28,6 +28,7 @@
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.sonar.db.rule.RuleDefinitionDto;


import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT; import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
Expand Down Expand Up @@ -63,7 +64,7 @@ public class IssueQuery {
private final Collection<String> directories; private final Collection<String> directories;
private final Collection<String> files; private final Collection<String> files;
private final Collection<String> views; private final Collection<String> views;
private final Collection<Integer> rules; private final Collection<RuleDefinitionDto> rules;
private final Collection<String> assignees; private final Collection<String> assignees;
private final Collection<String> authors; private final Collection<String> authors;
private final Collection<String> languages; private final Collection<String> languages;
Expand Down Expand Up @@ -162,7 +163,7 @@ public Collection<String> viewUuids() {
return views; return views;
} }


public Collection<Integer> rules() { public Collection<RuleDefinitionDto> rules() {
return rules; return rules;
} }


Expand Down Expand Up @@ -273,7 +274,7 @@ public static class Builder {
private Collection<String> directories; private Collection<String> directories;
private Collection<String> files; private Collection<String> files;
private Collection<String> views; private Collection<String> views;
private Collection<Integer> rules; private Collection<RuleDefinitionDto> rules;
private Collection<String> assignees; private Collection<String> assignees;
private Collection<String> authors; private Collection<String> authors;
private Collection<String> languages; private Collection<String> languages;
Expand Down Expand Up @@ -353,7 +354,7 @@ public Builder viewUuids(@Nullable Collection<String> l) {
return this; return this;
} }


public Builder rules(@Nullable Collection<Integer> rules) { public Builder rules(@Nullable Collection<RuleDefinitionDto> rules) {
this.rules = rules; this.rules = rules;
return this; return this;
} }
Expand Down
Expand Up @@ -28,6 +28,7 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
Expand All @@ -44,7 +45,6 @@
import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ServerSide; import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
Expand Down Expand Up @@ -364,14 +364,11 @@ private List<ComponentDto> getComponentsFromUuids(DbSession dbSession, Collectio
} }


@CheckForNull @CheckForNull
private Collection<Integer> ruleKeysToRuleId(DbSession dbSession, @Nullable Collection<String> rules) { private Collection<RuleDefinitionDto> ruleKeysToRuleId(DbSession dbSession, @Nullable Collection<String> rules) {
if (rules != null) { if (rules != null) {
return dbClient.ruleDao().selectDefinitionByKeys(dbSession, transform(rules, RuleKey::parse)) return dbClient.ruleDao().selectDefinitionByKeys(dbSession, transform(rules, RuleKey::parse));
.stream()
.map(RuleDefinitionDto::getId)
.collect(MoreCollectors.toList());
} }
return null; return Collections.emptyList();
} }


private static String toProjectUuid(ComponentDto componentDto) { private static String toProjectUuid(ComponentDto componentDto) {
Expand Down
Expand Up @@ -21,6 +21,7 @@


import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
Expand Down Expand Up @@ -363,7 +364,9 @@ private SearchWsResponse doHandle(SearchRequest request, Request wsRequest) {
(!query.projectUuids().isEmpty()) || query.organizationUuid() != null, "Facet(s) '%s' require to also filter by project or organization", (!query.projectUuids().isEmpty()) || query.organizationUuid() != null, "Facet(s) '%s' require to also filter by project or organization",
COMA_JOINER.join(facetsRequiringProjectOrOrganizationParameter)); COMA_JOINER.join(facetsRequiringProjectOrOrganizationParameter));
} }
SearchResponseData data = searchResponseLoader.load(collector, facets); SearchResponseData preloadedData = new SearchResponseData(emptyList());
preloadedData.setRules(ImmutableList.copyOf(query.rules()));
SearchResponseData data = searchResponseLoader.load(preloadedData, collector, facets);


// format response // format response


Expand Down
Expand Up @@ -29,7 +29,6 @@
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.util.stream.MoreCollectors; import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
Expand Down Expand Up @@ -78,32 +77,11 @@ public SearchResponseLoader(UserSession userSession, DbClient dbClient, Transiti
this.transitionService = transitionService; this.transitionService = transitionService;
} }


/**
* The issue keys are given by the multi-criteria search in Elasticsearch index.
*/
public SearchResponseData load(Collector collector, @Nullable Facets facets) {
try (DbSession dbSession = dbClient.openSession(false)) {
SearchResponseData result = new SearchResponseData(dbClient.issueDao().selectByOrderedKeys(dbSession, collector.getIssueKeys()));
collector.collect(result.getIssues());

loadRules(collector, dbSession, result);
// order is important - loading of comments complete the list of users: loadComments() is
// before loadUsers()
loadComments(collector, dbSession, result);
loadUsers(collector, dbSession, result);
loadComponents(collector, dbSession, result);
loadOrganizations(dbSession, result);
loadActionsAndTransitions(collector, result);
completeTotalEffortFromFacet(facets, result);
return result;
}
}

/** /**
* The issue keys are given by the multi-criteria search in Elasticsearch index. * The issue keys are given by the multi-criteria search in Elasticsearch index.
* <p> * <p>
* Same as {@link #load(Collector, Facets)} but will only retrieve from DB data which is not already provided by the * Same as {@link #load(SearchResponseData, Collector, Facets)} but will only retrieve from DB data which is not
* specified preloaded {@link SearchResponseData}.<br/> * already provided by the specified preloaded {@link SearchResponseData}.<br/>
* The returned {@link SearchResponseData} is <strong>not</strong> the one specified as argument. * The returned {@link SearchResponseData} is <strong>not</strong> the one specified as argument.
* </p> * </p>
*/ */
Expand Down Expand Up @@ -186,23 +164,17 @@ private void addProjectUuids(Collector collector, DbSession dbSession, SearchRes
private void loadRules(SearchResponseData preloadedResponseData, Collector collector, DbSession dbSession, SearchResponseData result) { private void loadRules(SearchResponseData preloadedResponseData, Collector collector, DbSession dbSession, SearchResponseData result) {
if (collector.contains(RULES)) { if (collector.contains(RULES)) {
List<RuleDefinitionDto> preloadedRules = firstNonNull(preloadedResponseData.getRules(), emptyList()); List<RuleDefinitionDto> preloadedRules = firstNonNull(preloadedResponseData.getRules(), emptyList());
Set<RuleKey> preloaedRuleKeys = preloadedRules.stream().map(RuleDefinitionDto::getKey).collect(MoreCollectors.toSet()); Set<Integer> preloaedRuleKeys = preloadedRules.stream().map(RuleDefinitionDto::getId).collect(MoreCollectors.toSet());
Set<RuleKey> ruleKeysToLoad = copyOf(difference(collector.get(RULES), preloaedRuleKeys)); Set<Integer> ruleKeysToLoad = copyOf(difference(collector.get(RULES), preloaedRuleKeys));
if (ruleKeysToLoad.isEmpty()) { if (ruleKeysToLoad.isEmpty()) {
result.setRules(preloadedResponseData.getRules()); result.setRules(preloadedResponseData.getRules());
} else { } else {
List<RuleDefinitionDto> loadedRules = dbClient.ruleDao().selectDefinitionByKeys(dbSession, ruleKeysToLoad); List<RuleDefinitionDto> loadedRules = dbClient.ruleDao().selectDefinitionByIds(dbSession, ruleKeysToLoad);
result.setRules(concat(preloadedRules.stream(), loadedRules.stream()).collect(toList(preloadedRules.size() + loadedRules.size()))); result.setRules(concat(preloadedRules.stream(), loadedRules.stream()).collect(toList(preloadedRules.size() + loadedRules.size())));
} }
} }
} }


private void loadUsers(Collector collector, DbSession dbSession, SearchResponseData result) {
if (collector.contains(USERS)) {
result.setUsers(dbClient.userDao().selectByLogins(dbSession, collector.getList(USERS)));
}
}

private void loadComments(Collector collector, DbSession dbSession, SearchResponseData result) { private void loadComments(Collector collector, DbSession dbSession, SearchResponseData result) {
if (collector.contains(COMMENTS)) { if (collector.contains(COMMENTS)) {
List<IssueChangeDto> comments = dbClient.issueChangeDao().selectByTypeAndIssueKeys(dbSession, collector.getIssueKeys(), IssueChangeDto.TYPE_COMMENT); List<IssueChangeDto> comments = dbClient.issueChangeDao().selectByTypeAndIssueKeys(dbSession, collector.getIssueKeys(), IssueChangeDto.TYPE_COMMENT);
Expand All @@ -220,20 +192,6 @@ private boolean canEditOrDelete(IssueChangeDto dto) {
return userSession.isLoggedIn() && userSession.getLogin().equals(dto.getUserLogin()); return userSession.isLoggedIn() && userSession.getLogin().equals(dto.getUserLogin());
} }


private void loadRules(Collector collector, DbSession dbSession, SearchResponseData result) {
if (collector.contains(RULES)) {
result.setRules(dbClient.ruleDao().selectDefinitionByIds(dbSession, collector.getList(RULES)));
}
}

private void loadComponents(Collector collector, DbSession dbSession, SearchResponseData result) {
// always load components and projects, because some issue fields still relate to component ids/keys.
// They should be dropped but are kept for backward-compatibility (see SearchResponseFormat)
result.addComponents(dbClient.componentDao().selectByUuids(dbSession, collector.getComponentUuids()));
result.addComponents(dbClient.componentDao().selectSubProjectsByComponentUuids(dbSession, collector.getComponentUuids()));
addProjectUuids(collector, dbSession, result);
}

private void loadOrganizations(DbSession dbSession, SearchResponseData result) { private void loadOrganizations(DbSession dbSession, SearchResponseData result) {
Collection<ComponentDto> components = result.getComponents(); Collection<ComponentDto> components = result.getComponents();
dbClient.organizationDao().selectByUuids( dbClient.organizationDao().selectByUuids(
Expand Down Expand Up @@ -364,10 +322,6 @@ <T> Set<T> get(SearchAdditionalField key) {
return (Set<T>) fieldValues.get(key); return (Set<T>) fieldValues.get(key);
} }


<T> List<T> getList(SearchAdditionalField key) {
return newArrayList(get(key));
}

boolean contains(SearchAdditionalField field) { boolean contains(SearchAdditionalField field) {
return fields.contains(field); return fields.contains(field);
} }
Expand Down
Expand Up @@ -25,6 +25,7 @@
import org.junit.Test; import org.junit.Test;
import org.sonar.api.issue.Issue; import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity; import org.sonar.api.rule.Severity;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.issue.IssueQuery.PeriodStart; import org.sonar.server.issue.IssueQuery.PeriodStart;


import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
Expand All @@ -36,8 +37,8 @@ public class IssueQueryTest {


@Test @Test
public void build_query() { public void build_query() {
int ruleId = nextInt(1000); RuleDefinitionDto rule = new RuleDefinitionDto().setId(nextInt(1000));
PeriodStart filterDate = new IssueQuery.PeriodStart(new Date(10_000_000_000L),false); PeriodStart filterDate = new IssueQuery.PeriodStart(new Date(10_000_000_000L), false);
IssueQuery query = IssueQuery.builder() IssueQuery query = IssueQuery.builder()
.issueKeys(newArrayList("ABCDE")) .issueKeys(newArrayList("ABCDE"))
.severities(newArrayList(Severity.BLOCKER)) .severities(newArrayList(Severity.BLOCKER))
Expand All @@ -46,7 +47,7 @@ public void build_query() {
.projectUuids(newArrayList("PROJECT")) .projectUuids(newArrayList("PROJECT"))
.componentUuids(newArrayList("org/struts/Action.java")) .componentUuids(newArrayList("org/struts/Action.java"))
.moduleUuids(newArrayList("org.struts:core")) .moduleUuids(newArrayList("org.struts:core"))
.rules(newArrayList(ruleId)) .rules(newArrayList(rule))
.assignees(newArrayList("gargantua")) .assignees(newArrayList("gargantua"))
.languages(newArrayList("xoo")) .languages(newArrayList("xoo"))
.tags(newArrayList("tag1", "tag2")) .tags(newArrayList("tag1", "tag2"))
Expand Down Expand Up @@ -77,7 +78,7 @@ public void build_query() {
assertThat(query.branchUuid()).isEqualTo("my_branch"); assertThat(query.branchUuid()).isEqualTo("my_branch");
assertThat(query.createdAfterByProjectUuids()).containsOnly(entry("PROJECT", filterDate)); assertThat(query.createdAfterByProjectUuids()).containsOnly(entry("PROJECT", filterDate));
assertThat(query.assigned()).isTrue(); assertThat(query.assigned()).isTrue();
assertThat(query.rules()).containsOnly(ruleId); assertThat(query.rules()).containsOnly(rule);
assertThat(query.createdAfter()).isNotNull(); assertThat(query.createdAfter()).isNotNull();
assertThat(query.createdBefore()).isNotNull(); assertThat(query.createdBefore()).isNotNull();
assertThat(query.createdAt()).isNotNull(); assertThat(query.createdAt()).isNotNull();
Expand Down
Expand Up @@ -526,8 +526,8 @@ public void filter_by_rules() {


indexIssues(newDoc("I1", file).setRuleId(ruleDefinitionDto.getId())); indexIssues(newDoc("I1", file).setRuleId(ruleDefinitionDto.getId()));


assertThatSearchReturnsOnly(IssueQuery.builder().rules(singletonList(ruleDefinitionDto.getId())), "I1"); assertThatSearchReturnsOnly(IssueQuery.builder().rules(singletonList(ruleDefinitionDto)), "I1");
assertThatSearchReturnsEmpty(IssueQuery.builder().rules(singletonList(-1))); assertThatSearchReturnsEmpty(IssueQuery.builder().rules(singletonList(new RuleDefinitionDto().setId(-1))));
} }


@Test @Test
Expand Down

0 comments on commit 682c8c5

Please sign in to comment.