mirror of https://github.com/apache/openjpa.git
OPENJPA-1801: Refactor cache statistics.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1004818 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a67852d2c0
commit
54bef663e7
|
@ -34,12 +34,16 @@ import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||||
import org.apache.openjpa.event.RemoteCommitEvent;
|
import org.apache.openjpa.event.RemoteCommitEvent;
|
||||||
import org.apache.openjpa.event.RemoteCommitListener;
|
import org.apache.openjpa.event.RemoteCommitListener;
|
||||||
|
import org.apache.openjpa.kernel.OpenJPAStateManager;
|
||||||
import org.apache.openjpa.lib.conf.Configurable;
|
import org.apache.openjpa.lib.conf.Configurable;
|
||||||
import org.apache.openjpa.lib.conf.Configuration;
|
import org.apache.openjpa.lib.conf.Configuration;
|
||||||
import org.apache.openjpa.lib.log.Log;
|
import org.apache.openjpa.lib.log.Log;
|
||||||
import org.apache.openjpa.lib.util.Localizer;
|
import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.lib.util.concurrent.AbstractConcurrentEventManager;
|
import org.apache.openjpa.lib.util.concurrent.AbstractConcurrentEventManager;
|
||||||
import org.apache.openjpa.util.GeneralException;
|
import org.apache.openjpa.util.GeneralException;
|
||||||
|
import org.apache.openjpa.util.InternalException;
|
||||||
|
import org.apache.openjpa.util.OpenJPAId;
|
||||||
|
|
||||||
import serp.util.Strings;
|
import serp.util.Strings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +58,7 @@ import serp.util.Strings;
|
||||||
public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
implements DataCache, Configurable {
|
implements DataCache, Configurable {
|
||||||
|
|
||||||
protected CacheStatistics.Default stats = new CacheStatistics.Default();
|
protected CacheStatisticsSPI _stats = new CacheStatisticsImpl();
|
||||||
|
|
||||||
private static final BitSet EMPTY_BITSET = new BitSet(0);
|
private static final BitSet EMPTY_BITSET = new BitSet(0);
|
||||||
|
|
||||||
|
@ -86,11 +90,11 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
}
|
}
|
||||||
public void setEnableStatistics(boolean enable){
|
public void setEnableStatistics(boolean enable){
|
||||||
if(enable == true){
|
if(enable == true){
|
||||||
stats.enable();
|
_stats.enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void getEnableStatistics(){
|
public void getEnableStatistics(){
|
||||||
stats.isEnabled();
|
_stats.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEvictionSchedule() {
|
public String getEvictionSchedule() {
|
||||||
|
@ -157,9 +161,6 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
|
|
||||||
public boolean contains(Object key) {
|
public boolean contains(Object key) {
|
||||||
DataCachePCData o = getInternal(key);
|
DataCachePCData o = getInternal(key);
|
||||||
if (stats.isEnabled()) {
|
|
||||||
stats.newGet(o == null ? null : o.getType(), o != null);
|
|
||||||
}
|
|
||||||
if (o != null && o.isTimedOut()) {
|
if (o != null && o.isTimedOut()) {
|
||||||
o = null;
|
o = null;
|
||||||
removeInternal(key);
|
removeInternal(key);
|
||||||
|
@ -195,9 +196,7 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
else
|
else
|
||||||
log.trace(s_loc.get("cache-hit", key));
|
log.trace(s_loc.get("cache-hit", key));
|
||||||
}
|
}
|
||||||
if (stats.isEnabled()) {
|
|
||||||
stats.newGet((o == null) ? null : o.getType(), o != null);
|
|
||||||
}
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,9 +212,6 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataCachePCData put(DataCachePCData data) {
|
public DataCachePCData put(DataCachePCData data) {
|
||||||
if (stats.isEnabled()) {
|
|
||||||
stats.newPut(data.getType());
|
|
||||||
}
|
|
||||||
DataCachePCData o = putInternal(data.getId(), data);
|
DataCachePCData o = putInternal(data.getId(), data);
|
||||||
if (log.isTraceEnabled())
|
if (log.isTraceEnabled())
|
||||||
log.trace(s_loc.get("cache-put", data.getId()));
|
log.trace(s_loc.get("cache-put", data.getId()));
|
||||||
|
@ -224,18 +220,12 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
|
|
||||||
public void update(DataCachePCData data) {
|
public void update(DataCachePCData data) {
|
||||||
if (recacheUpdates()) {
|
if (recacheUpdates()) {
|
||||||
if (stats.isEnabled()) {
|
|
||||||
stats.newPut(data.getType());
|
|
||||||
}
|
|
||||||
putInternal(data.getId(), data);
|
putInternal(data.getId(), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataCachePCData remove(Object key) {
|
public DataCachePCData remove(Object key) {
|
||||||
DataCachePCData o = removeInternal(key);
|
DataCachePCData o = removeInternal(key);
|
||||||
if (stats.isEnabled()) {
|
|
||||||
stats.newEvict(o == null ? null : o.getType());
|
|
||||||
}
|
|
||||||
if (o != null && o.isTimedOut())
|
if (o != null && o.isTimedOut())
|
||||||
o = null;
|
o = null;
|
||||||
if (log.isTraceEnabled()) {
|
if (log.isTraceEnabled()) {
|
||||||
|
@ -418,9 +408,6 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
*/
|
*/
|
||||||
protected void putAllInternal(Collection<DataCachePCData> pcs) {
|
protected void putAllInternal(Collection<DataCachePCData> pcs) {
|
||||||
for (DataCachePCData pc : pcs) {
|
for (DataCachePCData pc : pcs) {
|
||||||
if (stats.isEnabled()) {
|
|
||||||
stats.newPut(pc.getType());
|
|
||||||
}
|
|
||||||
putInternal(pc.getId(), pc);
|
putInternal(pc.getId(), pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,8 +480,8 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CacheStatistics getStatistics() {
|
public CacheStatistics getStatistics() {
|
||||||
return stats;
|
return _stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Configurable implementation ----------
|
// ---------- Configurable implementation ----------
|
||||||
|
@ -550,4 +537,8 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||||
_excludedTypes =
|
_excludedTypes =
|
||||||
StringUtils.isEmpty(types) ? null : new HashSet<String>(Arrays.asList(Strings.split(types, ";", 0)));
|
StringUtils.isEmpty(types) ? null : new HashSet<String>(Arrays.asList(Strings.split(types, ";", 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataCache selectCache(OpenJPAStateManager sm) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.openjpa.util.OpenJPAId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts number of read/write requests and hit ratio for a cache in total and
|
* Counts number of read/write requests and hit ratio for a cache in total and
|
||||||
* per-class basis.
|
* per-class basis.
|
||||||
|
@ -35,11 +37,9 @@ import java.util.Set;
|
||||||
* is registered under generic <code>java.lang.Object</code>.
|
* is registered under generic <code>java.lang.Object</code>.
|
||||||
*
|
*
|
||||||
* @since 1.3.0
|
* @since 1.3.0
|
||||||
*
|
|
||||||
* @author Pinaki Poddar
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface CacheStatistics extends Serializable {
|
public interface CacheStatistics extends Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets number of total read requests since last reset.
|
* Gets number of total read requests since last reset.
|
||||||
*/
|
*/
|
||||||
|
@ -104,26 +104,6 @@ public interface CacheStatistics extends Serializable {
|
||||||
*/
|
*/
|
||||||
public long getTotalWriteCount(Class<?> c);
|
public long getTotalWriteCount(Class<?> c);
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets number of total evictions since last reset.
|
|
||||||
*/
|
|
||||||
public long getEvictionCount();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets number of total evictions for the given class since last reset.
|
|
||||||
*/
|
|
||||||
public long getEvictionCount(Class<?> c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets number of total evictions in cache since start.
|
|
||||||
*/
|
|
||||||
public long getTotalEvictionCount();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets number of total evictions for the given class since start.
|
|
||||||
*/
|
|
||||||
public long getTotalEvictionCount(Class<?> c);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the time of last reset.
|
* Gets the time of last reset.
|
||||||
*/
|
*/
|
||||||
|
@ -150,153 +130,4 @@ public interface CacheStatistics extends Serializable {
|
||||||
*/
|
*/
|
||||||
public Set<Class<?>> classNames();
|
public Set<Class<?>> classNames();
|
||||||
|
|
||||||
/**
|
|
||||||
* A default implementation.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static class Default implements CacheStatistics {
|
|
||||||
private static final int ARRAY_SIZE = 4;
|
|
||||||
private long[] astat = new long[ARRAY_SIZE];
|
|
||||||
private long[] stat = new long[ARRAY_SIZE];
|
|
||||||
private Map<Class<?>, long[]> stats = new HashMap<Class<?>, long[]>();
|
|
||||||
private Map<Class<?>, long[]> astats = new HashMap<Class<?>, long[]>();
|
|
||||||
private Date start = new Date();
|
|
||||||
private Date since = new Date();
|
|
||||||
private boolean enabled = false;
|
|
||||||
|
|
||||||
private static final int READ = 0;
|
|
||||||
private static final int HIT = 1;
|
|
||||||
private static final int WRITE = 2;
|
|
||||||
private static final int EVICT = 3;
|
|
||||||
|
|
||||||
public long getReadCount() {
|
|
||||||
return stat[READ];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getHitCount() {
|
|
||||||
return stat[HIT];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getWriteCount() {
|
|
||||||
return stat[WRITE];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEvictionCount() {
|
|
||||||
return stat[EVICT];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalReadCount() {
|
|
||||||
return astat[READ];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalHitCount() {
|
|
||||||
return astat[HIT];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalWriteCount() {
|
|
||||||
return astat[WRITE];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalEvictionCount() {
|
|
||||||
return astat[EVICT];
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getReadCount(Class<?> c) {
|
|
||||||
return getCount(stats, c, READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getHitCount(Class<?> c) {
|
|
||||||
return getCount(stats, c, HIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getWriteCount(Class<?> c) {
|
|
||||||
return getCount(stats, c, WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEvictionCount(Class<?> c) {
|
|
||||||
return getCount(stats, c, EVICT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalReadCount(Class<?> c) {
|
|
||||||
return getCount(astats, c, READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalHitCount(Class<?> c) {
|
|
||||||
return getCount(astats, c, HIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalWriteCount(Class<?> c) {
|
|
||||||
return getCount(astats, c, WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalEvictionCount(Class<?> c) {
|
|
||||||
return getCount(astats, c, EVICT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getCount(Map<Class<?>, long[]> target, Class<?> c, int index) {
|
|
||||||
long[] row = target.get(c);
|
|
||||||
return (row == null) ? 0 : row[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date since() {
|
|
||||||
return since;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date start() {
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
stat = new long[ARRAY_SIZE];
|
|
||||||
stats.clear();
|
|
||||||
since = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
void enable(){
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
void newGet(Class<?> cls, boolean hit) {
|
|
||||||
cls = (cls == null) ? Object.class : cls;
|
|
||||||
addSample(cls, READ);
|
|
||||||
if (hit) {
|
|
||||||
addSample(cls, HIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void newPut(Class<?> cls) {
|
|
||||||
cls = (cls == null) ? Object.class : cls;
|
|
||||||
addSample(cls, WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void newEvict(Class<?> cls) {
|
|
||||||
cls = (cls == null) ? Object.class : cls;
|
|
||||||
addSample(cls, EVICT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSample(Class<?> c, int index) {
|
|
||||||
stat[index]++;
|
|
||||||
astat[index]++;
|
|
||||||
addSample(stats, c, index);
|
|
||||||
addSample(astats, c, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSample(Map<Class<?>, long[]> target, Class<?> c, int index) {
|
|
||||||
long[] row = target.get(c);
|
|
||||||
if (row == null) {
|
|
||||||
row = new long[ARRAY_SIZE];
|
|
||||||
}
|
|
||||||
row[index]++;
|
|
||||||
target.put(c, row);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Class<?>> classNames() {
|
|
||||||
return astats.keySet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.datacache;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.openjpa.util.OpenJPAId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default CacheStatistics(SPI) implementation.
|
||||||
|
*/
|
||||||
|
public class CacheStatisticsImpl implements CacheStatisticsSPI {
|
||||||
|
private static final long serialVersionUID = 9014495759588003166L;
|
||||||
|
private static final int ARRAY_SIZE = 3;
|
||||||
|
private long[] astat = new long[ARRAY_SIZE];
|
||||||
|
private long[] stat = new long[ARRAY_SIZE];
|
||||||
|
private Map<Class<?>, long[]> stats = new HashMap<Class<?>, long[]>();
|
||||||
|
private Map<Class<?>, long[]> astats = new HashMap<Class<?>, long[]>();
|
||||||
|
private Date start = new Date();
|
||||||
|
private Date since = new Date();
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
private static final int READ = 0;
|
||||||
|
private static final int HIT = 1;
|
||||||
|
private static final int WRITE = 2;
|
||||||
|
|
||||||
|
public long getReadCount() {
|
||||||
|
return stat[READ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getHitCount() {
|
||||||
|
return stat[HIT];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWriteCount() {
|
||||||
|
return stat[WRITE];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalReadCount() {
|
||||||
|
return astat[READ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalHitCount() {
|
||||||
|
return astat[HIT];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalWriteCount() {
|
||||||
|
return astat[WRITE];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getReadCount(Class<?> c) {
|
||||||
|
return getCount(stats, c, READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getHitCount(Class<?> c) {
|
||||||
|
return getCount(stats, c, HIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWriteCount(Class<?> c) {
|
||||||
|
return getCount(stats, c, WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalReadCount(Class<?> c) {
|
||||||
|
return getCount(astats, c, READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalHitCount(Class<?> c) {
|
||||||
|
return getCount(astats, c, HIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalWriteCount(Class<?> c) {
|
||||||
|
return getCount(astats, c, WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date since() {
|
||||||
|
return since;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date start() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
stat = new long[ARRAY_SIZE];
|
||||||
|
stats.clear();
|
||||||
|
since = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Class<?>> classNames() {
|
||||||
|
return astats.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI implementation
|
||||||
|
*/
|
||||||
|
public void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newGet(Class<?> cls, boolean hit) {
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cls == null) {
|
||||||
|
throw new RuntimeException("Snap! newGet will null cls Name");
|
||||||
|
}
|
||||||
|
cls = (cls == null) ? Object.class : cls;
|
||||||
|
addSample(cls, READ);
|
||||||
|
if (hit) {
|
||||||
|
addSample(cls, HIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newGet(Object oid, boolean hit) {
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (oid instanceof OpenJPAId) {
|
||||||
|
newGet(((OpenJPAId) oid).getType(), hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newPut(Class<?> cls) {
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cls = (cls == null) ? Object.class : cls;
|
||||||
|
addSample(cls, WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newPut(Object oid) {
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (oid instanceof OpenJPAId) {
|
||||||
|
newPut(((OpenJPAId) oid).getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private worker methods.
|
||||||
|
*/
|
||||||
|
private void addSample(Class<?> c, int index) {
|
||||||
|
stat[index]++;
|
||||||
|
astat[index]++;
|
||||||
|
addSample(stats, c, index);
|
||||||
|
addSample(astats, c, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSample(Map<Class<?>, long[]> target, Class<?> c, int index) {
|
||||||
|
long[] row = target.get(c);
|
||||||
|
if (row == null) {
|
||||||
|
row = new long[ARRAY_SIZE];
|
||||||
|
}
|
||||||
|
row[index]++;
|
||||||
|
target.put(c, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getCount(Map<Class<?>, long[]> target, Class<?> c, int index) {
|
||||||
|
long[] row = target.get(c);
|
||||||
|
return (row == null) ? 0 : row[index];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.datacache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The provider extensions to the CacheStatistics interface.
|
||||||
|
*/
|
||||||
|
public interface CacheStatisticsSPI extends CacheStatistics {
|
||||||
|
/**
|
||||||
|
* Record a new cache get.
|
||||||
|
*
|
||||||
|
* @param cls
|
||||||
|
* - The class describing the type that is contained in the cache.
|
||||||
|
* @param hit
|
||||||
|
* - true for a cache hit, false otherwise
|
||||||
|
*/
|
||||||
|
public void newGet(Class<?> cls, boolean hit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record a new cache get.
|
||||||
|
*
|
||||||
|
* @param oid
|
||||||
|
* - The cache key.
|
||||||
|
* @param hit
|
||||||
|
* - true for a cache hit, false otherwise
|
||||||
|
*/
|
||||||
|
public void newGet(Object oid, boolean hit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record a new cache put.
|
||||||
|
*
|
||||||
|
* @param cls
|
||||||
|
* - The class describing the type that is contained in the cache.
|
||||||
|
*/
|
||||||
|
public void newPut(Class<?> cls);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record a new cache put.
|
||||||
|
*
|
||||||
|
* @param oid
|
||||||
|
* - The cache key.
|
||||||
|
*/
|
||||||
|
public void newPut(Object oid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable statistics collection.
|
||||||
|
*/
|
||||||
|
public void enable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable statistics collection.
|
||||||
|
*/
|
||||||
|
public void disable();
|
||||||
|
}
|
|
@ -147,6 +147,10 @@ public class DataCacheStoreManager
|
||||||
data = newPCData(sm);
|
data = newPCData(sm);
|
||||||
data.store(sm);
|
data.store(sm);
|
||||||
mods.additions.add(new PCDataHolder(data, sm));
|
mods.additions.add(new PCDataHolder(data, sm));
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newPut(sm.getMetaData().getDescribedType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +186,10 @@ public class DataCacheStoreManager
|
||||||
data.store(sm, fields);
|
data.store(sm, fields);
|
||||||
mods.existingUpdates.add(new PCDataHolder(data, sm));
|
mods.existingUpdates.add(new PCDataHolder(data, sm));
|
||||||
}
|
}
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newPut(sm.getMetaData().getDescribedType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,8 +281,21 @@ public class DataCacheStoreManager
|
||||||
|
|
||||||
public boolean exists(OpenJPAStateManager sm, Object edata) {
|
public boolean exists(OpenJPAStateManager sm, Object edata) {
|
||||||
DataCache cache = _mgr.selectCache(sm);
|
DataCache cache = _mgr.selectCache(sm);
|
||||||
if (cache != null && !isLocking(null) && cache.contains(sm.getObjectId()))
|
CacheStatistics stats = cache.getStatistics();
|
||||||
|
if (cache != null && !isLocking(null) && cache.contains(sm.getObjectId())){
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
// delay this call ONLY if stats collection is enabled
|
||||||
|
Class<?> cls = sm.getMetaData().getDescribedType();
|
||||||
|
((CacheStatisticsSPI)stats).newGet(cls, false);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
// If isLocking(null)==true && cache.contains(..) == true... probably shouldn't count?
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
// delay this call ONLY if stats collection is enabled
|
||||||
|
Class<?> cls = sm.getMetaData().getDescribedType();
|
||||||
|
((CacheStatisticsSPI)stats).newGet(cls, false);
|
||||||
|
}
|
||||||
return super.exists(sm, edata);
|
return super.exists(sm, edata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +322,11 @@ public class DataCacheStoreManager
|
||||||
public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
|
public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
|
||||||
DataCache cache = _mgr.selectCache(sm);
|
DataCache cache = _mgr.selectCache(sm);
|
||||||
FetchConfiguration fc = sm.getContext().getFetchConfiguration();
|
FetchConfiguration fc = sm.getContext().getFetchConfiguration();
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
if (cache == null || sm.isEmbedded() || fc.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS) {
|
if (cache == null || sm.isEmbedded() || fc.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS) {
|
||||||
|
if(stats.isEnabled()){
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||||
|
}
|
||||||
return super.syncVersion(sm, edata);
|
return super.syncVersion(sm, edata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,6 +338,9 @@ public class DataCacheStoreManager
|
||||||
|
|
||||||
// if we have a cached version update from there
|
// if we have a cached version update from there
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
|
if(stats.isEnabled()){
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), true);
|
||||||
|
}
|
||||||
if (!version.equals(sm.getVersion())) {
|
if (!version.equals(sm.getVersion())) {
|
||||||
sm.setVersion(version);
|
sm.setVersion(version);
|
||||||
return false;
|
return false;
|
||||||
|
@ -320,6 +348,9 @@ public class DataCacheStoreManager
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(stats.isEnabled()){
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||||
|
}
|
||||||
// use data store version
|
// use data store version
|
||||||
return super.syncVersion(sm, edata);
|
return super.syncVersion(sm, edata);
|
||||||
}
|
}
|
||||||
|
@ -329,18 +360,29 @@ public class DataCacheStoreManager
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
return super.initialize(sm, state, fetch, edata);
|
return super.initialize(sm, state, fetch, edata);
|
||||||
}
|
}
|
||||||
|
Class<?> cls = sm.getMetaData().getDescribedType();
|
||||||
DataCachePCData data = cache.get(sm.getObjectId());
|
DataCachePCData data = cache.get(sm.getObjectId());
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
boolean fromDatabase = false;
|
boolean fromDatabase = false;
|
||||||
boolean alreadyCached = data != null;
|
boolean alreadyCached = data != null;
|
||||||
if (sm.isEmbedded()
|
if (sm.isEmbedded()
|
||||||
|| fetch.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS
|
|| fetch.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS
|
||||||
|| fetch.getCacheStoreMode() == DataCacheStoreMode.REFRESH) {
|
|| fetch.getCacheStoreMode() == DataCacheStoreMode.REFRESH) {
|
||||||
|
// stats -- Skipped reading from the cache, noop
|
||||||
fromDatabase = super.initialize(sm, state, fetch, edata);
|
fromDatabase = super.initialize(sm, state, fetch, edata);
|
||||||
} else {
|
} else {
|
||||||
if (alreadyCached && !isLocking(fetch)) {
|
if (alreadyCached && !isLocking(fetch)) {
|
||||||
sm.initialize(data.getType(), state);
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(cls, true);
|
||||||
|
}
|
||||||
|
sm.initialize(cls, state);
|
||||||
data.load(sm, fetch, edata);
|
data.load(sm, fetch, edata);
|
||||||
} else {
|
} else {
|
||||||
|
if (!alreadyCached) {
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(cls, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
fromDatabase = super.initialize(sm, state, fetch, edata);
|
fromDatabase = super.initialize(sm, state, fetch, edata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,6 +391,9 @@ public class DataCacheStoreManager
|
||||||
&& ((fetch.getCacheStoreMode() == DataCacheStoreMode.USE && !alreadyCached)
|
&& ((fetch.getCacheStoreMode() == DataCacheStoreMode.USE && !alreadyCached)
|
||||||
|| (fetch.getCacheStoreMode() == DataCacheStoreMode.REFRESH));
|
|| (fetch.getCacheStoreMode() == DataCacheStoreMode.REFRESH));
|
||||||
if (updateCache) {
|
if (updateCache) {
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newPut(cls);
|
||||||
|
}
|
||||||
cacheStateManager(cache, sm, data);
|
cacheStateManager(cache, sm, data);
|
||||||
}
|
}
|
||||||
return fromDatabase || alreadyCached;
|
return fromDatabase || alreadyCached;
|
||||||
|
@ -389,11 +434,17 @@ public class DataCacheStoreManager
|
||||||
if (cache == null || sm.isEmbedded() || bypass(fetch, StoreManager.FORCE_LOAD_NONE))
|
if (cache == null || sm.isEmbedded() || bypass(fetch, StoreManager.FORCE_LOAD_NONE))
|
||||||
return super.load(sm, fields, fetch, lockLevel, edata);
|
return super.load(sm, fields, fetch, lockLevel, edata);
|
||||||
|
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
|
Class<?> cls = sm.getMetaData().getDescribedType();
|
||||||
DataCachePCData data = cache.get(sm.getObjectId());
|
DataCachePCData data = cache.get(sm.getObjectId());
|
||||||
if (lockLevel == LockLevels.LOCK_NONE && !isLocking(fetch) && data != null)
|
if (lockLevel == LockLevels.LOCK_NONE && !isLocking(fetch) && data != null)
|
||||||
data.load(sm, fields, fetch, edata);
|
data.load(sm, fields, fetch, edata);
|
||||||
if (fields.length() == 0)
|
if (fields.length() == 0){
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(cls, true);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// load from store manager; clone the set of still-unloaded fields
|
// load from store manager; clone the set of still-unloaded fields
|
||||||
// so that if the store manager decides to modify it it won't affect us
|
// so that if the store manager decides to modify it it won't affect us
|
||||||
|
@ -452,15 +503,21 @@ public class DataCacheStoreManager
|
||||||
|
|
||||||
for (OpenJPAStateManager sm : smList) {
|
for (OpenJPAStateManager sm : smList) {
|
||||||
data = dataMap.get(sm.getObjectId());
|
data = dataMap.get(sm.getObjectId());
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
if (sm.getManagedInstance() == null) {
|
if (sm.getManagedInstance() == null) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
//### the 'data.type' access here probably needs
|
//### the 'data.type' access here probably needs
|
||||||
//### to be addressed for bug 511
|
//### to be addressed for bug 511
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), true);
|
||||||
|
}
|
||||||
sm.initialize(data.getType(), state);
|
sm.initialize(data.getType(), state);
|
||||||
data.load(sm, fetch, edata);
|
data.load(sm, fetch, edata);
|
||||||
} else {
|
} else {
|
||||||
unloaded = addUnloaded(sm, null, unloaded);
|
unloaded = addUnloaded(sm, null, unloaded);
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (load != FORCE_LOAD_NONE
|
} else if (load != FORCE_LOAD_NONE
|
||||||
|| sm.getPCState() == PCState.HOLLOW) {
|
|| sm.getPCState() == PCState.HOLLOW) {
|
||||||
|
@ -469,10 +526,22 @@ public class DataCacheStoreManager
|
||||||
// load unloaded fields
|
// load unloaded fields
|
||||||
fields = sm.getUnloaded(fetch);
|
fields = sm.getUnloaded(fetch);
|
||||||
data.load(sm, fields, fetch, edata);
|
data.load(sm, fields, fetch, edata);
|
||||||
if (fields.length() > 0)
|
if (fields.length() > 0){
|
||||||
unloaded = addUnloaded(sm, fields, unloaded);
|
unloaded = addUnloaded(sm, fields, unloaded);
|
||||||
} else
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else{
|
||||||
unloaded = addUnloaded(sm, null, unloaded);
|
unloaded = addUnloaded(sm, null, unloaded);
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,6 +586,10 @@ public class DataCacheStoreManager
|
||||||
cache.put(data);
|
cache.put(data);
|
||||||
else
|
else
|
||||||
cache.update(data);
|
cache.update(data);
|
||||||
|
CacheStatistics stats = cache.getStatistics();
|
||||||
|
if (stats.isEnabled()) {
|
||||||
|
((CacheStatisticsSPI)stats).newPut(sm.getMetaData().getDescribedType());
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
cache.writeUnlock();
|
cache.writeUnlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,46 +218,6 @@ public abstract class AbstractDataCacheInstrument extends AbstractInstrument
|
||||||
return NO_STATS;
|
return NO_STATS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getEvictionCount() {
|
|
||||||
CacheStatistics stats = getStatistics();
|
|
||||||
if (stats != null)
|
|
||||||
return stats.getEvictionCount();
|
|
||||||
return NO_STATS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEvictionCount(String className)
|
|
||||||
throws ClassNotFoundException {
|
|
||||||
Class<?> clazz = Class.forName(className);
|
|
||||||
return getEvictionCount(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEvictionCount(Class<?> c) {
|
|
||||||
CacheStatistics stats = getStatistics();
|
|
||||||
if (stats != null)
|
|
||||||
return stats.getEvictionCount(c);
|
|
||||||
return NO_STATS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalEvictionCount() {
|
|
||||||
CacheStatistics stats = getStatistics();
|
|
||||||
if (stats != null)
|
|
||||||
return stats.getTotalEvictionCount();
|
|
||||||
return NO_STATS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalEvictionCount(String className)
|
|
||||||
throws ClassNotFoundException {
|
|
||||||
Class<?> clazz = Class.forName(className);
|
|
||||||
return getTotalEvictionCount(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTotalEvictionCount(Class<?> c) {
|
|
||||||
CacheStatistics stats = getStatistics();
|
|
||||||
if (stats != null)
|
|
||||||
return stats.getTotalEvictionCount(c);
|
|
||||||
return NO_STATS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Set<String> classNames() {
|
public Set<String> classNames() {
|
||||||
CacheStatistics stats = getStatistics();
|
CacheStatistics stats = getStatistics();
|
||||||
|
|
|
@ -61,16 +61,6 @@ public interface DataCacheInstrument {
|
||||||
public long getTotalWriteCount(String className)
|
public long getTotalWriteCount(String className)
|
||||||
throws ClassNotFoundException;
|
throws ClassNotFoundException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of cache evictions from the last reset.
|
|
||||||
*/
|
|
||||||
public long getEvictionCount();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the total number of cache evictions since cache start.
|
|
||||||
*/
|
|
||||||
public long getTotalEvictionCount();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the cache
|
* Returns the name of the cache
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,12 +18,15 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.openjpa.persistence.datacache;
|
package org.apache.openjpa.persistence.datacache;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
|
||||||
import org.apache.openjpa.datacache.CacheStatistics;
|
import org.apache.openjpa.datacache.CacheStatistics;
|
||||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
|
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAPersistence;
|
||||||
import org.apache.openjpa.persistence.StoreCache;
|
import org.apache.openjpa.persistence.StoreCache;
|
||||||
import org.apache.openjpa.persistence.StoreCacheImpl;
|
import org.apache.openjpa.persistence.StoreCacheImpl;
|
||||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||||
|
@ -31,37 +34,43 @@ import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||||
/**
|
/**
|
||||||
* Tests statistics of data cache operation.
|
* Tests statistics of data cache operation.
|
||||||
*
|
*
|
||||||
* @author Pinaki Poddar
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class TestStatistics extends SingleEMFTestCase {
|
public class TestStatistics extends SingleEMFTestCase {
|
||||||
private static final boolean L2Cached = true;
|
private static final boolean L2Cached = true;
|
||||||
private static final boolean L1Cached = true;
|
private static final boolean L1Cached = true;
|
||||||
private static CachedPerson person;
|
private static final Class<?> cls = CachedEntityStatistics.class;
|
||||||
|
|
||||||
|
Object[] p =
|
||||||
|
new Object[] { CLEAR_TABLES, CachedEntityStatistics.class
|
||||||
|
,"openjpa.DataCache", "true(EnableStatistics=true)","openjpa.QueryCache", "true",
|
||||||
|
// "openjpa.ConnectionFactoryProperties", "PrintParameters=True", "openjpa.Log","SQL=trace",
|
||||||
|
};
|
||||||
|
|
||||||
private EntityManager em;
|
private EntityManager em;
|
||||||
private StoreCache cache;
|
private StoreCache cache;
|
||||||
CacheStatistics stats;
|
CacheStatistics stats;
|
||||||
|
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
super.setUp(CLEAR_TABLES, CachedPerson.class,
|
super.setUp(p);
|
||||||
"openjpa.DataCache", "true(EnableStatistics=true)",
|
|
||||||
"openjpa.QueryCache", "true",
|
|
||||||
"openjpa.RemoteCommitProvider", "sjvm");
|
|
||||||
cache = emf.getStoreCache();
|
cache = emf.getStoreCache();
|
||||||
assertNotNull(cache);
|
assertNotNull(cache);
|
||||||
stats = cache.getStatistics();
|
stats = cache.getStatistics();
|
||||||
assertNotNull(stats);
|
assertNotNull(stats);
|
||||||
em = emf.createEntityManager();
|
em = emf.createEntityManager();
|
||||||
|
|
||||||
person = createData();
|
|
||||||
stats.reset();
|
stats.reset();
|
||||||
em.clear();
|
em.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the CacheStatistics is disabled by default.
|
* Test that the CacheStatistics is disabled by default.
|
||||||
*/
|
*/
|
||||||
public void testDefaultSettings() {
|
public void testDefaultSettings() {
|
||||||
Object[] props = {"openjpa.DataCache", "true", "openjpa.RemoteCommitProvider", "sjvm"};
|
Object[] props = { "openjpa.DataCache", "true", "openjpa.RemoteCommitProvider", "sjvm" };
|
||||||
OpenJPAEntityManagerFactory emf1 = createNamedEMF("second-persistence-unit", props);
|
OpenJPAEntityManagerFactory emf1 = createNamedEMF("second-persistence-unit", props);
|
||||||
|
|
||||||
assertFalse(emf1.getStoreCache().getStatistics().isEnabled());
|
assertFalse(emf1.getStoreCache().getStatistics().isEnabled());
|
||||||
|
@ -70,37 +79,191 @@ public class TestStatistics extends SingleEMFTestCase {
|
||||||
/**
|
/**
|
||||||
* Finding an entity from a clean should hit the L2 cache.
|
* Finding an entity from a clean should hit the L2 cache.
|
||||||
*/
|
*/
|
||||||
public void testFind() {
|
public void testSimpleFind() {
|
||||||
|
int hit = 0, eviction = 0, read = 0, write = 0;
|
||||||
|
CachedEntityStatistics person = createData(false, false);
|
||||||
|
em.clear();
|
||||||
|
cache.getStatistics().reset();
|
||||||
assertTrue(cache.getStatistics().isEnabled());
|
assertTrue(cache.getStatistics().isEnabled());
|
||||||
Object pid = person.getId();
|
Object pid = person.getId();
|
||||||
|
// Note -- the StoreCache interface doesn't calculate statistics
|
||||||
assertCached(person, pid, !L1Cached, L2Cached);
|
assertCached(person, pid, !L1Cached, L2Cached);
|
||||||
|
|
||||||
long[] before = snapshot();
|
CachedEntityStatistics p = em.find(CachedEntityStatistics.class, pid);
|
||||||
CachedPerson p = em.find(CachedPerson.class, pid);
|
read++;
|
||||||
long[] after = snapshot();
|
hit++;
|
||||||
|
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
em.find(CachedEntityStatistics.class, -1);
|
||||||
|
read++;
|
||||||
|
|
||||||
assertDelta(before, after, 1, 1, 0); // READ:1 HIT:1, WRITE:0
|
|
||||||
assertCached(p, pid, L1Cached, L2Cached);
|
assertCached(p, pid, L1Cached, L2Cached);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFind() {
|
||||||
|
int hit = 0, evict = 0, read = 0, write = 0;
|
||||||
|
CachedEntityStatistics person = createData(true, true);
|
||||||
|
em.clear();
|
||||||
|
cache.evictAll();
|
||||||
|
cache.getStatistics().reset();
|
||||||
|
|
||||||
|
// Make sure cache is enabled and empty
|
||||||
|
assertTrue(cache.getStatistics().isEnabled());
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
Object pid = person.getId();
|
||||||
|
|
||||||
|
// Should have 3 reads and 3 writes because of pid and it's eager relationship
|
||||||
|
CachedEntityStatistics p = em.find(CachedEntityStatistics.class, pid);
|
||||||
|
read++;
|
||||||
|
read++;
|
||||||
|
read++;
|
||||||
|
write++;
|
||||||
|
write++;
|
||||||
|
write++;
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
em.clear();
|
||||||
|
em.find(CachedEntityStatistics.class, person.getEagerList().toArray(new CachedEntityStatistics[0])[0].getId());
|
||||||
|
read++;
|
||||||
|
hit++;
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
// Should have two reads and two hits
|
||||||
|
person = em.find(CachedEntityStatistics.class, pid);
|
||||||
|
read++;
|
||||||
|
read++;
|
||||||
|
read++;
|
||||||
|
hit++;
|
||||||
|
hit++;
|
||||||
|
hit++;
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
// Evict 1 eager field data from cache
|
||||||
|
cache.evict(CachedEntityStatistics.class, person.getEagerList().toArray(new CachedEntityStatistics[0])[0]
|
||||||
|
.getId());
|
||||||
|
evict++;
|
||||||
|
p = em.find(CachedEntityStatistics.class, pid);
|
||||||
|
read++;
|
||||||
|
read++;
|
||||||
|
read++;
|
||||||
|
hit++;
|
||||||
|
hit++;
|
||||||
|
write++;
|
||||||
|
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
// Test lazy field -- should be a cache miss
|
||||||
|
assertEquals(1, p.getLazyList().size());
|
||||||
|
read++;
|
||||||
|
write++;
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
em.find(CachedEntityStatistics.class, p.getLazyList().toArray(new CachedEntityStatistics[0])[0].getId());
|
||||||
|
read++;
|
||||||
|
hit++;
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultipleUnits() {
|
public void testMultipleUnits() {
|
||||||
String[] props = {"openjpa.DataCache", "true", "openjpa.RemoteCommitProvider", "sjvm"};
|
String[] props = { "openjpa.DataCache", "true", "openjpa.RemoteCommitProvider", "sjvm" };
|
||||||
OpenJPAEntityManagerFactory emf1 = createNamedEMF("test", props);
|
OpenJPAEntityManagerFactory emf1 = createNamedEMF("test", props);
|
||||||
OpenJPAEntityManagerFactory emf2 = createNamedEMF("empty-pu", props);
|
OpenJPAEntityManagerFactory emf2 = createNamedEMF("empty-pu", props);
|
||||||
assertNotSame(emf1, emf2);
|
assertNotSame(emf1, emf2);
|
||||||
assertNotSame(emf1.getStoreCache(), emf2.getStoreCache());
|
assertNotSame(emf1.getStoreCache(), emf2.getStoreCache());
|
||||||
assertNotSame(emf1.getStoreCache().getStatistics(), emf2.getStoreCache().getStatistics());
|
assertNotSame(emf1.getStoreCache().getStatistics(), emf2.getStoreCache().getStatistics());
|
||||||
assertNotSame(((StoreCacheImpl)emf1.getStoreCache()).getDelegate(),
|
assertNotSame(((StoreCacheImpl) emf1.getStoreCache()).getDelegate(), ((StoreCacheImpl) emf2.getStoreCache())
|
||||||
((StoreCacheImpl)emf2.getStoreCache()).getDelegate());
|
.getDelegate());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedPerson createData() {
|
public void testPersist() {
|
||||||
|
int hit = 0, evict = 0, read = 0, write = 0;
|
||||||
|
|
||||||
|
em = emf.createEntityManager();
|
||||||
|
// test single
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
CachedPerson p = new CachedPerson();
|
em.persist(new CachedEntityStatistics());
|
||||||
p.setId((int)System.currentTimeMillis());
|
write++;
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
// test multiple
|
||||||
|
CachedEntityStatistics root = new CachedEntityStatistics();
|
||||||
|
root.addEager(new CachedEntityStatistics());
|
||||||
|
root.addEager(new CachedEntityStatistics());
|
||||||
|
root.addLazy(new CachedEntityStatistics());
|
||||||
|
root.addLazy(new CachedEntityStatistics());
|
||||||
|
write += 5;
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(root);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRefresh() {
|
||||||
|
int hit = 0, evict = 0, read = 0, write = 0;
|
||||||
|
CachedEntityStatistics e = new CachedEntityStatistics();
|
||||||
|
em = emf.createEntityManager();
|
||||||
|
// test single
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(e);
|
||||||
|
write++;
|
||||||
|
em.getTransaction().commit();
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
em.refresh(e);
|
||||||
|
read++;
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMerge() {
|
||||||
|
int hit = 0, evict = 0, read = 0, write = 0;
|
||||||
|
CachedEntityStatistics e = new CachedEntityStatistics();
|
||||||
|
em = emf.createEntityManager();
|
||||||
|
// test single
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(e);
|
||||||
|
write++;
|
||||||
|
em.getTransaction().commit();
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
em.clear();
|
||||||
|
cache.evictAll();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.merge(e);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
// TODO -- BROKEN
|
||||||
|
// DataCacheStoreManager.flush(...) doesn't account for some of this traffic.
|
||||||
|
// read++;
|
||||||
|
assertion(cls, hit, read, write, stats);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedEntityStatistics createData(boolean lazy, boolean eager) {
|
||||||
|
List<CachedEntityStatistics> eagerList = null;
|
||||||
|
List<CachedEntityStatistics> lazyList = null;
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
CachedEntityStatistics p = new CachedEntityStatistics();
|
||||||
|
if (lazy) {
|
||||||
|
p.addLazy(new CachedEntityStatistics());
|
||||||
|
}
|
||||||
|
if (eager) {
|
||||||
|
p.addEager(new CachedEntityStatistics());
|
||||||
|
p.addEager(new CachedEntityStatistics());
|
||||||
|
}
|
||||||
em.persist(p);
|
em.persist(p);
|
||||||
|
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -109,38 +272,57 @@ public class TestStatistics extends SingleEMFTestCase {
|
||||||
* Get {hit,read,write} count for the cache across all instances.
|
* Get {hit,read,write} count for the cache across all instances.
|
||||||
*/
|
*/
|
||||||
long[] snapshot() {
|
long[] snapshot() {
|
||||||
return new long[]{stats.getReadCount(), stats.getHitCount(), stats.getWriteCount()};
|
return new long[] { stats.getReadCount(), stats.getHitCount(), stats.getWriteCount() };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get {hit,read,write} count for the cache across given class extent.
|
* Get {hit,read,write} count for the cache across given class extent.
|
||||||
*/
|
*/
|
||||||
long[] snapshot(Class<?> cls) {
|
long[] snapshot(Class<?> cls) {
|
||||||
return new long[]{stats.getReadCount(cls), stats.getHitCount(cls), stats.getWriteCount(cls)};
|
return new long[] { stats.getReadCount(cls), stats.getHitCount(cls), stats.getWriteCount(cls) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that the passed in hit/eviction/read/write match those values collected by stats.
|
||||||
|
*/
|
||||||
|
private static final void assertion(Class<?> cls, int hit, int read, int write, CacheStatistics stats) {
|
||||||
|
if (cls == null) {
|
||||||
|
throw new RuntimeException("invalid assertion. Null class");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
assertEquals("Hit count doesn't match", hit, stats.getHitCount(cls));
|
||||||
|
assertEquals("Read count doesn't match", read, stats.getReadCount(cls));
|
||||||
|
assertEquals("Write count doesn't match", write, stats.getWriteCount(cls));
|
||||||
|
} catch (AssertionFailedError t) {
|
||||||
|
System.out.println("hit : " + stats.getHitCount(cls) + " read: " + stats.getReadCount(cls) + " write: "
|
||||||
|
+ stats.getWriteCount(cls));
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertDelta(long[] before, long[] after, long readDelta, long hitDelta, long writeDelta) {
|
void assertDelta(long[] before, long[] after, long readDelta, long hitDelta, long writeDelta) {
|
||||||
assertEquals("READ count mismatch", readDelta, after[0] - before[0]);
|
assertEquals("READ count mismatch", readDelta, after[0] - before[0]);
|
||||||
assertEquals("HIT count mismatch", hitDelta, after[1] - before[1]);
|
assertEquals("HIT count mismatch", hitDelta, after[1] - before[1]);
|
||||||
assertEquals("WRITE count mismatch", writeDelta, after[2] - before[2]);
|
assertEquals("WRITE count mismatch", writeDelta, after[2] - before[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void assertCached(Object o, Object oid, boolean l1, boolean l2) {
|
void assertCached(Object o, Object oid, boolean l1, boolean l2) {
|
||||||
boolean l1a = em.contains(o);
|
boolean l1a = em.contains(o);
|
||||||
boolean l2a = cache.contains(o.getClass(), oid);
|
boolean l2a = cache.contains(o.getClass(), oid);
|
||||||
if (l1 != l1a) {
|
if (l1 != l1a) {
|
||||||
fail("Expected " + (l1 ? "":"not") + " to find instance " +
|
fail("Expected " + (l1 ? "" : "not") + " to find instance " + o.getClass().getSimpleName() + ":" + oid
|
||||||
o.getClass().getSimpleName()+":"+oid + " in L1 cache");
|
+ " in L1 cache");
|
||||||
}
|
}
|
||||||
if (l2 != l2a) {
|
if (l2 != l2a) {
|
||||||
fail("Expected " + (l2 ? "":"not") + " to find instance " +
|
fail("Expected " + (l2 ? "" : "not") + " to find instance " + o.getClass().getSimpleName() + ":" + oid
|
||||||
o.getClass().getSimpleName()+":"+oid + " in L2 cache");
|
+ " in L2 cache");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(String msg, CacheStatistics stats) {
|
void print(String msg, CacheStatistics stats) {
|
||||||
System.err.println(msg + stats + " H:" + stats.getHitCount() + " R:" + stats.getReadCount() + " W:" +
|
System.err.println(msg + stats + " H:" + stats.getHitCount() + " R:" + stats.getReadCount() + " W:"
|
||||||
stats.getWriteCount());
|
+ stats.getWriteCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue