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.event.RemoteCommitEvent;
|
||||
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.Configuration;
|
||||
import org.apache.openjpa.lib.log.Log;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.concurrent.AbstractConcurrentEventManager;
|
||||
import org.apache.openjpa.util.GeneralException;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
import org.apache.openjpa.util.OpenJPAId;
|
||||
|
||||
import serp.util.Strings;
|
||||
|
||||
/**
|
||||
|
@ -54,7 +58,7 @@ import serp.util.Strings;
|
|||
public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
||||
implements DataCache, Configurable {
|
||||
|
||||
protected CacheStatistics.Default stats = new CacheStatistics.Default();
|
||||
protected CacheStatisticsSPI _stats = new CacheStatisticsImpl();
|
||||
|
||||
private static final BitSet EMPTY_BITSET = new BitSet(0);
|
||||
|
||||
|
@ -86,11 +90,11 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
}
|
||||
public void setEnableStatistics(boolean enable){
|
||||
if(enable == true){
|
||||
stats.enable();
|
||||
_stats.enable();
|
||||
}
|
||||
}
|
||||
public void getEnableStatistics(){
|
||||
stats.isEnabled();
|
||||
_stats.isEnabled();
|
||||
}
|
||||
|
||||
public String getEvictionSchedule() {
|
||||
|
@ -157,9 +161,6 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
|
||||
public boolean contains(Object key) {
|
||||
DataCachePCData o = getInternal(key);
|
||||
if (stats.isEnabled()) {
|
||||
stats.newGet(o == null ? null : o.getType(), o != null);
|
||||
}
|
||||
if (o != null && o.isTimedOut()) {
|
||||
o = null;
|
||||
removeInternal(key);
|
||||
|
@ -195,9 +196,7 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
else
|
||||
log.trace(s_loc.get("cache-hit", key));
|
||||
}
|
||||
if (stats.isEnabled()) {
|
||||
stats.newGet((o == null) ? null : o.getType(), o != null);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
@ -213,9 +212,6 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
}
|
||||
|
||||
public DataCachePCData put(DataCachePCData data) {
|
||||
if (stats.isEnabled()) {
|
||||
stats.newPut(data.getType());
|
||||
}
|
||||
DataCachePCData o = putInternal(data.getId(), data);
|
||||
if (log.isTraceEnabled())
|
||||
log.trace(s_loc.get("cache-put", data.getId()));
|
||||
|
@ -224,18 +220,12 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
|
||||
public void update(DataCachePCData data) {
|
||||
if (recacheUpdates()) {
|
||||
if (stats.isEnabled()) {
|
||||
stats.newPut(data.getType());
|
||||
}
|
||||
putInternal(data.getId(), data);
|
||||
}
|
||||
}
|
||||
|
||||
public DataCachePCData remove(Object key) {
|
||||
DataCachePCData o = removeInternal(key);
|
||||
if (stats.isEnabled()) {
|
||||
stats.newEvict(o == null ? null : o.getType());
|
||||
}
|
||||
if (o != null && o.isTimedOut())
|
||||
o = null;
|
||||
if (log.isTraceEnabled()) {
|
||||
|
@ -418,9 +408,6 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
*/
|
||||
protected void putAllInternal(Collection<DataCachePCData> pcs) {
|
||||
for (DataCachePCData pc : pcs) {
|
||||
if (stats.isEnabled()) {
|
||||
stats.newPut(pc.getType());
|
||||
}
|
||||
putInternal(pc.getId(), pc);
|
||||
}
|
||||
}
|
||||
|
@ -492,9 +479,9 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
public boolean isPartitioned() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public CacheStatistics getStatistics() {
|
||||
return stats;
|
||||
|
||||
public CacheStatistics getStatistics() {
|
||||
return _stats;
|
||||
}
|
||||
|
||||
// ---------- Configurable implementation ----------
|
||||
|
@ -550,4 +537,8 @@ public abstract class AbstractDataCache extends AbstractConcurrentEventManager
|
|||
_excludedTypes =
|
||||
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.Set;
|
||||
|
||||
import org.apache.openjpa.util.OpenJPAId;
|
||||
|
||||
/**
|
||||
* Counts number of read/write requests and hit ratio for a cache in total and
|
||||
* per-class basis.
|
||||
|
@ -35,11 +37,9 @@ import java.util.Set;
|
|||
* is registered under generic <code>java.lang.Object</code>.
|
||||
*
|
||||
* @since 1.3.0
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public interface CacheStatistics extends Serializable {
|
||||
|
||||
/**
|
||||
* Gets number of total read requests since last reset.
|
||||
*/
|
||||
|
@ -104,26 +104,6 @@ public interface CacheStatistics extends Serializable {
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -149,154 +129,5 @@ public interface CacheStatistics extends Serializable {
|
|||
* @return
|
||||
*/
|
||||
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.store(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);
|
||||
mods.existingUpdates.add(new PCDataHolder(data, sm));
|
||||
}
|
||||
CacheStatistics stats = cache.getStatistics();
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newPut(sm.getMetaData().getDescribedType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,9 +280,22 @@ public class DataCacheStoreManager
|
|||
}
|
||||
|
||||
public boolean exists(OpenJPAStateManager sm, Object edata) {
|
||||
DataCache cache = _mgr.selectCache(sm);
|
||||
if (cache != null && !isLocking(null) && cache.contains(sm.getObjectId()))
|
||||
DataCache cache = _mgr.selectCache(sm);
|
||||
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;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -301,7 +322,11 @@ public class DataCacheStoreManager
|
|||
public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
|
||||
DataCache cache = _mgr.selectCache(sm);
|
||||
FetchConfiguration fc = sm.getContext().getFetchConfiguration();
|
||||
CacheStatistics stats = cache.getStatistics();
|
||||
if (cache == null || sm.isEmbedded() || fc.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS) {
|
||||
if(stats.isEnabled()){
|
||||
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||
}
|
||||
return super.syncVersion(sm, edata);
|
||||
}
|
||||
|
||||
|
@ -313,6 +338,9 @@ public class DataCacheStoreManager
|
|||
|
||||
// if we have a cached version update from there
|
||||
if (version != null) {
|
||||
if(stats.isEnabled()){
|
||||
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), true);
|
||||
}
|
||||
if (!version.equals(sm.getVersion())) {
|
||||
sm.setVersion(version);
|
||||
return false;
|
||||
|
@ -320,6 +348,9 @@ public class DataCacheStoreManager
|
|||
return true;
|
||||
}
|
||||
|
||||
if(stats.isEnabled()){
|
||||
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||
}
|
||||
// use data store version
|
||||
return super.syncVersion(sm, edata);
|
||||
}
|
||||
|
@ -329,18 +360,29 @@ public class DataCacheStoreManager
|
|||
if (cache == null) {
|
||||
return super.initialize(sm, state, fetch, edata);
|
||||
}
|
||||
Class<?> cls = sm.getMetaData().getDescribedType();
|
||||
DataCachePCData data = cache.get(sm.getObjectId());
|
||||
CacheStatistics stats = cache.getStatistics();
|
||||
boolean fromDatabase = false;
|
||||
boolean alreadyCached = data != null;
|
||||
if (sm.isEmbedded()
|
||||
|| fetch.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS
|
||||
|| fetch.getCacheStoreMode() == DataCacheStoreMode.REFRESH) {
|
||||
// stats -- Skipped reading from the cache, noop
|
||||
fromDatabase = super.initialize(sm, state, fetch, edata);
|
||||
} else {
|
||||
if (alreadyCached && !isLocking(fetch)) {
|
||||
sm.initialize(data.getType(), state);
|
||||
if (alreadyCached && !isLocking(fetch)) {
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newGet(cls, true);
|
||||
}
|
||||
sm.initialize(cls, state);
|
||||
data.load(sm, fetch, edata);
|
||||
} else {
|
||||
if (!alreadyCached) {
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newGet(cls, false);
|
||||
}
|
||||
}
|
||||
fromDatabase = super.initialize(sm, state, fetch, edata);
|
||||
}
|
||||
}
|
||||
|
@ -349,6 +391,9 @@ public class DataCacheStoreManager
|
|||
&& ((fetch.getCacheStoreMode() == DataCacheStoreMode.USE && !alreadyCached)
|
||||
|| (fetch.getCacheStoreMode() == DataCacheStoreMode.REFRESH));
|
||||
if (updateCache) {
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newPut(cls);
|
||||
}
|
||||
cacheStateManager(cache, sm, data);
|
||||
}
|
||||
return fromDatabase || alreadyCached;
|
||||
|
@ -389,11 +434,17 @@ public class DataCacheStoreManager
|
|||
if (cache == null || sm.isEmbedded() || bypass(fetch, StoreManager.FORCE_LOAD_NONE))
|
||||
return super.load(sm, fields, fetch, lockLevel, edata);
|
||||
|
||||
CacheStatistics stats = cache.getStatistics();
|
||||
Class<?> cls = sm.getMetaData().getDescribedType();
|
||||
DataCachePCData data = cache.get(sm.getObjectId());
|
||||
if (lockLevel == LockLevels.LOCK_NONE && !isLocking(fetch) && data != null)
|
||||
data.load(sm, fields, fetch, edata);
|
||||
if (fields.length() == 0)
|
||||
if (fields.length() == 0){
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newGet(cls, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -452,15 +503,21 @@ public class DataCacheStoreManager
|
|||
|
||||
for (OpenJPAStateManager sm : smList) {
|
||||
data = dataMap.get(sm.getObjectId());
|
||||
|
||||
CacheStatistics stats = cache.getStatistics();
|
||||
if (sm.getManagedInstance() == null) {
|
||||
if (data != null) {
|
||||
//### the 'data.type' access here probably needs
|
||||
//### to be addressed for bug 511
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), true);
|
||||
}
|
||||
sm.initialize(data.getType(), state);
|
||||
data.load(sm, fetch, edata);
|
||||
} else {
|
||||
unloaded = addUnloaded(sm, null, unloaded);
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||
}
|
||||
}
|
||||
} else if (load != FORCE_LOAD_NONE
|
||||
|| sm.getPCState() == PCState.HOLLOW) {
|
||||
|
@ -469,10 +526,22 @@ public class DataCacheStoreManager
|
|||
// load unloaded fields
|
||||
fields = sm.getUnloaded(fetch);
|
||||
data.load(sm, fields, fetch, edata);
|
||||
if (fields.length() > 0)
|
||||
if (fields.length() > 0){
|
||||
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);
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newGet(sm.getMetaData().getDescribedType(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -517,6 +586,10 @@ public class DataCacheStoreManager
|
|||
cache.put(data);
|
||||
else
|
||||
cache.update(data);
|
||||
CacheStatistics stats = cache.getStatistics();
|
||||
if (stats.isEnabled()) {
|
||||
((CacheStatisticsSPI)stats).newPut(sm.getMetaData().getDescribedType());
|
||||
}
|
||||
} finally {
|
||||
cache.writeUnlock();
|
||||
}
|
||||
|
|
|
@ -218,46 +218,6 @@ public abstract class AbstractDataCacheInstrument extends AbstractInstrument
|
|||
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")
|
||||
public Set<String> classNames() {
|
||||
CacheStatistics stats = getStatistics();
|
||||
|
|
|
@ -60,17 +60,7 @@ public interface DataCacheInstrument {
|
|||
*/
|
||||
public long getTotalWriteCount(String className)
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -18,129 +18,311 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.datacache;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.apache.openjpa.datacache.CacheStatistics;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
|
||||
import org.apache.openjpa.persistence.OpenJPAPersistence;
|
||||
import org.apache.openjpa.persistence.StoreCache;
|
||||
import org.apache.openjpa.persistence.StoreCacheImpl;
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
/**
|
||||
* Tests statistics of data cache operation.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TestStatistics extends SingleEMFTestCase {
|
||||
private static final boolean L2Cached = 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 StoreCache cache;
|
||||
CacheStatistics stats;
|
||||
|
||||
public void setUp() {
|
||||
super.setUp(CLEAR_TABLES, CachedPerson.class,
|
||||
"openjpa.DataCache", "true(EnableStatistics=true)",
|
||||
"openjpa.QueryCache", "true",
|
||||
"openjpa.RemoteCommitProvider", "sjvm");
|
||||
super.setUp(p);
|
||||
cache = emf.getStoreCache();
|
||||
assertNotNull(cache);
|
||||
stats = cache.getStatistics();
|
||||
assertNotNull(stats);
|
||||
em = emf.createEntityManager();
|
||||
|
||||
person = createData();
|
||||
|
||||
stats.reset();
|
||||
em.clear();
|
||||
}
|
||||
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the CacheStatistics is disabled by default.
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
assertFalse(emf1.getStoreCache().getStatistics().isEnabled());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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());
|
||||
Object pid = person.getId();
|
||||
// Note -- the StoreCache interface doesn't calculate statistics
|
||||
assertCached(person, pid, !L1Cached, L2Cached);
|
||||
|
||||
long[] before = snapshot();
|
||||
CachedPerson p = em.find(CachedPerson.class, pid);
|
||||
long[] after = snapshot();
|
||||
|
||||
assertDelta(before, after, 1, 1, 0); // READ:1 HIT:1, WRITE:0
|
||||
CachedEntityStatistics p = em.find(CachedEntityStatistics.class, pid);
|
||||
read++;
|
||||
hit++;
|
||||
|
||||
assertion(cls, hit, read, write, stats);
|
||||
|
||||
em.find(CachedEntityStatistics.class, -1);
|
||||
read++;
|
||||
|
||||
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() {
|
||||
String[] props = {"openjpa.DataCache", "true", "openjpa.RemoteCommitProvider", "sjvm"};
|
||||
String[] props = { "openjpa.DataCache", "true", "openjpa.RemoteCommitProvider", "sjvm" };
|
||||
OpenJPAEntityManagerFactory emf1 = createNamedEMF("test", props);
|
||||
OpenJPAEntityManagerFactory emf2 = createNamedEMF("empty-pu", props);
|
||||
assertNotSame(emf1, emf2);
|
||||
assertNotSame(emf1.getStoreCache(), emf2.getStoreCache());
|
||||
assertNotSame(emf1.getStoreCache().getStatistics(), emf2.getStoreCache().getStatistics());
|
||||
assertNotSame(((StoreCacheImpl)emf1.getStoreCache()).getDelegate(),
|
||||
((StoreCacheImpl)emf2.getStoreCache()).getDelegate());
|
||||
|
||||
assertNotSame(((StoreCacheImpl) emf1.getStoreCache()).getDelegate(), ((StoreCacheImpl) emf2.getStoreCache())
|
||||
.getDelegate());
|
||||
|
||||
}
|
||||
|
||||
CachedPerson createData() {
|
||||
|
||||
public void testPersist() {
|
||||
int hit = 0, evict = 0, read = 0, write = 0;
|
||||
|
||||
em = emf.createEntityManager();
|
||||
// test single
|
||||
em.getTransaction().begin();
|
||||
CachedPerson p = new CachedPerson();
|
||||
p.setId((int)System.currentTimeMillis());
|
||||
em.persist(new CachedEntityStatistics());
|
||||
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.getTransaction().commit();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get {hit,read,write} count for the cache across all instances.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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) {
|
||||
assertEquals("READ count mismatch", readDelta, after[0] - before[0]);
|
||||
assertEquals("HIT count mismatch", hitDelta, after[1] - before[1]);
|
||||
assertEquals("READ count mismatch", readDelta, after[0] - before[0]);
|
||||
assertEquals("HIT count mismatch", hitDelta, after[1] - before[1]);
|
||||
assertEquals("WRITE count mismatch", writeDelta, after[2] - before[2]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void assertCached(Object o, Object oid, boolean l1, boolean l2) {
|
||||
boolean l1a = em.contains(o);
|
||||
boolean l2a = cache.contains(o.getClass(), oid);
|
||||
if (l1 != l1a) {
|
||||
fail("Expected " + (l1 ? "":"not") + " to find instance " +
|
||||
o.getClass().getSimpleName()+":"+oid + " in L1 cache");
|
||||
fail("Expected " + (l1 ? "" : "not") + " to find instance " + o.getClass().getSimpleName() + ":" + oid
|
||||
+ " in L1 cache");
|
||||
}
|
||||
if (l2 != l2a) {
|
||||
fail("Expected " + (l2 ? "":"not") + " to find instance " +
|
||||
o.getClass().getSimpleName()+":"+oid + " in L2 cache");
|
||||
fail("Expected " + (l2 ? "" : "not") + " to find instance " + o.getClass().getSimpleName() + ":" + oid
|
||||
+ " in L2 cache");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void print(String msg, CacheStatistics stats) {
|
||||
System.err.println(msg + stats + " H:" + stats.getHitCount() + " R:" + stats.getReadCount() + " W:" +
|
||||
stats.getWriteCount());
|
||||
System.err.println(msg + stats + " H:" + stats.getHitCount() + " R:" + stats.getReadCount() + " W:"
|
||||
+ stats.getWriteCount());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue