You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/07/27 14:30:30 UTC

[2/2] cayenne git commit: CAY-2446 Run Disjoint By Id queries outside of synchronized block

CAY-2446 Run Disjoint By Id queries outside of synchronized block


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/8339c199
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/8339c199
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/8339c199

Branch: refs/heads/master
Commit: 8339c19959aa9bc6e0e05b1536af5622b13ae670
Parents: 28af933
Author: Nikita Timofeev <st...@gmail.com>
Authored: Fri Jul 27 17:30:13 2018 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Jul 27 17:30:13 2018 +0300

----------------------------------------------------------------------
 RELEASE-NOTES.txt                               |   2 +
 .../access/HierarchicalObjectResolver.java      | 142 ++++++++++++-------
 2 files changed, 89 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/8339c199/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index b52a4f3..8db9264 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -13,6 +13,8 @@ Date:
 ----------------------------------
 Changes/New Features:
 
+CAY-2446 Run Disjoint By Id queries outside of synchronized block
+
 Bug Fixes:
 
 CAY-2444 Change URI from http:// to https:// in xsi:schemaLocation

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8339c199/cayenne-server/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java b/cayenne-server/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
index e24209c..201f304 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
@@ -59,74 +59,54 @@ class HierarchicalObjectResolver {
     }
 
     HierarchicalObjectResolver(DataContext context, QueryMetadata metadata,
-            ClassDescriptor descriptor, boolean needToSaveDuplicates) {
+                               ClassDescriptor descriptor, boolean needToSaveDuplicates) {
         this(context, metadata);
         this.descriptor = descriptor;
         this.needToSaveDuplicates = needToSaveDuplicates;
     }
 
     /**
-     * Properly synchronized version of 'resolveObjectTree'.
+     * Properly synchronized object resolution
      */
     PrefetchProcessorNode synchronizedRootResultNodeFromDataRows(
             PrefetchTreeNode tree,
             List<DataRow> mainResultRows,
             Map<String, List<?>> extraResultsByPath) {
 
-        synchronized (context.getObjectStore()) {
-            return resolveObjectTree(tree, mainResultRows, extraResultsByPath);
-        }
-    }
-
-    private PrefetchProcessorNode resolveObjectTree(
-            PrefetchTreeNode tree,
-            List<DataRow> mainResultRows,
-            Map<String, List<?>> extraResultsByPath) {
+        PrefetchProcessorNode decoratedTree = decorateTree(tree, mainResultRows, extraResultsByPath);
 
-        // create a copy of the tree using DecoratedPrefetchNodes and then traverse it
-        // resolving objects...
-        PrefetchProcessorNode decoratedTree = new PrefetchProcessorTreeBuilder(
-                this,
-                mainResultRows,
-                extraResultsByPath).buildTree(tree);
+        // prepare data for disjoint by id prefetches
+        decoratedTree.traverse(new DisjointByIdProcessor());
 
-        // do a single path for disjoint prefetches, joint subtrees will be processed at
-        // each disjoint node that is a parent of joint prefetches.
-        decoratedTree.traverse(new DisjointProcessor());
+        // resolve objects under global lock to keep object graph consistent
+        synchronized (context.getObjectStore()) {
+            // do a single path for disjoint prefetches, joint subtrees will be processed at
+            // each disjoint node that is a parent of joint prefetches.
+            decoratedTree.traverse(new DisjointProcessor());
 
-        // connect related objects
-        decoratedTree.traverse(new PostProcessor());
+            // connect related objects
+            decoratedTree.traverse(new PostProcessor());
+        }
 
         return decoratedTree;
     }
 
-    final class DisjointProcessor implements PrefetchProcessor {
-
-        @Override
-        public boolean startDisjointPrefetch(PrefetchTreeNode node) {
-
-            PrefetchProcessorNode processorNode = (PrefetchProcessorNode) node;
-
-            // this means something bad happened during fetch
-            if (processorNode.getDataRows() == null) {
-                return false;
-            }
-
-            // continue with processing even if the objects list is empty to handle multi-step prefetches.
-            if (processorNode.getDataRows().isEmpty()) {
-                return true;
-            }
-
-            List<Persistent> objects = processorNode.getResolver().objectsFromDataRows(processorNode.getDataRows());
-            processorNode.setObjects(objects);
+    /**
+     * create a copy of the tree using DecoratedPrefetchNodes and then traverse it resolving objects...
+     */
+    private PrefetchProcessorNode decorateTree(PrefetchTreeNode tree,
+                                               List<DataRow> mainResultRows,
+                                               Map<String, List<?>> extraResultsByPath) {
+        return new PrefetchProcessorTreeBuilder(this, mainResultRows, extraResultsByPath)
+                .buildTree(tree);
+    }
 
-            return true;
-        }
+    final class DisjointByIdProcessor implements PrefetchProcessor {
 
         @Override
         public boolean startDisjointByIdPrefetch(PrefetchTreeNode node) {
             if (node.getParent().isPhantom()) {
-                // TODO: doing nothing in current implementation if parent node is phantom
+                // doing nothing in current implementation if parent node is phantom
                 return true;
             }
 
@@ -139,7 +119,6 @@ class HierarchicalObjectResolver {
 
             String pathPrefix = "";
             if (dbRelationships.size() > 1) {
-
                 // we need path prefix for flattened relationships
                 StringBuilder buffer = new StringBuilder();
                 for (int i = dbRelationships.size() - 1; i >= 1; i--) {
@@ -154,14 +133,14 @@ class HierarchicalObjectResolver {
             }
 
             List<DataRow> parentDataRows;
-            
-			// note that a disjoint prefetch that has adjacent joint prefetches
-			// will be a PrefetchProcessorJointNode, so here check for semantics, not node type
-			if (parentProcessorNode.getSemantics() == PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS) {
-				parentDataRows = ((PrefetchProcessorJointNode) parentProcessorNode).getResolvedRows();
-			} else {
-				parentDataRows = parentProcessorNode.getDataRows();
-			}
+
+            // note that a disjoint prefetch that has adjacent joint prefetches
+            // will be a PrefetchProcessorJointNode, so here check for semantics, not node type
+            if (parentProcessorNode.getSemantics() == PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS) {
+                parentDataRows = ((PrefetchProcessorJointNode) parentProcessorNode).getResolvedRows();
+            } else {
+                parentDataRows = parentProcessorNode.getDataRows();
+            }
 
             int maxIdQualifierSize = context.getParentDataDomain().getMaxIdQualifierSize();
             List<DbJoin> joins = lastDbRelationship.getJoins();
@@ -221,7 +200,7 @@ class HierarchicalObjectResolver {
             }
             processorNode.setDataRows(dataRows);
 
-            return startDisjointPrefetch(node);
+            return true;
         }
 
         private void createDisjointByIdPrefetchQualifier(String pathPrefix, PrefetchSelectQuery currentQuery,
@@ -249,6 +228,59 @@ class HierarchicalObjectResolver {
         }
 
         @Override
+        public boolean startPhantomPrefetch(PrefetchTreeNode node) {
+            return true;
+        }
+
+        @Override
+        public boolean startDisjointPrefetch(PrefetchTreeNode node) {
+            return true;
+        }
+
+        @Override
+        public boolean startJointPrefetch(PrefetchTreeNode node) {
+            return true;
+        }
+
+        @Override
+        public boolean startUnknownPrefetch(PrefetchTreeNode node) {
+            throw new CayenneRuntimeException("Unknown prefetch node: %s", node);
+        }
+
+        @Override
+        public void finishPrefetch(PrefetchTreeNode node) {
+        }
+    }
+
+    final class DisjointProcessor implements PrefetchProcessor {
+
+        @Override
+        public boolean startDisjointPrefetch(PrefetchTreeNode node) {
+
+            PrefetchProcessorNode processorNode = (PrefetchProcessorNode) node;
+
+            // this means something bad happened during fetch
+            if (processorNode.getDataRows() == null) {
+                return false;
+            }
+
+            // continue with processing even if the objects list is empty to handle multi-step prefetches.
+            if (processorNode.getDataRows().isEmpty()) {
+                return true;
+            }
+
+            List<Persistent> objects = processorNode.getResolver().objectsFromDataRows(processorNode.getDataRows());
+            processorNode.setObjects(objects);
+
+            return true;
+        }
+
+        @Override
+        public boolean startDisjointByIdPrefetch(PrefetchTreeNode node) {
+            return startDisjointPrefetch(node);
+        }
+
+        @Override
         public boolean startJointPrefetch(PrefetchTreeNode node) {
 
             // delegate processing of the top level joint prefetch to a joint processor,
@@ -332,7 +364,7 @@ class HierarchicalObjectResolver {
 
     // a processor of a single joint result set that walks a subtree of prefetch nodes
     // that use this result set.
-    final class JointProcessor implements PrefetchProcessor {
+    final static class JointProcessor implements PrefetchProcessor {
 
         DataRow currentFlatRow;
         PrefetchProcessorNode rootNode;