001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2011 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.core.purge;
021
022 import org.sonar.api.batch.Purge;
023 import org.sonar.api.database.DatabaseSession;
024 import org.sonar.api.database.model.*;
025 import org.sonar.api.design.DependencyDto;
026 import org.sonar.api.utils.TimeProfiler;
027
028 import java.util.List;
029
030 import javax.persistence.Query;
031
032 /**
033 * @deprecated since 2.5. The DBCleaner plugin implements all required purge taks, but you can extend org.sonar.plugins.dbcleaner.api.Purge
034 */
035 @Deprecated
036 public abstract class AbstractPurge implements Purge {
037
038 private static final int MAX_IN_ELEMENTS = 950;
039
040 private int sqlInPageSize = MAX_IN_ELEMENTS;
041 private DatabaseSession session;
042 private TimeProfiler profiler = new TimeProfiler().setLevelToDebug();
043
044 public AbstractPurge(DatabaseSession session) {
045 this.session = session;
046 }
047
048 protected DatabaseSession getSession() {
049 return session;
050 }
051
052 /**
053 * Delete SNAPSHOTS and all dependent tables (MEASURES, ...)
054 */
055 protected void deleteSnapshotData(List<Integer> snapshotIds) {
056 deleteMeasuresBySnapshotId(snapshotIds);
057 deleteSources(snapshotIds);
058 deleteViolations(snapshotIds);
059 deleteDependencies(snapshotIds);
060 deleteSnapshots(snapshotIds);
061 }
062
063 protected void deleteDependencies(List<Integer> snapshotIds) {
064 executeQuery("delete dependencies", snapshotIds, "delete from " + DependencyDto.class.getSimpleName()
065 + " d where d.fromSnapshotId in (:ids)");
066 executeQuery("delete dependencies", snapshotIds, "delete from " + DependencyDto.class.getSimpleName()
067 + " d where d.toSnapshotId in (:ids)");
068 }
069
070 /**
071 * Delete all measures, including MEASURE_DATA
072 */
073 protected void deleteMeasuresBySnapshotId(List<Integer> snapshotIds) {
074 executeQuery("delete measures by snapshot id", snapshotIds, "delete from " + MeasureData.class.getSimpleName()
075 + " m where m.snapshotId in (:ids)");
076 executeQuery("delete measures by snapshot id", snapshotIds, "delete from " + MeasureModel.class.getSimpleName()
077 + " m where m.snapshotId in (:ids)");
078 }
079
080 /**
081 * Delete all measures, including MEASURE_DATA
082 */
083 protected void deleteMeasuresById(List<Integer> measureIds) {
084 executeQuery("delete measures by id", measureIds, "delete from " + MeasureData.class.getSimpleName()
085 + " m where m.measure.id in (:ids)");
086 executeQuery("delete measures by id", measureIds, "delete from " + MeasureModel.class.getSimpleName() + " m where m.id in (:ids)");
087 }
088
089 /**
090 * Delete SNAPSHOT_SOURCES table
091 */
092 protected void deleteSources(List<Integer> snapshotIds) {
093 executeQuery("delete sources", snapshotIds, "delete from " + SnapshotSource.class.getSimpleName() + " e where e.snapshotId in (:ids)");
094 }
095
096 /**
097 * Delete violations (RULE_FAILURES table)
098 */
099 protected void deleteViolations(List<Integer> snapshotIds) {
100 executeQuery("delete violations", snapshotIds, "delete from " + RuleFailureModel.class.getSimpleName()
101 + " e where e.snapshotId in (:ids)");
102 }
103
104 /**
105 * Delete SNAPSHOTS table
106 */
107 protected void deleteSnapshots(List<Integer> snapshotIds) {
108 executeQuery("delete snapshots", snapshotIds, "delete from " + Snapshot.class.getSimpleName() + " s where s.id in (:ids)");
109 }
110
111 /**
112 * Paginate execution of SQL requests to avoid exceeding size of rollback segment
113 */
114 private void executeQuery(String name, List<Integer> ids, String hql) {
115 if (ids == null || ids.isEmpty()) {
116 return;
117 }
118
119 TimeProfiler profiler = new TimeProfiler().setLevelToDebug().start("Execute " + name);
120
121 int page = 1;
122 int index = 0;
123 while (index < ids.size()) {
124 TimeProfiler pageProfiler = new TimeProfiler().setLevelToDebug().start("Execute " + name + " " + page + " page");
125 Query query = session.createQuery(hql);
126 List<Integer> paginedSids = ids.subList(index, Math.min(ids.size(), index + sqlInPageSize));
127 query.setParameter("ids", paginedSids);
128 query.executeUpdate();
129 index += sqlInPageSize;
130 page++;
131 session.commit();
132 pageProfiler.stop();
133 }
134
135 profiler.stop();
136 }
137
138 protected void executeQuery(List<Integer> ids, String hql) {
139 executeQuery("delete for " + getClass().getSimpleName(), ids, hql);
140 }
141
142 protected List<Integer> selectIds(Query query) {
143 profiler.start("Select IDs for " + getClass().getSimpleName());
144 List<Integer> result = query.getResultList();
145 profiler.stop();
146 return result;
147 }
148 }