added a butt load more test cases verifying will crazy corner cases.

Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/989237fd
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/989237fd
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/989237fd

Branch: refs/heads/master
Commit: 989237fd07a5693121400fe60bb3890c6573543d
Parents: f6b6697
Author: Marko A. Rodriguez <okramma...@gmail.com>
Authored: Thu Jan 26 15:02:05 2017 -0700
Committer: Marko A. Rodriguez <okramma...@gmail.com>
Committed: Fri Jan 27 14:24:18 2017 -0700

----------------------------------------------------------------------
 .../optimization/SingleIterationStrategy.java   | 22 ++++++++-----
 .../SingleIterationStrategyTest.java            | 34 ++++++++++++++------
 .../SparkSingleIterationStrategy.java           | 17 +++++-----
 .../SparkSingleIterationStrategyTest.java       | 26 ++++++++++++++-
 4 files changed, 73 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/989237fd/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
index efcbe9a..19d9854 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
@@ -29,9 +29,11 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTrav
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
 import org.apache.tinkerpop.gremlin.process.traversal.step.LambdaHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaFlatMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
@@ -41,6 +43,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.Adja
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.InlineFilterStrategy;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -93,22 +96,25 @@ public final class SingleIterationStrategy extends 
AbstractTraversalStrategy<Tra
                 final boolean beyondStarGraph =
                         
TraversalHelper.hasStepOfAssignableClassRecursively(Scope.global, 
LambdaHolder.class, computerTraversal) ||
                                 
!TraversalHelper.isLocalStarGraph(computerTraversal);
-                if (!beyondStarGraph &&                                        
                                // if we move beyond the star graph, then 
localization is not possible.
-                        !(computerTraversal.getStartStep().getNextStep() 
instanceof EmptyStep) &&              // if its just a g.V()/E(), then don't 
localize
-                        !(computerTraversal.getStartStep().getNextStep() 
instanceof LocalStep) &&              // removes the potential for the infinite 
recursive application of the traversal
-                        !(computerTraversal.getStartStep().getNextStep() 
instanceof Barrier) &&                // if the second step is a barrier, no 
point in trying to localize anything
-                        
!(TraversalHelper.getStepsOfAssignableClass(TraversalParent.class, 
computerTraversal). // this is a strict precaution that could be loosed with 
deeper logic on barriers in global children
+                if (!beyondStarGraph &&                                        
                                                         // if we move beyond 
the star graph, then localization is not possible.
+                        (computerTraversal.getStartStep() instanceof 
GraphStep) &&                                                      // while 
GraphComputer requires GraphStep starts, this is just a precaution when 
inject() starts are supported
+                        !(computerTraversal.getStartStep().getNextStep() 
instanceof EmptyStep) &&                                       // if its just a 
g.V()/E(), then don't localize
+                        !(computerTraversal.getStartStep().getNextStep() 
instanceof LocalStep) &&                                       // removes the 
potential for the infinite recursive application of the traversal
+                        !(computerTraversal.getStartStep().getNextStep() 
instanceof Barrier) &&                                         // if the second 
step is a barrier, no point in trying to localize anything
+                        
!computerTraversal.getTraverserRequirements().contains(TraverserRequirement.LABELED_PATH)
 &&                    // this is to alleviate issues with DetachedElement in 
paths (TODO: when detachment is dynamic, remove this)
+                        
!computerTraversal.getTraverserRequirements().contains(TraverserRequirement.PATH)
 &&                            // this is to alleviate issues with 
DetachedElement in paths (TODO: when detachment is dynamic, remove this)
+                        
TraversalHelper.getStepsOfAssignableClassRecursively(SideEffectCapable.class, 
computerTraversal).isEmpty() &&   // this is to alleviate issues with 
DetachedElement in paths (TODO: when detachment is dynamic, remove this)
+                        
!(TraversalHelper.getStepsOfAssignableClass(TraversalParent.class, 
computerTraversal).                          // this is a strict precaution 
that could be loosed with deeper logic on barriers in global children
                                 stream().
                                 filter(parent -> 
!parent.getGlobalChildren().isEmpty()).findAny().isPresent())) {
 
                     final Traversal.Admin<?, ?> newComputerTraversal = 
step.computerTraversal.getPure();
                     final Traversal.Admin localTraversal = new 
DefaultGraphTraversal<>();
                     final Step barrier = (Step) 
TraversalHelper.getFirstStepOfAssignableClass(Barrier.class, 
newComputerTraversal).orElse(null);
-                    final Step endStep = null == barrier ? 
newComputerTraversal.getEndStep() : barrier.getPreviousStep();
-                    if (!(endStep instanceof VertexStep || endStep instanceof 
EdgeVertexStep)) {
+                    if (null == barrier || !(barrier instanceof 
TraversalParent && (barrier.getPreviousStep() instanceof VertexStep || 
barrier.getPreviousStep() instanceof EdgeVertexStep))) {
                         
TraversalHelper.removeToTraversal(newComputerTraversal.getStartStep().getNextStep(),
 null == barrier ? EmptyStep.instance() : barrier, localTraversal);
                         assert !localTraversal.getSteps().isEmpty(); // given 
the if() constraints, this is impossible
-                        if (localTraversal.getSteps().size() > 1) { // if its 
just a single step, a local wrap will not alter its locus of computation
+                        if (localTraversal.getSteps().size() > 1) {  // if its 
just a single step, a local wrap will not alter its locus of computation
                             if (null == barrier)
                                 TraversalHelper.insertTraversal(0, 
(Traversal.Admin) __.local(localTraversal), newComputerTraversal);
                             else

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/989237fd/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
index 612fb9d..09887f3 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
@@ -27,6 +27,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTrav
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
+import org.apache.tinkerpop.gremlin.structure.Column;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -35,6 +36,10 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.inE;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
+import static org.apache.tinkerpop.gremlin.structure.Column.keys;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -77,8 +82,9 @@ public class SingleIterationStrategyTest {
                 {__.V().id(), __.V().id(), Collections.emptyList()},
                 {__.V().out().count(), __.V().out().count(), 
Collections.emptyList()},
                 {__.V().out().label().count(), __.V().out().label().count(), 
Collections.emptyList()},
-                {__.V().in().id(), __.V().local(__.in().id()), 
Collections.emptyList()},
-                {__.V().out().id(), __.V().local(__.out().id()), 
Collections.emptyList()},
+                {__.V().in().id(), __.V().local(in().id()), 
Collections.emptyList()},
+                {in().id(), in().id(), Collections.emptyList()}, // test inject
+                {__.V().out().id(), __.V().local(out().id()), 
Collections.emptyList()},
                 {__.V().both().id(), __.V().local(__.both().id()), 
Collections.emptyList()},
                 {__.V().outE().inV().id().count(), 
__.V().local(__.outE().inV().id()).count(), Collections.emptyList()},
                 {__.V().map(__.outE().inV()).count(), 
__.V().map(__.outE().inV()).count(), Collections.emptyList()},
@@ -86,15 +92,25 @@ public class SingleIterationStrategyTest {
                 {__.V().outE().map(__.inV()).id().count(), 
__.V().outE().map(__.inV()).id().count(), Collections.emptyList()},
                 {__.V().outE().map(__.inV()).count(), 
__.V().outE().map(__.inV()).count(), Collections.emptyList()},
                 {__.V().outE().map(__.inV()).values("name").count(), 
__.V().outE().map(__.inV()).values("name").count(), Collections.emptyList()},
-                {__.V().outE().inV().count(), __.V().outE().inV().count(), 
Collections.emptyList()},
-                {__.V().out().id().count(), 
__.V().local(__.out().id()).count(), Collections.emptyList()},
-                {__.V().in().id().count(), __.V().local(__.in().id()).count(), 
Collections.emptyList()},
-                {__.V().in().id().select("id-map").dedup().count(), 
__.V().local(__.in().id().select("id-map")).dedup().count(), 
Collections.emptyList()},
+                {__.V().outE().inV().count(), 
__.V().local(__.outE().inV()).count(), Collections.emptyList()},
+                {__.V().out().id().count(), __.V().local(out().id()).count(), 
Collections.emptyList()},
+                {__.V().in().id().count(), __.V().local(in().id()).count(), 
Collections.emptyList()},
+                {__.V().in().id().select("id-map").dedup().count(), 
__.V().local(in().id().select("id-map")).dedup().count(), 
Collections.emptyList()},
+                
{__.V().in().id().groupCount().select(keys).unfold().dedup().count(), 
__.V().local(in().id()).groupCount().select(keys).unfold().dedup().count(), 
Collections.emptyList()},
                 {__.V().outE().values("weight"), 
__.V().outE().values("weight"), Collections.emptyList()},
                 {__.V().outE().values("weight").sum(), 
__.V().outE().values("weight").sum(), Collections.emptyList()},
-                {__.V().inE().values("weight"), 
__.V().local(__.inE().values("weight")), Collections.emptyList()},
-                {__.V().inE().values("weight").sum(), 
__.V().local(__.inE().values("weight")).sum(), Collections.emptyList()},
-                {__.V().inE().values("weight").sum().dedup().count(), 
__.V().local(__.inE().values("weight")).sum().dedup().count(), 
Collections.emptyList()},
+                {__.V().inE().values("weight"), 
__.V().local(inE().values("weight")), Collections.emptyList()},
+                {__.V().inE().values("weight").sum(), 
__.V().local(inE().values("weight")).sum(), Collections.emptyList()},
+                {__.V().inE().values("weight").sum().dedup().count(), 
__.V().local(inE().values("weight")).sum().dedup().count(), 
Collections.emptyList()},
+                {__.V().as("a").out("knows").as("b").select("a", "b"), 
__.V().as("a").out("knows").as("b").select("a", "b"), Collections.emptyList()},
+                {__.V().out().groupCount("x").cap("x"), 
__.V().out().groupCount("x").cap("x"), Collections.emptyList()},
+                
{__.V().outE().inV().groupCount().select(Column.values).unfold().dedup().count(),
 
__.V().outE().inV().groupCount().select(Column.values).unfold().dedup().count(),
 Collections.emptyList()},
+                {__.V().outE().inV().groupCount(), 
__.V().outE().inV().groupCount(), Collections.emptyList()},
+                {__.V().outE().inV().groupCount().by("name"), 
__.V().outE().inV().groupCount().by("name"), Collections.emptyList()},
+                {__.V().inE().id().groupCount(), 
__.V().local(inE().id()).groupCount(), Collections.emptyList()},
+                {__.V().inE().values("weight").groupCount(), 
__.V().local(inE().values("weight")).groupCount(), Collections.emptyList()},
+                {__.V().outE().inV().tree(), __.V().outE().inV().tree(), 
Collections.emptyList()},
+                {__.V().in().values("name").groupCount(), 
__.V().in().values("name").groupCount(), Collections.emptyList()}
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/989237fd/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategy.java
----------------------------------------------------------------------
diff --git 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategy.java
 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategy.java
index 2abb9b8..1288b0d 100644
--- 
a/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategy.java
+++ 
b/spark-gremlin/src/main/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategy.java
@@ -33,14 +33,13 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaFlatMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SelectOneStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SelectStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalFlatMapStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -83,7 +82,10 @@ public final class SparkSingleIterationStrategy extends 
AbstractTraversalStrateg
                     }
                 }
             }
-            if (!doesMessagePass && 
!SparkSingleIterationStrategy.endsWithInElement(computerTraversal)) {
+            if (!doesMessagePass &&
+                    
!SparkSingleIterationStrategy.endsWithInElement(computerTraversal) &&
+                    
!(computerTraversal.getTraverserRequirements().contains(TraverserRequirement.LABELED_PATH)
 || // todo: remove this when dynamic detachment is available in 3.3.0
+                            
computerTraversal.getTraverserRequirements().contains(TraverserRequirement.PATH)))
 {  // todo: remove this when dynamic detachment is available in 3.3.0
                 step.setComputer(step.getComputer()
                         // if no message passing, don't partition the loaded 
graph
                         .configure(Constants.GREMLIN_SPARK_SKIP_PARTITIONER, 
true)
@@ -95,6 +97,9 @@ public final class SparkSingleIterationStrategy extends 
AbstractTraversalStrateg
 
     private static final boolean endsWithInElement(final Traversal.Admin<?, ?> 
traversal) {
         Step<?, ?> current = traversal.getEndStep();
+        while (current instanceof Barrier) { // clip off any tail barriers
+            current = current.getPreviousStep();
+        }
         while (!(current instanceof EmptyStep)) {
             if ((current instanceof VertexStep && (((VertexStep) 
current).returnsVertex() ||
                     !((VertexStep) 
current).getDirection().equals(Direction.OUT))) ||
@@ -107,11 +112,7 @@ public final class SparkSingleIterationStrategy extends 
AbstractTraversalStrateg
                 if (((TraversalParent) 
current).getGlobalChildren().stream().filter(SparkSingleIterationStrategy::endsWithInElement).findAny().isPresent())
                     return true;
             }
-            if (!(current instanceof FilterStep ||
-                    current instanceof SideEffectStep ||
-                    current instanceof SelectStep ||
-                    current instanceof SelectOneStep ||
-                    current instanceof Barrier)) {
+            if (!(current instanceof FilterStep || current instanceof 
SideEffectStep)) { // side-effects and filters do not alter the mapping and 
thus, deeper analysis is required
                 return false;
             }
             current = current.getPreviousStep();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/989237fd/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
----------------------------------------------------------------------
diff --git 
a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
 
b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
index 20596d7..b055eb8 100644
--- 
a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
+++ 
b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
@@ -43,6 +43,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import static org.apache.tinkerpop.gremlin.structure.Column.keys;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -127,12 +128,23 @@ public class SparkSingleIterationStrategyTest extends 
AbstractSparkTest {
         test(true, 6L, g.V().inE().id().count());
         test(true, 6L, g.V().outE().count());
         test(true, 4L, g.V().outE().inV().id().dedup().count());
-        test(true, 6L, g.V().as("a").outE().inV().as("b").id().dedup("a", 
"b").by(T.id).count());
         test(true, 4L, g.V().filter(__.in()).count());
         test(true, 6L, g.V().sideEffect(__.in()).count());
+        test(true, 6L, g.V().map(__.constant("hello")).count());
+        test(true, g.V().groupCount());
+        test(true, g.V().groupCount("x"));
+        test(true, g.V().groupCount("x").cap("x"));
+        test(true, g.V().id().groupCount("x").cap("x"));
+        test(true, g.V().outE().groupCount());
+        test(true, g.V().outE().groupCount().by("weight"));
+        test(true, g.V().inE().id().groupCount());
+        test(true, g.V().inE().values("weight").groupCount());
         /////
+        test(false, 6L, g.V().as("a").outE().inV().as("b").id().dedup("a", 
"b").by(T.id).count());
         test(false, 6L, g.V().local(__.inE()).count());
         test(false, 6L, g.V().outE().outV().count()); // todo: low probability 
traversal, but none the less could be optimized for
+        test(false, g.V().out().id().groupCount("x")); // todo: low 
probability traversal, but none the less could be optimized for
+        test(false, g.V().inE().values("weight").groupCount("x")); // todo: 
low probability traversal, but none the less could be optimized for
         test(false, 6L, g.V().in().count());
         test(false, 6L, g.V().flatMap(__.in()).count());
         test(false, 4L, g.V().map(__.in()).count());
@@ -150,6 +162,18 @@ public class SparkSingleIterationStrategyTest extends 
AbstractSparkTest {
         test(false, g.V().out().valueMap());
         test(false, 6L, 
g.V().as("a").outE().inV().values("name").as("b").dedup("a", "b").count());
         test(false, 2L, 
g.V().outE().inV().groupCount().select(Column.values).unfold().dedup().count());
+        test(false, g.V().out().groupCount("x"));
+        test(false, g.V().out().groupCount("x").cap("x"));
+        test(false, 6L, 
g.V().both().groupCount("x").cap("x").select(keys).unfold().count());
+        test(false, g.V().outE().inV().groupCount());
+        test(false, g.V().outE().inV().groupCount().by("name"));
+        test(false, g.V().outE().inV().tree());
+        test(false, g.V().inE().groupCount());
+        test(false, g.V().inE().groupCount().by("weight"));
+        test(false, g.V().in().values("name").groupCount());
+        test(false, g.V().out().groupCount("x"));
+        test(false, g.V().in().groupCount("x"));
+        test(false, g.V().both().groupCount("x").cap("x"));
     }
 
     private static <R> void test(boolean singleIteration, final Traversal<?, 
R> traversal) {

Reply via email to