diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-06-29 11:39:44 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-07-04 15:20:30 +0200 |
commit | 3f55a9c69829198a0931f45e5a85f19960af37b5 (patch) | |
tree | 677688824c20cd0bbbb09b51d3455a431bd661b6 /sonar-db | |
parent | 57954d360f60214e732aa002f03af12f69e21d49 (diff) | |
download | sonarqube-3f55a9c69829198a0931f45e5a85f19960af37b5.tar.gz sonarqube-3f55a9c69829198a0931f45e5a85f19960af37b5.zip |
SONAR-7705 ProjectCleaner now deal with analyses (not snapshots)
Diffstat (limited to 'sonar-db')
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; } } |