aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-core/src/main
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2012-01-25 17:38:50 +0100
committerSimon Brandhof <simon.brandhof@gmail.com>2012-01-25 17:39:14 +0100
commit8c6df4977b90cfce0cc6797e3b1ba23b1253a62c (patch)
treebf1af9f518adeebd8e7ff9434a7c1c0e13835392 /sonar-core/src/main
parent319a66df83a3aa19eea3612901626a6223f4e1d4 (diff)
downloadsonarqube-8c6df4977b90cfce0cc6797e3b1ba23b1253a62c.tar.gz
sonarqube-8c6df4977b90cfce0cc6797e3b1ba23b1253a62c.zip
SONAR-2757 Refactor the purge mechanisms to prevent any fullscan SQL requests on snapshots table
Diffstat (limited to 'sonar-core/src/main')
-rw-r--r--sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDao.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/dashboard/DashboardDao.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/core/duplication/DuplicationDao.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/BatchSession.java75
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DatabaseMigrator.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java13
-rw-r--r--sonar-core/src/main/java/org/sonar/core/purge/PurgeDao.java156
-rw-r--r--sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java25
-rw-r--r--sonar-core/src/main/java/org/sonar/core/purge/PurgeSnapshotQuery.java40
-rw-r--r--sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java59
-rw-r--r--sonar-core/src/main/java/org/sonar/core/resource/ResourceIndexerDao.java6
-rw-r--r--sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java3
-rw-r--r--sonar-core/src/main/java/org/sonar/core/review/ReviewDao.java6
-rw-r--r--sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/core/template/LoadedTemplateDao.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/jpa/entity/SchemaMigration.java2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml79
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml3
20 files changed, 381 insertions, 110 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDao.java b/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDao.java
index 1e283c6f541..7df166b99b9 100644
--- a/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/dashboard/ActiveDashboardDao.java
@@ -39,7 +39,7 @@ public class ActiveDashboardDao implements BatchComponent, ServerComponent {
mapper.insert(activeDashboardDto);
session.commit();
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/dashboard/DashboardDao.java b/sonar-core/src/main/java/org/sonar/core/dashboard/DashboardDao.java
index b70433dbf92..b6e828223d1 100644
--- a/sonar-core/src/main/java/org/sonar/core/dashboard/DashboardDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/dashboard/DashboardDao.java
@@ -38,7 +38,7 @@ public class DashboardDao implements BatchComponent, ServerComponent {
DashboardMapper mapper = session.getMapper(DashboardMapper.class);
return mapper.selectGlobalDashboard(name);
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -59,7 +59,7 @@ public class DashboardDao implements BatchComponent, ServerComponent {
}
session.commit();
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/duplication/DuplicationDao.java b/sonar-core/src/main/java/org/sonar/core/duplication/DuplicationDao.java
index e557d061ca7..fb6503ccb0a 100644
--- a/sonar-core/src/main/java/org/sonar/core/duplication/DuplicationDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/duplication/DuplicationDao.java
@@ -42,7 +42,7 @@ public class DuplicationDao implements BatchComponent, ServerComponent {
DuplicationMapper mapper = session.getMapper(DuplicationMapper.class);
return mapper.selectCandidates(resourceSnapshotId, lastSnapshotId, language);
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -60,7 +60,7 @@ public class DuplicationDao implements BatchComponent, ServerComponent {
session.commit();
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
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
new file mode 100644
index 00000000000..7a333228a08
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/BatchSession.java
@@ -0,0 +1,75 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.core.persistence;
+
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.SqlSession;
+
+public final class BatchSession {
+
+ public static final int MAX_BATCH_SIZE = 1000;
+
+ private final SqlSession session;
+ private final int batchSize;
+ private int count = 0;
+
+ BatchSession(SqlSession session) {
+ this(session, MAX_BATCH_SIZE);
+ }
+
+ BatchSession(SqlSession session, int batchSize) {
+ this.session = session;
+ 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;
+ }
+
+ public BatchSession commit() {
+ session.commit();
+ count = 0;
+ return this;
+ }
+
+ public <T> T getMapper(Class<T> type) {
+ return session.getMapper(type);
+ }
+
+ public SqlSession getSqlSession() {
+ return session;
+ }
+
+ public void select(String statement, Object parameter, ResultHandler handler) {
+ session.select(statement, parameter, handler);
+ }
+
+ public void select(String statement, ResultHandler handler) {
+ session.select(statement, handler);
+ }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
index 5f337782152..a6d536ca07f 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
@@ -23,6 +23,7 @@ import org.sonar.core.dashboard.ActiveDashboardDao;
import org.sonar.core.dashboard.DashboardDao;
import org.sonar.core.duplication.DuplicationDao;
import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.core.review.ReviewDao;
import org.sonar.core.rule.RuleDao;
@@ -45,6 +46,7 @@ public final class DaoUtils {
LoadedTemplateDao.class,
PurgeDao.class,
ResourceIndexerDao.class,
+ ResourceDao.class,
ReviewDao.class,
RuleDao.class));
}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseMigrator.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseMigrator.java
index 0f7a0f0faac..e2688a408ef 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseMigrator.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseMigrator.java
@@ -52,7 +52,7 @@ public class DatabaseMigrator implements ServerComponent {
DdlUtils.createSchema(connection, database.getDialect().getId());
} finally {
try {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
// The connection is probably already closed by session.close()
// but it's not documented in mybatis javadoc.
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
index 59da8b5aeea..8837db3c6d7 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
@@ -102,7 +102,12 @@ public class MyBatis implements BatchComponent, ServerComponent {
return sessionFactory.openSession(type);
}
- public static void closeSessionQuietly(SqlSession session) {
+ public BatchSession openBatchSession() {
+ SqlSession session = openSession(ExecutorType.BATCH);
+ return new BatchSession(session);
+ }
+
+ public static void closeQuietly(SqlSession session) {
if (session != null) {
try {
session.close();
@@ -113,6 +118,12 @@ public class MyBatis implements BatchComponent, ServerComponent {
}
}
+ public static void closeQuietly(BatchSession session) {
+ if (session != null) {
+ closeQuietly(session.getSqlSession());
+ }
+ }
+
private void loadMapper(Configuration conf, Class mapperClass) throws IOException {
// trick to use database-specific XML files for a single Mapper Java interface
InputStream input = getPathToMapper(mapperClass);
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 510537f9b57..2c2db13d8e3 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
@@ -23,91 +23,130 @@ import org.apache.ibatis.session.ExecutorType;
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;
+
+import java.util.List;
public class PurgeDao {
private final MyBatis mybatis;
+ private final ResourceDao resourceDao;
- public PurgeDao(MyBatis mybatis) {
+ public PurgeDao(MyBatis mybatis, ResourceDao resourceDao) {
this.mybatis = mybatis;
+ this.resourceDao = resourceDao;
}
- public PurgeDao disableOrphanResources(Object... handlers) {
+ public PurgeDao purgeProject(long rootProjectId) {
SqlSession session = mybatis.openSession(ExecutorType.BATCH);
+ PurgeMapper purgeMapper = session.getMapper(PurgeMapper.class);
try {
- final PurgeMapper mapper = session.getMapper(PurgeMapper.class);
- final BatchSession batchSession = new BatchSession(session);
- session.select("selectResourceIdsToDisable", new ResultHandler() {
- public void handleResult(ResultContext context) {
- Long resourceId = (Long) context.getResultObject();
- // TODO execute handlers in order to close reviews
- batchSession.increment(disableResource(resourceId, mapper));
- }
- });
- batchSession.commit();
- return this;
+ List<Long> projectIds = resourceDao.getDescendantProjectIdsAndSelf(rootProjectId, session);
+ for (Long projectId : projectIds) {
+ purgeProject(projectId, session, purgeMapper);
+ }
+ for (Long projectId : projectIds) {
+ disableOrphanResources(projectId, session, purgeMapper);
+ }
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
+ return this;
}
- public PurgeDao disableResource(long resourceId, Object... handlers) {
- SqlSession session = mybatis.openSession(ExecutorType.BATCH);
+ private void purgeProject(final Long projectId, final SqlSession session, final PurgeMapper purgeMapper) {
+ List<Long> projectSnapshotIds = purgeMapper.selectSnapshotIds(PurgeSnapshotQuery.create().setResourceId(projectId).setIslast(false).setNotPurged(true));
+ for (final Long projectSnapshotId : projectSnapshotIds) {
+ PurgeSnapshotQuery query = PurgeSnapshotQuery.create().setRootSnapshotId(projectSnapshotId).setNotPurged(true);
+ session.select("org.sonar.core.purge.PurgeMapper.selectSnapshotIds", query, new ResultHandler() {
+ public void handleResult(ResultContext resultContext) {
+ Long snapshotId = (Long) resultContext.getResultObject();
+ purgeSnapshot(snapshotId, purgeMapper);
+ }
+ });
+ // must be executed at the end for reentrance
+ purgeSnapshot(projectSnapshotId, purgeMapper);
+ }
+ session.commit();
+ }
+
+ private void disableOrphanResources(final Long projectId, final SqlSession session, final PurgeMapper purgeMapper) {
+ session.select("org.sonar.core.purge.PurgeMapper.selectResourceIdsToDisable", projectId, new ResultHandler() {
+ public void handleResult(ResultContext resultContext) {
+ Long resourceId = (Long) resultContext.getResultObject();
+ disableResource(resourceId, purgeMapper);
+ }
+ });
+ session.commit();
+ }
+
+ public PurgeDao deleteProject(long rootProjectId) {
+ final BatchSession session = mybatis.openBatchSession();
try {
final PurgeMapper mapper = session.getMapper(PurgeMapper.class);
- disableResource(resourceId, mapper);
+ List<Long> projectIds = resourceDao.getDescendantProjectIdsAndSelf(rootProjectId, session.getSqlSession());
+ 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();
return this;
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
+ void deleteResource(final long resourceId, final BatchSession session, final PurgeMapper mapper) {
+ session.select("org.sonar.core.purge.PurgeMapper.selectSnapshotIdsByResource", new ResultHandler() {
+ public void handleResult(ResultContext context) {
+ Long snapshotId = (Long) context.getResultObject();
+ session.increment(deleteSnapshot(snapshotId, mapper));
+ }
+ });
+ // TODO optimization: filter requests according to resource scope
+ mapper.deleteResourceLinks(resourceId);
+ mapper.deleteResourceProperties(resourceId);
+ mapper.deleteResourceIndex(resourceId);
+ mapper.deleteResourceGroupRoles(resourceId);
+ mapper.deleteResourceUserRoles(resourceId);
+ mapper.deleteResourceManualMeasures(resourceId);
+ mapper.deleteResourceReviews(resourceId);
+ mapper.deleteResourceEvents(resourceId);
+ mapper.deleteResource(resourceId);
+ session.increment(9);
+ }
+
int disableResource(long resourceId, PurgeMapper mapper) {
- mapper.disableResource(resourceId);
mapper.deleteResourceIndex(resourceId);
- mapper.unsetSnapshotIslast(resourceId);
+ mapper.setSnapshotIsLastToFalse(resourceId);
+ mapper.disableResource(resourceId);
// TODO close reviews
return 3; // nb of SQL requests
}
- public PurgeDao deleteSnapshots(PurgeSnapshotQuery query) {
- SqlSession session = mybatis.openSession(ExecutorType.BATCH);
- try {
- final PurgeMapper mapper = session.getMapper(PurgeMapper.class);
- final BatchSession batchSession = new BatchSession(session);
- session.select("selectSnapshotIds", query, new ResultHandler() {
- public void handleResult(ResultContext context) {
- Long snapshotId = (Long) context.getResultObject();
- batchSession.increment(deleteSnapshot(snapshotId, mapper));
- }
- });
- batchSession.commit();
- return this;
-
- } finally {
- MyBatis.closeSessionQuietly(session);
- }
- }
- public PurgeDao purgeSnapshots(PurgeSnapshotQuery query) {
- SqlSession session = mybatis.openSession(ExecutorType.BATCH);
+ public PurgeDao deleteSnapshots(PurgeSnapshotQuery query) {
+ final BatchSession session = mybatis.openBatchSession();
try {
final PurgeMapper mapper = session.getMapper(PurgeMapper.class);
- final BatchSession batchSession = new BatchSession(session);
- session.select("selectSnapshotIdsToPurge", query, new ResultHandler() {
+ session.select("org.sonar.core.purge.PurgeMapper.selectSnapshotIds", query, new ResultHandler() {
public void handleResult(ResultContext context) {
Long snapshotId = (Long) context.getResultObject();
- batchSession.increment(purgeSnapshot(snapshotId, mapper));
+ session.increment(deleteSnapshot(snapshotId, mapper));
}
});
- batchSession.commit();
+ session.commit();
return this;
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -135,31 +174,4 @@ public class PurgeDao {
mapper.deleteSnapshot(snapshotId);
return 8; // nb of SQL requests
}
-
- // TODO could be moved to org.sonar.core.persistence
- private static class BatchSession {
- static final int MAX_BATCH_SIZE = 1000;
-
- int count = 0;
- SqlSession session;
-
- private BatchSession(SqlSession session) {
- this.session = session;
- }
-
- BatchSession increment(int i) {
- count += i;
- if (count > MAX_BATCH_SIZE) {
- commit();
- }
- return this;
- }
-
- BatchSession commit() {
- session.commit();
- count = 0;
- return this;
- }
-
- }
}
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 2ee5c5857ba..7662417ac72 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
@@ -19,7 +19,12 @@
*/
package org.sonar.core.purge;
+import java.util.List;
+
public interface PurgeMapper {
+
+ List<Long> selectSnapshotIds(PurgeSnapshotQuery query);
+
void deleteSnapshot(long snapshotId);
void deleteSnapshotDependencies(long snapshotId);
@@ -46,5 +51,23 @@ public interface PurgeMapper {
void deleteResourceIndex(long resourceId);
- void unsetSnapshotIslast(long resourceId);
+ void deleteEvent(long eventId);
+
+ void setSnapshotIsLastToFalse(long resourceId);
+
+ void deleteResourceLinks(long resourceId);
+
+ void deleteResourceProperties(long resourceId);
+
+ void deleteResource(long resourceId);
+
+ void deleteResourceGroupRoles(long resourceId);
+
+ void deleteResourceUserRoles(long resourceId);
+
+ void deleteResourceManualMeasures(long resourceId);
+
+ void deleteResourceReviews(long resourceId);
+
+ void deleteResourceEvents(long resourceId);
}
diff --git a/sonar-core/src/main/java/org/sonar/core/purge/PurgeSnapshotQuery.java b/sonar-core/src/main/java/org/sonar/core/purge/PurgeSnapshotQuery.java
index bb16364e559..95dadd2f03c 100644
--- a/sonar-core/src/main/java/org/sonar/core/purge/PurgeSnapshotQuery.java
+++ b/sonar-core/src/main/java/org/sonar/core/purge/PurgeSnapshotQuery.java
@@ -23,10 +23,14 @@ import java.util.Date;
public final class PurgeSnapshotQuery {
private Long rootProjectId;
+ private Long rootSnapshotId;
+ private Long resourceId;
private Date beforeBuildDate;
private String[] scopes;
private String[] qualifiers;
private String[] status;
+ private Boolean islast;
+ private Boolean notPurged;
private PurgeSnapshotQuery() {
}
@@ -79,4 +83,40 @@ public final class PurgeSnapshotQuery {
this.status = status;
return this;
}
+
+ public Boolean getIslast() {
+ return islast;
+ }
+
+ public PurgeSnapshotQuery setIslast(Boolean islast) {
+ this.islast = islast;
+ return this;
+ }
+
+ public Boolean getNotPurged() {
+ return notPurged;
+ }
+
+ public PurgeSnapshotQuery setNotPurged(Boolean notPurged) {
+ this.notPurged = notPurged;
+ return this;
+ }
+
+ public Long getRootSnapshotId() {
+ return rootSnapshotId;
+ }
+
+ public PurgeSnapshotQuery setRootSnapshotId(Long rootSnapshotId) {
+ this.rootSnapshotId = rootSnapshotId;
+ return this;
+ }
+
+ public Long getResourceId() {
+ return resourceId;
+ }
+
+ public PurgeSnapshotQuery setResourceId(Long l) {
+ this.resourceId = l;
+ return this;
+ }
}
diff --git a/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java b/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
new file mode 100644
index 00000000000..3703c6b7ed4
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
@@ -0,0 +1,59 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.core.resource;
+
+import com.google.common.collect.Lists;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.core.persistence.MyBatis;
+
+import java.util.List;
+
+public class ResourceDao {
+ private MyBatis mybatis;
+
+ public ResourceDao(MyBatis mybatis) {
+ this.mybatis = mybatis;
+ }
+
+ public List<Long> getDescendantProjectIdsAndSelf(long projectId) {
+ SqlSession session = mybatis.openSession();
+ try {
+ return getDescendantProjectIdsAndSelf(projectId, session);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public List<Long> getDescendantProjectIdsAndSelf(long projectId, SqlSession session) {
+ ResourceMapper mapper = session.getMapper(ResourceMapper.class);
+ List<Long> ids = Lists.newArrayList();
+ appendChildProjectIds(projectId, mapper, ids);
+ return ids;
+ }
+
+ private void appendChildProjectIds(long projectId, ResourceMapper mapper, List<Long> ids) {
+ ids.add(projectId);
+ List<Long> subProjectIds = mapper.selectDescendantProjectIds(projectId);
+ for (Long subProjectId : subProjectIds) {
+ ids.add(subProjectId);
+ appendChildProjectIds(subProjectId, mapper, ids);
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/resource/ResourceIndexerDao.java b/sonar-core/src/main/java/org/sonar/core/resource/ResourceIndexerDao.java
index 44f1d533210..af07153a03a 100644
--- a/sonar-core/src/main/java/org/sonar/core/resource/ResourceIndexerDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/resource/ResourceIndexerDao.java
@@ -58,7 +58,7 @@ public class ResourceIndexerDao {
return this;
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -79,7 +79,7 @@ public class ResourceIndexerDao {
return this;
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -160,7 +160,7 @@ public class ResourceIndexerDao {
}
}
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
return indexed;
diff --git a/sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java b/sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java
index deb72aeb3ad..24bdb00a289 100644
--- a/sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java
+++ b/sonar-core/src/main/java/org/sonar/core/resource/ResourceMapper.java
@@ -19,6 +19,9 @@
*/
package org.sonar.core.resource;
+import java.util.List;
+
public interface ResourceMapper {
SnapshotDto selectSnapshotById(Long snapshotId);
+ List<Long> selectDescendantProjectIds(long rootProjectId);
}
diff --git a/sonar-core/src/main/java/org/sonar/core/review/ReviewDao.java b/sonar-core/src/main/java/org/sonar/core/review/ReviewDao.java
index c090251153d..b9d7f7283a8 100644
--- a/sonar-core/src/main/java/org/sonar/core/review/ReviewDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/review/ReviewDao.java
@@ -40,7 +40,7 @@ public class ReviewDao implements BatchComponent, ServerComponent {
ReviewMapper mapper = session.getMapper(ReviewMapper.class);
return mapper.selectById(id);
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -59,7 +59,7 @@ public class ReviewDao implements BatchComponent, ServerComponent {
}
return result;
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -77,7 +77,7 @@ public class ReviewDao implements BatchComponent, ServerComponent {
}
return result;
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java b/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java
index 1b4b6545ea2..b353cbbb0b4 100644
--- a/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java
@@ -40,7 +40,7 @@ public class RuleDao implements BatchComponent, ServerComponent {
RuleMapper mapper = session.getMapper(RuleMapper.class);
return mapper.selectAll();
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -50,7 +50,7 @@ public class RuleDao implements BatchComponent, ServerComponent {
RuleMapper mapper = session.getMapper(RuleMapper.class);
return mapper.selectById(id);
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/template/LoadedTemplateDao.java b/sonar-core/src/main/java/org/sonar/core/template/LoadedTemplateDao.java
index 7067d03bd7c..83b47f07548 100644
--- a/sonar-core/src/main/java/org/sonar/core/template/LoadedTemplateDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/template/LoadedTemplateDao.java
@@ -38,7 +38,7 @@ public class LoadedTemplateDao implements BatchComponent, ServerComponent {
try {
return mapper.countByTypeAndKey(type, key);
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
@@ -49,7 +49,7 @@ public class LoadedTemplateDao implements BatchComponent, ServerComponent {
mapper.insert(loadedTemplateDto);
session.commit();
} finally {
- MyBatis.closeSessionQuietly(session);
+ MyBatis.closeQuietly(session);
}
}
diff --git a/sonar-core/src/main/java/org/sonar/jpa/entity/SchemaMigration.java b/sonar-core/src/main/java/org/sonar/jpa/entity/SchemaMigration.java
index 5efe3e48193..a6e8c7653e0 100644
--- a/sonar-core/src/main/java/org/sonar/jpa/entity/SchemaMigration.java
+++ b/sonar-core/src/main/java/org/sonar/jpa/entity/SchemaMigration.java
@@ -34,7 +34,7 @@ public class SchemaMigration {
public final static int VERSION_UNKNOWN = -1;
- public static final int LAST_VERSION = 252;
+ public static final int LAST_VERSION = 253;
public static final int VERSION_2_13 = 241;
public final static String TABLE_NAME = "schema_migrations";
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql
index 8144ad8cb05..6b842872b00 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-derby.sql
@@ -170,6 +170,8 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('240');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('241');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('250');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('251');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('252');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('253');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
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 aa92585f3d6..9e857f38a87 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
@@ -6,10 +6,21 @@
<select id="selectSnapshotIds" parameterType="map" resultType="long">
select id from snapshots
<where>
- islast=${_false}
+ <if test="islast != null">
+ and islast=#{islast}
+ </if>
+ <if test="notPurged != null and notPurged">
+ and (purge_status is null or purge_status=0)
+ </if>
+ <if test="rootSnapshotId != null">
+ and root_snapshot_id=#{rootSnapshotId}
+ </if>
<if test="rootProjectId != null">
and root_project_id=#{rootProjectId}
</if>
+ <if test="resourceId != null">
+ and project_id=#{resourceId}
+ </if>
<if test="beforeBuildDate != null">
and build_date &lt;= #{beforeBuildDate}
</if>
@@ -23,29 +34,23 @@
</if>
<if test="qualifiers != null">
and qualifier in
- <foreach item="qualifier" index="index" collection="qualifiers" open="(" separator="," close=")">#{qualifier}
- </foreach>
+ <foreach item="qualifier" index="index" collection="qualifiers" open="(" separator="," close=")">#{qualifier}</foreach>
</if>
</where>
</select>
- <select id="selectResourceIdsToDisable" resultType="long">
- select s1.project_id from snapshots s1
- where s1.islast=${_true} and s1.root_snapshot_id is not null and not exists(select s2.id from snapshots s2 where
- s2.id=s1.root_snapshot_id and s2.islast=${_true})
+ <select id="selectResourceIdsToDisable" resultType="long" parameterType="long">
+ select p.id from projects p
+ where (p.id=#{id} or p.root_id=#{id}) and p.enabled=${_true}
+ and not exists(select s.project_id from snapshots s where s.islast=${_true} and s.project_id=p.id)
</select>
- <select id="selectSnapshotIdsToPurge" parameterType="map" resultType="long">
- select id from snapshots
- <where>
- islast=${_false} and (purge_status is null or purge_status=0)
- <if test="rootProjectId != null">
- and root_project_id=#{rootProjectId}
- </if>
- <if test="beforeBuildDate!= null">
- and build_date &lt;= #{beforeBuildDate}
- </if>
- </where>
+ <select id="selectResourceIdsByRootId" resultType="long" parameterType="long">
+ select id from projects where root_id=#{id} or id=#{id}
+ </select>
+
+ <select id="selectSnapshotIdsByResource" parameterType="long" resultType="long">
+ select id from snapshots where project_id=#{id}
</select>
<delete id="deleteSnapshotMeasures" parameterType="long">
@@ -100,7 +105,43 @@
delete from resource_index where resource_id=#{id}
</delete>
- <update id="unsetSnapshotIslast" parameterType="long">
+ <delete id="deleteEvent" parameterType="long">
+ delete from events where id=#{id}
+ </delete>
+
+ <delete id="deleteResourceLinks" parameterType="long">
+ delete from project_links where project_id=#{id}
+ </delete>
+
+ <delete id="deleteResourceProperties" parameterType="long">
+ delete from properties where resource_id=#{id}
+ </delete>
+
+ <delete id="deleteResource" parameterType="long">
+ delete from projects where id=#{id}
+ </delete>
+
+ <delete id="deleteResourceGroupRoles" parameterType="long">
+ delete from group_roles where resource_id=#{id}
+ </delete>
+
+ <delete id="deleteResourceUserRoles" parameterType="long">
+ delete from user_roles where resource_id=#{id}
+ </delete>
+
+ <delete id="deleteResourceManualMeasures" parameterType="long">
+ delete from manual_measures where resource_id=#{id}
+ </delete>
+
+ <delete id="deleteResourceReviews" parameterType="long">
+ delete from reviews where resource_id=#{id}
+ </delete>
+
+ <delete id="deleteResourceEvents" parameterType="long">
+ delete from events where resource_id=#{id}
+ </delete>
+
+ <update id="setSnapshotIsLastToFalse" parameterType="long">
update snapshots set islast=${_false} where project_id=#{id}
</update>
</mapper>
diff --git a/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml b/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml
index 9ef0bcd36de..f16cc1849dd 100644
--- a/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/resource/ResourceMapper.xml
@@ -27,5 +27,8 @@
select * from snapshots where id=#{id}
</select>
+ <select id="selectDescendantProjectIds" parameterType="long" resultType="long">
+ select id from projects where scope='PRJ' and root_id=#{id}
+ </select>
</mapper>