Selaa lähdekoodia

SONAR-19324 Fix api/projects/search low performances

tags/10.2.0.77647
Alain Kermis 9 kuukautta sitten
vanhempi
commit
41ab6192d3
16 muutettua tiedostoa jossa 214 lisäystä ja 171 poistoa
  1. 38
    51
      server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java
  2. 5
    5
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
  3. 2
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java
  4. 0
    31
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java
  5. 16
    45
      server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
  6. 43
    27
      server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml
  7. 1
    0
      server/sonar-db-dao/src/schema/schema-sq.ddl
  8. 2
    4
      server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java
  9. 33
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateIndexProjectUuidInProjectBranches.java
  10. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/DbVersion102.java
  11. 49
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/CreateIndexProjectUuidInProjectBranchesTest.java
  12. 15
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/CreateIndexProjectUuidInProjectBranchesTest/schema.sql
  13. 1
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
  14. 3
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/template/BulkApplyTemplateAction.java
  15. 2
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
  16. 2
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchAction.java

+ 38
- 51
server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java Näytä tiedosto

@@ -44,6 +44,7 @@ import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.Pagination;
import org.sonar.db.RowNotFoundException;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.NoOpAuditPersister;
@@ -79,6 +80,7 @@ import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.SUBVIEW;
import static org.sonar.api.resources.Qualifiers.VIEW;
import static org.sonar.api.utils.DateUtils.parseDate;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
import static org.sonar.db.component.BranchType.BRANCH;
import static org.sonar.db.component.BranchType.PULL_REQUEST;
@@ -931,35 +933,35 @@ public class ComponentDaoIT {
SnapshotDto analyzedPortfolio = db.components().insertProjectAndSnapshot(ComponentTesting.newPortfolio());

Supplier<ComponentQuery.Builder> query = () -> ComponentQuery.builder().setQualifiers(PROJECT).setOnProvisionedOnly(true);
assertThat(underTest.selectByQuery(dbSession, query.get().build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsOnly(provisionedProject.uuid());

// pagination
assertThat(underTest.selectByQuery(dbSession, query.get().build(), 2, 10)).isEmpty();
assertThat(underTest.selectByQuery(dbSession, query.get().build(), forPage(3).andSize(10))).isEmpty();

// filter on qualifiers
assertThat(underTest.selectByQuery(dbSession, query.get().setQualifiers("XXX").build(), 0, 10)).isEmpty();
assertThat(underTest.selectByQuery(dbSession, query.get().setQualifiers(PROJECT, "XXX").build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().setQualifiers("XXX").build(), forPage(1).andSize(10))).isEmpty();
assertThat(underTest.selectByQuery(dbSession, query.get().setQualifiers(PROJECT, "XXX").build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsOnly(provisionedProject.uuid());
assertThat(underTest.selectByQuery(dbSession, query.get().setQualifiers(PROJECT, Qualifiers.VIEW).build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().setQualifiers(PROJECT, Qualifiers.VIEW).build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsOnly(provisionedProject.uuid(), provisionedPortfolio.uuid());

// match key
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery(provisionedProject.getKey()).build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery(provisionedProject.getKey()).build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsExactly(provisionedProject.uuid());
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("pROvisiONed.proJEcT").setPartialMatchOnKey(true).build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("pROvisiONed.proJEcT").setPartialMatchOnKey(true).build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsExactly(provisionedProject.uuid());
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("missing").setPartialMatchOnKey(true).build(), 0, 10)).isEmpty();
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("to be escaped '\"\\%").setPartialMatchOnKey(true).build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("missing").setPartialMatchOnKey(true).build(), forPage(1).andSize(10))).isEmpty();
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("to be escaped '\"\\%").setPartialMatchOnKey(true).build(), forPage(1).andSize(10)))
.isEmpty();

// match name
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("ned proj").setPartialMatchOnKey(true).build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().setNameOrKeyQuery("ned proj").setPartialMatchOnKey(true).build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsExactly(provisionedProject.uuid());
}
@@ -972,7 +974,7 @@ public class ComponentDaoIT {

// the project does not have any analysis
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
assertThat(underTest.selectByQuery(dbSession, query.get().build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().build(), forPage(1).andSize(10)))
.extracting(ComponentDto::uuid)
.containsOnly(project.uuid());

@@ -981,7 +983,7 @@ public class ComponentDaoIT {
ComponentDto branchWithoutAnalysis = db.components().insertProjectBranch(project);
ComponentDto branchWithAnalysis = db.components().insertProjectBranch(project);
db.components().insertSnapshot(branchWithAnalysis);
assertThat(underTest.selectByQuery(dbSession, query.get().build(), 0, 10))
assertThat(underTest.selectByQuery(dbSession, query.get().build(), forPage(1).andSize(10)))
.isEmpty();
}

@@ -999,7 +1001,7 @@ public class ComponentDaoIT {
.setQualifiers(PROJECT)
.setOnProvisionedOnly(true);

List<ComponentDto> results = underTest.selectByQuery(dbSession, query.get().build(), 0, 10);
List<ComponentDto> results = underTest.selectByQuery(dbSession, query.get().build(), forPage(1).andSize(10));
assertThat(results)
.extracting(ComponentDto::uuid)
.containsExactly(
@@ -1172,7 +1174,8 @@ public class ComponentDaoIT {

private void assertThatSelectByQueryThrowsIAE(ComponentQuery.Builder query, String expectedMessage) {
ComponentQuery componentQuery = query.build();
assertThatThrownBy(() -> underTest.selectByQuery(dbSession, componentQuery, 0, Integer.MAX_VALUE))
Pagination pagination = forPage(1).andSize(Integer.MAX_VALUE);
assertThatThrownBy(() -> underTest.selectByQuery(dbSession, componentQuery, pagination))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(expectedMessage);
}
@@ -1186,12 +1189,12 @@ public class ComponentDaoIT {
}

ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("oJect").setQualifiers(PROJECT).build();
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 1, 3);
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, forPage(2).andSize(3));
int count = underTest.countByQuery(dbSession, query);

assertThat(result).hasSize(3);
assertThat(count).isEqualTo(9);
assertThat(result).extracting(ComponentDto::name).containsExactly("project-2", "project-3", "project-4");
assertThat(result).extracting(ComponentDto::name).containsExactly("project-4", "project-5", "project-6");
}

@Test
@@ -1199,8 +1202,8 @@ public class ComponentDaoIT {
ComponentDto main = db.components().insertPublicProject().getMainBranchComponent();
ComponentDto branch = db.components().insertProjectBranch(main);

assertThat(underTest.selectByQuery(dbSession, ALL_PROJECTS_COMPONENT_QUERY, 0, 2)).hasSize(1);
assertThat(underTest.selectByQuery(dbSession, ALL_PROJECTS_COMPONENT_QUERY, 0, 2).get(0).uuid()).isEqualTo(main.uuid());
assertThat(underTest.selectByQuery(dbSession, ALL_PROJECTS_COMPONENT_QUERY, forPage(1).andSize(2))).hasSize(1);
assertThat(underTest.selectByQuery(dbSession, ALL_PROJECTS_COMPONENT_QUERY, forPage(1).andSize(2)).get(0).uuid()).isEqualTo(main.uuid());
}

@Test
@@ -1216,7 +1219,7 @@ public class ComponentDaoIT {
db.components().insertProjectAndSnapshot(newPrivateProjectDto().setName("project-\\_%/-name"));

ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("-\\_%/-").setQualifiers(PROJECT).build();
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, forPage(1).andSize(10));

assertThat(result).hasSize(1);
assertThat(result.get(0).name()).isEqualTo("project-\\_%/-name");
@@ -1228,7 +1231,7 @@ public class ComponentDaoIT {
db.components().insertProjectAndSnapshot(newPrivateProjectDto().setKey("project-key-that-does-not-match"));

ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("project-_%-key").setQualifiers(PROJECT).build();
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, forPage(1).andSize(10));

assertThat(result).hasSize(1);
assertThat(result.get(0).getKey()).isEqualTo("project-_%-key");
@@ -1242,7 +1245,7 @@ public class ComponentDaoIT {
.setNameOrKeyQuery("JECT-K")
.setPartialMatchOnKey(true)
.setQualifiers(PROJECT).build();
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, forPage(1).andSize(10));

assertThat(result).hasSize(1);
assertThat(result.get(0).getKey()).isEqualTo("project-key");
@@ -1267,19 +1270,11 @@ public class ComponentDaoIT {
.containsExactlyInAnyOrder(oldProject.uuid(), recentProject.uuid());

// before date on any branch
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedBefore(recentTime)))
assertThat(selectProjectUuidsByQuery(q -> q.setAllBranchesAnalyzedBefore(recentTime)))
.containsExactlyInAnyOrder(oldProject.uuid());
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedBefore(aLongTimeAgo)))
assertThat(selectProjectUuidsByQuery(q -> q.setAllBranchesAnalyzedBefore(aLongTimeAgo)))
.isEmpty();
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedBefore(recentTime + 1_000L)))
.containsExactlyInAnyOrder(oldProject.uuid(), recentProject.uuid());

// after date
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedAfter(recentTime - 1_000L)))
.containsExactlyInAnyOrder(recentProject.uuid());
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedAfter(recentTime + 1_000L)))
.isEmpty();
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedAfter(aLongTimeAgo)))
assertThat(selectProjectUuidsByQuery(q -> q.setAllBranchesAnalyzedBefore(recentTime + 1_000L)))
.containsExactlyInAnyOrder(oldProject.uuid(), recentProject.uuid());
}

@@ -1306,19 +1301,11 @@ public class ComponentDaoIT {
assertThat(selectProjectUuidsByQuery(q -> q.setAnalyzedBefore(recentTime + 1_000L))).isEmpty();

// before date on any branch
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedBefore(recentTime)))
assertThat(selectProjectUuidsByQuery(q -> q.setAllBranchesAnalyzedBefore(recentTime)))
.containsExactlyInAnyOrder(oldProject.uuid());
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedBefore(aLongTimeAgo)))
.isEmpty();
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedBefore(recentTime + 1_000L)))
.containsExactlyInAnyOrder(oldProject.uuid(), recentProject.uuid());

// after date
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedAfter(recentTime - 1_000L)))
.containsExactlyInAnyOrder(recentProject.uuid());
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedAfter(recentTime + 1_000L)))
assertThat(selectProjectUuidsByQuery(q -> q.setAllBranchesAnalyzedBefore(aLongTimeAgo)))
.isEmpty();
assertThat(selectProjectUuidsByQuery(q -> q.setAnyBranchAnalyzedAfter(aLongTimeAgo)))
assertThat(selectProjectUuidsByQuery(q -> q.setAllBranchesAnalyzedBefore(recentTime + 1_000L)))
.containsExactlyInAnyOrder(oldProject.uuid(), recentProject.uuid());
}

@@ -1387,7 +1374,7 @@ public class ComponentDaoIT {
private List<String> selectUuidsByQuery(String qualifier, Consumer<ComponentQuery.Builder> query) {
ComponentQuery.Builder builder = ComponentQuery.builder().setQualifiers(qualifier);
query.accept(builder);
return underTest.selectByQuery(dbSession, builder.build(), 0, 5)
return underTest.selectByQuery(dbSession, builder.build(), forPage(1).andSize(5))
.stream()
.map(ComponentDto::uuid)
.toList();
@@ -1402,9 +1389,9 @@ public class ComponentDaoIT {
ComponentQuery publicProjectsQuery = ComponentQuery.builder().setPrivate(false).setQualifiers(PROJECT).build();
ComponentQuery allProjectsQuery = ComponentQuery.builder().setPrivate(null).setQualifiers(PROJECT).build();

assertThat(underTest.selectByQuery(dbSession, privateProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsExactly("private-key");
assertThat(underTest.selectByQuery(dbSession, publicProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsExactly("public-key");
assertThat(underTest.selectByQuery(dbSession, allProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsOnly("public-key", "private-key");
assertThat(underTest.selectByQuery(dbSession, privateProjectsQuery, forPage(1).andSize(10))).extracting(ComponentDto::getKey).containsExactly("private-key");
assertThat(underTest.selectByQuery(dbSession, publicProjectsQuery, forPage(1).andSize(10))).extracting(ComponentDto::getKey).containsExactly("public-key");
assertThat(underTest.selectByQuery(dbSession, allProjectsQuery, forPage(1).andSize(10))).extracting(ComponentDto::getKey).containsOnly("public-key", "private-key");
}

@Test
@@ -1412,7 +1399,7 @@ public class ComponentDaoIT {
db.components().insertPrivateProject().getMainBranchComponent();
ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(PROJECT).setComponentKeys(emptySet()).build();

List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, forPage(1).andSize(10));
int count = underTest.countByQuery(dbSession, dbQuery);

assertThat(result).isEmpty();
@@ -1427,7 +1414,7 @@ public class ComponentDaoIT {
ComponentQuery query = ComponentQuery.builder().setQualifiers(PROJECT)
.setComponentKeys(newHashSet(sonarqube.getKey(), jdk8.getKey())).build();

List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, forPage(1).andSize(10));

assertThat(result).hasSize(2).extracting(ComponentDto::getKey)
.containsExactlyInAnyOrder(sonarqube.getKey(), jdk8.getKey())
@@ -1439,7 +1426,7 @@ public class ComponentDaoIT {
db.components().insertPrivateProject().getMainBranchComponent();
ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(PROJECT).setComponentUuids(emptySet()).build();

List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, forPage(1).andSize(10));
int count = underTest.countByQuery(dbSession, dbQuery);

assertThat(result).isEmpty();
@@ -1454,7 +1441,7 @@ public class ComponentDaoIT {
ComponentQuery query = ComponentQuery.builder().setQualifiers(PROJECT)
.setComponentUuids(newHashSet(sonarqube.uuid(), jdk8.uuid())).build();

List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
List<ComponentDto> result = underTest.selectByQuery(dbSession, query, forPage(1).andSize(10));

assertThat(result).hasSize(2).extracting(ComponentDto::uuid)
.containsOnlyOnce(sonarqube.uuid(), jdk8.uuid())

+ 5
- 5
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java Näytä tiedosto

@@ -31,10 +31,10 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.sonar.api.resources.Qualifiers;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.Pagination;
import org.sonar.db.RowNotFoundException;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.model.ComponentNewValue;
@@ -104,8 +104,8 @@ public class ComponentDao implements Dao {
* @throws IllegalArgumentException if parameter query#getComponentKeys() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values
* @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values
*/
public List<ComponentDto> selectByQuery(DbSession dbSession, ComponentQuery query, int offset, int limit) {
return selectByQueryImpl(dbSession, query, offset, limit);
public List<ComponentDto> selectByQuery(DbSession dbSession, ComponentQuery query, Pagination pagination) {
return selectByQueryImpl(dbSession, query, pagination);
}

/**
@@ -117,12 +117,12 @@ public class ComponentDao implements Dao {
return countByQueryImpl(session, query);
}

private static List<ComponentDto> selectByQueryImpl(DbSession session, ComponentQuery query, int offset, int limit) {
private static List<ComponentDto> selectByQueryImpl(DbSession session, ComponentQuery query, Pagination pagination) {
if (query.hasEmptySetOfComponents()) {
return emptyList();
}
checkThatNotTooManyComponents(query);
return mapper(session).selectByQuery(query, new RowBounds(offset, limit));
return mapper(session).selectByQuery(query, pagination);
}

private static int countByQueryImpl(DbSession session, ComponentQuery query) {

+ 2
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java Näytä tiedosto

@@ -26,7 +26,7 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.sonar.db.Pagination;

public interface ComponentMapper {
@CheckForNull
@@ -54,7 +54,7 @@ public interface ComponentMapper {

List<ComponentDto> selectComponentsByQualifiers(@Param("qualifiers") Collection<String> qualifiers);

List<ComponentDto> selectByQuery(@Param("query") ComponentQuery query, RowBounds rowBounds);
List<ComponentDto> selectByQuery(@Param("query") ComponentQuery query, @Param("pagination") Pagination pagination);

int countByQuery(@Param("query") ComponentQuery query);


+ 0
- 31
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java Näytä tiedosto

@@ -38,8 +38,6 @@ public class ComponentQuery {
private final Set<String> componentUuids;
private final Set<String> componentKeys;
private final Long analyzedBefore;
private final Long anyBranchAnalyzedBefore;
private final Long anyBranchAnalyzedAfter;
private final Long allBranchesAnalyzedBefore;
private final Date createdAfter;
private final boolean onProvisionedOnly;
@@ -52,8 +50,6 @@ public class ComponentQuery {
this.componentKeys = builder.componentKeys;
this.isPrivate = builder.isPrivate;
this.analyzedBefore = builder.analyzedBefore;
this.anyBranchAnalyzedBefore = builder.anyBranchAnalyzedBefore;
this.anyBranchAnalyzedAfter = builder.anyBranchAnalyzedAfter;
this.allBranchesAnalyzedBefore = builder.allBranchesAnalyzedBefore;
this.createdAfter = builder.createdAfter;
this.onProvisionedOnly = builder.onProvisionedOnly;
@@ -103,16 +99,6 @@ public class ComponentQuery {
return analyzedBefore;
}

@CheckForNull
public Long getAnyBranchAnalyzedBefore() {
return anyBranchAnalyzedBefore;
}

@CheckForNull
public Long getAnyBranchAnalyzedAfter() {
return anyBranchAnalyzedAfter;
}

@CheckForNull
public Long getAllBranchesAnalyzedBefore() {
return allBranchesAnalyzedBefore;
@@ -144,8 +130,6 @@ public class ComponentQuery {
private Set<String> componentUuids;
private Set<String> componentKeys;
private Long analyzedBefore;
private Long anyBranchAnalyzedBefore;
private Long anyBranchAnalyzedAfter;
private Long allBranchesAnalyzedBefore;
private Date createdAfter;
private boolean onProvisionedOnly = false;
@@ -193,21 +177,6 @@ public class ComponentQuery {
return this;
}

/**
* Filter on date of last analysis. On projects, all branches and pull requests are taken into
* account. For example the analysis of a branch is included in the filter
* even if the main branch has never been analyzed.
*/
public Builder setAnyBranchAnalyzedAfter(@Nullable Long l) {
this.anyBranchAnalyzedAfter = l;
return this;
}

public Builder setAnyBranchAnalyzedBefore(@Nullable Long l) {
this.anyBranchAnalyzedBefore = l;
return this;
}

public Builder setCreatedAfter(@Nullable Date l) {
this.createdAfter = l;
return this;

+ 16
- 45
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml Näytä tiedosto

@@ -210,19 +210,34 @@
</select>

<select id="selectByQuery" resultType="Component">
<include refid="mainBranchAndPortfoliosWith"/>
select
<include refid="componentColumns"/>
<include refid="sqlSelectByQuery"/>
ORDER BY LOWER(p.name), p.name, p.created_at
offset (#{pagination.startRowNumber,jdbcType=INTEGER}-1) rows fetch next #{pagination.pageSize,jdbcType=INTEGER} rows only
</select>

<select id="countByQuery" resultType="int">
<include refid="mainBranchAndPortfoliosWith"/>
select count(p.uuid)
<include refid="sqlSelectByQuery"/>
</select>

<sql id="mainBranchAndPortfoliosWith">
WITH main_branch_and_portfolios AS (SELECT p.uuid as projectUuid, p.kee as kee, p.uuid
from portfolios p
UNION
SELECT pb.project_uuid as projectUuid, p.kee as kee, pb.uuid
FROM project_branches pb
INNER JOIN projects p on pb.project_uuid = p.uuid
where pb.is_main = ${_true}
)
</sql>

<sql id="sqlSelectByQuery">
from components p
from main_branch_and_portfolios mbp
INNER JOIN components p on mbp.kee = p.kee and p.branch_uuid = mbp.uuid
<if test="query.analyzedBefore!=null">
inner join snapshots sa on sa.root_component_uuid=p.uuid
and sa.status='P' and sa.islast=${_true} and sa.created_at &lt; #{query.analyzedBefore,jdbcType=BIGINT}
@@ -230,8 +245,6 @@
left join project_branches pb on pb.uuid = p.branch_uuid
where
p.enabled=${_true}
AND <include refid="mainBranchOrPortfolio"/>
AND p.copy_component_uuid is null
<if test="query.qualifiers!=null">
and p.qualifier in
<foreach collection="query.qualifiers" item="qualifier" open="(" close=")" separator=",">
@@ -280,48 +293,6 @@
where pb2.project_uuid = pb.project_uuid
)
</if>
<if test="query.anyBranchAnalyzedAfter != null">
and (
exists(
-- branches of projects and applications
select 1 from snapshots s
inner join project_branches pb2 on s.root_component_uuid = pb2.uuid
where pb2.project_uuid = pb.project_uuid
and s.status='P'
and s.islast = ${_true}
and s.created_at &gt;= #{query.anyBranchAnalyzedAfter,jdbcType=BIGINT}
)
or exists (
-- portfolios
select 1 from snapshots s
where s.root_component_uuid = p.uuid
and s.status='P'
and s.islast = ${_true}
and s.created_at &gt;= #{query.anyBranchAnalyzedAfter,jdbcType=BIGINT}
)
)
</if>
<if test="query.anyBranchAnalyzedBefore != null">
and (
exists(
-- branches of projects and applications
select 1 from snapshots s
inner join project_branches pb2 on s.root_component_uuid = pb2.uuid
where pb2.project_uuid = pb.project_uuid
and s.status='P'
and s.islast = ${_true}
and s.created_at &lt; #{query.anyBranchAnalyzedBefore,jdbcType=BIGINT}
)
or exists (
-- portfolios
select 1 from snapshots s
where s.root_component_uuid = p.uuid
and s.status='P'
and s.islast = ${_true}
and s.created_at &lt; #{query.anyBranchAnalyzedBefore,jdbcType=BIGINT}
)
)
</if>
<if test="query.allBranchesAnalyzedBefore != null">
and
(

+ 43
- 27
server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml Näytä tiedosto

@@ -54,38 +54,54 @@
and coalesce(pb.project_uuid, p.branch_uuid) = #{projectUuid,jdbcType=VARCHAR}
</select>

<select id="selectLastAnalysisDateByProjectUuids" resultType="org.sonar.db.component.ProjectLastAnalysisDateDto">
<select id="selectLastAnalysisDateByProjectUuids" resultType="org.sonar.db.component.ProjectLastAnalysisDateDto">
select
result_with_duplicates.project_uuid as project_uuid ,
result_with_duplicates.project_uuid as project_uuid,
max(result_with_duplicates.last_analysis_date) as last_analysis_date
from
FROM
(
select
coalesce(pb.project_uuid, c.branch_uuid) as project_uuid,
s.created_at as last_analysis_date
from
snapshots s
inner join components c on s.root_component_uuid = c.branch_uuid
left join project_branches pb on pb.uuid = c.branch_uuid
where
s.islast = ${_true}
and (
<!-- case of an analysis of a project or app, with entries in project_branches -->
(pb.uuid is not null and pb.project_uuid in
<foreach collection="projectUuids" item="projectUuid" separator="," open="(" close=")">
#{projectUuid,jdbcType=VARCHAR}
</foreach>)
or
<!-- case of an analysis of a portfolio, where there are no branches -->
(pb.uuid is null and c.branch_uuid in
<foreach collection="projectUuids" item="projectUuid" separator="," open="(" close=")">
#{projectUuid,jdbcType=VARCHAR}
</foreach>)
)
<!-- cases of an analysis of a project or app, with entries in project_branches -->
SELECT project_uuid, last_analysis_date
FROM (
SELECT
COALESCE(pb.project_uuid, c.branch_uuid) AS project_uuid,
s.created_at AS last_analysis_date
FROM snapshots s
INNER JOIN components c ON s.root_component_uuid = c.branch_uuid
LEFT JOIN project_branches pb ON pb.uuid = c.branch_uuid
WHERE
s.islast = ${_true}
AND pb.uuid IS NOT NULL
AND pb.project_uuid IN
<foreach collection="projectUuids" item="projectUuid" separator="," open="(" close=")">
#{projectUuid,jdbcType=VARCHAR}
</foreach>
) project_case

UNION

<!-- cases of an analysis of a portfolio, where there are no branches -->
SELECT project_uuid, last_analysis_date
FROM (
SELECT
COALESCE(pb.project_uuid, c.branch_uuid) AS project_uuid,
s.created_at AS last_analysis_date
FROM snapshots s
INNER JOIN components c ON s.root_component_uuid = c.branch_uuid
LEFT JOIN project_branches pb ON pb.uuid = c.branch_uuid
WHERE
s.islast = ${_true}
AND pb.branch_type IS NULL
AND pb.uuid IS NULL
AND c.branch_uuid IN
<foreach collection="projectUuids" item="projectUuid" separator="," open="(" close=")">
#{projectUuid,jdbcType=VARCHAR}
</foreach>
) portfolio_case
) result_with_duplicates
group by
result_with_duplicates.project_uuid
GROUP BY project_uuid
</select>

<select id="selectLastSnapshotByRootComponentUuid" resultType="Snapshot">
select <include refid="snapshotColumns" />
from snapshots s

+ 1
- 0
server/sonar-db-dao/src/schema/schema-sq.ddl Näytä tiedosto

@@ -690,6 +690,7 @@ CREATE TABLE "PROJECT_BRANCHES"(
);
ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);
CREATE INDEX "PROJECT_BRANCHES_PROJECT_UUID" ON "PROJECT_BRANCHES"("PROJECT_UUID" NULLS FIRST);

CREATE TABLE "PROJECT_LINKS"(
"UUID" CHARACTER VARYING(40) NOT NULL,

+ 2
- 4
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java Näytä tiedosto

@@ -36,16 +36,14 @@ public class ComponentQueryTest {
public void build_query() {
ComponentQuery underTest = ComponentQuery.builder()
.setNameOrKeyQuery("key")
.setAnyBranchAnalyzedBefore(100L)
.setAnyBranchAnalyzedAfter(200L)
.setAllBranchesAnalyzedBefore(100L)
.setCreatedAfter(new Date(300L))
.setQualifiers(PROJECT)
.build();

assertThat(underTest.getNameOrKeyQuery()).isEqualTo("key");
assertThat(underTest.getQualifiers()).containsOnly(PROJECT);
assertThat(underTest.getAnyBranchAnalyzedBefore()).isEqualTo(100L);
assertThat(underTest.getAnyBranchAnalyzedAfter()).isEqualTo(200L);
assertThat(underTest.getAllBranchesAnalyzedBefore()).isEqualTo(100L);
assertThat(underTest.getCreatedAfter().getTime()).isEqualTo(300L);
assertThat(underTest.isOnProvisionedOnly()).isFalse();
assertThat(underTest.isPartialMatchOnKey()).isFalse();

+ 33
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/CreateIndexProjectUuidInProjectBranches.java Näytä tiedosto

@@ -0,0 +1,33 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.platform.db.migration.version.v102;

import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.CreateIndexOnColumn;

class CreateIndexProjectUuidInProjectBranches extends CreateIndexOnColumn {

private static final String TABLE_NAME = "project_branches";
private static final String COLUMN_NAME = "project_uuid";

public CreateIndexProjectUuidInProjectBranches(Database db) {
super(db, TABLE_NAME, COLUMN_NAME, false);
}
}

+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v102/DbVersion102.java Näytä tiedosto

@@ -25,7 +25,6 @@ import org.sonar.server.platform.db.migration.version.DbVersion;
// ignoring bad number formatting, as it's indented that we align the migration numbers to SQ versions
@SuppressWarnings("java:S3937")
public class DbVersion102 implements DbVersion {

/**
* We use the start of the 10.X cycle as an opportunity to align migration numbers with the SQ version number.
* Please follow this pattern:
@@ -98,6 +97,7 @@ public class DbVersion102 implements DbVersion {
.add(10_2_043, "Create 'previous_non_compliant_value' in 'new_code_periods' table", CreatePreviousNonCompliantValueInNewCodePeriods.class)
.add(10_2_044, "Update column 'value' and populate column 'previous_non_compliant_value' in 'new_code_periods' table",
UpdateValueAndPopulatePreviousNonCompliantValueInNewCodePeriods.class)
.add(10_2_045, "Alter 'project_uuid' in 'user_dismissed_messages' - make it nullable", MakeProjectUuidNullableInUserDismissedMessages.class);
.add(10_2_045, "Alter 'project_uuid' in 'user_dismissed_messages' - make it nullable", MakeProjectUuidNullableInUserDismissedMessages.class)
.add(10_2_046, "Create index 'project_branches_project_uuid' in 'project_branches' table", CreateIndexProjectUuidInProjectBranches.class);
}
}

+ 49
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v102/CreateIndexProjectUuidInProjectBranchesTest.java Näytä tiedosto

@@ -0,0 +1,49 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.platform.db.migration.version.v102;

import java.sql.SQLException;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.db.CoreDbTester;

public class CreateIndexProjectUuidInProjectBranchesTest {
@Rule
public final CoreDbTester db = CoreDbTester.createForSchema(CreateIndexProjectUuidInProjectBranchesTest.class, "schema.sql");

private final CreateIndexProjectUuidInProjectBranches createIndex = new CreateIndexProjectUuidInProjectBranches(db.database());

@Test
public void migration_should_create_index() throws SQLException {
db.assertIndexDoesNotExist("project_branches", "project_branches_project_uuid");

createIndex.execute();

db.assertIndex("project_branches", "project_branches_project_uuid", "project_uuid");
}

@Test
public void migration_should_be_reentrant() throws SQLException {
createIndex.execute();
createIndex.execute();

db.assertIndex("project_branches", "project_branches_project_uuid", "project_uuid");
}
}

+ 15
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v102/CreateIndexProjectUuidInProjectBranchesTest/schema.sql Näytä tiedosto

@@ -0,0 +1,15 @@
CREATE TABLE "PROJECT_BRANCHES"(
"UUID" CHARACTER VARYING(50) NOT NULL,
"PROJECT_UUID" CHARACTER VARYING(50) NOT NULL,
"KEE" CHARACTER VARYING(255) NOT NULL,
"BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL,
"MERGE_BRANCH_UUID" CHARACTER VARYING(50),
"PULL_REQUEST_BINARY" BINARY LARGE OBJECT,
"MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40),
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL,
"EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL,
"NEED_ISSUE_SYNC" BOOLEAN NOT NULL
);
ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST);

+ 1
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/ActivityAction.java Näytä tiedosto

@@ -298,7 +298,7 @@ public class ActivityAction implements CeWsAction {
.setNameOrKeyQuery(componentQuery)
.setQualifiers(POSSIBLE_QUALIFIERS)
.build();
List<ComponentDto> componentDtos = dbClient.componentDao().selectByQuery(dbSession, componentDtoQuery, 0, CeTaskQuery.MAX_COMPONENT_UUIDS);
List<ComponentDto> componentDtos = dbClient.componentDao().selectByQuery(dbSession, componentDtoQuery, forPage(1).andSize(CeTaskQuery.MAX_COMPONENT_UUIDS));
return dbClient.entityDao().selectByKeys(dbSession, componentDtos.stream().map(ComponentDto::getKey).collect(toSet()));
}


+ 3
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/template/BulkApplyTemplateAction.java Näytä tiedosto

@@ -37,6 +37,7 @@ import org.sonar.core.i18n.I18n;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ce.CeTaskQuery;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentQuery;
import org.sonar.db.entity.EntityDto;
@@ -54,6 +55,7 @@ import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;
import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdmin;
import static org.sonar.server.permission.ws.template.WsTemplateRef.newTemplateRef;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
@@ -156,7 +158,7 @@ public class BulkApplyTemplateAction implements PermissionsWsAction {
checkGlobalAdmin(userSession);

ComponentQuery componentQuery = buildDbQuery(request);
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, componentQuery, 0, Integer.MAX_VALUE);
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, componentQuery, forPage(1).andSize(CeTaskQuery.MAX_COMPONENT_UUIDS));

Set<String> entityUuids = components.stream()
.map(ComponentDto::getKey)

+ 2
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java Näytä tiedosto

@@ -57,6 +57,7 @@ import static java.util.stream.Collectors.toSet;
import static org.sonar.api.resources.Qualifiers.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.server.project.ws.SearchAction.buildDbQuery;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
@@ -150,7 +151,7 @@ public class BulkDeleteAction implements ProjectsWsAction {
checkIfAnalyzedBeforeIsFutureDate(searchRequest);

ComponentQuery query = buildDbQuery(searchRequest);
Set<ComponentDto> componentDtos = new HashSet<>(dbClient.componentDao().selectByQuery(dbSession, query, 0, Integer.MAX_VALUE));
Set<ComponentDto> componentDtos = new HashSet<>(dbClient.componentDao().selectByQuery(dbSession, query, forPage(1).andSize(Integer.MAX_VALUE)));
List<EntityDto> entities = dbClient.entityDao().selectByKeys(dbSession, componentDtos.stream().map(ComponentDto::getKey).collect(toSet()));
Set<String> entityUuids = entities.stream().map(EntityDto::getUuid).collect(toSet());
Map<String, String> mainBranchUuidByEntityUuid = dbClient.branchDao().selectMainBranchesByProjectUuids(dbSession, entityUuids).stream()

+ 2
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchAction.java Näytä tiedosto

@@ -53,6 +53,7 @@ import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.server.project.Visibility.PUBLIC;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
@@ -167,7 +168,7 @@ public class SearchAction implements ProjectsWsAction {

ComponentQuery query = buildDbQuery(request);
Paging paging = buildPaging(dbSession, request, query);
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, query, paging.offset(), paging.pageSize());
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, query, forPage(paging.pageIndex()).andSize(paging.pageSize()));
Set<String> componentUuids = components.stream().map(ComponentDto::uuid).collect(Collectors.toSet());
List<BranchDto> branchDtos = dbClient.branchDao().selectByUuids(dbSession, componentUuids);
Map<String, String> componentUuidToProjectUuid = branchDtos.stream().collect(Collectors.toMap(BranchDto::getUuid,BranchDto::getProjectUuid));

Loading…
Peruuta
Tallenna