OPENJPA-1739 Added basic stats tracking to query result cache. Updates to JMX provider. Added tests to jmx module for query cache and prepared SQL cache instruments.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@984633 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jeremy Bauer 2010-08-12 02:40:23 +00:00
parent 0876c93ff6
commit 25ccc95d6c
11 changed files with 675 additions and 143 deletions

View File

@ -19,14 +19,22 @@
package org.apache.openjpa.integration.jmx;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.persistence.Query;
import org.apache.openjpa.instrumentation.DataCacheInstrument;
import org.apache.openjpa.instrumentation.InstrumentationManager;
import org.apache.openjpa.instrumentation.PreparedQueryCacheInstrument;
import org.apache.openjpa.instrumentation.QueryCacheInstrument;
import org.apache.openjpa.instrumentation.jmx.JMXProvider;
import org.apache.openjpa.lib.instrumentation.Instrument;
import org.apache.openjpa.lib.instrumentation.InstrumentationProvider;
@ -35,11 +43,10 @@ import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
public class TestJMXPlatformMBeans extends AbstractPersistenceTestCase {
/**
* Verifies the data cache metrics are available through simple instrumentation.
*/
@SuppressWarnings("deprecation")
/**
* Verifies data cache metrics are available through simple instrumentation.
*/
public void testDataCacheInstrument() {
OpenJPAEntityManagerFactorySPI oemf = createNamedEMF("openjpa-integration-jmx");
@ -78,30 +85,167 @@ public class TestJMXPlatformMBeans extends AbstractPersistenceTestCase {
// Thread out to do out-of-band MBean-based validation. This could
// have been done on the same thread, but threading out makes for a
// more realistic test.
Thread thr = new Thread(new DCMBeanThread());
thr.start();
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Boolean> result = executor.submit(new DCMBeanCallable());
try {
thr.join(60000); // Wait for 1 minute for the MBean thread to return.
if (thr.isAlive()) {
// MBean did not return within a minute, interrupt it.
thr.interrupt();
Thread.sleep(5000);
if (thr.isAlive()) {
// Attempt to hard kill the thread to prevent the test from hanging
thr.stop();
}
fail("DataCache MBean verification thread failed.");
}
assertTrue(result.get());
} catch (Throwable t) {
fail("Caught unexpected throwable: " + t);
fail("DataCache verification failed: " + t);
}
closeEMF(oemf);
}
public class DCMBeanThread implements Runnable {
/**
* Verifies query cache metrics are available through simple instrumentation.
*/
public void testQueryCacheInstrument() {
OpenJPAEntityManagerFactorySPI oemf = createNamedEMF("openjpa-integration-jmx");
// Verify an EMF was created with the supplied instrumentation
assertNotNull(oemf);
public void run() {
// Verify an instrumentation manager is available
InstrumentationManager mgr = oemf.getConfiguration().getInstrumentationManagerInstance();
assertNotNull(mgr);
// Get the in-band data cache instrument
Set<InstrumentationProvider> providers = mgr.getProviders();
assertNotNull(providers);
assertEquals(1, providers.size());
InstrumentationProvider provider = providers.iterator().next();
assertEquals(provider.getClass(), JMXProvider.class);
Instrument inst = provider.getInstrumentByName("QueryCache");
assertNotNull(inst);
assertTrue(inst instanceof QueryCacheInstrument);
QueryCacheInstrument qci = (QueryCacheInstrument)inst;
assertEquals(0,qci.getExecutionCount());
assertEquals(0,qci.getTotalExecutionCount());
assertEquals(0,qci.getHitCount());
assertEquals(0,qci.getTotalHitCount());
OpenJPAEntityManagerSPI oem = oemf.createEntityManager();
CachedEntity ce = new CachedEntity();
int id = new Random().nextInt();
ce.setId(id);
CachedEntity ce2 = new CachedEntity();
id = new Random().nextInt();
ce2.setId(id);
oem.getTransaction().begin();
oem.persist(ce);
oem.persist(ce2);
oem.getTransaction().commit();
Query q = oem.createQuery("SELECT ce FROM CachedEntity ce");
List<?> result = q.getResultList();
assertNotNull(result);
assertTrue(result.size() > 1);
oem.clear();
result = q.getResultList();
assertTrue(qci.getExecutionCount() > 0);
assertTrue(qci.getTotalExecutionCount() > 0);
assertTrue(qci.getHitCount() > 0);
assertTrue(qci.getTotalHitCount() > 0);
// Thread out to do out-of-band MBean-based validation. This could
// have been done on the same thread, but threading out makes for a
// more realistic test.
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Boolean> execResult = executor.submit(new QueryCachesMBeanCallable(
QueryCachesMBeanCallable.QC_OBJNAME,
QueryCachesMBeanCallable.QC_QM));
try {
assertTrue(execResult.get());
} catch (Throwable t) {
fail("QueryCache verification failed: " + t);
}
closeEMF(oemf);
}
/**
* Verifies prepared query cache metrics are available through simple instrumentation.
*/
public void testPreparedQueryCacheInstrument() {
OpenJPAEntityManagerFactorySPI oemf = createNamedEMF("openjpa-integration-jmx-qsc");
// Verify an EMF was created with the supplied instrumentation
assertNotNull(oemf);
// Verify an instrumentation manager is available
InstrumentationManager mgr = oemf.getConfiguration().getInstrumentationManagerInstance();
assertNotNull(mgr);
// Get the in-band data cache instrument
Set<InstrumentationProvider> providers = mgr.getProviders();
assertNotNull(providers);
assertEquals(1, providers.size());
InstrumentationProvider provider = providers.iterator().next();
assertEquals(provider.getClass(), JMXProvider.class);
Instrument inst = provider.getInstrumentByName("QuerySQLCache");
assertNotNull(inst);
assertTrue(inst instanceof PreparedQueryCacheInstrument);
PreparedQueryCacheInstrument qci = (PreparedQueryCacheInstrument)inst;
assertEquals(0,qci.getExecutionCount());
assertEquals(0,qci.getTotalExecutionCount());
assertEquals(0,qci.getHitCount());
assertEquals(0,qci.getTotalHitCount());
OpenJPAEntityManagerSPI oem = oemf.createEntityManager();
CachedEntity ce = new CachedEntity();
int id = new Random().nextInt();
ce.setId(id);
CachedEntity ce2 = new CachedEntity();
id = new Random().nextInt();
ce2.setId(id);
oem.getTransaction().begin();
oem.persist(ce);
oem.persist(ce2);
oem.getTransaction().commit();
Query q = oem.createQuery("SELECT ce FROM CachedEntity ce");
List<?> result = q.getResultList();
assertNotNull(result);
assertTrue(result.size() > 1);
oem.clear();
result = q.getResultList();
assertTrue(qci.getExecutionCount() > 0);
assertTrue(qci.getTotalExecutionCount() > 0);
assertTrue(qci.getHitCount() > 0);
assertTrue(qci.getTotalHitCount() > 0);
// Thread out to do out-of-band MBean-based validation. This could
// have been done on the same thread, but threading out makes for a
// more realistic test.
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Boolean> execResult = executor.submit(new QueryCachesMBeanCallable(
QueryCachesMBeanCallable.QSC_OBJNAME,
QueryCachesMBeanCallable.QSC_QM));
try {
assertTrue(execResult.get());
} catch (Throwable t) {
fail("QueryCache verification failed: " + t);
}
closeEMF(oemf);
}
public class DCMBeanCallable implements Callable<Boolean> {
public Boolean call() {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
assertNotNull(mbs);
ObjectName objname = null;
@ -144,7 +288,88 @@ public class TestJMXPlatformMBeans extends AbstractPersistenceTestCase {
assertEquals(0, clsWriteCount);
} catch (Exception e) {
fail("Unexpected exception: " + e);
return false;
}
return true;
}
}
public class QueryCachesMBeanCallable implements Callable<Boolean> {
public static final String QC_OBJNAME = "org.apache.openjpa:type=QueryCache,cfgid=openjpa-integration-jmx,*";
public static final String QSC_OBJNAME = "org.apache.openjpa:type=QuerySQLCache,cfgid=openjpa-integration-jmx-qsc,*";
public static final String QC_QM = "queryKeys";
public static final String QSC_QM = "queries";
private String _objNameStr;
private String _queryMethod;
public QueryCachesMBeanCallable(String objName, String queryMethod) {
setObjName(objName);
setQueryMethod(queryMethod);
}
@SuppressWarnings("unchecked")
public Boolean call() {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
assertNotNull(mbs);
ObjectName objname = null;
try {
// Query for the QueryCache bean
objname = new ObjectName(getObjName());
Set<ObjectName> ons = mbs.queryNames(objname, null);
assertEquals(1, ons.size());
ObjectName on = ons.iterator().next();
// Assert query cache attributes can be accessed and are being updated through the MBean
long hitCount = (Long)mbs.getAttribute(on, "HitCount");
long execCount = (Long)mbs.getAttribute(on, "ExecutionCount");
assertTrue(hitCount > 0);
assertTrue(execCount > 0);
// Assert data cache MBean methods can be invoked
Set<String> keys = (Set<String>)mbs.invoke(on, getQueryMethod(), null, null);
assertNotNull(keys);
assertTrue(keys.size() > 0);
String[] sigs = new String[] { "java.lang.String" };
for (String key : keys) {
Object[] parms = new Object[] { key };
long queryHitCount = (Long)mbs.invoke(on, "getHitCount", parms, sigs);
long queryReadCount = (Long)mbs.invoke(on, "getExecutionCount", parms, sigs);
assertTrue(queryHitCount > 0);
assertTrue(queryReadCount > 0);
}
// Invoke the reset method and recollect stats
mbs.invoke(on, "reset", null, null);
hitCount = (Long)mbs.getAttribute(on, "HitCount");
execCount = (Long)mbs.getAttribute(on, "ExecutionCount");
assertEquals(0, hitCount);
assertEquals(0, execCount);
keys = (Set<String>)mbs.invoke(on, getQueryMethod(), null, null);
assertNotNull(keys);
assertEquals(0, keys.size());
} catch (Exception e) {
fail("Unexpected exception: " + e);
return false;
}
return true;
}
public void setObjName(String objNameStr) {
this._objNameStr = objNameStr;
}
public String getObjName() {
return _objNameStr;
}
public void setQueryMethod(String _queryMethod) {
this._queryMethod = _queryMethod;
}
public String getQueryMethod() {
return _queryMethod;
}
}
}

View File

@ -24,11 +24,23 @@
<description>PU for JMX Platform MBean Testing</description>
<class>org.apache.openjpa.integration.jmx.CachedEntity</class>
<properties>
<property name="openjpa.Instrumentation" value="jmx(Instrument=DataCache)"/>
<property name="openjpa.Instrumentation" value="jmx(Instrument='DataCache,QueryCache')"/>
<property name="openjpa.DataCache" value="true(EnableStatistics=true)"/>
<property name="openjpa.QueryCache" value="true(EnableStatistics=true)"/>
<property name="openjpa.RemoteCommitProvider" value="sjvm"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="openjpa.DynamicEnhancementAgent" value="false"/>
</properties>
</persistence-unit>
<persistence-unit name="openjpa-integration-jmx-qsc">
<description>PU for JMX Platform MBean Testing with PreparedQueryCache/QuerySQLCache</description>
<class>org.apache.openjpa.integration.jmx.CachedEntity</class>
<properties>
<property name="openjpa.Instrumentation" value="jmx(Instrument=QuerySQLCache)"/>
<property name="openjpa.jdbc.QuerySQLCache" value="true(EnableStatistics=true)"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="openjpa.DynamicEnhancementAgent" value="false"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -18,9 +18,11 @@
*/
package org.apache.openjpa.datacache;
import java.io.PrintStream;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -32,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.event.RemoteCommitEvent;
import org.apache.openjpa.event.RemoteCommitListener;
import org.apache.openjpa.kernel.QueryStatistics;
import org.apache.openjpa.lib.conf.Configurable;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.log.Log;
@ -39,6 +42,7 @@ import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.concurrent.AbstractConcurrentEventManager;
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashSet;
import org.apache.openjpa.lib.util.concurrent.SizedConcurrentHashMap;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.util.Id;
@ -77,7 +81,21 @@ public abstract class AbstractQueryCache
// default evict policy
public EvictPolicy evictPolicy = EvictPolicy.DEFAULT;
private QueryStatistics<QueryKey> _stats;
private boolean _statsEnabled = false;
public void setEnableStatistics(boolean enable){
_statsEnabled = enable;
}
public boolean getEnableStatistics(){
return _statsEnabled;
}
public QueryStatistics<QueryKey> getStatistics() {
return _stats;
}
public void initialize(DataCacheManager manager) {
if (evictPolicy == EvictPolicy.TIMESTAMP) {
entityTimestampMap = new ConcurrentHashMap<String,Long>();
@ -137,6 +155,9 @@ public abstract class AbstractQueryCache
}
public QueryResult get(QueryKey key) {
if (_statsEnabled) {
_stats.recordExecution(key);
}
QueryResult o = getInternal(key);
if (o != null && o.isTimedOut()) {
o = null;
@ -151,6 +172,9 @@ public abstract class AbstractQueryCache
else
log.trace(s_loc.get("cache-hit", key));
}
if (_statsEnabled && o != null) {
((Default<QueryKey>)_stats).recordHit(key);
}
return o;
}
@ -200,6 +224,9 @@ public abstract class AbstractQueryCache
clearInternal();
if (log.isTraceEnabled())
log.trace(s_loc.get("cache-clear", "<query-cache>"));
if (_statsEnabled) {
_stats.clear();
}
}
public void close() {
@ -339,6 +366,8 @@ public abstract class AbstractQueryCache
}
public void endConfiguration() {
_stats = _statsEnabled ? new Default<QueryKey>() :
new QueryStatistics.None<QueryKey>();
}
// ---------- AbstractEventManager implementation ----------
@ -418,4 +447,159 @@ public abstract class AbstractQueryCache
public String getName() {
return _name;
}
/**
* A default implementation of query statistics for the Query result cache.
*
* Maintains statistics for only a fixed number of queries.
* Statistical counts are approximate and not exact (to keep thread synchorization overhead low).
*
*/
public static class Default<T> implements QueryStatistics<T> {
private static final long serialVersionUID = -7889619105916307055L;
private static final int FIXED_SIZE = 1000;
private static final float LOAD_FACTOR = 0.75f;
private static final int CONCURRENCY = 16;
private static final int ARRAY_SIZE = 2;
private static final int READ = 0;
private static final int HIT = 1;
private long[] astat = new long[ARRAY_SIZE];
private long[] stat = new long[ARRAY_SIZE];
private Map<T, long[]> stats = new SizedConcurrentHashMap(FIXED_SIZE, LOAD_FACTOR, CONCURRENCY);
private Map<T, long[]> astats = new SizedConcurrentHashMap(FIXED_SIZE, LOAD_FACTOR, CONCURRENCY);
private Date start = new Date();
private Date since = start;
public Set<T> keys() {
return stats.keySet();
}
public long getExecutionCount() {
return stat[READ];
}
public long getTotalExecutionCount() {
return astat[READ];
}
public long getExecutionCount(T query) {
return getCount(stats, query, READ);
}
public long getTotalExecutionCount(T query) {
return getCount(astats, query, READ);
}
public long getHitCount() {
return stat[HIT];
}
public long getTotalHitCount() {
return astat[HIT];
}
public long getHitCount(T query) {
return getCount(stats, query, HIT);
}
public long getTotalHitCount(T query) {
return getCount(astats, query, HIT);
}
private long getCount(Map<T, long[]> target, T query, int i) {
long[] row = target.get(query);
return (row == null) ? 0 : row[i];
}
public Date since() {
return since;
}
public Date start() {
return start;
}
public synchronized void reset() {
stat = new long[ARRAY_SIZE];
stats.clear();
since = new Date();
}
@SuppressWarnings("unchecked")
public synchronized void clear() {
astat = new long[ARRAY_SIZE];
stat = new long[ARRAY_SIZE];
stats = new SizedConcurrentHashMap(FIXED_SIZE, LOAD_FACTOR, CONCURRENCY);
astats = new SizedConcurrentHashMap(FIXED_SIZE, LOAD_FACTOR, CONCURRENCY);
start = new Date();
since = start;
}
private void addSample(T query, int index) {
stat[index]++;
astat[index]++;
addSample(stats, query, index);
addSample(astats, query, index);
}
private void addSample(Map<T, long[]> target, T query, int i) {
long[] row = target.get(query);
if (row == null) {
row = new long[ARRAY_SIZE];
}
row[i]++;
target.put(query, row);
}
public void recordExecution(T query) {
if (query == null)
return;
addSample(query, READ);
}
public void recordHit(T query) {
addSample(query, HIT);
}
public void dump(PrintStream out) {
String header = "Query Statistics starting from " + start;
out.print(header);
if (since == start) {
out.println();
out.println("Total Query Execution: " + toString(astat));
out.println("\tTotal \t\tQuery");
} else {
out.println(" last reset on " + since);
out.println("Total Query Execution since start " +
toString(astat) + " since reset " + toString(stat));
out.println("\tSince Start \tSince Reset \t\tQuery");
}
int i = 0;
for (T key : stats.keySet()) {
i++;
long[] arow = astats.get(key);
if (since == start) {
out.println(i + ". \t" + toString(arow) + " \t" + key);
} else {
long[] row = stats.get(key);
out.println(i + ". \t" + toString(arow) + " \t" + toString(row) + " \t\t" + key);
}
}
}
long pct(long per, long cent) {
if (cent <= 0)
return 0;
return (100*per)/cent;
}
String toString(long[] row) {
return row[READ] + ":" + row[HIT] + "(" + pct(row[HIT], row[READ]) + "%)";
}
}
}

View File

@ -19,6 +19,7 @@
package org.apache.openjpa.datacache;
import org.apache.commons.lang.ObjectUtils;
import org.apache.openjpa.kernel.QueryStatistics;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
/**
@ -216,4 +217,14 @@ public class DelegatingQueryCache
throw translate(re);
}
}
public QueryStatistics<QueryKey> getStatistics() {
if (_cache == null)
return null;
try {
return _cache.getStatistics();
} catch (RuntimeException re) {
throw translate(re);
}
}
}

View File

@ -20,6 +20,7 @@ package org.apache.openjpa.datacache;
import java.util.Map;
import org.apache.openjpa.kernel.QueryStatistics;
import org.apache.openjpa.lib.util.Closeable;
/**
@ -135,4 +136,11 @@ public interface QueryCache
* Free the resources used by this cache.
*/
public void close ();
/**
* Gets the simple statistics for query results.
* If the statistics gathering is disabled, an empty statistics is returned.
* @since 2.1.0
*/
public QueryStatistics<QueryKey> getStatistics();
}

View File

@ -19,6 +19,7 @@
package org.apache.openjpa.instrumentation;
import java.util.Date;
import java.util.Set;
import org.apache.openjpa.kernel.PreparedQueryCache;
import org.apache.openjpa.kernel.QueryStatistics;
@ -141,6 +142,13 @@ public abstract class AbstractPreparedQueryCacheInstrument extends AbstractInstr
return null;
}
public Set<String> queries() {
QueryStatistics<String> stats = getStatistics();
if (stats != null)
return stats.keys();
return null;
}
public InstrumentationLevel getLevel() {
return InstrumentationLevel.FACTORY;
}

View File

@ -19,9 +19,12 @@
package org.apache.openjpa.instrumentation;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.apache.openjpa.datacache.CacheStatistics;
import org.apache.openjpa.datacache.QueryCache;
import org.apache.openjpa.datacache.QueryKey;
import org.apache.openjpa.kernel.QueryStatistics;
import org.apache.openjpa.lib.instrumentation.AbstractInstrument;
import org.apache.openjpa.lib.instrumentation.InstrumentationLevel;
@ -46,94 +49,143 @@ public abstract class AbstractQueryCacheInstrument extends AbstractInstrument
_qc = qc;
}
// TODO : Cache stats must be added to query cache. They will likely be
// tracked by a QueryStatistics type when that takes place.
private CacheStatistics getStatistics() {
if (_qc == null)
return null;
return null; // _qc.getStatistics();
}
public long getHitCount() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.getHitCount();
return NO_STATS;
}
public long getReadCount() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.getReadCount();
return NO_STATS;
}
public long getTotalHitCount() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.getTotalHitCount();
return NO_STATS;
}
public long getTotalReadCount() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.getTotalReadCount();
return NO_STATS;
}
public long getTotalWriteCount() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.getTotalWriteCount();
return NO_STATS;
}
public long getWriteCount() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.getWriteCount();
return NO_STATS;
}
public void reset() {
CacheStatistics stats = getStatistics();
if (stats != null)
stats.reset();
}
public Date sinceDate() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.since();
return null;
}
public Date startDate() {
CacheStatistics stats = getStatistics();
if (stats != null)
return stats.start();
return null;
}
public String getConfigId() {
return _configId;
}
public void setConfigId(String cid) {
_configId = cid;
}
public String getContextRef() {
return _configRef;
}
public void setContextRef(String cref) {
_configRef = cref;
}
public String getConfigId() {
return _configId;
}
public String getContextRef() {
return _configRef;
}
public void setPreparedQueryCache(QueryCache qc) {
_qc = qc;
}
private QueryStatistics<QueryKey> getStatistics() {
if (_qc == null)
return null;
return _qc.getStatistics();
}
public long getExecutionCount() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
return stats.getExecutionCount();
return NO_STATS;
}
public long getExecutionCount(String queryKey) {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null) {
QueryKey qk = findKey(queryKey);
return stats.getExecutionCount(qk);
}
return NO_STATS;
}
public long getTotalExecutionCount() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
return stats.getTotalExecutionCount();
return NO_STATS;
}
public long getTotalExecutionCount(String queryKey) {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null) {
QueryKey qk = findKey(queryKey);
return stats.getTotalExecutionCount(qk);
}
return NO_STATS;
}
public long getHitCount() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
return stats.getHitCount();
return NO_STATS;
}
public long getHitCount(String queryKey) {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null) {
QueryKey qk = findKey(queryKey);
return stats.getHitCount(qk);
}
return NO_STATS;
}
public long getTotalHitCount() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
return stats.getTotalHitCount();
return NO_STATS;
}
public long getTotalHitCount(String queryKey) {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null) {
QueryKey qk = findKey(queryKey);
return stats.getTotalHitCount(qk);
}
return NO_STATS;
}
public void reset() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
stats.reset();
}
public Date sinceDate() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
return stats.since();
return null;
}
public Date startDate() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null)
return stats.start();
return null;
}
/**
* Returns all query keys currently tracked in the cache.
* @return
*/
public Set<String> queryKeys() {
QueryStatistics<QueryKey> stats = getStatistics();
if (stats != null) {
Set<String> keys = new HashSet<String>();
for (QueryKey qk : stats.keys()) {
keys.add(qk.toString());
}
return keys;
}
return null;
}
private QueryKey findKey(String key) {
QueryStatistics<QueryKey> stats = getStatistics();
for (QueryKey qk : stats.keys()) {
if (qk.toString().equals(key.toString())) {
return qk;
}
}
return null;
}
public InstrumentationLevel getLevel() {
return InstrumentationLevel.FACTORY;
}
}

View File

@ -19,6 +19,7 @@
package org.apache.openjpa.instrumentation;
import java.util.Date;
import java.util.Set;
public interface PreparedQueryCacheInstrument {
@ -63,18 +64,7 @@ public interface PreparedQueryCacheInstrument {
* Returns number of total read requests that has been found since start.
*/
public long getTotalHitCount(String query);
/**
* Returns the config id for the configuration attached to this cache
*/
public String getConfigId();
/**
* Returns the context unique id for the configuration attached to this
* cache
*/
public String getContextRef();
/**
* Resets cache statistics
*/
@ -89,4 +79,10 @@ public interface PreparedQueryCacheInstrument {
* Returns date cache statistics collection started.
*/
public Date startDate();
/**
* Returns all queries currently tracked in the cache.
* @return
*/
public Set<String> queries();
}

View File

@ -19,12 +19,33 @@
package org.apache.openjpa.instrumentation;
import java.util.Date;
import java.util.Set;
/**
* Interface for providing instrumented data cache metrics and operations.
*/
public interface QueryCacheInstrument {
/**
* Returns number of total exec requests since start.
*/
public long getTotalExecutionCount();
/**
* Returns number of total exec requests since start.
*/
public long getTotalExecutionCount(String queryKey);
/**
* Returns number of total execution requests since last reset
*/
public long getExecutionCount();
/**
* Returns number of total execution requests since last reset
*/
public long getExecutionCount(String queryKey);
/**
* Returns number of total read requests that have been found in cache since
* last reset.
@ -32,19 +53,10 @@ public interface QueryCacheInstrument {
public long getHitCount();
/**
* Returns number of total read requests since last reset
* Returns number of total read requests that have been found in cache since
* last reset.
*/
public long getReadCount();
/**
* Returns number of total write requests since last reset.
*/
public long getWriteCount();
/**
* Returns number of total read requests since start.
*/
public long getTotalReadCount();
public long getHitCount(String queryKey);
/**
* Returns number of total read requests that has been found since start.
@ -52,21 +64,10 @@ public interface QueryCacheInstrument {
public long getTotalHitCount();
/**
* Returns number of total write requests for the given class since start.
* Returns number of total read requests that has been found since start.
*/
public long getTotalWriteCount();
/**
* Returns the config id for the configuration attached to this cache
*/
public String getConfigId();
/**
* Returns the system unique id for the configuration attached to this
* cache
*/
public String getContextRef();
public long getTotalHitCount(String queryKey);
/**
* Resets cache statistics
*/
@ -81,4 +82,10 @@ public interface QueryCacheInstrument {
* Returns date cache statistics collection started.
*/
public Date startDate();
/**
* Returns all query keys currently in the cache.
* @return
*/
public Set<String> queryKeys();
}

View File

@ -20,9 +20,11 @@ package org.apache.openjpa.instrumentation.jmx;
import java.lang.management.ManagementFactory;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import org.apache.openjpa.lib.instrumentation.AbstractInstrumentationProvider;
@ -38,12 +40,12 @@ public class JMXProvider
// Aliases for built-in JMX Instrumentation
public static final String[] JMX_INSTRUMENT_ALIASES = {
"DataCache", "org.apache.openjpa.instrumentation.jmx.DataCacheJMXInstrument",
"QueryCache", "org.apache.openjpa.insrumentation.jmx.QueryCacheJMXInstrument",
"QuerySQLCache", "org.apache.openjpa.insrumentation.jmx.PreparedQueryCacheJMXInstrument"
"QueryCache", "org.apache.openjpa.instrumentation.jmx.QueryCacheJMXInstrument",
"QuerySQLCache", "org.apache.openjpa.instrumentation.jmx.PreparedQueryCacheJMXInstrument"
};
/**
* The standard mbean package for OpenJPA
* The MBean domain for OpenJPA
*/
public static final String MBEAN_DOMAIN = "org.apache.openjpa";
@ -80,14 +82,33 @@ public class JMXProvider
if (mbs == null) {
throw new UserException("jmx-server-failed-creation");
}
setStarted(true);
} catch (Throwable t) {
throw new UserException("jmx-server-unavailable",t);
}
}
/**
* Stops all instruments registered with this provider and releases the
* reference to the Platform MBean server instance.
*/
@Override
public void stop() {
// no-op with the built in MBean server
if (isStarted()) {
Set<Instrument> instruments = getInstruments();
if (instruments != null && instruments.size() > 0) {
for (Instrument inst : instruments) {
stopInstrument(inst);
}
}
// The MBean server factory does appear to ref count properly so the
// platform server cannot released from the factory once it is acquired.
// Multiple attempts to capture and release the server will result in a
// runtime exception.
// MBeanServerFactory.releaseMBeanServer(getMBeanServer());
// _mbs = null;
setStarted(false);
}
}
/**
@ -125,6 +146,7 @@ public class JMXProvider
public void startInstrument(Instrument instrument) {
if (!instrument.isStarted()) {
registerMBean((JMXInstrument)instrument);
instrument.setStarted(true);
}
}
@ -135,6 +157,7 @@ public class JMXProvider
if (instrument.isStarted() || force) {
try {
getMBeanServer().unregisterMBean(((JMXInstrument)instrument).getObjectName());
instrument.setStarted(false);
} catch (Exception e) {
// If force, swallow the exception since the bean may not even
// be registered.

View File

@ -86,6 +86,12 @@ public interface Instrument {
*/
public boolean isStarted();
/**
* Sets whether the instrument is an available state.
* @param started
*/
public void setStarted(boolean started);
/**
* Starts the instrument. Typically this will be performed through the provider,
* but in some cases an instrument will have its own specialized startup.