aboutsummaryrefslogtreecommitdiffstats
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
parent319a66df83a3aa19eea3612901626a6223f4e1d4 (diff)
downloadsonarqube-8c6df4977b90cfce0cc6797e3b1ba23b1253a62c.tar.gz
sonarqube-8c6df4977b90cfce0cc6797e3b1ba23b1253a62c.zip
SONAR-2757 Refactor the purge mechanisms to prevent any fullscan SQL requests on snapshots table
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java15
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/api/DbCleanerConstants.java1
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteAbortedBuilds.java43
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteDirectoryHistory.java51
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/DeleteFileHistory.java41
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurge.java28
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeContext.java28
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/ProjectPurgeTask.java57
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/runner/ProjectPurgePostJob.java71
-rw-r--r--plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/DbCleanerPluginTest.java2
-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
-rw-r--r--sonar-core/src/test/java/org/sonar/core/purge/PurgeDaoTest.java36
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots-result.xml35
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDeleteSnapshots.xml35
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot-result.xml56
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldDisableResourcesWithoutLastSnapshot.xml49
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles-result.xml88
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeDirectoriesAndFiles.xml82
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject-result.xml43
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeProject.xml43
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots-result.xml102
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldPurgeSnapshots.xml102
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/db/migrate/253_update_snapshots_purge_status.rb30
42 files changed, 927 insertions, 602 deletions
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> 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>
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 @@
+<dataset>
+
+ <!-- do not delete if islast=true -->
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- delete only resource 1 -->
+ <snapshots id="2"
+ project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- to be deleted -->
+ <!--<snapshots id="3"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>-->
+</dataset> \ 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 @@
+<dataset>
+
+ <!-- do not delete if islast=true -->
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- delete only resource 1 -->
+ <snapshots id="2"
+ project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- to be deleted -->
+ <snapshots id="3"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+</dataset> \ 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 @@
+<!--
+
+What has been changed :
+* enabled=false on projects
+* purge_status=1 on snapshots
+
+-->
+<dataset>
+
+ <!-- the project -->
+ <projects id="1" enabled="false" root_id="[null]"
+ long_name="[null]" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the directory -->
+ <projects id="2" enabled="false" root_id="1"
+ long_name="[null]" scope="DIR" qualifier="DIR" kee="project:my/dir" name="my/dir"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the file -->
+ <projects id="3" enabled="false" root_id="1"
+ long_name="[null]" scope="FIL" qualifier="FIL" kee="project:my/dir/File.java" name="my/dir/File.java"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <snapshots id="2"
+ project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <snapshots id="3"
+ project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+</dataset> \ 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 @@
+<dataset>
+
+ <!-- the project -->
+ <projects id="1" enabled="true" root_id="[null]"
+ long_name="[null]" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the directory -->
+ <projects id="2" enabled="true" root_id="1"
+ long_name="[null]" scope="DIR" qualifier="DIR" kee="project:my/dir" name="my/dir"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the file -->
+ <projects id="3" enabled="true" root_id="1"
+ long_name="[null]" scope="FIL" qualifier="FIL" kee="project:my/dir/File.java" name="my/dir/File.java"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <snapshots id="2"
+ project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <snapshots id="3"
+ project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+</dataset> \ 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 @@
+<!--
+
+What has been changed : purge_status=1 on snapshots 4, 5 and 6
+
+-->
+
+<dataset>
+
+ <!-- the project -->
+ <projects id="1" enabled="true" root_id="[null]"
+ long_name="[null]" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the directory -->
+ <projects id="2" enabled="true" root_id="1"
+ long_name="[null]" scope="DIR" qualifier="DIR" kee="project:my/dir" name="my/dir"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the file -->
+ <projects id="3" enabled="true" root_id="1"
+ long_name="[null]" scope="FIL" qualifier="FIL" kee="project:my/dir/File.java" name="my/dir/File.java"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- do not purge last snapshots -->
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <snapshots id="2"
+ project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <snapshots id="3"
+ project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- snapshots to be purged -->
+ <snapshots id="4"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <snapshots id="5"
+ project_id="2" parent_snapshot_id="4" root_project_id="1" root_snapshot_id="4"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <snapshots id="6"
+ project_id="3" parent_snapshot_id="5" root_project_id="1" root_snapshot_id="4"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+</dataset> \ 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 @@
+<dataset>
+
+ <!-- the project -->
+ <projects id="1" enabled="true" root_id="[null]"
+ long_name="[null]" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the directory -->
+ <projects id="2" enabled="true" root_id="1"
+ long_name="[null]" scope="DIR" qualifier="DIR" kee="project:my/dir" name="my/dir"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- the file -->
+ <projects id="3" enabled="true" root_id="1"
+ long_name="[null]" scope="FIL" qualifier="FIL" kee="project:my/dir/File.java" name="my/dir/File.java"
+ description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <!-- do not purge last snapshots -->
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <snapshots id="2"
+ project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <snapshots id="3"
+ project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- snapshots to be purged -->
+ <snapshots id="4"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <snapshots id="5"
+ project_id="2" parent_snapshot_id="4" root_project_id="1" root_snapshot_id="4"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <snapshots id="6"
+ project_id="3" parent_snapshot_id="5" root_project_id="1" root_snapshot_id="4"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+</dataset> \ 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 @@
+<dataset>
+
+ <!-- the project -->
+ <projects id="1" enabled="true"
+ long_name="[null]" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ root_id="[null]" description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+
+ <!-- snapshot already purged -->
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <!-- do not purge snapshot with islast=true-->
+ <snapshots id="2"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- snapshot to be purged -->
+ <snapshots id="3"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+</dataset> \ 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 @@
+<dataset>
+
+ <!-- the project -->
+ <projects id="1" enabled="true"
+ long_name="[null]" scope="PRJ" qualifier="TRK" kee="project" name="project"
+ root_id="[null]" description="[null]" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+
+ <!-- snapshot already purged -->
+ <snapshots id="1"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="1"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+
+ <!-- do not purge snapshot with islast=true-->
+ <snapshots id="2"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="true" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+ <!-- snapshot to be purged -->
+ <snapshots id="3"
+ project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
+ status="P" islast="false" purge_status="[null]"
+ period1_mode="[null]" period1_param="[null]" period1_date="[null]"
+ period2_mode="[null]" period2_param="[null]" period2_date="[null]"
+ period3_mode="[null]" period3_param="[null]" period3_date="[null]"
+ period4_mode="[null]" period4_param="[null]" period4_date="[null]"
+ period5_mode="[null]" period5_param="[null]" period5_date="[null]"
+ depth="[null]" scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00" version="[null]" path="[null]"/>
+
+</dataset> \ 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 @@
-<dataset>
-
- <!-- snapshot already purged -->
- <snapshots id="1" purge_status="1" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]"
- period3_mode="[null]" period3_param="[null]"
- period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]"
- period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- depth="[null]"
- scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00"
- version="[null]"
- project_id="1"
- parent_snapshot_id="[null]" root_project_id="[null]" root_snapshot_id="[null]" status="P" islast="false"
- path="[null]"/>
-
-
- <!-- do not purge snapshot with islast=true-->
- <snapshots id="2" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]"
- period3_mode="[null]" period3_param="[null]"
- period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]"
- period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- depth="[null]"
- scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00"
- version="[null]"
- project_id="1"
- parent_snapshot_id="[null]" root_project_id="[null]" root_snapshot_id="[null]" status="P" islast="true"
- path="[null]"/>
- <SNAPSHOT_SOURCES ID="2" SNAPSHOT_ID="2" DATA="foo"/>
- <rule_failures switched_off="[null]" permanent_id="[null]" ID="2" SNAPSHOT_ID="2" RULE_ID="3" FAILURE_LEVEL="2"
- MESSAGE="msg1" LINE="[null]" COST="[null]"
- created_at="2008-12-02 13:58:00.00"
- checksum="[null]" committer="[null]"/>
- <events id="2" name="Version 1.0" resource_id="1" snapshot_id="2" category="VERSION" description="[null]"
- event_date="2008-12-02 13:58:00.00" created_at="[null]"/>
- <duplications_index project_snapshot_id="1" snapshot_id="1" hash="bb" index_in_file="0" start_line="0" end_line="0"/>
- <dependencies id="1" from_resource_id="1" from_snapshot_id="1" to_resource_id="2" to_snapshot_id="2"
- parent_dependency_id="[null]" project_snapshot_id="1"
- dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="PRJ"/>
-
-
- <!-- snapshot to purge -> purge_status is set to 1 -->
- <snapshots id="3" purge_status="1" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]"
- period3_mode="[null]" period3_param="[null]"
- period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]"
- period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- depth="[null]"
- scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00"
- version="[null]"
- project_id="1"
- parent_snapshot_id="[null]" root_project_id="[null]" root_snapshot_id="[null]" status="P" islast="false"
- path="[null]"/>
-
- <!-- source: to be deleted -->
- <!--<SNAPSHOT_SOURCES ID="3" SNAPSHOT_ID="3" DATA="foo"/>-->
-
- <!-- violation: to be deleted -->
- <!--<rule_failures switched_off="[null]" permanent_id="[null]" ID="1" SNAPSHOT_ID="3" RULE_ID="1" FAILURE_LEVEL="2"-->
- <!--MESSAGE="msg1" LINE="[null]" COST="[null]"-->
- <!--created_at="2008-12-02 13:58:00.00"-->
- <!--checksum="[null]" committer="[null]"/>-->
-
- <!-- measure: do not delete -->
- <project_measures ID="1" characteristic_id="[null]" url="[null]" variation_value_1="[null]" variation_value_2="[null]"
- variation_value_3="[null]" variation_value_4="[null]"
- variation_value_5="[null]"
- rule_priority="[null]"
- alert_text="[null]" VALUE="10.0" METRIC_ID="1" SNAPSHOT_ID="3" rules_category_id="[null]"
- RULE_ID="[null]"
- text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]"/>
-
- <measure_data id="1" measure_id="1" snapshot_id="3" data="[null]"/>
-
- <!-- rule measure: to be deleted -->
- <!--<project_measures ID="2" characteristic_id="[null]" url="[null]" variation_value_1="[null]" variation_value_2="[null]"-->
- <!--variation_value_3="[null]" variation_value_4="[null]"-->
- <!--variation_value_5="[null]"-->
- <!--rule_priority="[null]"-->
- <!--alert_text="[null]" VALUE="10.0" METRIC_ID="1" SNAPSHOT_ID="3" rules_category_id="[null]"-->
- <!--RULE_ID="1"-->
- <!--text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"-->
- <!--alert_status="[null]" description="[null]"/>-->
-
- <!-- dependencies: to be deleted -->
- <!--<dependencies id="2" from_resource_id="1" from_snapshot_id="3" to_resource_id="30" to_snapshot_id="30"-->
- <!--parent_dependency_id="[null]" project_snapshot_id="1"-->
- <!--dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="PRJ"/>-->
- <!--<dependencies id="3" from_resource_id="100" from_snapshot_id="100" to_resource_id="1" to_snapshot_id="3"-->
- <!--parent_dependency_id="[null]" project_snapshot_id="100"-->
- <!--dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="PRJ"/>-->
-
-
- <!--events: do not delete -->
- <events id="3" name="Version 1.0" resource_id="1" snapshot_id="3" category="VERSION" description="[null]"
- event_date="2008-12-02 13:58:00.00" created_at="[null]"/>
-
- <!--duplications: to be deleted -->
- <!--<duplications_index project_snapshot_id="100" snapshot_id="3" hash="bb" index_in_file="0" start_line="0" end_line="0"/>-->
-
-</dataset> \ 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 @@
-<dataset>
-
- <!-- snapshot already purged -->
- <snapshots id="1" purge_status="1" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]"
- period3_mode="[null]" period3_param="[null]"
- period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]"
- period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- depth="[null]"
- scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00"
- version="[null]"
- project_id="1"
- parent_snapshot_id="[null]" root_project_id="[null]" root_snapshot_id="[null]" status="P" islast="false"
- path="[null]"/>
-
-
- <!-- do not purge snapshot with islast=true-->
- <snapshots id="2" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]"
- period3_mode="[null]" period3_param="[null]"
- period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]"
- period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- depth="[null]"
- scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00"
- version="[null]"
- project_id="1"
- parent_snapshot_id="[null]" root_project_id="[null]" root_snapshot_id="[null]" status="P" islast="true"
- path="[null]"/>
- <SNAPSHOT_SOURCES ID="2" SNAPSHOT_ID="2" DATA="foo"/>
- <rule_failures switched_off="[null]" permanent_id="[null]" ID="2" SNAPSHOT_ID="2" RULE_ID="3" FAILURE_LEVEL="2"
- MESSAGE="msg1" LINE="[null]" COST="[null]"
- created_at="2008-12-02 13:58:00.00"
- checksum="[null]" committer="[null]"/>
- <events id="2" name="Version 1.0" resource_id="1" snapshot_id="2" category="VERSION" description="[null]"
- event_date="2008-12-02 13:58:00.00" created_at="[null]"/>
- <duplications_index project_snapshot_id="1" snapshot_id="1" hash="bb" index_in_file="0" start_line="0" end_line="0"/>
- <dependencies id="1" from_resource_id="1" from_snapshot_id="1" to_resource_id="2" to_snapshot_id="2"
- parent_dependency_id="[null]" project_snapshot_id="1"
- dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="PRJ"/>
-
- <!-- snapshot to purge -->
- <snapshots id="3" purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]"
- period2_mode="[null]" period2_param="[null]" period2_date="[null]"
- period3_mode="[null]" period3_param="[null]"
- period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]"
- period5_mode="[null]" period5_param="[null]" period5_date="[null]"
- depth="[null]"
- scope="PRJ" qualifier="TRK" created_at="2008-12-02 13:58:00.00" build_date="2008-12-02 13:58:00.00"
- version="[null]"
- project_id="1"
- parent_snapshot_id="[null]" root_project_id="[null]" root_snapshot_id="[null]" status="P" islast="false"
- path="[null]"/>
-
- <!-- source: to be deleted -->
- <SNAPSHOT_SOURCES ID="3" SNAPSHOT_ID="3" DATA="foo"/>
-
- <!-- violation: to be deleted -->
- <rule_failures switched_off="[null]" permanent_id="[null]" ID="3" SNAPSHOT_ID="3" RULE_ID="1" FAILURE_LEVEL="2"
- MESSAGE="msg1" LINE="[null]" COST="[null]"
- created_at="2008-12-02 13:58:00.00"
- checksum="[null]" committer="[null]"/>
-
- <!-- measure: do not delete -->
- <project_measures ID="1" characteristic_id="[null]" url="[null]" variation_value_1="[null]" variation_value_2="[null]"
- variation_value_3="[null]" variation_value_4="[null]"
- variation_value_5="[null]"
- rule_priority="[null]"
- alert_text="[null]" VALUE="10.0" METRIC_ID="1" SNAPSHOT_ID="3" rules_category_id="[null]"
- RULE_ID="[null]"
- text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]"/>
-
- <measure_data id="1" measure_id="1" snapshot_id="3" data="[null]"/>
-
- <!-- rule measure: to be deleted -->
- <project_measures ID="2" characteristic_id="[null]" url="[null]" variation_value_1="[null]" variation_value_2="[null]"
- variation_value_3="[null]" variation_value_4="[null]"
- variation_value_5="[null]"
- rule_priority="[null]"
- alert_text="[null]" VALUE="10.0" METRIC_ID="1" SNAPSHOT_ID="3" rules_category_id="[null]"
- RULE_ID="1"
- text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
- alert_status="[null]" description="[null]"/>
-
- <!-- dependencies: to be deleted -->
- <dependencies id="2" from_resource_id="1" from_snapshot_id="3" to_resource_id="30" to_snapshot_id="30"
- parent_dependency_id="[null]" project_snapshot_id="1"
- dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="PRJ"/>
- <dependencies id="3" from_resource_id="100" from_snapshot_id="100" to_resource_id="1" to_snapshot_id="3"
- parent_dependency_id="[null]" project_snapshot_id="100"
- dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="PRJ"/>
-
-
- <!--events: do not delete -->
- <events id="3" name="Version 1.0" resource_id="1" snapshot_id="3" category="VERSION" description="[null]"
- event_date="2008-12-02 13:58:00.00" created_at="[null]"/>
-
- <!-- duplications: to be deleted -->
- <duplications_index project_snapshot_id="100" snapshot_id="3" hash="bb" index_in_file="0" start_line="0"
- end_line="0"/>
-
-</dataset> \ 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