From 3a1b309e342a4b61cbc7ff06c6900150beee3573 Mon Sep 17 00:00:00 2001 From: simonbrandhof Date: Thu, 26 Jan 2012 23:13:09 +0100 Subject: SONAR-2757 improve reentrance of project deletion --- .../org/sonar/core/persistence/BatchSession.java | 38 ++++++------ .../main/java/org/sonar/core/purge/PurgeDao.java | 38 ++++++------ .../java/org/sonar/core/purge/PurgeMapper.java | 4 +- .../resources/org/sonar/core/purge/PurgeMapper.xml | 24 +++++--- .../org/sonar/core/persistence/DaoTestCase.java | 2 +- .../java/org/sonar/core/purge/PurgeDaoTest.java | 25 +++++++- .../purge/PurgeDaoTest/shouldDeleteProject.xml | 67 ++++++++++++++++++++++ .../purge/PurgeDaoTest/shouldDeleteResource.xml | 21 +++++++ 8 files changed, 170 insertions(+), 49 deletions(-) create mode 100644 sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml create mode 100644 sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteResource.xml (limited to 'sonar-core') diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/BatchSession.java b/sonar-core/src/main/java/org/sonar/core/persistence/BatchSession.java index 2a416fd11b3..4413fff3aee 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/BatchSession.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/BatchSession.java @@ -46,21 +46,6 @@ public final class BatchSession implements SqlSession { this.batchSize = batchSize; } - /** - * This method must be called when executing SQL requests. - */ - public BatchSession increment(int nbSqlRequests) { - count += nbSqlRequests; - if (count >= batchSize) { - commit(); - } - return this; - } - - private void reset() { - count=0; - } - public void select(String statement, Object parameter, ResultHandler handler) { reset(); session.select(statement, parameter, handler); @@ -117,32 +102,32 @@ public final class BatchSession implements SqlSession { } public int insert(String statement) { - increment(1); + increment(); return session.insert(statement); } public int insert(String statement, Object parameter) { - increment(1); + increment(); return session.insert(statement, parameter); } public int update(String statement) { - increment(1); + increment(); return session.update(statement); } public int update(String statement, Object parameter) { - increment(1); + increment(); return session.update(statement, parameter); } public int delete(String statement) { - increment(1); + increment(); return session.delete(statement); } public int delete(String statement, Object parameter) { - increment(1); + increment(); return session.delete(statement, parameter); } @@ -192,4 +177,15 @@ public final class BatchSession implements SqlSession { return session.getConnection(); } + private BatchSession increment() { + count += 1; + if (count >= batchSize) { + commit(); + } + return this; + } + + private void reset() { + count = 0; + } } diff --git a/sonar-core/src/main/java/org/sonar/core/purge/PurgeDao.java b/sonar-core/src/main/java/org/sonar/core/purge/PurgeDao.java index 726f59dcb52..e751cc32f20 100644 --- a/sonar-core/src/main/java/org/sonar/core/purge/PurgeDao.java +++ b/sonar-core/src/main/java/org/sonar/core/purge/PurgeDao.java @@ -24,7 +24,6 @@ import com.google.common.collect.Lists; import org.apache.ibatis.session.ResultContext; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.SqlSession; -import org.sonar.core.persistence.BatchSession; import org.sonar.core.persistence.MyBatis; import org.sonar.core.resource.ResourceDao; @@ -100,28 +99,33 @@ public class PurgeDao { } public PurgeDao deleteProject(long rootProjectId) { - final BatchSession session = mybatis.openBatchSession(); + final SqlSession session = mybatis.openBatchSession(); + final PurgeMapper mapper = session.getMapper(PurgeMapper.class); try { - final PurgeMapper mapper = session.getMapper(PurgeMapper.class); - List projectIds = resourceDao.getDescendantProjectIdsAndSelf(rootProjectId, session); - for (Long projectId : projectIds) { - session.select("org.sonar.core.purge.PurgeMapper.selectResourceIdsByRootId", projectId, new ResultHandler() { - public void handleResult(ResultContext context) { - Long resourceId = (Long) context.getResultObject(); - deleteResource(resourceId, session, mapper); - } - }); - } - session.commit(); + deleteProject(rootProjectId, session, mapper); return this; - } finally { MyBatis.closeQuietly(session); } } - void deleteResource(final long resourceId, final BatchSession session, final PurgeMapper mapper) { - session.select("org.sonar.core.purge.PurgeMapper.selectSnapshotIdsByResource", new ResultHandler() { + private void deleteProject(final long rootProjectId, final SqlSession session, final PurgeMapper mapper) { + List childrenIds = mapper.selectProjectIdsByRootId(rootProjectId); + for (Long childId : childrenIds) { + deleteProject(childId, session, mapper); + } + + session.select("org.sonar.core.purge.PurgeMapper.selectResourceTreeIdsByRootId", rootProjectId, new ResultHandler() { + public void handleResult(ResultContext context) { + Long resourceId = (Long) context.getResultObject(); + deleteResource(resourceId, session, mapper); + } + }); + session.commit(); + } + + void deleteResource(final long resourceId, final SqlSession session, final PurgeMapper mapper) { + session.select("org.sonar.core.purge.PurgeMapper.selectSnapshotIdsByResource", resourceId, new ResultHandler() { public void handleResult(ResultContext context) { Long snapshotId = (Long) context.getResultObject(); deleteSnapshot(snapshotId, mapper); @@ -149,7 +153,7 @@ public class PurgeDao { public PurgeDao deleteSnapshots(PurgeSnapshotQuery query) { - final BatchSession session = mybatis.openBatchSession(); + final SqlSession session = mybatis.openBatchSession(); try { final PurgeMapper mapper = session.getMapper(PurgeMapper.class); session.select("org.sonar.core.purge.PurgeMapper.selectSnapshotIds", query, new ResultHandler() { diff --git a/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java b/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java index 31993b1896f..d663cd44c53 100644 --- a/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java @@ -25,6 +25,8 @@ public interface PurgeMapper { List selectSnapshotIds(PurgeSnapshotQuery query); + List selectProjectIdsByRootId(long rootResourceId); + void deleteSnapshot(long snapshotId); void deleteSnapshotDependencies(long snapshotId); @@ -70,7 +72,7 @@ public interface PurgeMapper { void deleteResourceEvents(long resourceId); void closeResourceReviews(long resourceId); - + List selectPurgeableSnapshotsWithVersionEvent(long resourceId); List selectPurgeableSnapshotsWithoutVersionEvent(long resourceId); diff --git a/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml b/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml index e0a7f656c3d..34c85d4f7e2 100644 --- a/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml @@ -34,7 +34,8 @@ and s.qualifier in - #{qualifier} + #{qualifier} + @@ -48,13 +49,17 @@ - + select id from projects where root_id=#{id} and scope='PRJ' + + + @@ -105,7 +114,8 @@ delete from project_measures where snapshot_id=#{id} and - (characteristic_id is not null or rule_id is not null or metric_id in (select id from metrics where delete_historical_data=${_true})) + (characteristic_id is not null or rule_id is not null or metric_id in (select id from metrics where + delete_historical_data=${_true})) diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DaoTestCase.java b/sonar-core/src/test/java/org/sonar/core/persistence/DaoTestCase.java index d7b54126fd4..02f6be17c39 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/DaoTestCase.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/DaoTestCase.java @@ -185,7 +185,7 @@ public abstract class DaoTestCase { protected final void assertEmptyTables(String... emptyTables) { for (String table : emptyTables) { try { - Assert.assertEquals(0, getCurrentDataSet().getTable(table).getRowCount()); + Assert.assertEquals("Table " + table + " not empty.", 0, getCurrentDataSet().getTable(table).getRowCount()); } catch (DataSetException e) { throw translateException("Error while checking results", e); } diff --git a/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java b/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java index a165063ee30..c1a3541aeb0 100644 --- a/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java @@ -29,7 +29,6 @@ import org.sonar.core.persistence.MyBatis; import org.sonar.core.resource.ResourceDao; import java.util.List; -import java.util.SortedSet; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -156,6 +155,28 @@ public class PurgeDaoTest extends DaoTestCase { assertThat(snapshots.size(), is(3)); } + @Test + public void shouldDeleteResource() { + setupData("shouldDeleteResource"); + SqlSession session = getMyBatis().openSession(); + try { + // this method does not commit and close the session + dao.deleteResource(1L, session, session.getMapper(PurgeMapper.class)); + session.commit(); + + } finally { + MyBatis.closeQuietly(session); + } + assertEmptyTables("projects", "snapshots", "events"); + } + + @Test + public void shouldDeleteProject() { + setupData("shouldDeleteProject"); + dao.deleteProject(1L); + assertEmptyTables("projects", "snapshots"); + } + static final class SnapshotMatcher extends BaseMatcher { long snapshotId; boolean isLast; @@ -169,7 +190,7 @@ public class PurgeDaoTest extends DaoTestCase { public boolean matches(Object o) { PurgeableSnapshotDto obj = (PurgeableSnapshotDto) o; - return obj.getSnapshotId() == snapshotId && obj.isLast()==isLast && obj.hasVersionEvent()==hasVersionEvent; + return obj.getSnapshotId() == snapshotId && obj.isLast() == isLast && obj.hasVersionEvent() == hasVersionEvent; } public void describeTo(Description description) { diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml new file mode 100644 index 00000000000..2a1e333079f --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteProject.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteResource.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteResource.xml new file mode 100644 index 00000000000..3ed5a6f4d36 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteResource.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file -- cgit v1.2.3