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.plugins.dbcleaner.api; 021 022 import java.util.List; 023 024 import javax.persistence.Query; 025 026 import org.apache.commons.configuration.Configuration; 027 import org.sonar.api.batch.Event; 028 import org.sonar.api.database.DatabaseSession; 029 import org.sonar.api.database.model.MeasureData; 030 import org.sonar.api.database.model.MeasureModel; 031 import org.sonar.api.database.model.RuleFailureModel; 032 import org.sonar.api.database.model.Snapshot; 033 import org.sonar.api.database.model.SnapshotSource; 034 import org.sonar.api.design.DependencyDto; 035 import org.sonar.api.utils.TimeProfiler; 036 import org.sonar.jpa.entity.DuplicationBlock; 037 038 /** 039 * @since 2.5 040 */ 041 public final class PurgeUtils { 042 043 public static final int DEFAULT_MINIMUM_PERIOD_IN_HOURS = 12; 044 public static final String PROP_KEY_MINIMUM_PERIOD_IN_HOURS = "sonar.purge.minimumPeriodInHours"; 045 046 /** 047 * Maximum elements in the SQL statement "IN" due to an Oracle limitation (see error ORA-01795) 048 */ 049 public static final int MAX_IN_ELEMENTS = 950; 050 051 private PurgeUtils() { 052 // only static methods 053 } 054 055 public static int getMinimumPeriodInHours(Configuration conf) { 056 int hours = DEFAULT_MINIMUM_PERIOD_IN_HOURS; 057 if (conf != null) { 058 hours = conf.getInt(PROP_KEY_MINIMUM_PERIOD_IN_HOURS, DEFAULT_MINIMUM_PERIOD_IN_HOURS); 059 } 060 return hours; 061 } 062 063 public static void deleteSnapshotsData(DatabaseSession session, List<Integer> snapshotIds) { 064 deleteMeasuresBySnapshotId(session, snapshotIds); 065 deleteSources(session, snapshotIds); 066 deleteViolations(session, snapshotIds); 067 deleteDependencies(session, snapshotIds); 068 deleteDuplicationBlocks(session, snapshotIds); 069 deleteEvents(session, snapshotIds); 070 deleteSnapshots(session, snapshotIds); 071 } 072 073 public static void deleteDependencies(DatabaseSession session, List<Integer> snapshotIds) { 074 executeQuery(session, "delete dependencies", snapshotIds, "delete from " + DependencyDto.class.getSimpleName() + " d where d.fromSnapshotId in (:ids)"); 075 executeQuery(session, "delete dependencies", snapshotIds, "delete from " + DependencyDto.class.getSimpleName() + " d where d.toSnapshotId in (:ids)"); 076 } 077 078 /** 079 * Delete all measures, including MEASURE_DATA 080 */ 081 public static void deleteMeasuresBySnapshotId(DatabaseSession session, List<Integer> snapshotIds) { 082 executeQuery(session, "delete measures by snapshot id", snapshotIds, "delete from " + MeasureData.class.getSimpleName() + " m where m.snapshotId in (:ids)"); 083 executeQuery(session, "delete measures by snapshot id", snapshotIds, "delete from " + MeasureModel.class.getSimpleName() + " m where m.snapshotId in (:ids)"); 084 } 085 086 /** 087 * Delete all measures, including MEASURE_DATA 088 */ 089 public static void deleteMeasuresById(DatabaseSession session, List<Integer> measureIds) { 090 executeQuery(session, "delete measures by id", measureIds, "delete from " + MeasureData.class.getSimpleName() + " m where m.measure.id in (:ids)"); 091 executeQuery(session, "delete measures by id", measureIds, "delete from " + MeasureModel.class.getSimpleName() + " m where m.id in (:ids)"); 092 } 093 094 /** 095 * Delete SNAPSHOT_SOURCES table 096 */ 097 public static void deleteSources(DatabaseSession session, List<Integer> snapshotIds) { 098 executeQuery(session, "delete sources", snapshotIds, "delete from " + SnapshotSource.class.getSimpleName() + " e where e.snapshotId in (:ids)"); 099 } 100 101 /** 102 * Delete violations (RULE_FAILURES table) 103 */ 104 public static void deleteViolations(DatabaseSession session, List<Integer> snapshotIds) { 105 executeQuery(session, "delete violations", snapshotIds, "delete from " + RuleFailureModel.class.getSimpleName() + " e where e.snapshotId in (:ids)"); 106 } 107 108 /** 109 * @since 2.11 110 */ 111 private static void deleteDuplicationBlocks(DatabaseSession session, List<Integer> snapshotIds) { 112 executeQuery(session, "delete duplication blocks", snapshotIds, "delete from " + DuplicationBlock.class.getSimpleName() + " e where e.snapshotId in (:ids)"); 113 } 114 115 /** 116 * Delete EVENTS table 117 */ 118 public static void deleteEvents(DatabaseSession session, List<Integer> snapshotIds) { 119 executeQuery(session, "delete events", snapshotIds, "delete from " + Event.class.getSimpleName() + " e where e.snapshot.id in (:ids)"); 120 } 121 122 /** 123 * Delete SNAPSHOTS table 124 */ 125 public static void deleteSnapshots(DatabaseSession session, List<Integer> snapshotIds) { 126 executeQuery(session, "delete snapshots", snapshotIds, "delete from " + Snapshot.class.getSimpleName() + " s where s.id in (:ids)"); 127 } 128 129 /** 130 * Paginate execution of SQL requests to avoid exceeding size of rollback segment 131 */ 132 public static void executeQuery(DatabaseSession session, String description, List<Integer> ids, String hql) { 133 if (ids == null || ids.isEmpty()) { 134 return; 135 } 136 137 TimeProfiler profiler = new TimeProfiler().setLevelToDebug().start("Execute " + description); 138 139 int index = 0; 140 while (index < ids.size()) { 141 Query query = session.createQuery(hql); 142 List<Integer> paginedSids = ids.subList(index, Math.min(ids.size(), index + MAX_IN_ELEMENTS)); 143 query.setParameter("ids", paginedSids); 144 query.executeUpdate(); 145 index += MAX_IN_ELEMENTS; 146 session.commit(); 147 } 148 149 profiler.stop(); 150 } 151 152 }