cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject svn commit: r1501800 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access: HierarchicalObjectResolverNode.java PrefetchProcessorTreeBuilder.java
Date Wed, 10 Jul 2013 15:39:31 GMT
Author: aadamchik
Date: Wed Jul 10 15:39:30 2013
New Revision: 1501800

URL: http://svn.apache.org/r1501800
Log:
CAY-1695  Unexpected null value in bidirectional one-to-one prefetch

inferring seen objects based on row version number
TODO: is this a good universal strategy?

Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java?rev=1501800&r1=1501799&r2=1501800&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolverNode.java
Wed Jul 10 15:39:30 2013
@@ -19,24 +19,26 @@
 package org.apache.cayenne.access;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.DataObject;
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
+import org.apache.cayenne.graph.GraphManager;
 import org.apache.cayenne.reflect.ClassDescriptor;
 
 class HierarchicalObjectResolverNode extends ObjectResolver {
 
     private PrefetchProcessorNode node;
+    private long txStartRowVersion;
 
     HierarchicalObjectResolverNode(PrefetchProcessorNode node, DataContext context, ClassDescriptor
descriptor,
-            boolean refresh) {
+            boolean refresh, long txStartRowVersion) {
         super(context, descriptor, refresh);
         this.node = node;
+        this.txStartRowVersion = txStartRowVersion;
     }
 
     @Override
@@ -48,15 +50,7 @@ class HierarchicalObjectResolverNode ext
 
         List<Persistent> results = new ArrayList<Persistent>(rows.size());
 
-        // here we can get the same object repeated multiple times in case of
-        // many-to-many between prefetched and main entity... this is needed to
-        // connect prefetched objects to the main objects. To avoid needlessly
-        // refreshing
-        // the same object multiple times, track which objectids area already
-        // loaded in
-        // this pass
-        Map<ObjectId, Persistent> seen = new HashMap<ObjectId, Persistent>();
-
+        GraphManager graphManager = context.getGraphManager();
         for (DataRow row : rows) {
 
             // determine entity to use
@@ -67,15 +61,24 @@ class HierarchicalObjectResolverNode ext
             // has all needed metadata already cached.
             ObjectId anId = createObjectId(row, classDescriptor.getEntity(), null);
 
-            Persistent object = seen.get(anId);
+            // skip processing of objects that were already processed in this
+            // transaction, either by this node or by some other node...
+            // added per CAY-1695 ..
+
+            // TODO: is it going to have any side effects? It is run from the
+            // synchronized block, so I guess other threads can't stick their
+            // versions of this object in here?
+            // TODO: also this logic implies that main rows are always fetched
+            // first... I guess this has to stay true if prefetching is
+            // involved.
 
-            if (object == null) {
+            Persistent object = (Persistent) graphManager.getNode(anId);
+            if (object == null || ((DataObject) object).getSnapshotVersion() < txStartRowVersion)
{
                 object = objectFromDataRow(row, anId, classDescriptor);
 
                 if (object == null) {
                     throw new CayenneRuntimeException("Can't build Object from row: " + row);
                 }
-                seen.put(anId, object);
             }
 
             // keep the dupe objects (and data rows) around, as there maybe an

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java?rev=1501800&r1=1501799&r2=1501800&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorTreeBuilder.java
Wed Jul 10 15:39:30 2013
@@ -23,6 +23,8 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.DataObject;
+import org.apache.cayenne.DataRow;
 import org.apache.cayenne.query.PrefetchProcessor;
 import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.QueryMetadata;
@@ -172,11 +174,21 @@ final class PrefetchProcessorTreeBuilder
 
         node.setIncoming(arc);
         if (node.getParent() != null && !node.isJointPrefetch()) {
+            
+            long txStartRowVersion;
+            if (mainResultRows.isEmpty()) {
+                txStartRowVersion = DataObject.DEFAULT_VERSION;
+            } else {
+                DataRow firstRow = (DataRow) mainResultRows.get(0);
+                txStartRowVersion = firstRow.getVersion();
+            }
+            
             node.setResolver(new HierarchicalObjectResolverNode(
                     node,
                     context,
                     descriptor,
-                    queryMetadata.isRefreshingObjects()));
+                    queryMetadata.isRefreshingObjects(), 
+                    txStartRowVersion));
         }
         else {
             node.setResolver(new ObjectResolver(context, descriptor, queryMetadata



Mime
View raw message