001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 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 */ 020package org.sonar.plugins.dbcleaner.api; 021 022import com.google.common.annotations.VisibleForTesting; 023import org.apache.commons.configuration.Configuration; 024import org.sonar.api.batch.Event; 025import org.sonar.api.database.DatabaseSession; 026import org.sonar.api.database.model.*; 027import org.sonar.api.design.DependencyDto; 028import org.sonar.api.utils.TimeProfiler; 029 030import javax.persistence.Query; 031import java.util.List; 032 033/** 034 * @since 2.5 035 * @deprecated Useless since version 2.14 because of the refactoring of the cleanup mechanism (see SONAR-2757). 036 */ 037@Deprecated 038public final class PurgeUtils { 039 040 public static final int DEFAULT_MINIMUM_PERIOD_IN_HOURS = 12; 041 public static final String PROP_KEY_MINIMUM_PERIOD_IN_HOURS = "sonar.purge.minimumPeriodInHours"; 042 043 /** 044 * Maximum elements in the SQL statement "IN" due to an Oracle limitation (see error ORA-01795) 045 */ 046 public static final int MAX_IN_ELEMENTS = 950; 047 048 private PurgeUtils() { 049 // only static methods 050 } 051 052 public static int getMinimumPeriodInHours(Configuration conf) { 053 int hours = DEFAULT_MINIMUM_PERIOD_IN_HOURS; 054 if (conf != null) { 055 hours = conf.getInt(PROP_KEY_MINIMUM_PERIOD_IN_HOURS, DEFAULT_MINIMUM_PERIOD_IN_HOURS); 056 } 057 return hours; 058 } 059 060 public static void deleteSnapshotsData(DatabaseSession session, List<Integer> snapshotIds) { 061 deleteMeasuresBySnapshotId(session, snapshotIds); 062 deleteSources(session, snapshotIds); 063 deleteViolations(session, snapshotIds); 064 deleteDependencies(session, snapshotIds); 065 deleteDuplicationBlocks(session, snapshotIds); 066 deleteEvents(session, snapshotIds); 067 deleteSnapshots(session, snapshotIds); 068 } 069 070 public static void deleteDependencies(DatabaseSession session, List<Integer> snapshotIds) { 071 executeQuery(session, "delete dependencies", snapshotIds, "delete from " + DependencyDto.class.getSimpleName() + " d where d.fromSnapshotId in (:ids)"); 072 executeQuery(session, "delete dependencies", snapshotIds, "delete from " + DependencyDto.class.getSimpleName() + " d where d.toSnapshotId in (:ids)"); 073 } 074 075 /** 076 * Delete all measures, including MEASURE_DATA 077 */ 078 public static void deleteMeasuresBySnapshotId(DatabaseSession session, List<Integer> snapshotIds) { 079 executeQuery(session, "delete measures by snapshot id", snapshotIds, "delete from " + MeasureData.class.getSimpleName() + " m where m.snapshotId in (:ids)"); 080 executeQuery(session, "delete measures by snapshot id", snapshotIds, "delete from " + MeasureModel.class.getSimpleName() + " m where m.snapshotId in (:ids)"); 081 } 082 083 /** 084 * Delete all measures, including MEASURE_DATA 085 */ 086 public static void deleteMeasuresById(DatabaseSession session, List<Integer> measureIds) { 087 executeQuery(session, "delete measures by id", measureIds, "delete from " + MeasureData.class.getSimpleName() + " m where m.measure.id in (:ids)"); 088 executeQuery(session, "delete measures by id", measureIds, "delete from " + MeasureModel.class.getSimpleName() + " m where m.id in (:ids)"); 089 } 090 091 /** 092 * Delete SNAPSHOT_SOURCES table 093 */ 094 public static void deleteSources(DatabaseSession session, List<Integer> snapshotIds) { 095 executeQuery(session, "delete sources", snapshotIds, "delete from " + SnapshotSource.class.getSimpleName() + " e where e.snapshotId in (:ids)"); 096 } 097 098 /** 099 * Delete violations (RULE_FAILURES table) 100 */ 101 public static void deleteViolations(DatabaseSession session, List<Integer> snapshotIds) { 102 executeQuery(session, "delete violations", snapshotIds, "delete from " + RuleFailureModel.class.getSimpleName() + " e where e.snapshotId in (:ids)"); 103 } 104 105 /** 106 * Delete DUPLICATIONS_INDEX table 107 * 108 * @since 2.11 109 */ 110 private static void deleteDuplicationBlocks(DatabaseSession session, List<Integer> snapshotIds) { 111 executeNativeQuery(session, "delete duplication blocks", snapshotIds, "delete from duplications_index where snapshot_id in (:ids)"); 112 } 113 114 /** 115 * Delete EVENTS table 116 */ 117 public static void deleteEvents(DatabaseSession session, List<Integer> snapshotIds) { 118 executeQuery(session, "delete events", snapshotIds, "delete from " + Event.class.getSimpleName() + " e where e.snapshot.id in (:ids)"); 119 } 120 121 /** 122 * Delete SNAPSHOTS table 123 */ 124 public static void deleteSnapshots(DatabaseSession session, List<Integer> snapshotIds) { 125 executeQuery(session, "delete snapshots", snapshotIds, "delete from " + Snapshot.class.getSimpleName() + " s where s.id in (:ids)"); 126 } 127 128 public static void deleteResources(DatabaseSession session, List<Integer> ids) { 129 executeQuery(session, "", ids, "DELETE FROM " + ResourceModel.class.getSimpleName() + " WHERE id in (:ids)"); 130 deleteResourceIndex(session, ids); 131 } 132 133 /** 134 * Delete RESOURCE_INDEX table 135 */ 136 public static void deleteResourceIndex(DatabaseSession session, List<Integer> resourceIds) { 137 executeNativeQuery(session, "delete resource_index", resourceIds, "delete from resource_index where resource_id in (:ids)"); 138 } 139 140 /** 141 * Paginate execution of SQL requests to avoid exceeding size of rollback segment 142 */ 143 public static void executeQuery(DatabaseSession session, String description, List<Integer> ids, String hql) { 144 if (ids == null || ids.isEmpty()) { 145 return; 146 } 147 TimeProfiler profiler = new TimeProfiler().setLevelToDebug().start("Execute " + description); 148 int index = 0; 149 while (index < ids.size()) { 150 List<Integer> paginedSids = ids.subList(index, Math.min(ids.size(), index + MAX_IN_ELEMENTS)); 151 Query query = session.createQuery(hql); 152 query.setParameter("ids", paginedSids); 153 query.executeUpdate(); 154 index += MAX_IN_ELEMENTS; 155 session.commit(); 156 } 157 profiler.stop(); 158 } 159 160 /** 161 * @since 2.13 162 */ 163 @VisibleForTesting 164 static void executeNativeQuery(DatabaseSession session, String description, List<Integer> ids, String sql) { 165 if (ids == null || ids.isEmpty()) { 166 return; 167 } 168 TimeProfiler profiler = new TimeProfiler().setLevelToDebug().start("Execute " + description); 169 int index = 0; 170 while (index < ids.size()) { 171 List<Integer> paginedSids = ids.subList(index, Math.min(ids.size(), index + MAX_IN_ELEMENTS)); 172 Query query = session.createNativeQuery(sql); 173 query.setParameter("ids", paginedSids); 174 query.executeUpdate(); 175 index += MAX_IN_ELEMENTS; 176 session.commit(); 177 } 178 profiler.stop(); 179 } 180 181}