You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ol...@apache.org on 2003/08/25 21:28:27 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/otm/util IdentityHashMap.java IdentityMapFactory.java

olegnitz    2003/08/25 12:28:27

  Modified:    src/java/org/apache/ojb/broker/accesslayer
                        CollectionPrefetcher.java ReferencePrefetcher.java
                        RelationshipPrefetcherImpl.java RsIterator.java
               src/java/org/apache/ojb/broker/core
                        PersistenceBrokerImpl.java
               src/java/org/apache/ojb/otm/copy
                        MetadataObjectCopyStrategy.java
                        ReflectiveObjectCopyStrategy.java
  Added:       src/java/org/apache/ojb/broker/util IdentityHashMap.java
                        IdentityMapFactory.java
  Removed:     src/java/org/apache/ojb/otm/util IdentityHashMap.java
                        IdentityMapFactory.java
  Log:
  Optimization of retriaval operations via gathering them into batches, see details in the ojb-dev mailing list
  
  Revision  Changes    Path
  1.14      +104 -46   db-ojb/src/java/org/apache/ojb/broker/accesslayer/CollectionPrefetcher.java
  
  Index: CollectionPrefetcher.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/CollectionPrefetcher.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- CollectionPrefetcher.java	24 May 2003 23:58:20 -0000	1.13
  +++ CollectionPrefetcher.java	25 Aug 2003 19:28:27 -0000	1.14
  @@ -54,11 +54,15 @@
    * <http://www.apache.org/>.
    */
   
  +import java.lang.reflect.Array;
   import java.util.ArrayList;
   import java.util.Collection;
   import java.util.Iterator;
  +import java.util.HashMap;
   
   import org.apache.ojb.broker.Identity;
  +import org.apache.ojb.broker.ManageableCollection;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
  @@ -71,6 +75,7 @@
   import org.apache.ojb.broker.query.Query;
   import org.apache.ojb.broker.query.QueryByCriteria;
   import org.apache.ojb.broker.query.QueryFactory;
  +import org.apache.ojb.broker.util.collections.RemovalAwareCollection;
   
   /**
    * Relationship Prefetcher for Collections.
  @@ -92,6 +97,34 @@
       }
   
       /**
  +     * Build the multiple queries for one relationship because of limitation of IN(...)
  +     * @param owners Collection containing all objects of the ONE side
  +     */
  +    protected Query[] buildPrefetchQueries(Collection owners)
  +    {
  +        Collection queries = new ArrayList();
  +        Collection ownerSubset = new ArrayList();
  +        Iterator iter = owners.iterator();
  +        
  +        while (iter.hasNext())
  +        {
  +            ownerSubset.add(iter.next());
  +            if (ownerSubset.size() == pkLimit)
  +            {
  +                queries.add(buildPrefetchQuery(ownerSubset));
  +                ownerSubset.clear();
  +            }
  +        }
  +
  +        if (ownerSubset.size() > 0)
  +        {
  +            queries.add(buildPrefetchQuery(ownerSubset));
  +        }
  +
  +        return (Query[]) queries.toArray(new Query[queries.size()]);
  +    }
  +    
  +    /**
        * Build the query to perform a batched read get orderBy settings from
        * CollectionDescriptor
        * @param owners Collection containing all objects of the ONE side
  @@ -136,7 +169,7 @@
       private Criteria buildPrefetchCriteriaSingleKey(Collection owners, FieldDescriptor fkField)
       {
           Criteria crit = new Criteria();
  -        Collection pkValues = new ArrayList();
  +        ArrayList pkValues = new ArrayList();
           Iterator iter = owners.iterator();
           Object pkVal;
           Object owner;
  @@ -149,10 +182,17 @@
               pkValues.add(pkVal);
           }
   
  -        // create IN (...) for the single key field
  -        if (!pkValues.isEmpty())
  +        switch (pkValues.size())
           {
  -            crit.addIn(fkField.getAttributeName(), pkValues);
  +            case 0:
  +                break;
  +            case 1:
  +                crit.addEqualTo(fkField.getAttributeName(), pkValues.get(0));
  +                break;
  +            default:
  +                // create IN (...) for the single key field
  +                crit.addIn(fkField.getAttributeName(), pkValues);
  +                break;
           }
   
           return crit;
  @@ -196,69 +236,87 @@
        */
       protected void associateBatched(Collection owners, Collection children)
       {
  +        CollectionDescriptor cds = getCollectionDescriptor();
           ClassDescriptor cld = getItemClassDescriptor();
           Iterator iter = children.iterator();
  -        PersistentField field = getObjectReferenceDescriptor().getPersistentField();
  -        Class ownerClass = getBroker().getTopLevelClass(getOwnerClassDescriptor().getClassOfObject());
  +        PersistentField field = cds.getPersistentField();
  +        PersistenceBroker pb = getBroker();
  +        ClassDescriptor ownerCld = getOwnerClassDescriptor();
  +        Class ownerClass = pb.getTopLevelClass(ownerCld.getClassOfObject());
  +        // this collection type will be used:
  +        Class collectionClass = cds.getCollectionClass();
           Object owner, relatedObject;
           Object fkValues[];
           Identity id;
  +        HashMap ownerIdsToLists = new HashMap();
  +        ArrayList list;
  +        Object result;
  +
  +        // ensure that all owners will get non-null collections
  +        iter = owners.iterator();
  +        while (iter.hasNext())
  +        {
  +            id = new Identity(iter.next(), pb);
  +            ownerIdsToLists.put(id, new ArrayList());
  +        }
   
  +        iter = children.iterator();
           while (iter.hasNext())
           {
               relatedObject = iter.next();
  -            fkValues = getObjectReferenceDescriptor().getForeignKeyValues(relatedObject, cld);
  -            id = new Identity(getOwnerClassDescriptor().getClassOfObject(), ownerClass, fkValues);
  -            owner = getBroker().getObjectByIdentity(id);
  +            fkValues = cds.getForeignKeyValues(relatedObject, cld);
  +            id = new Identity(ownerCld.getClassOfObject(), ownerClass, fkValues);
  +            list = (ArrayList) ownerIdsToLists.get(id);
  +
  +            // BRJ: do not add object if it's already in the list
  +            if (!list.contains(relatedObject))
  +            {
  +                list.add(relatedObject);
  +            }
  +        }
   
  -            if (Collection.class.isAssignableFrom(field.getType()))
  +        for (Iterator it = ownerIdsToLists.keySet().iterator(); it.hasNext(); )
  +        {
  +            id = (Identity) it.next();
  +            list = (ArrayList) ownerIdsToLists.get(id);
  +            owner = pb.getObjectByIdentity(id);
  +            if ((collectionClass == null)
  +                && field.getType().isArray())
               {
  -                Collection relatedData = (Collection) field.get(owner);
  -                if (relatedData == null)
  +                int length = list.size();
  +                Class itemtype = field.getType().getComponentType();
  +                result = Array.newInstance(itemtype, length);
  +                for (int j = 0; j < length; j++)
  +                {
  +                    Array.set(result, j, list.get(j));
  +                }
  +            }
  +            else
  +            {
  +                ManageableCollection col;
  +
  +                if (collectionClass == null)
  +                {
  +                    col = new RemovalAwareCollection();
  +                }
  +                else
                   {
                       try
                       {
  -                        // instantiate and set the owners collection
  -                        relatedData = (Collection) children.getClass().newInstance();
  -                        field.set(owner, relatedData);
  +                        col = (ManageableCollection) collectionClass.newInstance();
                       }
                       catch (Exception e)
                       {
  -                        getLogger().error("Can't create new Collection for owner", e);
  +                        throw new OJBRuntimeException("Can't create new Collection for owner", e);
                       }
                   }
  -
  -                // BRJ: do not add object if it's already in the list
  -                if (!relatedData.contains(relatedObject))
  +                for (Iterator it2 = list.iterator(); it2.hasNext(); )
                   {
  -                    relatedData.add(relatedObject);
  +                    col.ojbAdd(it2.next());
                   }
  +                result = col;
               }
  -            else
  -            {
  -                getLogger().error("Prefetch works with Collections only");
  -            }
  -        }
  -    }
  -
  -    /**
  -     * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#prefetchRelationship(Collection)
  -     */
  -    public void prefetchRelationship(Collection owners)
  -    {
  -        PersistentField f = getObjectReferenceDescriptor().getPersistentField();
  -
  -        if (f.getType().isArray())
  -        {
  -            throw new PersistenceBrokerException("Prefetch does not yet work with Arrays: '" + f.getName() + "'");
  -        }
  -        if (getCollectionDescriptor().isLazy())
  -        {
  -            getLogger().warn("Prefetching a proxied collection does not make sense: '" + f.getName() + "'");
  -        }
  -        else
  -        {
  -            super.prefetchRelationship(owners);
  +            field.set(owner, result);
           }
       }
   
  
  
  
  1.6       +61 -17    db-ojb/src/java/org/apache/ojb/broker/accesslayer/ReferencePrefetcher.java
  
  Index: ReferencePrefetcher.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/ReferencePrefetcher.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ReferencePrefetcher.java	24 May 2003 23:58:20 -0000	1.5
  +++ ReferencePrefetcher.java	25 Aug 2003 19:28:27 -0000	1.6
  @@ -56,10 +56,12 @@
   
   import java.util.ArrayList;
   import java.util.Collection;
  +import java.util.HashSet;
   import java.util.Iterator;
   
   import org.apache.ojb.broker.Identity;
   import org.apache.ojb.broker.PersistenceBroker;
  +import org.apache.ojb.broker.cache.ObjectCache;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.FieldDescriptor;
   import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
  @@ -112,10 +114,52 @@
   		}
   	}
   
  -	/**
  +    /**
  +     * Build the multiple queries for one relationship because of limitation of IN(...)
  +     * @param owners Collection containing all objects of the ONE side
  +     */
  +    protected Query[] buildPrefetchQueries(Collection owners)
  +    {
  +        ClassDescriptor cld = getOwnerClassDescriptor();
  +        ObjectReferenceDescriptor ord = getObjectReferenceDescriptor();
  +        Collection queries = new ArrayList();
  +        Collection idsSubset = new HashSet();
  +        Iterator iter = owners.iterator();
  +        Class topLevelClass = getBroker().getTopLevelClass(ord.getItemClass());
  +        Class realClass = ord.getItemClass();
  +        Object[] fkValues;
  +        Object owner;
  +        Identity id;
  +        ObjectCache cache = getBroker().serviceObjectCache();
  +
  +        while (iter.hasNext())
  +        {
  +            owner = iter.next();
  +            fkValues = ord.getForeignKeyValues(owner,cld);
  +            id = new Identity(realClass, topLevelClass, fkValues);
  +            if (cache.lookup(id) == null)
  +            {
  +                idsSubset.add(id);
  +            }
  +            if (idsSubset.size() == pkLimit)
  +            {
  +                queries.add(buildPrefetchQuery(idsSubset));
  +                idsSubset.clear();
  +            }
  +        }
  +
  +        if (idsSubset.size() > 0)
  +        {
  +            queries.add(buildPrefetchQuery(idsSubset));
  +        }
  +
  +        return (Query[]) queries.toArray(new Query[queries.size()]);
  +    }
  +
  +    /**
   	 * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcherImpl#buildPrefetchQuery(Collection)
   	 */
  -	protected Query buildPrefetchQuery(Collection owners)
  +	protected Query buildPrefetchQuery(Collection ids)
   	{
   		ObjectReferenceDescriptor ord = getObjectReferenceDescriptor();
           FieldDescriptor pkFields[] = getItemClassDescriptor().getPkFields();
  @@ -123,11 +167,11 @@
   
           if (pkFields.length == 1)
           {
  -            crit = buildPrefetchCriteriaSingleKey(owners, pkFields[0]);
  +            crit = buildPrefetchCriteriaSingleKey(ids, pkFields[0]);
           }
           else
           {
  -            crit = buildPrefetchCriteriaMultipleKeys(owners, pkFields);
  +            crit = buildPrefetchCriteriaMultipleKeys(ids, pkFields);
           }
   
   		return QueryFactory.newQuery(ord.getItemClass(), crit);
  @@ -135,22 +179,22 @@
   
       /**
        * Build the Criteria using IN(...) for single keys
  -     * @param owners
  +     * @param ids
        * @param pkField
        * @return Criteria
        */
  -    private Criteria buildPrefetchCriteriaSingleKey(Collection owners, FieldDescriptor pkField)
  +    private Criteria buildPrefetchCriteriaSingleKey(Collection ids, FieldDescriptor pkField)
       {
           Criteria crit = new Criteria();
           Collection fkValues = new ArrayList();
  -        Iterator iter = owners.iterator();
  +        Iterator iter = ids.iterator();
  +        Identity id;
           Object fkVal;
  -        Object owner;
   
           while (iter.hasNext())
           {
  -            owner = iter.next();
  -            fkVal = getObjectReferenceDescriptor().getForeignKeyValues(owner, getOwnerClassDescriptor())[0];
  +            id = (Identity) iter.next();
  +            fkVal = id.getPrimaryKeyValues()[0];
               if (fkVal != null)
               {
                   fkValues.add(fkVal);
  @@ -168,22 +212,22 @@
   
       /**
        * Build the Criteria using multiple ORs
  -     * @param owners
  +     * @param ids
        * @param pkFields
        * @return Criteria
        */
  -    private Criteria buildPrefetchCriteriaMultipleKeys(Collection owners, FieldDescriptor pkFields[])
  +    private Criteria buildPrefetchCriteriaMultipleKeys(Collection ids, FieldDescriptor pkFields[])
       {
           Criteria crit = new Criteria();
  -        Iterator iter = owners.iterator();
  +        Iterator iter = ids.iterator();
           Object[] fkVal;
  -        Object owner;
  +        Identity id;
   
           while (iter.hasNext())
           {
               Criteria c = new Criteria();
  -            owner = iter.next();
  -            fkVal = getObjectReferenceDescriptor().getForeignKeyValues(owner, getOwnerClassDescriptor());
  +            id = (Identity) iter.next();
  +            fkVal = id.getPrimaryKeyValues();
               for (int i=0;i < fkVal.length;i++)
               {
                   if (fkVal[i] != null)
  
  
  
  1.5       +20 -48    db-ojb/src/java/org/apache/ojb/broker/accesslayer/RelationshipPrefetcherImpl.java
  
  Index: RelationshipPrefetcherImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RelationshipPrefetcherImpl.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- RelationshipPrefetcherImpl.java	26 Apr 2003 23:18:25 -0000	1.4
  +++ RelationshipPrefetcherImpl.java	25 Aug 2003 19:28:27 -0000	1.5
  @@ -82,6 +82,7 @@
   	private PersistenceBroker broker;
   	private ObjectReferenceDescriptor objectReferenceDescriptor;
   	private boolean cascadeRetrieve;
  +    protected final int pkLimit; // max number of pk's in one query
   
   	protected static final int IN_LIMIT = getPrefetchInLimit();
   
  @@ -110,7 +111,7 @@
   		setBroker(aBroker);
   		setObjectReferenceDescriptor(anOrd);
   		setLogger(LoggerFactory.getLogger(this.getClass()));
  -
  +        pkLimit = getPrefetchInLimit() / getItemClassDescriptor().getPkFields().length;
   	}
   
   	/**
  @@ -127,23 +128,22 @@
   	 */
   	protected abstract void associateBatched(Collection owners, Collection children);
   
  -	/**
  -	 * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#prefetchRelationship(Collection)
  -	 */
  -	public void prefetchRelationship(Collection owners)
  -	{
  -		Query queries[];
  -		Collection children;
  -
  -		queries = buildPrefetchQueries(owners, IN_LIMIT);
  -
  -		for (int i = 0; i < queries.length; i++)
  -		{
  -			children = getBroker().getCollectionByQuery(queries[i]);
  -			associateBatched(owners, children);
  -		}
  -
  -	}
  +    /**
  +    * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#prefetchRelationship(Collection)
  +    */
  +    public void prefetchRelationship(Collection owners)
  +    {
  +        Query queries[];
  +        Collection children = new ArrayList();
  +
  +        queries = buildPrefetchQueries(owners);
  +
  +        for (int i = 0; i < queries.length; i++)
  +        {
  +            children.addAll(getBroker().getCollectionByQuery(queries[i]));
  +        }
  +        associateBatched(owners, children);
  +    }
   
   	/**
   	 * Return the DescriptorRepository
  @@ -171,35 +171,7 @@
   		return getDescriptorRepository().getDescriptorFor(getObjectReferenceDescriptor().getItemClass());
   	}
   
  -	/**
  -	 * Build the query (using IN(...) )to perform a batched read
  -	 * @param owners Collection containing all objects of the ONE side
  -	 */
  -	protected abstract Query buildPrefetchQuery(Collection owners);
  -
  -	/**
  -	 * Build the multiple queries for one relationship because of limitation of IN(...)
  -	 * @param owners Collection containing all objects of the ONE side
  -	 * @param inLimit the max number of values of IN(), -1 is unlimited
  -	 */
  -	protected Query[] buildPrefetchQueries(Collection owners, int inLimit)
  -	{
  -		Collection queries = new ArrayList();
  -		Collection ownerSubset = new ArrayList();
  -		Iterator iter = owners.iterator();
  -
  -		while (iter.hasNext())
  -		{
  -			ownerSubset.add(iter.next());
  -			if (ownerSubset.size() == inLimit || !iter.hasNext())
  -			{
  -				queries.add(buildPrefetchQuery(ownerSubset));
  -				ownerSubset = new ArrayList();
  -			}
  -		}
  -
  -		return (Query[]) queries.toArray(new Query[queries.size()]);
  -	}
  +	protected abstract Query[] buildPrefetchQueries(Collection owners);
   
   	/**
   	 * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#restoreRelationshipSettings()
  
  
  
  1.42      +20 -3     db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java
  
  Index: RsIterator.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java,v
  retrieving revision 1.41
  retrieving revision 1.42
  diff -u -r1.41 -r1.42
  --- RsIterator.java	3 Aug 2003 09:26:36 -0000	1.41
  +++ RsIterator.java	25 Aug 2003 19:28:27 -0000	1.42
  @@ -155,6 +155,17 @@
        * return value of the previously called hasNext from m_rs
        */
       protected boolean hasNext = false;
  +    
  +    /**
  +     * This is the place to add retrieval tasks that are grouped by 
  +     * ObjectReferenceDescriptors (keys) which are mapped to 
  +     * IdentityHashMaps mapping owner objects to itself (~IdentityHashSet).
  +     * After thit Iterator will be traversed, all the tasks will
  +     * be performed: related objects for the gathered owners will
  +     * be loaded and set as values of respective fields of owners.
  +     */
  +    protected HashMap m_retrievalTasks;
  +
       private boolean advancedJDBCSupport = false;
       private boolean JDBCSupportAssessed = false;
       private Query m_query = null;
  @@ -277,6 +288,11 @@
       {
           throw new UnsupportedOperationException("removing not supported by RsIterator");
       }
  +    
  +    public void setRetrievalTasks(HashMap retrievalTasks)
  +    {
  +        m_retrievalTasks = retrievalTasks;
  +    }
   
       /**
        * read all objects of this iterator. objects will be placed in cache
  @@ -446,8 +462,9 @@
                           ClassDescriptor cld = m_cld.getRepository().getDescriptorFor(result.getClass());
                           // don't force loading of reference
                           final boolean unforced = false;
  -                        m_broker.retrieveReferences(result, cld, unforced);
  -                        m_broker.retrieveCollections(result, cld, unforced);
  +                        // Maps ReferenceDescriptors to HashSets of owners
  +                        m_broker.retrieveReferences(result, cld, unforced, m_retrievalTasks);
  +                        m_broker.retrieveCollections(result, cld, unforced, m_retrievalTasks);
                       }
                   }
               }
  
  
  
  1.33      +126 -50   db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
  
  Index: PersistenceBrokerImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java,v
  retrieving revision 1.32
  retrieving revision 1.33
  diff -u -r1.32 -r1.33
  --- PersistenceBrokerImpl.java	11 Aug 2003 22:54:51 -0000	1.32
  +++ PersistenceBrokerImpl.java	25 Aug 2003 19:28:27 -0000	1.33
  @@ -59,7 +59,9 @@
   import java.util.Collection;
   import java.util.Enumeration;
   import java.util.Iterator;
  +import java.util.HashMap;
   import java.util.List;
  +import java.util.Map;
   import java.util.Vector;
   
   import org.apache.ojb.broker.*;
  @@ -88,6 +90,7 @@
   import org.apache.ojb.broker.query.ReportQueryByMtoNCriteria;
   import org.apache.ojb.broker.util.ArrayIterator;
   import org.apache.ojb.broker.util.BrokerHelper;
  +import org.apache.ojb.broker.util.IdentityMapFactory;
   import org.apache.ojb.broker.util.ObjectModification;
   import org.apache.ojb.broker.util.ProxyHelper;
   import org.apache.ojb.broker.util.collections.RemovalAwareCollection;
  @@ -124,6 +127,8 @@
   {
       private Logger logger = LoggerFactory.getLogger(PersistenceBrokerImpl.class);
   
  +    private boolean autoPrefetch = true;
  +
       protected PersistenceBrokerFactoryIF pbf;
   
       /**
  @@ -991,8 +996,20 @@
           ClassDescriptor cld = descriptorRepository.getDescriptorFor(pInstance.getClass());
           // force loading of references
           final boolean forced = true;
  -        retrieveReferences(pInstance, cld, forced);
  -        retrieveCollections(pInstance, cld, forced);
  +        retrieveReferences(pInstance, cld, forced, null);
  +        retrieveCollections(pInstance, cld, forced, null);
  +    }
  +
  +    private void addRetrievalTask(HashMap retrievalTasks, Object obj, ObjectReferenceDescriptor rds)
  +    {
  +        Map identityMap = (Map) retrievalTasks.get(rds);
  +
  +        if (identityMap == null)
  +        {
  +            identityMap = IdentityMapFactory.getIdentityMap();
  +            retrievalTasks.put(rds, identityMap);
  +        }
  +        identityMap.put(obj, obj);
       }
   
       /**
  @@ -1007,14 +1024,14 @@
           CollectionDescriptor cod = cld.getCollectionDescriptorByName(pAttributeName);
           if (cod != null)
           {
  -            retrieveCollection(pInstance, cld, cod, true);
  +            retrieveCollection(pInstance, cld, cod, true, null);
           }
           else
           {
               ObjectReferenceDescriptor ord = cld.getObjectReferenceDescriptorByName(pAttributeName);
               if (ord != null)
               {
  -                retrieveReference(pInstance, cld, ord, true);
  +                retrieveReference(pInstance, cld, ord, true, null);
               }
               else
               {
  @@ -1030,15 +1047,16 @@
        * @param newObj the instance to be loaded or refreshed
        * @param cld the ClassDescriptor of the instance
        * @param forced if set to true loading is forced even if cld differs.
  +     * @param retrievalTasks tasks for reference or collection retrieval grouped by descriptor
        */
  -    public void retrieveReferences(Object newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
  +    public void retrieveReferences(Object newObj, ClassDescriptor cld, boolean forced, HashMap retrievalTasks) throws PersistenceBrokerException
       {
           Iterator i = cld.getObjectReferenceDescriptors().iterator();
           ObjectReferenceDescriptor rds = null;
           while (i.hasNext())
           {
               rds = (ObjectReferenceDescriptor) i.next();
  -            retrieveReference(newObj, cld, rds, forced);
  +            retrieveReference(newObj, cld, rds, forced, retrievalTasks);
           }
       }
   
  @@ -1051,16 +1069,25 @@
        * @param cld - the ClassDescriptor describring obj
        * @param rds - the ObjectReferenceDescriptor of the reference attribute to be loaded
        * @param forced - if set to true, the reference is loaded even if the rds differs.
  +     * @param retrievalTasks tasks for reference or collection retrieval grouped by descriptor
        */
  -    private void retrieveReference(Object obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced)
  +    private void retrieveReference(Object obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced, HashMap retrievalTasks)
       {
           PersistentField refField;
           Object refObj;
           if (forced || rds.getCascadeRetrieve())
           {
  -            refObj = getReferencedObject(obj, rds, cld);
  -            refField = rds.getPersistentField();
  -            refField.set(obj, refObj);
  +            if ((retrievalTasks != null) && !rds.isLazy()
  +                    && (rds.getItemProxyClass() == null))
  +            {
  +                addRetrievalTask(retrievalTasks, obj, rds);
  +            }
  +            else
  +            {
  +                refObj = getReferencedObject(obj, rds, cld);
  +                refField = rds.getPersistentField();
  +                refField.set(obj, refObj);
  +            }
           }
       }
   
  @@ -1073,44 +1100,54 @@
        * @param cld - the ClassDescriptor describing obj
        * @param cds - the CollectionDescriptor describing the collection attribute to be loaded
        * @param forced - if set to true loading is forced, even if cds differs.
  +     * @param retrievalTasks tasks for reference or collection retrieval grouped by descriptor
        *
        */
  -    private void retrieveCollection(Object obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced)
  +    private void retrieveCollection(Object obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced, HashMap retrievalTasks)
       {
           if (forced || cds.getCascadeRetrieve())
           {
  -            // this collection type will be used:
  -            Class collectionClass = cds.getCollectionClass();
  -            PersistentField collectionField = cds.getPersistentField();
  -			Query fkQuery = getFKQuery(obj, cld, cds);
  -
  -            if (collectionClass == null)
  -            {
  -                Collection result = getCollectionByQuery(fkQuery, cds.isLazy());
  -
  -                // assign collection to objects attribute
  -                // if attribute has an array type build an array, else assign collection directly
  -                if (collectionField.getType().isArray())
  +            if ((retrievalTasks != null) && !cds.isLazy() && !cds.isMtoNRelation()
  +                    && (cds.getItemProxyClass() == null)
  +                    && (cds.getQueryCustomizer() == null))
  +            {
  +                addRetrievalTask(retrievalTasks, obj, cds);
  +            }
  +            else
  +            {
  +                // this collection type will be used:
  +                Class collectionClass = cds.getCollectionClass();
  +                PersistentField collectionField = cds.getPersistentField();
  +                Query fkQuery = getFKQuery(obj, cld, cds);
  +
  +                if (collectionClass == null)
                   {
  -                    int length = result.size();
  -                    Class itemtype = collectionField.getType().getComponentType();
  -                    Object resultArray = Array.newInstance(itemtype, length);
  -                    for (int j = 0; j < length; j++)
  +                    Collection result = getCollectionByQuery(fkQuery, cds.isLazy());
  +
  +                    // assign collection to objects attribute
  +                    // if attribute has an array type build an array, else assign collection directly
  +                    if (collectionField.getType().isArray())
                       {
  -                        Array.set(resultArray, j, ((Vector) result).get(j));
  +                        int length = result.size();
  +                        Class itemtype = collectionField.getType().getComponentType();
  +                        Object resultArray = Array.newInstance(itemtype, length);
  +                        for (int j = 0; j < length; j++)
  +                        {
  +                            Array.set(resultArray, j, ((Vector) result).get(j));
  +                        }
  +                        collectionField.set(obj, resultArray);
  +                    }
  +                    else
  +                    {
  +                        collectionField.set(obj, result);
                       }
  -                    collectionField.set(obj, resultArray);
                   }
                   else
                   {
  +                    ManageableCollection result = getCollectionByQuery(collectionClass, fkQuery, cds.isLazy());
                       collectionField.set(obj, result);
                   }
               }
  -            else
  -            {
  -                ManageableCollection result = getCollectionByQuery(collectionClass, fkQuery, cds.isLazy());
  -                collectionField.set(obj, result);
  -            }
           }
       }
   
  @@ -1187,16 +1224,17 @@
        * @param newObj the instance to be loaded or refreshed
        * @param cld the ClassDescriptor of the instance
        * @param forced if set to true, loading is forced even if cld differs
  +     * @param retrievalTasks tasks for reference or collection retrieval grouped by descriptor
        *
        */
  -    public void retrieveCollections(Object newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
  +    public void retrieveCollections(Object newObj, ClassDescriptor cld, boolean forced, HashMap retrievalTasks) throws PersistenceBrokerException
       {
           Iterator i = cld.getCollectionDescriptors().iterator();
           CollectionDescriptor cds;
           while (i.hasNext())
           {
               cds = (CollectionDescriptor) i.next();
  -            retrieveCollection(newObj, cld, cds, forced);
  +            retrieveCollection(newObj, cld, cds, forced, retrievalTasks);
           }
       }
   
  @@ -1218,7 +1256,7 @@
               cds = (CollectionDescriptor) iter.next();
               if (cds.isRefresh())
               {
  -                retrieveCollection(obj, cld, cds, false);
  +                retrieveCollection(obj, cld, cds, false, null);
               }
           }
           //
  @@ -1230,7 +1268,7 @@
               rds = (ObjectReferenceDescriptor) iter.next();
               if (rds.isRefresh())
               {
  -                retrieveReference(obj, cld, rds, false);
  +                retrieveReference(obj, cld, rds, false, null);
               }
           }
       }
  @@ -1325,11 +1363,14 @@
           ClassDescriptor cld = descriptorRepository.getDescriptorFor(itemClass);
           ManageableCollection result = null;
           OJBIterator iter = null;
  +        // Maps ReferenceDescriptors to HashSets of owners
  +        HashMap retrievalTasks = (autoPrefetch ? new HashMap() : null);
  +
           try
           {
               result = (ManageableCollection) collectionClass.newInstance();
               // now iterate over all elements and add them to the new collection
  -            iter = getIteratorFromQuery(query, cld);
  +            iter = getIteratorFromQuery(query, cld, retrievalTasks);
               /**
                * if the query has specified a start at index, and an end at index move to the start at index.
                */
  @@ -1387,6 +1428,7 @@
   
                   }
               }
  +            performRetrievalTasks(retrievalTasks);
               /**
                * Set full size of query to pass back to client.
                *
  @@ -1453,6 +1495,32 @@
           return result;
       }
   
  +    private void performRetrievalTasks(HashMap retrievalTasks)
  +    {
  +        if (retrievalTasks == null)
  +        {
  +            return;
  +        }
  +
  +        for (Iterator it = retrievalTasks.keySet().iterator(); it.hasNext(); )
  +        {
  +            ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) it.next();
  +            RelationshipPrefetcher prefetcher;
  +            Map identityMap = (Map) retrievalTasks.get(ord);
  +            Collection owners = identityMap.values();
  +
  +            if (ord instanceof CollectionDescriptor)
  +            {
  +                prefetcher = new CollectionPrefetcher(this, ord);
  +            }
  +            else
  +            {
  +                prefetcher = new ReferencePrefetcher(this, ord);
  +            }
  +            prefetcher.prefetchRelationship(owners);
  +        }
  +    }
  +
       /**
        * retrieve a collection of type collectionClass matching the Query query
        *
  @@ -1609,9 +1677,9 @@
   				final boolean unforced = false;
   
                   // 2. retrieve non-skalar fields that contain objects retrievable from other tables
  -                retrieveReferences(newObj, newObjCld, unforced);
  +                retrieveReferences(newObj, newObjCld, unforced, null);
                   // 3. retrieve collection fields from foreign-key related tables:
  -                retrieveCollections(newObj, newObjCld, unforced);
  +                retrieveCollections(newObj, newObjCld, unforced, null);
               }
           }
   
  @@ -1681,7 +1749,7 @@
       {
           Class itemClass = query.getSearchClass();
           ClassDescriptor cld = descriptorRepository.getDescriptorFor(itemClass);
  -        return getIteratorFromQuery(query, cld);
  +        return getIteratorFromQuery(query, cld, null);
       }
   
       /**
  @@ -1689,13 +1757,14 @@
        *
        * @param query
        * @param cld the ClassDescriptor
  +     * @param retrievalTasks tasks for reference or collection retrieval grouped by descriptor
        * @return OJBIterator
        */
  -    private OJBIterator getIteratorFromQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
  +    private OJBIterator getIteratorFromQuery(Query query, ClassDescriptor cld, HashMap retrievalTasks) throws PersistenceBrokerException
       {
           RsIteratorFactory factory = RsIteratorFactoryImpl.getInstance();
   
  -        return getRsIteratorFromQuery(query, cld, factory);
  +        return getRsIteratorFromQuery(query, cld, factory, retrievalTasks);
       }
   
       /**
  @@ -2343,11 +2412,14 @@
        * @param query
        * @param cld
        * @param factory the Factory for the RsIterator
  +     * @param retrievalTasks tasks for reference or collection retrieval grouped by descriptor
        * @return OJBIterator
        */
  -    private OJBIterator getRsIteratorFromQuery(Query query, ClassDescriptor cld, RsIteratorFactory factory)
  +    private OJBIterator getRsIteratorFromQuery(Query query, ClassDescriptor cld, RsIteratorFactory factory, HashMap retrievalTasks)
           throws PersistenceBrokerException
       {
  +        RsIterator it;
  +
           if (query instanceof QueryBySQL)
           {
               if(logger.isDebugEnabled()) logger.debug("Creating SQL-RsIterator for class ["+cld.getClassNameOfObject()+"]");
  @@ -2359,7 +2431,9 @@
           {
               // no extents just use the plain vanilla RsIterator
               if(logger.isDebugEnabled()) logger.debug("Creating RsIterator for class ["+cld.getClassNameOfObject()+"]");
  -            return factory.createRsIterator(query, cld, this);
  +            it = factory.createRsIterator(query, cld, this);
  +            it.setRetrievalTasks(retrievalTasks);
  +            return it;
           }
   
           OJBIterator iter = null;
  @@ -2373,7 +2447,9 @@
           if (!cld.isInterface())
           {
               if(logger.isDebugEnabled()) logger.debug("Adding RsIterator for class ["+cld.getClassNameOfObject()+"] to ChainingIterator");
  -            ((ChainingIterator) iter).addIterator(factory.createRsIterator(query, cld, this));
  +            it = factory.createRsIterator(query, cld, this);
  +            it.setRetrievalTasks(retrievalTasks);
  +            ((ChainingIterator) iter).addIterator(it);
           }
   
           for (int i = 0; i < extentClasses.size(); i++)
  @@ -2392,7 +2468,7 @@
               // add the iterator to the chaining iterator.
               // BRJ: look for multilevel hierarchies
               if(logger.isDebugEnabled()) logger.debug("Adding RsIterator of class ["+ec+"] to ChainingIterator");
  -            ((ChainingIterator) iter).addIterator(getRsIteratorFromQuery(query, cld, factory));
  +            ((ChainingIterator) iter).addIterator(getRsIteratorFromQuery(query, cld, factory, retrievalTasks));
           }
           return iter;
       }
  @@ -2409,7 +2485,7 @@
       {
           RsIteratorFactory factory = ReportRsIteratorFactoryImpl.getInstance();
   
  -        return getRsIteratorFromQuery(query, cld, factory);
  +        return getRsIteratorFromQuery(query, cld, factory, null);
       }
   
       /**
  
  
  
  1.6       +109 -94   db-ojb/src/java/org/apache/ojb/broker/util/IdentityHashMap.java
  
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/util/IdentityMapFactory.java
  
  Index: IdentityMapFactory.java
  ===================================================================
  package org.apache.ojb.broker.util;
  
  import java.util.Map;
  
  /**
   * Created by IntelliJ IDEA.
   * User: matthew.baird
   * Date: Jul 29, 2003
   * Time: 9:16:27 AM
   * To change this template use Options | File Templates.
   */
  public final class IdentityMapFactory
  {
  	private static boolean HAS_JDK_IDENTITY_MAP = true;
  	private static final String CLASS_NAME = "java.util.IdentityHashMap";
  	private static Class JDK_IDENTITY_MAP;
  
  	static
  	{
  		try
  		{
  			JDK_IDENTITY_MAP = Thread.currentThread().getContextClassLoader().loadClass(CLASS_NAME);
  		}
  		catch (ClassNotFoundException e)
  		{
  			HAS_JDK_IDENTITY_MAP = false;
  		}
  	}
  	
  	private IdentityMapFactory() {}
  
  	public static Map getIdentityMap()
  	{
  		Map retval = null;
  		if (HAS_JDK_IDENTITY_MAP)
  		{
  			try
  			{
  				retval = (Map) JDK_IDENTITY_MAP.newInstance();
  			}
  			catch (InstantiationException e)
  			{
  				HAS_JDK_IDENTITY_MAP = false;
  			}
  			catch (IllegalAccessException e)
  			{
  				HAS_JDK_IDENTITY_MAP = false;
  			}
  		}
  		if (!HAS_JDK_IDENTITY_MAP)
  		{
  			retval = new org.apache.ojb.broker.util.IdentityHashMap();
  		}
  		return retval;
  	}
  }
  
  
  
  1.13      +1 -1      db-ojb/src/java/org/apache/ojb/otm/copy/MetadataObjectCopyStrategy.java
  
  Index: MetadataObjectCopyStrategy.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/copy/MetadataObjectCopyStrategy.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- MetadataObjectCopyStrategy.java	10 Aug 2003 09:53:13 -0000	1.12
  +++ MetadataObjectCopyStrategy.java	25 Aug 2003 19:28:27 -0000	1.13
  @@ -59,7 +59,7 @@
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
   import org.apache.ojb.broker.accesslayer.CollectionProxy;
   import org.apache.ojb.broker.util.ConstructorHelper;
  -import org.apache.ojb.otm.util.IdentityMapFactory;
  +import org.apache.ojb.broker.util.IdentityMapFactory;
   
   import java.lang.reflect.Constructor;
   import java.util.Map;
  
  
  
  1.12      +1 -1      db-ojb/src/java/org/apache/ojb/otm/copy/ReflectiveObjectCopyStrategy.java
  
  Index: ReflectiveObjectCopyStrategy.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/copy/ReflectiveObjectCopyStrategy.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- ReflectiveObjectCopyStrategy.java	10 Aug 2003 09:53:13 -0000	1.11
  +++ ReflectiveObjectCopyStrategy.java	25 Aug 2003 19:28:27 -0000	1.12
  @@ -54,7 +54,7 @@
    * <http://www.apache.org/>.
    */
   
  -import org.apache.ojb.otm.util.IdentityMapFactory;
  +import org.apache.ojb.broker.util.IdentityMapFactory;
   
   import java.lang.reflect.Array;
   import java.lang.reflect.Constructor;
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org