Browse Source

SONAR-11626 baseline analysis can not be deleted by PeriodCleaner

tags/7.7
Sébastien Lesaint 5 years ago
parent
commit
1d627934e3

+ 38
- 10
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java View File

@@ -20,13 +20,14 @@
package org.sonar.db.purge;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -46,8 +47,8 @@ import static org.sonar.db.DatabaseUtils.executeLargeInputs;
public class PurgeDao implements Dao {
private static final Logger LOG = Loggers.get(PurgeDao.class);
private static final String[] UNPROCESSED_STATUS = new String[] {"U"};
private static final ImmutableSet<String> QUALIFIERS_PROJECT_VIEW = ImmutableSet.of("TRK", "VW");
private static final ImmutableSet<String> QUALIFIERS_MODULE_SUBVIEW = ImmutableSet.of("BRC", "SVW");
private static final Set<String> QUALIFIERS_PROJECT_VIEW = ImmutableSet.of("TRK", "VW");
private static final Set<String> QUALIFIERS_MODULE_SUBVIEW = ImmutableSet.of("BRC", "SVW");
private static final String SCOPE_PROJECT = "PRJ";

private final ComponentDao componentDao;
@@ -157,12 +158,38 @@ public class PurgeDao implements Dao {
}

public List<PurgeableAnalysisDto> selectPurgeableAnalyses(String componentUuid, DbSession session) {
List<PurgeableAnalysisDto> result = Lists.newArrayList();
result.addAll(mapper(session).selectPurgeableAnalysesWithEvents(componentUuid));
result.addAll(mapper(session).selectPurgeableAnalysesWithoutEvents(componentUuid));
// sort by date
Collections.sort(result);
return result;
PurgeMapper mapper = mapper(session);
Stream<PurgeableAnalysisDto> allPurgeableAnalyses = Stream.concat(
mapper.selectPurgeableAnalysesWithEvents(componentUuid).stream(),
mapper.selectPurgeableAnalysesWithoutEvents(componentUuid).stream());
return allPurgeableAnalyses
.filter(new ManualBaselineAnalysisFilter(mapper, componentUuid))
.sorted()
.collect(MoreCollectors.toList());
}

private static final class ManualBaselineAnalysisFilter implements Predicate<PurgeableAnalysisDto> {
private static final String[] NO_BASELINE = {null};

private final PurgeMapper mapper;
private final String componentUuid;
private String[] manualBaselineAnalysisUuid;

private ManualBaselineAnalysisFilter(PurgeMapper mapper, String componentUuid) {
this.mapper = mapper;
this.componentUuid = componentUuid;
}

@Override
public boolean test(PurgeableAnalysisDto purgeableAnalysisDto) {
if (manualBaselineAnalysisUuid == null) {
manualBaselineAnalysisUuid = Optional.ofNullable(mapper.selectManualBaseline(componentUuid))
.map(t -> new String[] {t})
.orElse(NO_BASELINE);
}

return !Objects.equals(manualBaselineAnalysisUuid[0], purgeableAnalysisDto.getAnalysisUuid());
}
}

public void deleteBranch(DbSession session, String uuid) {
@@ -257,4 +284,5 @@ public class PurgeDao implements Dao {
private static PurgeMapper mapper(DbSession session) {
return session.getMapper(PurgeMapper.class);
}

}

+ 6
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java View File

@@ -20,6 +20,7 @@
package org.sonar.db.purge;

import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.ibatis.annotations.Param;

@@ -53,8 +54,8 @@ public interface PurgeMapper {
void deleteAnalysisWastedMeasures(@Param("analysisUuids") List<String> analysisUuids, @Param("metricIds") List<Long> metricIds);

/**
* Purge status flag is used to not attempt to remove duplications & historical data of analysis of which we already
* removed them.
* Purge status flag is used to not attempt to remove duplications & historical data of analyses
* for which we already removed them.
*/
void updatePurgeStatusToOne(@Param("analysisUuids") List<String> analysisUuid);

@@ -90,6 +91,9 @@ public interface PurgeMapper {

List<String> selectStaleShortLivingBranchesAndPullRequests(@Param("projectUuid") String projectUuid, @Param("toDate") Long toDate);

@CheckForNull
String selectManualBaseline(@Param("projectUuid") String projectUuid);

void deleteIssuesFromKeys(@Param("keys") List<String> keys);

void deleteIssueChangesFromIssueKeys(@Param("issueKeys") List<String> issueKeys);

+ 10
- 1
server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml View File

@@ -43,7 +43,16 @@
and not exists(select e.id from events e where e.analysis_uuid=s.uuid)
</select>

<select id="selectStaleShortLivingBranchesAndPullRequests" parameterType="map" resultType="String">
<select id="selectManualBaseline" parameterType="String" resultType="String">
select
manual_baseline_analysis_uuid
from
project_branches pb
where
pb.uuid=#{projectUuid,jdbcType=VARCHAR}
</select>

<select id="selectStaleShortLivingBranchesAndPullRequests" parameterType="map" resultType="String">
select
pb.uuid
from

+ 0
- 1
server/sonar-db-dao/src/test/java/org/sonar/db/event/EventTesting.java View File

@@ -37,7 +37,6 @@ public class EventTesting {
.setName(randomAlphanumeric(400))
.setDescription(null)
.setCategory("Other")
.setComponentUuid(analysis.getComponentUuid())
.setCreatedAt(System.currentTimeMillis())
.setDate(System.currentTimeMillis());
}

+ 105
- 13
server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java View File

@@ -58,6 +58,7 @@ import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.event.EventComponentChangeDto;
import org.sonar.db.event.EventDto;
import org.sonar.db.event.EventTesting;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.measure.LiveMeasureDto;
import org.sonar.db.measure.MeasureDto;
@@ -85,6 +86,10 @@ import static org.sonar.db.component.ComponentTesting.newDirectory;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newProjectCopy;
import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED;
import static org.sonar.db.component.SnapshotDto.STATUS_UNPROCESSED;
import static org.sonar.db.component.SnapshotTesting.newSnapshot;
import static org.sonar.db.event.EventDto.CATEGORY_VERSION;
import static org.sonar.db.webhook.WebhookDeliveryTesting.newDto;
import static org.sonar.db.webhook.WebhookDeliveryTesting.selectAllDeliveryUuids;

@@ -364,19 +369,106 @@ public class PurgeDaoTest {

@Test
public void selectPurgeableAnalyses() {
db.prepareDbUnit(getClass(), "shouldSelectPurgeableAnalysis.xml");
List<PurgeableAnalysisDto> analyses = underTest.selectPurgeableAnalyses(PROJECT_UUID, dbSession);

assertThat(analyses).hasSize(3);
assertThat(getById(analyses, "u1").isLast()).isTrue();
assertThat(getById(analyses, "u1").hasEvents()).isFalse();
assertThat(getById(analyses, "u1").getVersion()).isNull();
assertThat(getById(analyses, "u4").isLast()).isFalse();
assertThat(getById(analyses, "u4").hasEvents()).isFalse();
assertThat(getById(analyses, "u4").getVersion()).isNull();
assertThat(getById(analyses, "u5").isLast()).isFalse();
assertThat(getById(analyses, "u5").hasEvents()).isTrue();
assertThat(getById(analyses, "u5").getVersion()).isEqualTo("V5");
SnapshotDto[] analyses = new SnapshotDto[] {
newSnapshot()
.setUuid("u1")
.setComponentUuid(PROJECT_UUID)
.setStatus(STATUS_PROCESSED)
.setLast(true),
// not processed -> exclude
newSnapshot()
.setUuid("u2")
.setComponentUuid(PROJECT_UUID)
.setStatus(STATUS_UNPROCESSED)
.setLast(false),
// on other resource -> exclude
newSnapshot()
.setUuid("u3")
.setComponentUuid("uuid_222")
.setStatus(STATUS_PROCESSED)
.setLast(true),
// without event -> select
newSnapshot()
.setUuid("u4")
.setComponentUuid(PROJECT_UUID)
.setStatus(STATUS_PROCESSED)
.setLast(false),
// with event -> select
newSnapshot()
.setUuid("u5")
.setComponentUuid(PROJECT_UUID)
.setStatus(STATUS_PROCESSED)
.setLast(false)
.setCodePeriodVersion("V5")
};
db.components().insertSnapshots(analyses);
db.events().insertEvent(EventTesting.newEvent(analyses[4])
.setName("V5")
.setCategory(CATEGORY_VERSION));

List<PurgeableAnalysisDto> purgeableAnalyses = underTest.selectPurgeableAnalyses(PROJECT_UUID, dbSession);

assertThat(purgeableAnalyses).hasSize(3);
assertThat(getById(purgeableAnalyses, "u1").isLast()).isTrue();
assertThat(getById(purgeableAnalyses, "u1").hasEvents()).isFalse();
assertThat(getById(purgeableAnalyses, "u1").getVersion()).isNull();
assertThat(getById(purgeableAnalyses, "u4").isLast()).isFalse();
assertThat(getById(purgeableAnalyses, "u4").hasEvents()).isFalse();
assertThat(getById(purgeableAnalyses, "u4").getVersion()).isNull();
assertThat(getById(purgeableAnalyses, "u5").isLast()).isFalse();
assertThat(getById(purgeableAnalyses, "u5").hasEvents()).isTrue();
assertThat(getById(purgeableAnalyses, "u5").getVersion()).isEqualTo("V5");
}

@Test
public void selectPurgeableAnalyses_does_not_return_the_baseline() {
ComponentDto project1 = db.components().insertMainBranch(db.getDefaultOrganization(), "master");
SnapshotDto analysis1 = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(project1.uuid())
.setStatus(STATUS_PROCESSED)
.setLast(false));
dbClient.branchDao().updateManualBaseline(dbSession, project1.uuid(), analysis1.getUuid());
ComponentDto project2 = db.components().insertPrivateProject();
SnapshotDto analysis2 = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(project2.uuid())
.setStatus(STATUS_PROCESSED)
.setLast(false));
db.components().insertProjectBranch(project2);

assertThat(underTest.selectPurgeableAnalyses(project1.uuid(), dbSession)).isEmpty();
assertThat(underTest.selectPurgeableAnalyses(project2.uuid(), dbSession))
.extracting(PurgeableAnalysisDto::getAnalysisUuid)
.containsOnly(analysis2.getUuid());
}

@Test
public void selectPurgeableAnalyses_does_not_return_the_baseline_of_specific_branch() {
ComponentDto project = db.components().insertMainBranch(db.getDefaultOrganization(), "master");
SnapshotDto analysisProject = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(project.uuid())
.setStatus(STATUS_PROCESSED)
.setLast(false));
dbClient.branchDao().updateManualBaseline(dbSession, project.uuid(), analysisProject.getUuid());
ComponentDto branch1 = db.components().insertProjectBranch(project);
SnapshotDto analysisBranch1 = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(branch1.uuid())
.setStatus(STATUS_PROCESSED)
.setLast(false));
ComponentDto branch2 = db.components().insertProjectBranch(project);
SnapshotDto analysisBranch2 = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(branch2.uuid())
.setStatus(STATUS_PROCESSED)
.setLast(false));
dbClient.branchDao().updateManualBaseline(dbSession, branch2.uuid(), analysisBranch2.getUuid());
dbSession.commit();

assertThat(underTest.selectPurgeableAnalyses(project.uuid(), dbSession))
.isEmpty();
assertThat(underTest.selectPurgeableAnalyses(branch1.uuid(), dbSession))
.extracting(PurgeableAnalysisDto::getAnalysisUuid)
.containsOnly(analysisBranch1.getUuid());
assertThat(underTest.selectPurgeableAnalyses(branch2.uuid(), dbSession))
.isEmpty();
}

@Test

+ 0
- 154
server/sonar-db-dao/src/test/resources/org/sonar/db/purge/PurgeDaoTest/shouldSelectPurgeableAnalysis.xml View File

@@ -1,154 +0,0 @@
<dataset>

<!-- last -> select -->
<snapshots id="1"
uuid="u1"
component_uuid="P1"
status="P"
islast="[true]"
purge_status="[null]"
period1_mode="[null]"
period1_param="[null]"
period1_date="[null]"
period2_mode="[null]"
period2_param="[null]"
period2_date="[null]"
period3_mode="[null]"
period3_param="[null]"
period3_date="[null]"
period4_mode="[null]"
period4_param="[null]"
period4_date="[null]"
period5_mode="[null]"
period5_param="[null]"
period5_date="[null]"
created_at="1228222680000"
build_date="1228222680000"
version="[null]"
project_version="[null]"
/>

<!-- not processed -> exclude -->
<snapshots id="2"
uuid="u2"
component_uuid="P1"
status="U"
islast="[false]"
purge_status="[null]"
period1_mode="[null]"
period1_param="[null]"
period1_date="[null]"
period2_mode="[null]"
period2_param="[null]"
period2_date="[null]"
period3_mode="[null]"
period3_param="[null]"
period3_date="[null]"
period4_mode="[null]"
period4_param="[null]"
period4_date="[null]"
period5_mode="[null]"
period5_param="[null]"
period5_date="[null]"
created_at="1228222680000"
build_date="1228222680000"
version="[null]"
project_version="[null]"
/>

<!-- on other resource -> exclude -->
<snapshots id="3"
uuid="u3"
component_uuid="uuid_222"
status="P"
islast="[true]"
purge_status="[null]"
period1_mode="[null]"
period1_param="[null]"
period1_date="[null]"
period2_mode="[null]"
period2_param="[null]"
period2_date="[null]"
period3_mode="[null]"
period3_param="[null]"
period3_date="[null]"
period4_mode="[null]"
period4_param="[null]"
period4_date="[null]"
period5_mode="[null]"
period5_param="[null]"
period5_date="[null]"
created_at="1228222680000"
build_date="1228222680000"
version="[null]"
project_version="[null]"
/>

<!-- without event -> select -->
<snapshots id="4"
uuid="u4"
component_uuid="P1"
status="P"
islast="[false]"
purge_status="[null]"
period1_mode="[null]"
period1_param="[null]"
period1_date="[null]"
period2_mode="[null]"
period2_param="[null]"
period2_date="[null]"
period3_mode="[null]"
period3_param="[null]"
period3_date="[null]"
period4_mode="[null]"
period4_param="[null]"
period4_date="[null]"
period5_mode="[null]"
period5_param="[null]"
period5_date="[null]"
created_at="1228222680000"
build_date="1228222680000"
version="[null]"
project_version="[null]"
/>

<!-- with event -> select -->
<snapshots id="5"
uuid="u5"
component_uuid="P1"
status="P"
islast="[false]"
purge_status="[null]"
period1_mode="[null]"
period1_param="[null]"
period1_date="[null]"
period2_mode="[null]"
period2_param="[null]"
period2_date="[null]"
period3_mode="[null]"
period3_param="[null]"
period3_date="[null]"
period4_mode="[null]"
period4_param="[null]"
period4_date="[null]"
period5_mode="[null]"
period5_param="[null]"
period5_date="[null]"
created_at="1228222680000"
build_date="1228222680000"
version="V5"
project_version="[null]"
/>

<events id="2"
uuid="P2"
analysis_uuid="u5"
component_uuid="1"
category="Version"
description="[null]"
name="V5"
event_date="1228222680000"
created_at="1228222680000"
event_data="[null]"/>

</dataset>

Loading…
Cancel
Save