mirror of https://github.com/apache/openjpa.git
OPENJPA-263 : Introducing getAll(List) method for data cache to be called by loadAll()
will allow data cache plug-ins to leverage the advantage of any third-party cache that provides a way to get multiple object in one call by providing a list of keys (oids). git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@558125 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a5d1acd44e
commit
168c0076c8
|
@ -21,7 +21,10 @@ package org.apache.openjpa.datacache;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||||
import org.apache.openjpa.event.RemoteCommitEvent;
|
import org.apache.openjpa.event.RemoteCommitEvent;
|
||||||
|
@ -439,4 +442,14 @@ public abstract class AbstractDataCache
|
||||||
log.warn(s_loc.get("exp-listener-ex"), e);
|
log.warn(s_loc.get("exp-listener-ex"), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the objects for the given key List.
|
||||||
|
*/
|
||||||
|
public Map getAll(List keys) {
|
||||||
|
Map resultMap = new HashMap(keys.size());
|
||||||
|
for(int i=0; i<keys.size(); i++)
|
||||||
|
resultMap.put(keys.get(i), get(keys.get(i)));
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.openjpa.datacache;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.openjpa.lib.util.Closeable;
|
import org.apache.openjpa.lib.util.Closeable;
|
||||||
|
@ -258,4 +259,9 @@ public interface DataCache
|
||||||
* Free the resources used by this cache.
|
* Free the resources used by this cache.
|
||||||
*/
|
*/
|
||||||
public void close ();
|
public void close ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns objects from the caches for a given list of keys
|
||||||
|
*/
|
||||||
|
public Map getAll(List keys);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.apache.openjpa.kernel.StoreManager;
|
||||||
import org.apache.openjpa.kernel.StoreQuery;
|
import org.apache.openjpa.kernel.StoreQuery;
|
||||||
import org.apache.openjpa.meta.ClassMetaData;
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
import org.apache.openjpa.meta.MetaDataRepository;
|
import org.apache.openjpa.meta.MetaDataRepository;
|
||||||
|
import org.apache.openjpa.util.OpenJPAId;
|
||||||
import org.apache.openjpa.util.OptimisticException;
|
import org.apache.openjpa.util.OptimisticException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -409,6 +410,8 @@ public class DataCacheStoreManager
|
||||||
return super.loadAll(sms, state, load, fetch, edata);
|
return super.loadAll(sms, state, load, fetch, edata);
|
||||||
|
|
||||||
Map unloaded = null;
|
Map unloaded = null;
|
||||||
|
List smList = null;
|
||||||
|
Map caches = new HashMap();
|
||||||
OpenJPAStateManager sm;
|
OpenJPAStateManager sm;
|
||||||
DataCache cache;
|
DataCache cache;
|
||||||
DataCachePCData data;
|
DataCachePCData data;
|
||||||
|
@ -422,29 +425,58 @@ public class DataCacheStoreManager
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sm.getManagedInstance() == null) {
|
if (sm.getManagedInstance() == null
|
||||||
data = cache.get(sm.getObjectId());
|
|| load != FORCE_LOAD_NONE
|
||||||
if (data != null) {
|
|
||||||
//### the 'data.type' access here probably needs
|
|
||||||
//### to be addressed for bug 511
|
|
||||||
sm.initialize(data.getType(), state);
|
|
||||||
data.load(sm, fetch, edata);
|
|
||||||
} else
|
|
||||||
unloaded = addUnloaded(sm, null, unloaded);
|
|
||||||
} else if (load != FORCE_LOAD_NONE
|
|
||||||
|| sm.getPCState() == PCState.HOLLOW) {
|
|| sm.getPCState() == PCState.HOLLOW) {
|
||||||
data = cache.get(sm.getObjectId());
|
smList = (List) caches.get(cache);
|
||||||
if (data != null) {
|
if (smList == null) {
|
||||||
// load unloaded fields
|
smList = new ArrayList();
|
||||||
fields = sm.getUnloaded(fetch);
|
caches.put(cache, smList);
|
||||||
data.load(sm, fields, fetch, edata);
|
}
|
||||||
if (fields.length() > 0)
|
smList.add(sm);
|
||||||
unloaded = addUnloaded(sm, fields, unloaded);
|
|
||||||
} else
|
|
||||||
unloaded = addUnloaded(sm, null, unloaded);
|
|
||||||
} else if (!cache.contains(sm.getObjectId()))
|
} else if (!cache.contains(sm.getObjectId()))
|
||||||
unloaded = addUnloaded(sm, null, unloaded);
|
unloaded = addUnloaded(sm, null, unloaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Iterator itr = caches.keySet().iterator(); itr.hasNext();) {
|
||||||
|
cache = (DataCache) itr.next();
|
||||||
|
smList = (List) caches.get(cache);
|
||||||
|
List oidList = new ArrayList(smList.size());
|
||||||
|
|
||||||
|
for (itr=smList.iterator();itr.hasNext();) {
|
||||||
|
sm = (OpenJPAStateManager) itr.next();
|
||||||
|
oidList.add((OpenJPAId) sm.getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map dataMap = cache.getAll(oidList);
|
||||||
|
|
||||||
|
for (itr=smList.iterator();itr.hasNext();) {
|
||||||
|
sm = (OpenJPAStateManager) itr.next();
|
||||||
|
data = (DataCachePCData) dataMap.get(
|
||||||
|
(OpenJPAId) sm.getObjectId());
|
||||||
|
|
||||||
|
if (sm.getManagedInstance() == null) {
|
||||||
|
if (data != null) {
|
||||||
|
//### the 'data.type' access here probably needs
|
||||||
|
//### to be addressed for bug 511
|
||||||
|
sm.initialize(data.getType(), state);
|
||||||
|
data.load(sm, fetch, edata);
|
||||||
|
} else
|
||||||
|
unloaded = addUnloaded(sm, null, unloaded);
|
||||||
|
} else if (load != FORCE_LOAD_NONE
|
||||||
|
|| sm.getPCState() == PCState.HOLLOW) {
|
||||||
|
data = cache.get(sm.getObjectId());
|
||||||
|
if (data != null) {
|
||||||
|
// load unloaded fields
|
||||||
|
fields = sm.getUnloaded(fetch);
|
||||||
|
data.load(sm, fields, fetch, edata);
|
||||||
|
if (fields.length() > 0)
|
||||||
|
unloaded = addUnloaded(sm, fields, unloaded);
|
||||||
|
} else
|
||||||
|
unloaded = addUnloaded(sm, null, unloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (unloaded == null)
|
if (unloaded == null)
|
||||||
return Collections.EMPTY_LIST;
|
return Collections.EMPTY_LIST;
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.openjpa.datacache;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang.ObjectUtils;
|
import org.apache.commons.lang.ObjectUtils;
|
||||||
import org.apache.openjpa.util.RuntimeExceptionTranslator;
|
import org.apache.openjpa.util.RuntimeExceptionTranslator;
|
||||||
|
@ -333,4 +335,14 @@ public class DelegatingDataCache
|
||||||
throw translate(re);
|
throw translate(re);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map getAll(List keys) {
|
||||||
|
if (_cache == null)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
return _cache.getAll(keys);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
throw translate(re);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,9 +75,8 @@ public abstract class AbstractPCData
|
||||||
case JavaTypes.COLLECTION:
|
case JavaTypes.COLLECTION:
|
||||||
ProxyDataList c = (ProxyDataList) data;
|
ProxyDataList c = (ProxyDataList) data;
|
||||||
Collection c2 = (Collection) sm.newFieldProxy(fmd.getIndex());
|
Collection c2 = (Collection) sm.newFieldProxy(fmd.getIndex());
|
||||||
for (int i = 0; i < c.size(); i++)
|
c2 = toNestedFields(sm, fmd.getElement(), (Collection) data,
|
||||||
c2.add(toNestedField(sm, fmd.getElement(), c.get(i),
|
fetch, context);
|
||||||
fetch, context));
|
|
||||||
if (c2 instanceof Proxy) {
|
if (c2 instanceof Proxy) {
|
||||||
ChangeTracker ct = ((Proxy) c2).getChangeTracker();
|
ChangeTracker ct = ((Proxy) c2).getChangeTracker();
|
||||||
if (ct != null)
|
if (ct != null)
|
||||||
|
@ -87,17 +86,18 @@ public abstract class AbstractPCData
|
||||||
case JavaTypes.MAP:
|
case JavaTypes.MAP:
|
||||||
Map m = (Map) data;
|
Map m = (Map) data;
|
||||||
Map m2 = (Map) sm.newFieldProxy(fmd.getIndex());
|
Map m2 = (Map) sm.newFieldProxy(fmd.getIndex());
|
||||||
Map.Entry e;
|
Collection keys = new ArrayList (m.size());
|
||||||
Object key;
|
|
||||||
Object value;
|
for (Iterator mi = m.entrySet().iterator(); mi.hasNext();)
|
||||||
for (Iterator mi = m.entrySet().iterator(); mi.hasNext();) {
|
keys.add(mi.next());
|
||||||
e = (Map.Entry) mi.next();
|
|
||||||
key = toNestedField(sm, fmd.getKey(), e.getKey(),
|
Object[] keyArray = keys.toArray();
|
||||||
fetch, context);
|
Object[] values = toNestedFields(sm, fmd.getElement(),
|
||||||
value = toNestedField(sm, fmd.getElement(), e.getValue(),
|
keys, fetch, context).toArray();
|
||||||
fetch, context);
|
int idx = 0;
|
||||||
m2.put(key, value);
|
for (Iterator mi = m.entrySet().iterator(); mi.hasNext(); idx++)
|
||||||
}
|
m2.put(keyArray[idx], values[idx]);
|
||||||
|
|
||||||
return m2;
|
return m2;
|
||||||
case JavaTypes.ARRAY:
|
case JavaTypes.ARRAY:
|
||||||
int length = Array.getLength(data);
|
int length = Array.getLength(data);
|
||||||
|
@ -151,6 +151,51 @@ public abstract class AbstractPCData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the given data value to its field value. The data value
|
||||||
|
* may be a key, value, or element of a map or collection.
|
||||||
|
*/
|
||||||
|
protected Collection toNestedFields(OpenJPAStateManager sm,
|
||||||
|
ValueMetaData vmd, Collection data, FetchConfiguration fetch,
|
||||||
|
Object context) {
|
||||||
|
if (data == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Collection ret = new ArrayList(data.size());
|
||||||
|
switch (vmd.getDeclaredTypeCode()) {
|
||||||
|
case JavaTypes.DATE:
|
||||||
|
for (Iterator itr=data.iterator(); itr.hasNext();)
|
||||||
|
ret.add(((Date)itr.next()).clone());
|
||||||
|
return ret;
|
||||||
|
case JavaTypes.LOCALE:
|
||||||
|
for (Iterator itr=data.iterator(); itr.hasNext();)
|
||||||
|
ret.add((Locale) itr.next());
|
||||||
|
return ret;
|
||||||
|
case JavaTypes.PC:
|
||||||
|
if (vmd.isEmbedded())
|
||||||
|
for (Iterator itr=data.iterator(); itr.hasNext();)
|
||||||
|
ret.add(toEmbeddedField(sm, vmd, itr.next(), fetch
|
||||||
|
, context));
|
||||||
|
// no break
|
||||||
|
case JavaTypes.PC_UNTYPED:
|
||||||
|
Object[] r = toRelationFields(sm, data, fetch);
|
||||||
|
if (r != null) {
|
||||||
|
for (int i = 0; i < r.length; i++)
|
||||||
|
if (r[i] != null)
|
||||||
|
ret.add(r[i]);
|
||||||
|
else {
|
||||||
|
ret.add(sm.getContext().getConfiguration().
|
||||||
|
getOrphanedKeyActionInstance().
|
||||||
|
orphan(data, sm, vmd));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the given data into a relation field value. Default
|
* Transform the given data into a relation field value. Default
|
||||||
* implementation assumes the data is an oid.
|
* implementation assumes the data is an oid.
|
||||||
|
@ -160,6 +205,15 @@ public abstract class AbstractPCData
|
||||||
return sm.getContext().find(data, fetch, null, null, 0);
|
return sm.getContext().find(data, fetch, null, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the given data into relation field values. Default
|
||||||
|
* implementation assumes the data is an oid.
|
||||||
|
*/
|
||||||
|
protected Object[] toRelationFields(OpenJPAStateManager sm,
|
||||||
|
Object data, FetchConfiguration fetch) {
|
||||||
|
return sm.getContext().findAll((Collection) data, fetch, null, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the given data into an embedded PC field value. Default
|
* Transform the given data into an embedded PC field value. Default
|
||||||
* implementation assumes the data is an {@link AbstractPCData}.
|
* implementation assumes the data is an {@link AbstractPCData}.
|
||||||
|
|
|
@ -184,6 +184,7 @@ public class BrokerImpl
|
||||||
private Set _updatedClss = null;
|
private Set _updatedClss = null;
|
||||||
private Set _deletedClss = null;
|
private Set _deletedClss = null;
|
||||||
private Set _pending = null;
|
private Set _pending = null;
|
||||||
|
private int findAllDepth = 0;
|
||||||
|
|
||||||
// track instances that become transactional after the first savepoint
|
// track instances that become transactional after the first savepoint
|
||||||
// (the first uses the transactional cache)
|
// (the first uses the transactional cache)
|
||||||
|
@ -903,6 +904,8 @@ public class BrokerImpl
|
||||||
*/
|
*/
|
||||||
protected Object[] findAll(Collection oids, FetchConfiguration fetch,
|
protected Object[] findAll(Collection oids, FetchConfiguration fetch,
|
||||||
BitSet exclude, Object edata, int flags, FindCallbacks call) {
|
BitSet exclude, Object edata, int flags, FindCallbacks call) {
|
||||||
|
findAllDepth ++;
|
||||||
|
|
||||||
// throw any exceptions for null oids up immediately
|
// throw any exceptions for null oids up immediately
|
||||||
if (oids == null)
|
if (oids == null)
|
||||||
throw new NullPointerException("oids == null");
|
throw new NullPointerException("oids == null");
|
||||||
|
@ -912,7 +915,9 @@ public class BrokerImpl
|
||||||
// we have to use a map of oid->sm rather than a simple
|
// we have to use a map of oid->sm rather than a simple
|
||||||
// array, so that we make sure not to create multiple sms for equivalent
|
// array, so that we make sure not to create multiple sms for equivalent
|
||||||
// oids if the user has duplicates in the given array
|
// oids if the user has duplicates in the given array
|
||||||
_loading = new HashMap((int) (oids.size() * 1.33 + 1));
|
if (_loading == null)
|
||||||
|
_loading = new HashMap((int) (oids.size() * 1.33 + 1));
|
||||||
|
|
||||||
if (call == null)
|
if (call == null)
|
||||||
call = this;
|
call = this;
|
||||||
if (fetch == null)
|
if (fetch == null)
|
||||||
|
@ -1007,7 +1012,9 @@ public class BrokerImpl
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
throw new GeneralException(re);
|
throw new GeneralException(re);
|
||||||
} finally {
|
} finally {
|
||||||
_loading = null;
|
findAllDepth--;
|
||||||
|
if (findAllDepth == 0)
|
||||||
|
_loading = null;
|
||||||
endOperation();
|
endOperation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,7 @@ public class PCDataImpl
|
||||||
loadImplData(sm);
|
loadImplData(sm);
|
||||||
|
|
||||||
FieldMetaData[] fmds = sm.getMetaData().getFields();
|
FieldMetaData[] fmds = sm.getMetaData().getFields();
|
||||||
|
((StateManagerImpl)sm).setLoading(true);
|
||||||
for (int i = 0; i < fmds.length; i++) {
|
for (int i = 0; i < fmds.length; i++) {
|
||||||
// load intermediate data for all unloaded fields and data for
|
// load intermediate data for all unloaded fields and data for
|
||||||
// fields in configured fetch groups
|
// fields in configured fetch groups
|
||||||
|
|
Loading…
Reference in New Issue