| /* |
| * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.gjc.util; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Timer; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import com.sun.logging.LogDomains; |
| |
| /** |
| * Maintains the Sql Tracing Cache used to store SQL statements used by the |
| * applications. This is used by the JDBCRA monitoring to display the most |
| * frequently used queries by applications. |
| * |
| * @author Shalini M |
| */ |
| public class SQLTraceCache { |
| |
| // List of sql trace objects |
| private final List<SQLTrace> list; |
| // Maximum size of the cache. |
| private int numTopQueriesToReport = 10; |
| private long timeToKeepQueries = 60 * 1000; |
| private SQLTraceTimerTask sqlTraceTimerTask; |
| private String poolName; |
| private String appName; |
| private String moduleName; |
| private final static Logger _logger = LogDomains.getLogger(SQLTraceCache.class, LogDomains.RSR_LOGGER); |
| private static final String LINE_BREAK = "%%%EOL%%%"; |
| |
| public SQLTraceCache(String poolName, String appName, String moduleName, int maxSize, long timeToKeepQueries) { |
| this.poolName = poolName; |
| this.appName = appName; |
| this.moduleName = moduleName; |
| this.numTopQueriesToReport = maxSize; |
| list = new ArrayList<SQLTrace>(); |
| this.timeToKeepQueries = timeToKeepQueries * 60 * 1000; |
| } |
| |
| public List<SQLTrace> getSqlTraceList() { |
| return list; |
| } |
| |
| public String getPoolName() { |
| return poolName; |
| } |
| |
| /** |
| * Schedule timer to perform purgeEntries on the cache after the specified |
| * timeToKeepQueries delay and period. |
| */ |
| public void scheduleTimerTask(Timer timer) { |
| |
| if (sqlTraceTimerTask != null) { |
| sqlTraceTimerTask.cancel(); |
| sqlTraceTimerTask = null; |
| } |
| |
| sqlTraceTimerTask = initializeTimerTask(); |
| |
| if (timer != null) { |
| |
| timer.scheduleAtFixedRate(sqlTraceTimerTask, timeToKeepQueries, timeToKeepQueries); |
| } |
| if (_logger.isLoggable(Level.FINEST)) { |
| _logger.finest("Scheduled Sql Trace Caching timer task"); |
| } |
| } |
| |
| /** |
| * Cancel the timer task used to perform a purgeEntries on the cache. |
| */ |
| public synchronized void cancelTimerTask() { |
| |
| if (_logger.isLoggable(Level.FINEST)) { |
| _logger.finest("Cancelling Sql Trace Caching timer task"); |
| } |
| if (sqlTraceTimerTask != null) { |
| sqlTraceTimerTask.cancel(); |
| } |
| sqlTraceTimerTask = null; |
| } |
| |
| /** |
| * Instantiate the timer task used to perform a purgeEntries on the cache |
| * |
| * @return SQLTraceTimerTask |
| */ |
| private SQLTraceTimerTask initializeTimerTask() { |
| if (_logger.isLoggable(Level.FINEST)) { |
| _logger.finest("Initializing Sql Trace Caching timer task"); |
| } |
| return new SQLTraceTimerTask(this); |
| } |
| |
| /** |
| * Request for adding a sql query in the form of SQLTrace to this cache. If the |
| * query is already found in the list, the number of times it is executed is |
| * incremented by one along with the timestamp. If the query is a new one, it is |
| * added to the list. |
| * |
| * @param cacheObj |
| * @return |
| */ |
| public void checkAndUpdateCache(SQLTrace cacheObj) { |
| synchronized (list) { |
| if (cacheObj != null) { |
| int index = list.indexOf(cacheObj); |
| if (index != -1) { |
| // If already found in the cache |
| // equals is invoked here and hence comparison based on query name is done |
| // Get the object at the index to update the numExecutions |
| SQLTrace cache = list.get(index); |
| cache.setNumExecutions(cache.getNumExecutions() + 1); |
| cache.setLastUsageTime(System.currentTimeMillis()); |
| } else { |
| // First occurrence of the query. query to be added. |
| cacheObj.setNumExecutions(1); |
| cacheObj.setLastUsageTime(System.currentTimeMillis()); |
| list.add(cacheObj); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Entries are removed from the list after sorting them in the least frequently |
| * used order. Only numTopQueriesToReport number of entries are maintained in |
| * the list after the purgeEntries. |
| */ |
| public void purgeEntries() { |
| synchronized (list) { |
| Collections.sort(list, Collections.reverseOrder()); |
| Iterator i = list.iterator(); |
| while (i.hasNext()) { |
| SQLTrace cacheObj = (SQLTrace) i.next(); |
| if (list.size() > numTopQueriesToReport) { |
| if (_logger.isLoggable(Level.FINEST)) { |
| _logger.finest("removing sql=" + cacheObj.getQueryName()); |
| } |
| i.remove(); |
| } else { |
| break; |
| } |
| } |
| // sort by most frequently used queries first |
| Collections.sort(list); |
| } |
| } |
| |
| /** |
| * Returns the String representation of the list of traced sql queries ordered |
| * by the number most frequently used, followed by the usage timestamp. Only the |
| * top 'n' queries represented by the numTopQueriesToReport are chosen for |
| * display. |
| * |
| * @return string representation of the list of sql queries sorted |
| */ |
| public String getTopQueries() { |
| purgeEntries(); |
| StringBuffer sb = new StringBuffer(); |
| for (SQLTrace cache : list) { |
| sb.append(LINE_BREAK); |
| sb.append(cache.getQueryName()); |
| } |
| return sb.toString(); |
| } |
| } |