aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-db
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-06-29 11:39:44 +0200
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-07-04 15:20:30 +0200
commit3f55a9c69829198a0931f45e5a85f19960af37b5 (patch)
tree677688824c20cd0bbbb09b51d3455a431bd661b6 /sonar-db
parent57954d360f60214e732aa002f03af12f69e21d49 (diff)
downloadsonarqube-3f55a9c69829198a0931f45e5a85f19960af37b5.tar.gz
sonarqube-3f55a9c69829198a0931f45e5a85f19960af37b5.zip
SONAR-7705 ProjectCleaner now deal with analyses (not snapshots)
Diffstat (limited to 'sonar-db')
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/IdUuidPair.java28
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/PurgeCommands.java28
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java5
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/PurgeMapper.java2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/PurgeableAnalysisDto.java10
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/period/DefaultPeriodCleaner.java40
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/purge/PurgeMapper.xml18
-rw-r--r--sonar-db/src/test/java/org/sonar/db/purge/period/DefaultPeriodCleanerTest.java63
8 files changed, 117 insertions, 77 deletions
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/IdUuidPair.java b/sonar-db/src/main/java/org/sonar/db/purge/IdUuidPair.java
index aebf9b21c0a..6a5171d13e3 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/IdUuidPair.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/IdUuidPair.java
@@ -19,6 +19,9 @@
*/
package org.sonar.db.purge;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
public class IdUuidPair {
private Long id;
private String uuid;
@@ -46,4 +49,29 @@ public class IdUuidPair {
public void setUuid(String uuid) {
this.uuid = uuid;
}
+
+ @Override
+ public String toString() {
+ return "IdUuidPair{" +
+ "id=" + id +
+ ", uuid='" + uuid + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ IdUuidPair that = (IdUuidPair) o;
+ return Objects.equals(id, that.id) && Objects.equals(uuid, that.uuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, uuid);
+ }
}
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/PurgeCommands.java b/sonar-db/src/main/java/org/sonar/db/purge/PurgeCommands.java
index bcfd60c6eb2..ab67bb7aa38 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/PurgeCommands.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/PurgeCommands.java
@@ -183,32 +183,30 @@ class PurgeCommands {
@VisibleForTesting
protected void deleteAnalyses(List<IdUuidPair> analysisIdUuids) {
- List<List<Long>> snapshotIdsPartitions = Lists.partition(IdUuidPairs.ids(analysisIdUuids), MAX_SNAPSHOTS_PER_QUERY);
- List<List<String>> snapshotUuidsPartitions = Lists.partition(IdUuidPairs.uuids(analysisIdUuids), MAX_SNAPSHOTS_PER_QUERY);
+ List<List<Long>> analysisIdsPartitions = Lists.partition(IdUuidPairs.ids(analysisIdUuids), MAX_SNAPSHOTS_PER_QUERY);
+ List<List<String>> analysisUuidsPartitions = Lists.partition(IdUuidPairs.uuids(analysisIdUuids), MAX_SNAPSHOTS_PER_QUERY);
- deleteSnapshotDuplications(snapshotUuidsPartitions);
+ deleteSnapshotDuplications(analysisUuidsPartitions);
profiler.start("deleteAnalyses (events)");
- for (List<String> snapshotUuidsPartition : snapshotUuidsPartitions) {
- purgeMapper.deleteSnapshotEvents(snapshotUuidsPartition);
- }
+ analysisUuidsPartitions.forEach(purgeMapper::deleteSnapshotEvents);
session.commit();
profiler.stop();
profiler.start("deleteAnalyses (project_measures)");
- for (List<Long> snapshotIdsPartition : snapshotIdsPartitions) {
- purgeMapper.deleteSnapshotMeasures(snapshotIdsPartition);
- }
+ analysisIdsPartitions.forEach(analysisIdsPartition -> {
+ purgeMapper.deleteSnapshotMeasures(analysisIdsPartition);
+ for (Long analysisId : analysisIdsPartition) {
+ List<List<Long>> snapshotIdPartitions = Lists.partition(purgeMapper.selectDescendantsSnapshotIds(analysisId), MAX_SNAPSHOTS_PER_QUERY);
+ snapshotIdPartitions.forEach(purgeMapper::deleteSnapshotMeasures);
+ }
+ });
session.commit();
profiler.stop();
profiler.start("deleteAnalyses (snapshots)");
- for (List<String> snapshotUuidsPartition : snapshotUuidsPartitions) {
- purgeMapper.deleteAnalyses(snapshotUuidsPartition);
- }
- for (List<Long> snapshotIdsPartition : snapshotIdsPartitions) {
- purgeMapper.deleteDescendantSnapshots(snapshotIdsPartition);
- }
+ analysisUuidsPartitions.forEach(purgeMapper::deleteAnalyses);
+ analysisIdsPartitions.forEach(purgeMapper::deleteDescendantSnapshots);
session.commit();
profiler.stop();
}
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java b/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java
index 286404d8909..1df8e29cf6c 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java
@@ -170,6 +170,10 @@ public class PurgeDao implements Dao {
return this;
}
+ public void deleteAnalyses(DbSession session, PurgeProfiler profiler, List<IdUuidPair> analysisIdUuids) {
+ new PurgeCommands(session, profiler).deleteAnalyses(analysisIdUuids);
+ }
+
/**
* Load the whole tree of projects, including the project given in parameter.
*/
@@ -180,5 +184,4 @@ public class PurgeDao implements Dao {
private static PurgeMapper mapper(DbSession session) {
return session.getMapper(PurgeMapper.class);
}
-
}
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/PurgeMapper.java b/sonar-db/src/main/java/org/sonar/db/purge/PurgeMapper.java
index a66f2d959f6..bc8cb45ebc5 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/PurgeMapper.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/PurgeMapper.java
@@ -32,6 +32,8 @@ public interface PurgeMapper {
*/
List<IdUuidPair> selectComponentsByProjectUuid(String projectUuid);
+ List<Long> selectDescendantsSnapshotIds(@Param("analysisId") long analysisId);
+
void deleteAnalyses(@Param("analysisUuids") List<String> analysisUuids);
void deleteDescendantSnapshots(@Param("snapshotIds") List<Long> snapshotIds);
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/PurgeableAnalysisDto.java b/sonar-db/src/main/java/org/sonar/db/purge/PurgeableAnalysisDto.java
index e313dfd3a21..426ac3e9e92 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/PurgeableAnalysisDto.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/PurgeableAnalysisDto.java
@@ -28,6 +28,7 @@ import org.apache.commons.lang.builder.ToStringStyle;
*/
public class PurgeableAnalysisDto implements Comparable<PurgeableAnalysisDto> {
private Date date;
+ private long analysisId;
private String analysisUuid;
private boolean hasEvents;
private boolean isLast;
@@ -41,6 +42,15 @@ public class PurgeableAnalysisDto implements Comparable<PurgeableAnalysisDto> {
return this;
}
+ public long getAnalysisId() {
+ return analysisId;
+ }
+
+ public PurgeableAnalysisDto setAnalysisId(long analysisId) {
+ this.analysisId = analysisId;
+ return this;
+ }
+
public String getAnalysisUuid() {
return analysisUuid;
}
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/period/DefaultPeriodCleaner.java b/sonar-db/src/main/java/org/sonar/db/purge/period/DefaultPeriodCleaner.java
index 660f63cace6..29fd532a760 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/period/DefaultPeriodCleaner.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/period/DefaultPeriodCleaner.java
@@ -20,17 +20,22 @@
package org.sonar.db.purge.period;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import java.util.ArrayList;
import java.util.List;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.stream.Collectors;
import org.sonar.db.DbSession;
+import org.sonar.db.purge.IdUuidPair;
import org.sonar.db.purge.PurgeDao;
import org.sonar.db.purge.PurgeProfiler;
-import org.sonar.db.purge.PurgeSnapshotQuery;
import org.sonar.db.purge.PurgeableAnalysisDto;
+import static org.sonar.core.util.stream.GuavaCollectors.toList;
+
public class DefaultPeriodCleaner {
private static final Logger LOG = Loggers.get(DefaultPeriodCleaner.class);
@@ -42,27 +47,36 @@ public class DefaultPeriodCleaner {
this.profiler = profiler;
}
- public void clean(DbSession session, String componentUuid, Settings settings) {
- doClean(componentUuid, new Filters(settings).all(), session);
+ public void clean(DbSession session, String rootUuid, Settings settings) {
+ doClean(rootUuid, new Filters(settings).all(), session);
}
@VisibleForTesting
- void doClean(String componentUuid, List<Filter> filters, DbSession session) {
- List<PurgeableAnalysisDto> history = selectAnalysesOfComponent(componentUuid, session);
+ void doClean(String rootUuid, List<Filter> filters, DbSession session) {
+ List<PurgeableAnalysisDto> history = new ArrayList<>(selectAnalysesOfComponent(rootUuid, session));
for (Filter filter : filters) {
filter.log();
- delete(filter.filter(history), session);
+ history.removeAll(delete(rootUuid, filter.filter(history), session));
}
}
- private void delete(List<PurgeableAnalysisDto> snapshots, DbSession session) {
- for (PurgeableAnalysisDto snapshot : snapshots) {
- LOG.debug("<- Delete snapshot: {} [{}]", DateUtils.formatDateTime(snapshot.getDate()), snapshot.getAnalysisUuid());
- purgeDao.deleteSnapshots(
- session, profiler,
- PurgeSnapshotQuery.create().setAnalysisUuid(snapshot.getAnalysisUuid()),
- PurgeSnapshotQuery.create().setSnapshotUuid(snapshot.getAnalysisUuid()));
+ private List<PurgeableAnalysisDto> delete(String rootUuid, List<PurgeableAnalysisDto> snapshots, DbSession session) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<- Delete analyses of component {}: {}",
+ rootUuid,
+ Joiner.on(", ").join(
+ snapshots.stream()
+ .map(snapshot -> snapshot.getAnalysisUuid() + "@" + DateUtils.formatDateTime(snapshot.getDate()))
+ .collect(Collectors.toList(snapshots.size()))));
}
+ purgeDao.deleteAnalyses(
+ session, profiler,
+ snapshots.stream().map(DefaultPeriodCleaner::toIdUuidPair).collect(toList(snapshots.size())));
+ return snapshots;
+ }
+
+ private static IdUuidPair toIdUuidPair(PurgeableAnalysisDto snapshot) {
+ return new IdUuidPair(snapshot.getAnalysisId(), snapshot.getAnalysisUuid());
}
private List<PurgeableAnalysisDto> selectAnalysesOfComponent(String componentUuid, DbSession session) {
diff --git a/sonar-db/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/sonar-db/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
index 45e05bc3607..2ec4712452a 100644
--- a/sonar-db/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
+++ b/sonar-db/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
@@ -48,7 +48,7 @@
<select id="selectPurgeableAnalysesWithEvents" parameterType="String" resultType="PurgeableAnalysis">
select
- s.uuid as "analysisUuid", s.created_at as "date", ${_true} as "hasEvents", islast as "isLast"
+ s.id as "analysisId", s.uuid as "analysisUuid", s.created_at as "date", ${_true} as "hasEvents", islast as "isLast"
from
snapshots s
where
@@ -61,7 +61,7 @@
<select id="selectPurgeableAnalysesWithoutEvents" parameterType="String" resultType="PurgeableAnalysis">
select
- s.uuid as "analysisUuid", s.created_at as "date", ${_false} as "hasEvents", islast as "isLast"
+ s.id as "analysisId", s.uuid as "analysisUuid", s.created_at as "date", ${_false} as "hasEvents", islast as "isLast"
from
snapshots s
where
@@ -91,11 +91,17 @@
select id, uuid from projects where project_uuid=#{uuid} or uuid=#{uuid}
</select>
+ <select id="selectDescendantsSnapshotIds" resultType="long" parameterType="long">
+ select id from snapshots where root_snapshot_id=#{analysisId}
+ </select>
+
<delete id="deleteSnapshotMeasures" parameterType="map">
- delete from project_measures where snapshot_id in
- <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
- #{snapshotId}
- </foreach>
+ delete from project_measures
+ where
+ snapshot_id in
+ <foreach collection="snapshotIds" open="(" close=")" item="snapshotId" separator=",">
+ #{snapshotId}
+ </foreach>
</delete>
<delete id="deleteSnapshotDuplications" parameterType="map">
diff --git a/sonar-db/src/test/java/org/sonar/db/purge/period/DefaultPeriodCleanerTest.java b/sonar-db/src/test/java/org/sonar/db/purge/period/DefaultPeriodCleanerTest.java
index e540c4732b0..218c216574c 100644
--- a/sonar-db/src/test/java/org/sonar/db/purge/period/DefaultPeriodCleanerTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/purge/period/DefaultPeriodCleanerTest.java
@@ -19,27 +19,24 @@
*/
package org.sonar.db.purge.period;
+import com.google.common.collect.ImmutableList;
import java.util.Arrays;
-import org.apache.commons.lang.ObjectUtils;
-import org.hamcrest.BaseMatcher;
+import java.util.Collections;
+import java.util.List;
import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
+import org.sonar.db.purge.IdUuidPair;
import org.sonar.db.purge.PurgeDao;
import org.sonar.db.purge.PurgeProfiler;
-import org.sonar.db.purge.PurgeSnapshotQuery;
import org.sonar.db.purge.PurgeableAnalysisDto;
-import static org.mockito.Matchers.any;
import static org.mockito.Mockito.anyListOf;
-import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class DefaultPeriodCleanerTest {
@@ -49,45 +46,27 @@ public class DefaultPeriodCleanerTest {
PurgeDao dao = mock(PurgeDao.class);
DbSession session = mock(DbSession.class);
when(dao.selectPurgeableAnalyses("uuid_123", session)).thenReturn(Arrays.asList(
- new PurgeableAnalysisDto().setAnalysisUuid("u999").setDate(System2.INSTANCE.now())));
- Filter filter1 = newLazyFilter();
- Filter filter2 = newLazyFilter();
+ new PurgeableAnalysisDto().setAnalysisId(999).setAnalysisUuid("u999").setDate(System2.INSTANCE.now()),
+ new PurgeableAnalysisDto().setAnalysisId(456).setAnalysisUuid("u456").setDate(System2.INSTANCE.now())
+ ));
+ Filter filter1 = newFirstSnapshotInListFilter();
+ Filter filter2 = newFirstSnapshotInListFilter();
- DefaultPeriodCleaner cleaner = new DefaultPeriodCleaner(dao, new PurgeProfiler());
+ PurgeProfiler profiler = new PurgeProfiler();
+ DefaultPeriodCleaner cleaner = new DefaultPeriodCleaner(dao, profiler);
cleaner.doClean("uuid_123", Arrays.asList(filter1, filter2), session);
- verify(filter1).log();
- verify(filter2).log();
- verify(dao, times(2)).deleteSnapshots(eq(session), any(PurgeProfiler.class), argThat(newRootSnapshotQuery()), argThat(newSnapshotIdQuery()));
+ InOrder inOrder = Mockito.inOrder(dao, filter1, filter2);
+ inOrder.verify(filter1).log();
+ inOrder.verify(dao, times(1)).deleteAnalyses(eq(session), eq(profiler), eq(ImmutableList.of(new IdUuidPair(999, "u999"))));
+ inOrder.verify(filter2).log();
+ inOrder.verify(dao, times(1)).deleteAnalyses(eq(session), eq(profiler), eq(ImmutableList.of(new IdUuidPair(456, "u456"))));
+ inOrder.verifyNoMoreInteractions();
}
- private BaseMatcher<PurgeSnapshotQuery> newRootSnapshotQuery() {
- return new ArgumentMatcher<PurgeSnapshotQuery>() {
- @Override
- public boolean matches(Object o) {
- PurgeSnapshotQuery query = (PurgeSnapshotQuery) o;
- return ObjectUtils.equals(query.getAnalysisUuid(), "u999");
- }
- };
- }
-
- private BaseMatcher<PurgeSnapshotQuery> newSnapshotIdQuery() {
- return new ArgumentMatcher<PurgeSnapshotQuery>() {
- @Override
- public boolean matches(Object o) {
- PurgeSnapshotQuery query = (PurgeSnapshotQuery) o;
- return ObjectUtils.equals(query.getSnapshotUuid(), "u999");
- }
- };
- }
-
- private Filter newLazyFilter() {
+ private Filter newFirstSnapshotInListFilter() {
Filter filter1 = mock(Filter.class);
- when(filter1.filter(anyListOf(PurgeableAnalysisDto.class))).thenAnswer(new Answer<Object>() {
- public Object answer(InvocationOnMock invocation) throws Throwable {
- return invocation.getArguments()[0];
- }
- });
+ when(filter1.filter(anyListOf(PurgeableAnalysisDto.class))).thenAnswer(invocation -> Collections.singletonList(((List) invocation.getArguments()[0]).iterator().next()));
return filter1;
}
}