mirror of https://github.com/apache/openjpa.git
OPENJPA-738 QueryCache Improvement
Committing patch provided by Sandhya Sturaga git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@706481 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
16e7a11f81
commit
e2388e9b3c
|
@ -18,12 +18,16 @@
|
|||
*/
|
||||
package org.apache.openjpa.datacache;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||
import org.apache.openjpa.event.RemoteCommitEvent;
|
||||
|
@ -31,6 +35,7 @@ import org.apache.openjpa.event.RemoteCommitListener;
|
|||
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.J2DoPrivHelper;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.concurrent.AbstractConcurrentEventManager;
|
||||
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashSet;
|
||||
|
@ -63,34 +68,65 @@ public abstract class AbstractQueryCache
|
|||
*/
|
||||
protected Log log;
|
||||
|
||||
protected ConcurrentHashMap<String,Long> entityTimestampMap = null;
|
||||
private boolean _closed = false;
|
||||
|
||||
protected String evictPolicy = "default";
|
||||
|
||||
public void initialize(DataCacheManager manager) {
|
||||
if(evictPolicy.equalsIgnoreCase("timestamp")) {
|
||||
entityTimestampMap = new ConcurrentHashMap<String,Long>();
|
||||
|
||||
// Get all persistence types to pre-load the entityTimestamp Map
|
||||
Collection perTypes = conf.getMetaDataRepositoryInstance().
|
||||
getPersistentTypeNames(false,
|
||||
(ClassLoader) AccessController.doPrivileged(
|
||||
J2DoPrivHelper.getContextClassLoaderAction()));
|
||||
|
||||
// Pre-load all the entity types into the HashMap to handle
|
||||
// synchronization on the map efficiently
|
||||
for (Object o : perTypes)
|
||||
entityTimestampMap.put((String)o, new Long(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void onTypesChanged(TypesChangedEvent ev) {
|
||||
writeLock();
|
||||
Collection keys = null;
|
||||
try {
|
||||
if (hasListeners())
|
||||
fireEvent(ev);
|
||||
keys = keySet();
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
|
||||
QueryKey qk;
|
||||
List removes = null;
|
||||
for (Iterator iter = keys.iterator(); iter.hasNext();) {
|
||||
qk = (QueryKey) iter.next();
|
||||
if (qk.changeInvalidatesQuery(ev.getTypes())) {
|
||||
if (removes == null)
|
||||
removes = new ArrayList();
|
||||
removes.add(qk);
|
||||
if (!evictPolicy.equalsIgnoreCase("timestamp")) {
|
||||
try {
|
||||
if (hasListeners())
|
||||
fireEvent(ev);
|
||||
keys = keySet();
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
|
||||
QueryKey qk;
|
||||
List<QueryKey> removes = null;
|
||||
for (Object o: keys) {
|
||||
qk = (QueryKey) o;
|
||||
if (qk.changeInvalidatesQuery(ev.getTypes())) {
|
||||
if (removes == null)
|
||||
removes = new ArrayList<QueryKey>();
|
||||
removes.add(qk);
|
||||
}
|
||||
}
|
||||
if (removes != null)
|
||||
removeAllInternal(removes);
|
||||
} else {
|
||||
Collection changedTypes = ev.getTypes();
|
||||
HashMap<String,Long> changedClasses =
|
||||
new HashMap<String,Long>();
|
||||
for (Object o: changedTypes) {
|
||||
String name = ((Class) o).getName();
|
||||
if(!changedClasses.containsKey(name))
|
||||
changedClasses.put(name,
|
||||
new Long(System.currentTimeMillis()));
|
||||
}
|
||||
// Now update entity timestamp map
|
||||
updateEntityTimestampMap(changedClasses);
|
||||
}
|
||||
if (removes != null)
|
||||
removeAllInternal(removes);
|
||||
}
|
||||
|
||||
public QueryResult get(QueryKey key) {
|
||||
|
@ -319,4 +355,50 @@ public abstract class AbstractQueryCache
|
|||
protected Collection newListenerCollection() {
|
||||
return new ConcurrentReferenceHashSet (ConcurrentReferenceHashSet.WEAK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the eviction policy for the query cache
|
||||
* @param evictPolicy -- String value that specifies the eviction policy
|
||||
*/
|
||||
public void setEvictPolicy(String evictPolicy) {
|
||||
this.evictPolicy = evictPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evictionPolicy for QueryCache
|
||||
* @return -- returns a String value of evictPolicy attribute
|
||||
*/
|
||||
public String getEvictPolicy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the entity timestamp map with the current time in milliseconds
|
||||
* @param timestampMap -- a map that contains entityname and its last updated timestamp
|
||||
*/
|
||||
protected void updateEntityTimestampMap(Map<String,Long> timestampMap) {
|
||||
if (entityTimestampMap != null)
|
||||
entityTimestampMap.putAll(timestampMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of timestamps in the form of Long objects
|
||||
* which are the last updated time stamps for the given entities in the
|
||||
* keylist.
|
||||
* @param keyList -- List of entity names
|
||||
* @return -- Returns a list that has the timestamp for the given entities
|
||||
*/
|
||||
public List<Long> getAllEntityTimestampFromMap(List<String> keyList) {
|
||||
ArrayList<Long> tmval = null;
|
||||
if (entityTimestampMap != null) {
|
||||
for (String s: keyList) {
|
||||
if (entityTimestampMap.containsKey(s)) {
|
||||
if(tmval == null)
|
||||
tmval = new ArrayList<Long>();
|
||||
tmval.add(entityTimestampMap.get(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmval;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,4 +137,11 @@ public class ConcurrentQueryCache
|
|||
protected Collection keySet() {
|
||||
return _cache.keySet ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the eviction policy of the query cache
|
||||
*/
|
||||
public String getEvictPolicy() {
|
||||
return super.evictPolicy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.collections.map.LinkedMap;
|
||||
|
@ -119,10 +120,34 @@ public class QueryCacheStoreQuery
|
|||
// get the cached data
|
||||
QueryResult res = _cache.get(qk);
|
||||
if (res == null)
|
||||
return null;
|
||||
return null;
|
||||
if (res.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
// this if block is invoked if the evictOnTimestamp is set to true
|
||||
if (_cache instanceof AbstractQueryCache) {
|
||||
AbstractQueryCache qcache = (AbstractQueryCache) _cache;
|
||||
if (qcache.getEvictPolicy().equalsIgnoreCase("timestamp")) {
|
||||
Set<String> classNames = qk.getAcessPathClassNames();
|
||||
List<String> keyList = new ArrayList<String>();
|
||||
keyList.addAll(classNames);
|
||||
|
||||
List<Long> timestamps =
|
||||
qcache.getAllEntityTimestampFromMap(keyList);
|
||||
long queryTS = res.getTimestamp();
|
||||
if (timestamps != null) {
|
||||
for (Long ts: timestamps) {
|
||||
// if this is true we have to evict the query
|
||||
// from cache
|
||||
if (queryTS < ts) {
|
||||
qcache.remove(qk);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int projs = getContext().getProjectionAliases().length;
|
||||
if (projs == 0) {
|
||||
// make sure the data cache contains the oids for the query result;
|
||||
|
@ -572,6 +597,7 @@ public class QueryCacheStoreQuery
|
|||
QueryResult res = null;
|
||||
synchronized (this) {
|
||||
res = new QueryResult(_qk, _data.values());
|
||||
res.setTimestamp(System.currentTimeMillis());
|
||||
}
|
||||
_cache.put(_qk, res);
|
||||
abortCaching();
|
||||
|
|
|
@ -200,6 +200,8 @@ public class QueryKey
|
|||
// since the class change framework deals with least-derived types,
|
||||
// record the least-derived access path types
|
||||
meta = metas[i];
|
||||
if (meta.getDataCache() != null)
|
||||
accessPathClassNames.add(meta.getDescribedType().getName());
|
||||
while (meta.getPCSuperclass() != null)
|
||||
meta = meta.getPCSuperclassMetaData();
|
||||
|
||||
|
@ -232,6 +234,7 @@ public class QueryKey
|
|||
if (metas[i].getDataCache() == null)
|
||||
return null;
|
||||
|
||||
accessPathClassNames.add(metas[i].getDescribedType().getName());
|
||||
subTimeout = metas[i].getDataCacheTimeout();
|
||||
if (subTimeout != -1 && subTimeout < timeout)
|
||||
timeout = subTimeout;
|
||||
|
@ -466,4 +469,12 @@ public class QueryKey
|
|||
_rangeEnd = in.readLong ();
|
||||
_timeout = in.readInt ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of the accessPathClassnames that exists in the query
|
||||
* @return -- Returns a set of accesspath classnames.
|
||||
*/
|
||||
public Set<String> getAcessPathClassNames() {
|
||||
return this._accessPathClassNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public class QueryResult
|
|||
|
||||
private final long _ex;
|
||||
|
||||
private long _timestamp = 0L;
|
||||
/**
|
||||
* Constructor; supply corresponding query key and result data.
|
||||
*/
|
||||
|
@ -64,4 +65,20 @@ public class QueryResult
|
|||
public boolean isTimedOut() {
|
||||
return _ex != -1 && _ex < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp of the query result.
|
||||
* @param ts -- Timestamp value in long
|
||||
*/
|
||||
public void setTimestamp(long ts) {
|
||||
this._timestamp = ts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp of the query result.
|
||||
* @return -- the timestamp value in long
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return this._timestamp;
|
||||
}
|
||||
}
|
||||
|
|
81
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/Part.java
vendored
Normal file
81
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/cache/Part.java
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.persistence.jdbc.query.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.apache.openjpa.persistence.DataCache;
|
||||
|
||||
@Entity
|
||||
//@MappedSuperclass
|
||||
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
|
||||
@DiscriminatorColumn(name="PARTTYPE")
|
||||
|
||||
@DataCache
|
||||
abstract public class Part {
|
||||
|
||||
@Id int partno;
|
||||
@Column(length=20)
|
||||
String name;
|
||||
int inventory;
|
||||
|
||||
@OneToMany(mappedBy="child",cascade=CascadeType.PERSIST)
|
||||
protected Collection<Usage> usedIn = new ArrayList<Usage>();
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public int getPartno() {
|
||||
return partno;
|
||||
}
|
||||
public void setPartno(int partno) {
|
||||
this.partno = partno;
|
||||
}
|
||||
public Collection<Usage> getUsedIn() {
|
||||
return usedIn;
|
||||
}
|
||||
public void setUsedIn(Collection<Usage> usedIn) {
|
||||
this.usedIn = usedIn;
|
||||
}
|
||||
public int getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
public void setInventory(int inventory) {
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.persistence.jdbc.query.cache;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToMany;
|
||||
|
||||
import org.apache.openjpa.persistence.DataCache;
|
||||
|
||||
|
||||
@Entity
|
||||
@DataCache
|
||||
public class PartBase extends Part {
|
||||
|
||||
double cost;
|
||||
double mass;
|
||||
int backOrder;
|
||||
|
||||
@ManyToMany(mappedBy="supplies")
|
||||
protected List<Supplier> suppliers = new ArrayList<Supplier>();
|
||||
|
||||
public PartBase() {}
|
||||
|
||||
public PartBase(int partno, String name, double cost, double mass){
|
||||
this.partno=partno;
|
||||
this.name = name;
|
||||
this.cost = cost;
|
||||
this.mass= mass;
|
||||
this.backOrder=0;
|
||||
this.inventory=0;
|
||||
}
|
||||
|
||||
public double getCost() {
|
||||
return cost;
|
||||
}
|
||||
|
||||
public void setCost(double cost) {
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
public double getMass() {
|
||||
return mass;
|
||||
}
|
||||
|
||||
public void setMass(double mass) {
|
||||
this.mass = mass;
|
||||
}
|
||||
|
||||
public Collection<Supplier> getSuppliers() {
|
||||
return suppliers;
|
||||
}
|
||||
|
||||
public void setSuppliers(List<Supplier> suppliers) {
|
||||
this.suppliers = suppliers;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String sup= "";
|
||||
if (getSuppliers()!=null)
|
||||
for (Supplier s : getSuppliers()){
|
||||
sup= sup+s.sid+",";
|
||||
}
|
||||
return "PartBase:"+partno+" name:+"+name+" cost:"+cost+" mass:"+mass+" supplies=["+sup+"]";
|
||||
}
|
||||
|
||||
public int getBackOrder() {
|
||||
return backOrder;
|
||||
}
|
||||
|
||||
public void setBackOrder(int backOrder) {
|
||||
this.backOrder = backOrder;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.persistence.jdbc.query.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.apache.openjpa.persistence.DataCache;
|
||||
|
||||
|
||||
@Entity
|
||||
@DataCache
|
||||
public class PartComposite extends Part {
|
||||
|
||||
double assemblyCost;
|
||||
double assemblyTime;
|
||||
double massIncrement;
|
||||
|
||||
@OneToMany( mappedBy="parent")
|
||||
Collection<Usage> partsUsed = new ArrayList<Usage>();
|
||||
|
||||
public PartComposite() {}
|
||||
|
||||
public PartComposite(int partno, String name, double asmCost, double massInc) {
|
||||
this.partno=partno;
|
||||
this.name=name;
|
||||
assemblyCost=asmCost;
|
||||
massIncrement=massInc;
|
||||
inventory=0;
|
||||
}
|
||||
|
||||
public PartComposite addSubPart(EntityManager em, int quantity, Part subpart) {
|
||||
Usage use = new Usage( this, quantity, subpart);
|
||||
em.persist(use);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getAssemblyCost() {
|
||||
return assemblyCost;
|
||||
}
|
||||
|
||||
public void setAssemblyCost(double assemblyCost) {
|
||||
this.assemblyCost = assemblyCost;
|
||||
}
|
||||
|
||||
|
||||
public double getMassIncrement() {
|
||||
return massIncrement;
|
||||
}
|
||||
|
||||
public void setMassIncrement(double massIncrement) {
|
||||
this.massIncrement = massIncrement;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
return "PartComposite:"+partno+" name:+"+name+" assemblyCost:"+assemblyCost+" massIncrement:"+massIncrement;
|
||||
}
|
||||
|
||||
public Collection<Usage> getPartsUsed() {
|
||||
return partsUsed;
|
||||
}
|
||||
|
||||
public void setPartsUsed(Collection<Usage> partsUsed) {
|
||||
this.partsUsed = partsUsed;
|
||||
}
|
||||
|
||||
public double getAssemblyTime() {
|
||||
return assemblyTime;
|
||||
}
|
||||
|
||||
public void setAssemblyTime(double assemblyTime) {
|
||||
this.assemblyTime = assemblyTime;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.persistence.jdbc.query.cache;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
import org.apache.openjpa.persistence.DataCache;
|
||||
|
||||
@Entity
|
||||
@DataCache
|
||||
|
||||
public class Supplier {
|
||||
|
||||
@Id int sid;
|
||||
@Column(length=20)
|
||||
String name;
|
||||
|
||||
@ManyToMany
|
||||
List<PartBase> supplies = new ArrayList<PartBase>();
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public Supplier(){}
|
||||
|
||||
public Supplier(int sid, String name){
|
||||
this.sid=sid;
|
||||
this.name=name;
|
||||
}
|
||||
|
||||
public Supplier addPart( PartBase p ) {
|
||||
supplies.add(p);
|
||||
p.getSuppliers().add(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public void setSid(int sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
public Collection<PartBase> getSupplies() {
|
||||
return supplies;
|
||||
}
|
||||
|
||||
public void setSupplies(List<PartBase> supplies) {
|
||||
this.supplies = supplies;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
return "Supplier:"+sid+" name:+"+name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* 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.persistence.jdbc.query.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.apache.openjpa.datacache.ConcurrentQueryCache;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
|
||||
import org.apache.openjpa.persistence.OpenJPAPersistence;
|
||||
import org.apache.openjpa.persistence.QueryResultCacheImpl;
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
import org.apache.openjpa.util.CacheMap;
|
||||
|
||||
public class TestQueryTimestampEviction extends SingleEMFTestCase {
|
||||
public void setUp() throws Exception {
|
||||
super.setUp(Part.class, PartBase.class, PartComposite.class,
|
||||
Supplier.class, Usage.class,
|
||||
"openjpa.DataCache", "true",
|
||||
"openjpa.QueryCache",
|
||||
"CacheSize=1000, evictPolicy='timestamp'",
|
||||
"openjpa.RemoteCommitProvider", "sjvm");
|
||||
|
||||
if (recreateData) {
|
||||
// deletes any data leftover data in the database due to the failed
|
||||
// last run of this testcase
|
||||
deleteAllData();
|
||||
reCreateData();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean deleteData = false;
|
||||
private boolean recreateData = true;
|
||||
|
||||
public void testLoadQueries() {
|
||||
|
||||
loadQueryCache();
|
||||
int cacheSizeBeforeUpdate = queryCacheGet();
|
||||
updateAnEntity();
|
||||
int cacheSizeAfterUpdate = queryCacheGet();
|
||||
|
||||
// If evictPolicy is timestamp the querycache size should be equal to
|
||||
// cacheSizeBeforeUpdate value.
|
||||
String evictPolicy = getQueryCache().getEvictPolicy();
|
||||
|
||||
if(evictPolicy.equalsIgnoreCase("timestamp"))
|
||||
assertEquals(cacheSizeBeforeUpdate, cacheSizeAfterUpdate);
|
||||
|
||||
this.recreateData = false;
|
||||
}
|
||||
|
||||
public void testEviction() {
|
||||
loadQueryCache();
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
updateAnEntity();
|
||||
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
String insert1 = "insert into part(partno,parttype,name,cost,mass)" +
|
||||
" values(13,'PartBase','breakes',1000.0,100.0)";
|
||||
em.createNativeQuery(insert1).executeUpdate();
|
||||
String insert2 = "insert into supplier_part(suppliers_sid," +
|
||||
"supplies_partno) values(1,13)";
|
||||
em.createNativeQuery(insert2).executeUpdate();
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
String sql = "select partno from part where cost > 120 ";
|
||||
Query nativeq = em.createNativeQuery(sql);
|
||||
List nativelist = nativeq.getResultList();
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
Query q = em.createQuery("select p from PartBase p where p.cost>?1");
|
||||
q.setParameter(1, new Double(120));
|
||||
List jpalist = q.getResultList();
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
// The resultlist of nativelist and jpalist should be the same
|
||||
// in both eviction policies(dafault/timestamp)
|
||||
assertEquals(nativelist.size(),jpalist.size());
|
||||
|
||||
this.deleteData = true;
|
||||
this.recreateData = true;
|
||||
}
|
||||
|
||||
private void loadQueryCache() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
String qry = "select p from PartBase p where p.cost > ?1";
|
||||
for (int i=120; i<155; i++) {
|
||||
Query q = em.createQuery(qry);
|
||||
q.setParameter(1, new Double(i));
|
||||
q.getResultList();
|
||||
}
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
private void updateAnEntity() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
//Update entity
|
||||
PartBase p = em.find(PartBase.class,11);
|
||||
double oldcost = p.getCost();
|
||||
if (p != null)
|
||||
p.setCost((oldcost + 10.0));
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
private ConcurrentQueryCache getQueryCache() {
|
||||
OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf);
|
||||
QueryResultCacheImpl scache = (QueryResultCacheImpl) oemf.
|
||||
getQueryResultCache();
|
||||
|
||||
return (ConcurrentQueryCache ) scache.getDelegate();
|
||||
}
|
||||
|
||||
private int queryCacheGet() {
|
||||
ConcurrentQueryCache dcache = getQueryCache();
|
||||
CacheMap map = dcache.getCacheMap();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
if (deleteData)
|
||||
deleteAllData();
|
||||
}
|
||||
|
||||
private void reCreateData() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
Supplier s1 = new Supplier(1, "S1");
|
||||
em.persist(s1);
|
||||
Supplier s2 = new Supplier(2, "S2");
|
||||
em.persist(s2);
|
||||
Supplier s3 = new Supplier(3, "S3");
|
||||
em.persist(s3);
|
||||
|
||||
PartBase p1 = new PartBase(10, "Wheel", 150, 15.00);
|
||||
em.persist(p1);
|
||||
PartBase p2 = new PartBase(11, "Frame", 550.00, 25.00);
|
||||
em.persist(p2);
|
||||
PartBase p3 = new PartBase(12, "HandleBar", 125.00, 80.00);
|
||||
em.persist(p3);
|
||||
|
||||
s1.addPart(p1).addPart(p2).addPart(p3);
|
||||
s2.addPart(p1).addPart(p3);
|
||||
|
||||
PartComposite p4 = new PartComposite(20, "Bike", 180, 1.0);
|
||||
em.persist(p4);
|
||||
p4.addSubPart(em, 2, p1).addSubPart(em, 1, p2).addSubPart(em, 1, p3);
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
private void deleteAllData() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
em.createNativeQuery("delete from supplier_part").executeUpdate();
|
||||
em.createQuery("delete from PartBase s").executeUpdate();
|
||||
em.createQuery("delete from Supplier s").executeUpdate();
|
||||
em.createQuery("delete from Usage u").executeUpdate();
|
||||
em.createQuery("delete from Part p").executeUpdate();
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.persistence.jdbc.query.cache;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
import org.apache.openjpa.persistence.DataCache;
|
||||
|
||||
@Entity
|
||||
@DataCache(timeout=100000)
|
||||
|
||||
public class Usage {
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
int id;
|
||||
int quantity;
|
||||
|
||||
@ManyToOne
|
||||
Part child;
|
||||
@ManyToOne
|
||||
PartComposite parent ;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
|
||||
public Usage(PartComposite p, int quantity, Part subpart) {
|
||||
parent=p;
|
||||
this.quantity=quantity;
|
||||
parent.getPartsUsed().add(this);
|
||||
setChild(subpart);
|
||||
subpart.getUsedIn().add(this);
|
||||
}
|
||||
|
||||
// JPA entity needs a public no-arg constructor !
|
||||
public Usage() {}
|
||||
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Part getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(PartComposite parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(int quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public Part getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public void setChild(Part child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Usage:"+id+" quantity:"+quantity+" child:"+child.getPartno()+" parent"+parent.getPartno();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue