From: Simon Brandhof Date: Wed, 25 Jan 2012 16:38:50 +0000 (+0100) Subject: SONAR-2757 Refactor the purge mechanisms to prevent any fullscan SQL requests on... X-Git-Tag: 2.14~243 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8c6df4977b90cfce0cc6797e3b1ba23b1253a62c;p=sonarqube.git SONAR-2757 Refactor the purge mechanisms to prevent any fullscan SQL requests on snapshots table --- diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java index 47a872a2fd6..0eb4d380281 100644 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java @@ -25,10 +25,6 @@ import org.sonar.api.SonarPlugin; import org.sonar.plugins.dbcleaner.api.DbCleanerConstants; import org.sonar.plugins.dbcleaner.period.DefaultPeriodCleaner; import org.sonar.plugins.dbcleaner.period.PeriodPurge; -import org.sonar.plugins.dbcleaner.purges.DeleteAbortedBuilds; -import org.sonar.plugins.dbcleaner.purges.DeleteDirectoryHistory; -import org.sonar.plugins.dbcleaner.purges.DeleteFileHistory; -import org.sonar.plugins.dbcleaner.purges.ProjectPurgeTask; import org.sonar.plugins.dbcleaner.runner.DeprecatedPurgePostJob; import org.sonar.plugins.dbcleaner.runner.ProjectPurgePostJob; @@ -59,13 +55,10 @@ public final class DbCleanerPlugin extends SonarPlugin { public List getExtensions() { return Arrays.asList( - // shared components - DefaultPeriodCleaner.class, ProjectPurgeTask.class, + DefaultPeriodCleaner.class, + PeriodPurge.class, - // purges - PeriodPurge.class, DeleteFileHistory.class, DeleteDirectoryHistory.class, DeleteAbortedBuilds.class, ProjectPurgePostJob.class, - - // post-job - DeprecatedPurgePostJob.class); + // post-jobs + ProjectPurgePostJob.class, DeprecatedPurgePostJob.class); } } diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/api/DbCleanerConstants.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/api/DbCleanerConstants.java index f003ac5e16e..a1e4bd8aabb 100644 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/api/DbCleanerConstants.java +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/api/DbCleanerConstants.java @@ -23,6 +23,7 @@ public interface DbCleanerConstants { String PLUGIN_KEY = "dbcleaner"; String PLUGIN_NAME = "DbCleaner"; + String PROPERTY_CLEAN_DIRECTORY = "sonar.dbcleaner.cleanDirectory"; String MONTHS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK = "sonar.dbcleaner.monthsBeforeKeepingOnlyOneSnapshotByWeek"; String MONTHS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH = "sonar.dbcleaner.monthsBeforeKeepingOnlyOneSnapshotByMonth"; String MONTHS_BEFORE_DELETING_ALL_SNAPSHOTS = "sonar.dbcleaner.monthsBeforeDeletingAllSnapshots"; diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteAbortedBuilds.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteAbortedBuilds.java deleted file mode 100644 index 464fd4b2714..00000000000 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteAbortedBuilds.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.plugins.dbcleaner.purges; - -import org.sonar.core.purge.PurgeDao; -import org.sonar.core.purge.PurgeSnapshotQuery; - -/** - * @since 2.14 - */ -public class DeleteAbortedBuilds extends ProjectPurge { - private PurgeDao purgeDao; - - public DeleteAbortedBuilds(PurgeDao purgeDao) { - this.purgeDao = purgeDao; - } - - @Override - public void execute(ProjectPurgeContext context) { - PurgeSnapshotQuery query = PurgeSnapshotQuery.create() - .setBeforeBuildDate(context.getBeforeBuildDate()) - .setRootProjectId(context.getRootProjectId()) - .setStatus(new String[]{"U"}); - purgeDao.deleteSnapshots(query); - } -} diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteDirectoryHistory.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteDirectoryHistory.java deleted file mode 100644 index dfaa68fd1f4..00000000000 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteDirectoryHistory.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.plugins.dbcleaner.purges; - -import org.sonar.api.Properties; -import org.sonar.api.Property; -import org.sonar.api.config.Settings; -import org.sonar.api.resources.Scopes; -import org.sonar.core.purge.PurgeDao; -import org.sonar.core.purge.PurgeSnapshotQuery; - -@Properties({ - @Property(key = "sonar.dbcleaner.cleanDirectory", defaultValue = "false", name = "Clean history data of directories/packages") -}) -public class DeleteDirectoryHistory extends ProjectPurge { - private PurgeDao purgeDao; - private Settings settings; - - public DeleteDirectoryHistory(PurgeDao purgeDao, Settings settings) { - this.purgeDao = purgeDao; - this.settings = settings; - } - - @Override - public void execute(ProjectPurgeContext context) { - if (settings.getBoolean("sonar.dbcleaner.cleanDirectoryHistory")) { - PurgeSnapshotQuery query = PurgeSnapshotQuery.create() - .setBeforeBuildDate(context.getBeforeBuildDate()) - .setRootProjectId(context.getRootProjectId()) - .setScopes(new String[]{Scopes.DIRECTORY}); - purgeDao.deleteSnapshots(query); - } - } -} diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteFileHistory.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteFileHistory.java deleted file mode 100644 index b0f48d93239..00000000000 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteFileHistory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.plugins.dbcleaner.purges; - -import org.sonar.api.resources.Scopes; -import org.sonar.core.purge.PurgeDao; -import org.sonar.core.purge.PurgeSnapshotQuery; - -public class DeleteFileHistory extends ProjectPurge { - private PurgeDao purgeDao; - - public DeleteFileHistory(PurgeDao purgeDao) { - this.purgeDao = purgeDao; - } - - @Override - public void execute(ProjectPurgeContext context) { - PurgeSnapshotQuery query = PurgeSnapshotQuery.create() - .setBeforeBuildDate(context.getBeforeBuildDate()) - .setRootProjectId(context.getRootProjectId()) - .setScopes(new String[]{Scopes.FILE}); - purgeDao.deleteSnapshots(query); - } -} diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurge.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurge.java deleted file mode 100644 index 41ecd85098f..00000000000 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurge.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.plugins.dbcleaner.purges; - -import org.sonar.api.BatchExtension; - -public abstract class ProjectPurge implements BatchExtension { - - public abstract void execute(ProjectPurgeContext context); - -} diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeContext.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeContext.java deleted file mode 100644 index e01330a0598..00000000000 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeContext.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.plugins.dbcleaner.purges; - -import java.util.Date; - -public interface ProjectPurgeContext { - Long getRootProjectId(); - - Date getBeforeBuildDate(); -} diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeTask.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeTask.java deleted file mode 100644 index de721ba1891..00000000000 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeTask.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.plugins.dbcleaner.purges; - -import org.slf4j.LoggerFactory; -import org.sonar.api.BatchExtension; -import org.sonar.core.purge.PurgeDao; -import org.sonar.core.purge.PurgeSnapshotQuery; - -public class ProjectPurgeTask implements BatchExtension { - - private ProjectPurge[] purges; - private PurgeDao purgeDao; - - public ProjectPurgeTask(ProjectPurge[] purges, PurgeDao purgeDao) { - this.purges = purges; - this.purgeDao = purgeDao; - } - - public ProjectPurgeTask execute(ProjectPurgeContext context) { - purgeProject(context); - purgeSnapshots(context); - return this; - } - - private void purgeProject(ProjectPurgeContext purgeContext) { - for (ProjectPurge purge : purges) { - LoggerFactory.getLogger(getClass()).debug("Executing purge " + purge); - purge.execute(purgeContext); - } - } - - private void purgeSnapshots(ProjectPurgeContext context) { - LoggerFactory.getLogger(getClass()).debug("Purging snapshots"); - PurgeSnapshotQuery query = PurgeSnapshotQuery.create() - .setBeforeBuildDate(context.getBeforeBuildDate()) - .setRootProjectId(context.getRootProjectId()); - purgeDao.purgeSnapshots(query); - } -} diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/runner/ProjectPurgePostJob.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/runner/ProjectPurgePostJob.java index 6dccaef73be..5a5646e4187 100644 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/runner/ProjectPurgePostJob.java +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/runner/ProjectPurgePostJob.java @@ -19,41 +19,70 @@ */ package org.sonar.plugins.dbcleaner.runner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.sonar.api.Properties; +import org.sonar.api.Property; import org.sonar.api.batch.PostJob; import org.sonar.api.batch.SensorContext; +import org.sonar.api.config.Settings; import org.sonar.api.resources.Project; +import org.sonar.api.resources.Scopes; import org.sonar.core.NotDryRun; -import org.sonar.plugins.dbcleaner.purges.ProjectPurgeContext; -import org.sonar.plugins.dbcleaner.purges.ProjectPurgeTask; - -import java.util.Date; +import org.sonar.core.purge.PurgeDao; +import org.sonar.core.purge.PurgeSnapshotQuery; +import org.sonar.plugins.dbcleaner.api.DbCleanerConstants; +@Properties({ + @Property( + key = DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY, + defaultValue = "false", + name = "Clean history data of directories/packages") +}) @NotDryRun public class ProjectPurgePostJob implements PostJob { - private ProjectPurgeTask task; + private PurgeDao purgeDao; + private Settings settings; - public ProjectPurgePostJob(ProjectPurgeTask task) { - this.task = task; + public ProjectPurgePostJob(PurgeDao purgeDao, Settings settings) { + this.purgeDao = purgeDao; + this.settings = settings; } public void executeOn(final Project project, SensorContext context) { - final Date beforeBuildDate = new Date(); + long projectId = (long) project.getId(); + deleteAbortedBuilds(projectId); + deleteFileHistory(projectId); + if (settings.getBoolean(DbCleanerConstants.PROPERTY_CLEAN_DIRECTORY)) { + deleteDirectoryHistory(projectId); + } + purgeProject(projectId); + } + + private void purgeProject(long projectId) { + purgeDao.purgeProject(projectId); + } - ProjectPurgeContext purgeContext = new ProjectPurgeContext() { - public Long getRootProjectId() { - return new Long(project.getId()); - } + private void deleteDirectoryHistory(long projectId) { + PurgeSnapshotQuery query = PurgeSnapshotQuery.create() + .setRootProjectId(projectId) + .setIslast(false) + .setScopes(new String[]{Scopes.DIRECTORY}); + purgeDao.deleteSnapshots(query); + } - public Date getBeforeBuildDate() { - return beforeBuildDate; - } - }; + private void deleteFileHistory(long projectId) { + PurgeSnapshotQuery query = PurgeSnapshotQuery.create() + .setRootProjectId(projectId) + .setIslast(false) + .setScopes(new String[]{Scopes.FILE}); + purgeDao.deleteSnapshots(query); + } - Logger logger = LoggerFactory.getLogger(getClass()); - logger.info("Optimizing project"); - task.execute(purgeContext); + private void deleteAbortedBuilds(long projectId) { + PurgeSnapshotQuery query = PurgeSnapshotQuery.create() + .setRootProjectId(projectId) + .setIslast(false) + .setStatus(new String[]{"U"}); + purgeDao.deleteSnapshots(query); } } diff --git a/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/DbCleanerPluginTest.java b/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/DbCleanerPluginTest.java index 9154cce3a28..f08ebf1f690 100644 --- a/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/DbCleanerPluginTest.java +++ b/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/DbCleanerPluginTest.java @@ -28,6 +28,6 @@ public class DbCleanerPluginTest { @Test public void shouldGetExtensions() { - assertThat(new DbCleanerPlugin().getExtensions().size(), greaterThan(5)); + assertThat(new DbCleanerPlugin().getExtensions().size(), greaterThan(2)); } } 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 getMapper(Class 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 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 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 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 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 getDescendantProjectIdsAndSelf(long projectId) { + SqlSession session = mybatis.openSession(); + try { + return getDescendantProjectIdsAndSelf(projectId, session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List getDescendantProjectIdsAndSelf(long projectId, SqlSession session) { + ResourceMapper mapper = session.getMapper(ResourceMapper.class); + List ids = Lists.newArrayList(); + appendChildProjectIds(projectId, mapper, ids); + return ids; + } + + private void appendChildProjectIds(long projectId, ResourceMapper mapper, List ids) { + ids.add(projectId); + List 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 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 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 id from projects where root_id=#{id} or id=#{id} + + + @@ -100,7 +105,43 @@ delete from resource_index where resource_id=#{id} - + + delete from events where id=#{id} + + + + delete from project_links where project_id=#{id} + + + + delete from properties where resource_id=#{id} + + + + delete from projects where id=#{id} + + + + delete from group_roles where resource_id=#{id} + + + + delete from user_roles where resource_id=#{id} + + + + delete from manual_measures where resource_id=#{id} + + + + delete from reviews where resource_id=#{id} + + + + delete from events where resource_id=#{id} + + + update snapshots set islast=${_false} where project_id=#{id} 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} + 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 3e8f6249081..7db16de255d 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 @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Test; import org.sonar.core.persistence.DaoTestCase; import org.sonar.core.persistence.MyBatis; +import org.sonar.core.resource.ResourceDao; public class PurgeDaoTest extends DaoTestCase { @@ -31,9 +32,12 @@ public class PurgeDaoTest extends DaoTestCase { @Before public void createDao() { - dao = new PurgeDao(getMyBatis()); + dao = new PurgeDao(getMyBatis(), new ResourceDao(getMyBatis())); } + /** + * Test that all related data is deleted. + */ @Test public void shouldDeleteSnapshot() { setupData("shouldDeleteSnapshot"); @@ -45,19 +49,37 @@ public class PurgeDaoTest extends DaoTestCase { session.commit(); } finally { - MyBatis.closeSessionQuietly(session); + MyBatis.closeQuietly(session); } checkTables("shouldDeleteSnapshot", "snapshots", "project_measures", "measure_data", "rule_failures", "snapshot_sources", "duplications_index", "events", "dependencies"); } @Test - public void shouldPurgeSnapshots() { - setupData("shouldPurgeSnapshots"); + public void shouldPurgeProject() { + setupData("shouldPurgeProject"); + dao.purgeProject(1); + checkTables("shouldPurgeProject", "projects", "snapshots"); + } - dao.purgeSnapshots(PurgeSnapshotQuery.create()); + @Test + public void shouldPurgeDirectoriesAndFiles() { + setupData("shouldPurgeDirectoriesAndFiles"); + dao.purgeProject(1); + checkTables("shouldPurgeDirectoriesAndFiles", "projects", "snapshots"); + } - checkTables("shouldPurgeSnapshots", - "snapshots", "project_measures", "measure_data", "rule_failures", "snapshot_sources", "duplications_index", "events", "dependencies"); + @Test + public void shouldDisableResourcesWithoutLastSnapshot() { + setupData("shouldDisableResourcesWithoutLastSnapshot"); + dao.purgeProject(1); + checkTables("shouldDisableResourcesWithoutLastSnapshot", "projects", "snapshots"); + } + + @Test + public void shouldDeleteSnapshots() { + setupData("shouldDeleteSnapshots"); + dao.deleteSnapshots(PurgeSnapshotQuery.create().setIslast(false).setResourceId(1L)); + checkTables("shouldDeleteSnapshots", "snapshots"); } } diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots-result.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots-result.xml new file mode 100644 index 00000000000..a995a2d6ab3 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots-result.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots.xml new file mode 100644 index 00000000000..9d00efd4cfa --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot-result.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot-result.xml new file mode 100644 index 00000000000..34d37de75a4 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot-result.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot.xml new file mode 100644 index 00000000000..00d35af353d --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles-result.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles-result.xml new file mode 100644 index 00000000000..1a0782c7cf5 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles-result.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles.xml new file mode 100644 index 00000000000..864dc0435ef --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject-result.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject-result.xml new file mode 100644 index 00000000000..1e879b7c7a8 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject-result.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject.xml new file mode 100644 index 00000000000..a391957b025 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots-result.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots-result.xml deleted file mode 100644 index 22327faf348..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots-result.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots.xml b/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots.xml deleted file mode 100644 index cc870ca1a5b..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/253_update_snapshots_purge_status.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/253_update_snapshots_purge_status.rb new file mode 100644 index 00000000000..0138aff4fd7 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/253_update_snapshots_purge_status.rb @@ -0,0 +1,30 @@ +# +# Sonar, entreprise quality control 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 +# + +# +# Sonar 2.14 +# +class UpdateSnapshotsPurgeStatus < ActiveRecord::Migration + + def self.up + Snapshot.update_all('purge_status=1', ['islast=?', false]) + end + +end