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:
David J. Wisneski 2007-07-20 20:37:08 +00:00
parent a5d1acd44e
commit 168c0076c8
7 changed files with 160 additions and 35 deletions

View File

@ -21,7 +21,10 @@ package org.apache.openjpa.datacache;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.event.RemoteCommitEvent;
@ -439,4 +442,14 @@ public abstract class AbstractDataCache
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;
}
}

View File

@ -20,6 +20,7 @@ package org.apache.openjpa.datacache;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.openjpa.lib.util.Closeable;
@ -258,4 +259,9 @@ public interface DataCache
* Free the resources used by this cache.
*/
public void close ();
/**
* returns objects from the caches for a given list of keys
*/
public Map getAll(List keys);
}

View File

@ -41,6 +41,7 @@ import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.kernel.StoreQuery;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.util.OpenJPAId;
import org.apache.openjpa.util.OptimisticException;
/**
@ -409,6 +410,8 @@ public class DataCacheStoreManager
return super.loadAll(sms, state, load, fetch, edata);
Map unloaded = null;
List smList = null;
Map caches = new HashMap();
OpenJPAStateManager sm;
DataCache cache;
DataCachePCData data;
@ -422,30 +425,59 @@ public class DataCacheStoreManager
continue;
}
if (sm.getManagedInstance() == null) {
data = cache.get(sm.getObjectId());
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
if (sm.getManagedInstance() == null
|| 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);
smList = (List) caches.get(cache);
if (smList == null) {
smList = new ArrayList();
caches.put(cache, smList);
}
smList.add(sm);
} else if (!cache.contains(sm.getObjectId()))
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)
return Collections.EMPTY_LIST;

View File

@ -20,6 +20,8 @@ package org.apache.openjpa.datacache;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
@ -333,4 +335,14 @@ public class DelegatingDataCache
throw translate(re);
}
}
public Map getAll(List keys) {
if (_cache == null)
return null;
try {
return _cache.getAll(keys);
} catch (RuntimeException re) {
throw translate(re);
}
}
}

View File

@ -75,9 +75,8 @@ public abstract class AbstractPCData
case JavaTypes.COLLECTION:
ProxyDataList c = (ProxyDataList) data;
Collection c2 = (Collection) sm.newFieldProxy(fmd.getIndex());
for (int i = 0; i < c.size(); i++)
c2.add(toNestedField(sm, fmd.getElement(), c.get(i),
fetch, context));
c2 = toNestedFields(sm, fmd.getElement(), (Collection) data,
fetch, context);
if (c2 instanceof Proxy) {
ChangeTracker ct = ((Proxy) c2).getChangeTracker();
if (ct != null)
@ -87,17 +86,18 @@ public abstract class AbstractPCData
case JavaTypes.MAP:
Map m = (Map) data;
Map m2 = (Map) sm.newFieldProxy(fmd.getIndex());
Map.Entry e;
Object key;
Object value;
for (Iterator mi = m.entrySet().iterator(); mi.hasNext();) {
e = (Map.Entry) mi.next();
key = toNestedField(sm, fmd.getKey(), e.getKey(),
fetch, context);
value = toNestedField(sm, fmd.getElement(), e.getValue(),
fetch, context);
m2.put(key, value);
}
Collection keys = new ArrayList (m.size());
for (Iterator mi = m.entrySet().iterator(); mi.hasNext();)
keys.add(mi.next());
Object[] keyArray = keys.toArray();
Object[] values = toNestedFields(sm, fmd.getElement(),
keys, fetch, context).toArray();
int idx = 0;
for (Iterator mi = m.entrySet().iterator(); mi.hasNext(); idx++)
m2.put(keyArray[idx], values[idx]);
return m2;
case JavaTypes.ARRAY:
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
* implementation assumes the data is an oid.
@ -160,6 +205,15 @@ public abstract class AbstractPCData
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
* implementation assumes the data is an {@link AbstractPCData}.

View File

@ -184,6 +184,7 @@ public class BrokerImpl
private Set _updatedClss = null;
private Set _deletedClss = null;
private Set _pending = null;
private int findAllDepth = 0;
// track instances that become transactional after the first savepoint
// (the first uses the transactional cache)
@ -903,6 +904,8 @@ public class BrokerImpl
*/
protected Object[] findAll(Collection oids, FetchConfiguration fetch,
BitSet exclude, Object edata, int flags, FindCallbacks call) {
findAllDepth ++;
// throw any exceptions for null oids up immediately
if (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
// array, so that we make sure not to create multiple sms for equivalent
// 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)
call = this;
if (fetch == null)
@ -1007,7 +1012,9 @@ public class BrokerImpl
} catch (RuntimeException re) {
throw new GeneralException(re);
} finally {
_loading = null;
findAllDepth--;
if (findAllDepth == 0)
_loading = null;
endOperation();
}
}

View File

@ -136,6 +136,7 @@ public class PCDataImpl
loadImplData(sm);
FieldMetaData[] fmds = sm.getMetaData().getFields();
((StateManagerImpl)sm).setLoading(true);
for (int i = 0; i < fmds.length; i++) {
// load intermediate data for all unloaded fields and data for
// fields in configured fetch groups