001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2009 SonarSource SA 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.api.database; 021 022 import org.hibernate.ejb.EntityManagerFactoryImpl; 023 import org.hibernate.ejb.HibernateEntityManagerFactory; 024 import org.hibernate.stat.QueryStatistics; 025 import org.hibernate.stat.Statistics; 026 import org.slf4j.Logger; 027 028 import javax.persistence.*; 029 030 public class StatisticsEntityManager implements EntityManager { 031 032 private final EntityManager manager; 033 private final Logger logger; 034 private EntityTransaction transaction; 035 private EntityManagerFactory factory; 036 037 public StatisticsEntityManager(EntityManagerFactory factory, EntityManager manager, Logger logger) { 038 super(); 039 this.manager = manager; 040 this.logger = logger; 041 this.factory = factory; 042 } 043 044 public void clear() { 045 manager.clear(); 046 } 047 048 public void close() { 049 manager.close(); 050 } 051 052 public boolean contains(Object entity) { 053 return manager.contains(entity); 054 } 055 056 public Query createNamedQuery(String name) { 057 return manager.createNamedQuery(name); 058 } 059 060 public Query createNativeQuery(String sqlString) { 061 return manager.createNativeQuery(sqlString); 062 } 063 064 public Query createNativeQuery(String sqlString, Class resultClass) { 065 return manager.createNativeQuery(sqlString, resultClass); 066 } 067 068 public Query createNativeQuery(String sqlString, String resultSetMapping) { 069 return manager.createNativeQuery(sqlString, resultSetMapping); 070 } 071 072 public Query createQuery(String qlString) { 073 return manager.createQuery(qlString); 074 } 075 076 public <T> T find(Class<T> entityClass, Object primaryKey) { 077 long start = System.currentTimeMillis(); 078 T hit = manager.find(entityClass, primaryKey); 079 long stop = System.currentTimeMillis() - start; 080 logger.info("Find took " + stop + " ms"); 081 return hit; 082 } 083 084 public void flush() { 085 long start = System.currentTimeMillis(); 086 manager.flush(); 087 long stop = System.currentTimeMillis() - start; 088 logger.info("Flush took " + stop + " ms"); 089 } 090 091 public Object getDelegate() { 092 return manager.getDelegate(); 093 } 094 095 public FlushModeType getFlushMode() { 096 return manager.getFlushMode(); 097 } 098 099 public <T> T getReference(Class<T> entityClass, Object primaryKey) { 100 return manager.getReference(entityClass, primaryKey); 101 } 102 103 private String getCallerStack(int depth) { 104 StackTraceElement[] stack = Thread.currentThread().getStackTrace(); 105 return stack[depth].toString(); 106 } 107 108 public EntityTransaction getTransaction() { 109 if (transaction == null) { 110 transaction = new EntityTransaction() { 111 112 private long beginTs; 113 114 public void begin() { 115 beginTs = System.currentTimeMillis(); 116 manager.getTransaction().begin(); 117 } 118 119 public void commit() { 120 long start = System.currentTimeMillis(); 121 manager.getTransaction().commit(); 122 Long commitTimeTaken = System.currentTimeMillis() - start; 123 Long transactionTimeTaken = System.currentTimeMillis() - beginTs; 124 logger.info("{}: Commit took {} ms, global transaction took {} ms", 125 new Object[]{getCallerStack(5), commitTimeTaken, transactionTimeTaken}); 126 127 dumpStatistics(); 128 beginTs = 0; 129 } 130 131 public boolean getRollbackOnly() { 132 return manager.getTransaction().getRollbackOnly(); 133 } 134 135 public boolean isActive() { 136 return manager.getTransaction().isActive(); 137 } 138 139 public void rollback() { 140 long start = System.currentTimeMillis(); 141 manager.getTransaction().rollback(); 142 long rollbackTimeTaken = System.currentTimeMillis() - start; 143 long transactionTimeTaken = System.currentTimeMillis() - beginTs; 144 logger.info("Rollback took " + rollbackTimeTaken + " ms, global transaction took " + transactionTimeTaken + " ms"); 145 beginTs = 0; 146 } 147 148 public void setRollbackOnly() { 149 manager.getTransaction().setRollbackOnly(); 150 } 151 152 }; 153 } 154 return transaction; 155 } 156 157 public boolean isOpen() { 158 return manager.isOpen(); 159 } 160 161 public void joinTransaction() { 162 manager.joinTransaction(); 163 } 164 165 public void lock(Object entity, LockModeType lockMode) { 166 manager.lock(entity, lockMode); 167 } 168 169 public <T> T merge(T entity) { 170 return manager.merge(entity); 171 } 172 173 public void persist(Object entity) { 174 manager.persist(entity); 175 } 176 177 public void refresh(Object entity) { 178 manager.refresh(entity); 179 } 180 181 public void remove(Object entity) { 182 manager.remove(entity); 183 } 184 185 public void setFlushMode(FlushModeType flushMode) { 186 manager.setFlushMode(flushMode); 187 } 188 189 private void dumpStatistics() { 190 if (logger.isDebugEnabled() && factory instanceof EntityManagerFactoryImpl) { 191 192 HibernateEntityManagerFactory hibernateFactory = (HibernateEntityManagerFactory) factory; 193 Statistics stats = hibernateFactory.getSessionFactory().getStatistics(); 194 for (String query : stats.getQueries()) { 195 QueryStatistics stat = stats.getQueryStatistics(query); 196 StringBuilder sb = new StringBuilder(); 197 sb.append(stats.getQueryExecutionMaxTime()); 198 sb.append("ms, count="); 199 sb.append(stat.getExecutionCount()); 200 sb.append(", sql="); 201 sb.append(stat.getCategoryName()); 202 logger.debug(sb.toString()); 203 } 204 stats.clear(); 205 } 206 } 207 208 }