You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2016/11/11 20:09:24 UTC

[01/17] tinkerpop git commit: fixed an NPE bug in profiling GroupSideEffectStep. It has to deal with how GroupSideEffectStep breaks apart the valueTraversal into a pre/post-traversal for pre-proecessing and reduction. While I was testing, I found another [Forced Update!]

Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1490 bda502784 -> e07cfd06e (forced update)


fixed an NPE bug in profiling GroupSideEffectStep. It has to deal with how GroupSideEffectStep breaks apart the valueTraversal into a pre/post-traversal for pre-proecessing and reduction. While I was testing, I found another bug where if the reducing traversal has no data, then don't .next() it. Basically, it is possible for Profiling to get a traversal that has not been next'd because the traversal's pre/post was being worked with.


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

Branch: refs/heads/TINKERPOP-1490
Commit: 3d70c3d15d4591acab84420f86991cd98a187c38
Parents: b4d0ef9
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 3 10:14:06 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 3 10:14:06 2016 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../process/traversal/step/map/GroupStep.java   | 33 +++++----
 .../step/sideEffect/GroupSideEffectStep.java    | 11 +--
 .../traversal/util/DefaultTraversalMetrics.java | 76 ++++++++++----------
 .../step/sideEffect/GroovyGroupTest.groovy      |  5 ++
 .../traversal/step/sideEffect/GroupTest.java    | 23 ++++++
 6 files changed, 95 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d70c3d1/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d87c0fd..766b135 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Fixed a `NullPointerException` bug with profiling `GroupSideEffectStep` in OLTP.
 * Improved ability to release resources in `GraphProvider` instances in the test suite.
 * Added a `force` option for killing sessions without waiting for transaction close or timeout of a currently running job or multiple jobs.
 * Deprecated `Session.kill()` and `Session.manualKill()`.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d70c3d1/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
index 84c5ca8..737c5f9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
@@ -22,7 +22,6 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ElementValueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.FunctionTraverser;
@@ -61,8 +60,8 @@ public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
 
     private char state = 'k';
     private Traversal.Admin<S, K> keyTraversal = null;
-    private Traversal.Admin<S, ?> preTraversal;
-    private Traversal.Admin<S, V> valueTraversal;
+    private Traversal.Admin<S, ?> preTraversal = null;
+    private Traversal.Admin<S, V> valueTraversal = null;
 
     public GroupStep(final Traversal.Admin traversal) {
         super(traversal);
@@ -109,10 +108,12 @@ public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
 
     @Override
     public List<Traversal.Admin<?, ?>> getLocalChildren() {
-        final List<Traversal.Admin<?, ?>> children = new ArrayList<>(2);
+        final List<Traversal.Admin<?, ?>> children = new ArrayList<>(3);
         if (null != this.keyTraversal)
-            children.add((Traversal.Admin) this.keyTraversal);
+            children.add(this.keyTraversal);
         children.add(this.valueTraversal);
+        if (null != this.preTraversal)
+            children.add(this.preTraversal);
         return children;
     }
 
@@ -127,7 +128,8 @@ public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
         if (null != this.keyTraversal)
             clone.keyTraversal = this.keyTraversal.clone();
         clone.valueTraversal = this.valueTraversal.clone();
-        clone.preTraversal = this.integrateChild(GroupStep.generatePreTraversal(clone.valueTraversal));
+        if (null != this.preTraversal)
+            clone.preTraversal = this.preTraversal.clone();
         return clone;
     }
 
@@ -332,26 +334,30 @@ public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
 
     public static Traversal.Admin<?, ?> generatePreTraversal(final Traversal.Admin<?, ?> valueTraversal) {
         if (!TraversalHelper.hasStepOfAssignableClass(Barrier.class, valueTraversal))
-            return valueTraversal;
+            return valueTraversal.clone();
         final Traversal.Admin<?, ?> first = __.identity().asAdmin();
+        boolean updated = false;
         for (final Step step : valueTraversal.getSteps()) {
             if (step instanceof Barrier)
                 break;
             first.addStep(step.clone());
+            updated = true;
         }
-        return first.getSteps().size() == 1 ? null : first;
+        return updated ? first : null;
     }
 
     public static <K, V> Map<K, V> doFinalReduction(final Map<K, Object> map, final Traversal.Admin<?, V> valueTraversal) {
         final Map<K, V> reducedMap = new HashMap<>(map.size());
         final Barrier reducingBarrierStep = TraversalHelper.getFirstStepOfAssignableClass(Barrier.class, valueTraversal).orElse(null);
         IteratorUtils.removeOnNext(map.entrySet().iterator()).forEachRemaining(entry -> {
-            valueTraversal.reset();
             if (null == reducingBarrierStep) {
-                reducedMap.put(entry.getKey(), entry.getValue() instanceof TraverserSet ?
-                        ((TraverserSet<V>) entry.getValue()).iterator().next().get() :
-                        (V) entry.getValue());
+                if (entry.getValue() instanceof TraverserSet) {
+                    if (!((TraverserSet) entry.getValue()).isEmpty())
+                        reducedMap.put(entry.getKey(), ((TraverserSet<V>) entry.getValue()).peek().get());
+                } else
+                    reducedMap.put(entry.getKey(), (V) entry.getValue());
             } else {
+                valueTraversal.reset();
                 if (entry.getValue() instanceof Traverser.Admin)
                     ((Step) reducingBarrierStep).addStart((Traverser.Admin) entry.getValue());
                 else if (entry.getValue() instanceof TraverserSet)
@@ -361,7 +367,8 @@ public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
                     reducingBarrierStep.addBarrier((((Pair) entry.getValue()).getValue1()));
                 } else
                     reducingBarrierStep.addBarrier(entry.getValue());
-                reducedMap.put(entry.getKey(), valueTraversal.next());
+                if (valueTraversal.hasNext())
+                    reducedMap.put(entry.getKey(), valueTraversal.next());
             }
         });
         assert map.isEmpty();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d70c3d1/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
index b5deb02..f2699e0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
@@ -45,7 +45,7 @@ public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S> implem
     private char state = 'k';
     private Traversal.Admin<S, K> keyTraversal = null;
     private Traversal.Admin<S, ?> preTraversal = null;
-    private Traversal.Admin<S, V> valueTraversal = this.integrateChild(__.fold().asAdmin());
+    private Traversal.Admin<S, V> valueTraversal = null;
     ///
     private String sideEffectKey;
 
@@ -99,10 +99,12 @@ public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S> implem
 
     @Override
     public List<Traversal.Admin<?, ?>> getLocalChildren() {
-        final List<Traversal.Admin<?, ?>> children = new ArrayList<>(2);
+        final List<Traversal.Admin<?, ?>> children = new ArrayList<>(3);
         if (null != this.keyTraversal)
-            children.add((Traversal.Admin) this.keyTraversal);
+            children.add(this.keyTraversal);
         children.add(this.valueTraversal);
+        if (null != this.preTraversal)
+            children.add(this.preTraversal);
         return children;
     }
 
@@ -117,7 +119,8 @@ public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S> implem
         if (null != this.keyTraversal)
             clone.keyTraversal = this.keyTraversal.clone();
         clone.valueTraversal = this.valueTraversal.clone();
-        clone.preTraversal = this.integrateChild(GroupStep.generatePreTraversal(clone.valueTraversal));
+        if (null != this.preTraversal)
+            clone.preTraversal = this.preTraversal.clone();
         return clone;
     }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d70c3d1/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalMetrics.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalMetrics.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalMetrics.java
index ce52ffc..ecf28e0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalMetrics.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversalMetrics.java
@@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit;
 
 /**
  * @author Bob Briody (http://bobbriody.com)
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public final class DefaultTraversalMetrics implements TraversalMetrics, Serializable {
     /**
@@ -61,29 +62,29 @@ public final class DefaultTraversalMetrics implements TraversalMetrics, Serializ
      */
     public DefaultTraversalMetrics(final long totalStepDurationNs, final List<MutableMetrics> metricsMap) {
         this.totalStepDuration = totalStepDurationNs;
-        this.computedMetrics = new LinkedHashMap<>(metrics.size());
-        metricsMap.forEach(m -> computedMetrics.put(m.getId(), m.getImmutableClone()));
+        this.computedMetrics = new LinkedHashMap<>(this.metrics.size());
+        metricsMap.forEach(metric -> this.computedMetrics.put(metric.getId(), metric.getImmutableClone()));
     }
 
     @Override
     public long getDuration(final TimeUnit unit) {
-        return unit.convert(totalStepDuration, MutableMetrics.SOURCE_UNIT);
+        return unit.convert(this.totalStepDuration, MutableMetrics.SOURCE_UNIT);
     }
 
     @Override
     public Metrics getMetrics(final int index) {
         // adjust index to account for the injected profile steps
-        return (Metrics) computedMetrics.get(indexToLabelMap.get(index));
+        return this.computedMetrics.get(this.indexToLabelMap.get(index));
     }
 
     @Override
     public Metrics getMetrics(final String id) {
-        return computedMetrics.get(id);
+        return this.computedMetrics.get(id);
     }
 
     @Override
     public Collection<ImmutableMetrics> getMetrics() {
-        return computedMetrics.values();
+        return this.computedMetrics.values();
     }
 
     @Override
@@ -96,7 +97,7 @@ public final class DefaultTraversalMetrics implements TraversalMetrics, Serializ
 
         sb.append("\n=============================================================================================================");
 
-        appendMetrics(computedMetrics.values(), sb, 0);
+        appendMetrics(this.computedMetrics.values(), sb, 0);
 
         // Append total duration
         sb.append(String.format("%n%50s %21s %11s %15.3f %8s",
@@ -150,25 +151,25 @@ public final class DefaultTraversalMetrics implements TraversalMetrics, Serializ
 
     private void computeTotals() {
         // Create temp list of ordered metrics
-        List<MutableMetrics> tempMetrics = new ArrayList<>(metrics.size());
-        for (String label : indexToLabelMap.values()) {
+        final List<MutableMetrics> tempMetrics = new ArrayList<>(this.metrics.size());
+        for (final String label : this.indexToLabelMap.values()) {
             // The indexToLabelMap is sorted by index (key)
-            tempMetrics.add(metrics.get(label).clone());
+            tempMetrics.add(this.metrics.get(label).clone());
         }
 
         // Calculate total duration
         this.totalStepDuration = 0;
-        tempMetrics.forEach(m -> this.totalStepDuration += m.getDuration(MutableMetrics.SOURCE_UNIT));
+        tempMetrics.forEach(metric -> this.totalStepDuration += metric.getDuration(MutableMetrics.SOURCE_UNIT));
 
         // Assign %'s
         tempMetrics.forEach(m -> {
-            double dur = m.getDuration(TimeUnit.NANOSECONDS) * 100.d / this.totalStepDuration;
+            final double dur = m.getDuration(TimeUnit.NANOSECONDS) * 100.d / this.totalStepDuration;
             m.setAnnotation(PERCENT_DURATION_KEY, dur);
         });
 
         // Store immutable instances of the calculated metrics
-        computedMetrics = new LinkedHashMap<>(metrics.size());
-        tempMetrics.forEach(it -> computedMetrics.put(it.getId(), it.getImmutableClone()));
+        this.computedMetrics = new LinkedHashMap<>(this.metrics.size());
+        tempMetrics.forEach(it -> this.computedMetrics.put(it.getId(), it.getImmutableClone()));
     }
 
     public static DefaultTraversalMetrics merge(final Iterator<DefaultTraversalMetrics> toMerge) {
@@ -186,7 +187,7 @@ public final class DefaultTraversalMetrics implements TraversalMetrics, Serializ
 
                     newTraversalMetrics.metrics.put(metricsId, aggregateMetrics);
                     // Set the index of the Metrics
-                    for (Map.Entry<Integer, String> entry : inTraversalMetrics.indexToLabelMap.entrySet()) {
+                    for (final Map.Entry<Integer, String> entry : inTraversalMetrics.indexToLabelMap.entrySet()) {
                         if (metricsId.equals(entry.getValue())) {
                             newTraversalMetrics.indexToLabelMap.put(entry.getKey(), metricsId);
                             break;
@@ -199,7 +200,7 @@ public final class DefaultTraversalMetrics implements TraversalMetrics, Serializ
         return newTraversalMetrics;
     }
 
-    public void setMetrics(Traversal.Admin traversal, boolean onGraphComputer) {
+    public void setMetrics(final Traversal.Admin traversal, final boolean onGraphComputer) {
         addTopLevelMetrics(traversal, onGraphComputer);
         handleNestedTraversals(traversal, null, onGraphComputer);
         computeTotals();
@@ -222,36 +223,37 @@ public final class DefaultTraversalMetrics implements TraversalMetrics, Serializ
         }
     }
 
-    private void handleNestedTraversals(Traversal.Admin traversal, MutableMetrics parentMetrics, boolean onGraphComputer) {
+    private void handleNestedTraversals(final Traversal.Admin traversal, final MutableMetrics parentMetrics, final boolean onGraphComputer) {
         long prevDur = 0;
-        for (int ii = 0; ii < traversal.getSteps().size(); ii++) {
-            Step step = (Step) traversal.getSteps().get(ii);
-            if (!(step instanceof ProfileStep)) {
+        for (int i = 0; i < traversal.getSteps().size(); i++) {
+            final Step step = (Step) traversal.getSteps().get(i);
+            if (!(step instanceof ProfileStep))
                 continue;
-            }
 
             final MutableMetrics metrics = onGraphComputer ?
                     traversal.getSideEffects().get(step.getId()) :
                     ((ProfileStep) step).getMetrics();
 
-            if (!onGraphComputer) {
-                // subtract upstream duration.
-                long durBeforeAdjustment = metrics.getDuration(TimeUnit.NANOSECONDS);
-                // adjust duration
-                metrics.setDuration(metrics.getDuration(TimeUnit.NANOSECONDS) - prevDur, TimeUnit.NANOSECONDS);
-                prevDur = durBeforeAdjustment;
-            }
-
-            if (parentMetrics != null) {
-                parentMetrics.addNested(metrics);
-            }
+            if (null != metrics) { // this happens when a particular branch never received a .next() call (the metrics were never initialized)
+                if (!onGraphComputer) {
+                    // subtract upstream duration.
+                    long durBeforeAdjustment = metrics.getDuration(TimeUnit.NANOSECONDS);
+                    // adjust duration
+                    metrics.setDuration(metrics.getDuration(TimeUnit.NANOSECONDS) - prevDur, TimeUnit.NANOSECONDS);
+                    prevDur = durBeforeAdjustment;
+                }
 
-            if (step.getPreviousStep() instanceof TraversalParent) {
-                for (Traversal.Admin<?, ?> t : ((TraversalParent) step.getPreviousStep()).getLocalChildren()) {
-                    handleNestedTraversals(t, metrics, onGraphComputer);
+                if (parentMetrics != null) {
+                    parentMetrics.addNested(metrics);
                 }
-                for (Traversal.Admin<?, ?> t : ((TraversalParent) step.getPreviousStep()).getGlobalChildren()) {
-                    handleNestedTraversals(t, metrics, onGraphComputer);
+
+                if (step.getPreviousStep() instanceof TraversalParent) {
+                    for (Traversal.Admin<?, ?> t : ((TraversalParent) step.getPreviousStep()).getLocalChildren()) {
+                        handleNestedTraversals(t, metrics, onGraphComputer);
+                    }
+                    for (Traversal.Admin<?, ?> t : ((TraversalParent) step.getPreviousStep()).getGlobalChildren()) {
+                        handleNestedTraversals(t, metrics, onGraphComputer);
+                    }
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d70c3d1/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovyGroupTest.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovyGroupTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovyGroupTest.groovy
index 13802b8..84da296 100644
--- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovyGroupTest.groovy
+++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovyGroupTest.groovy
@@ -118,5 +118,10 @@ public abstract class GroovyGroupTest {
         public Traversal<Vertex, Map<String, Map<String, Number>>> get_g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX() {
             new ScriptTraversal<>(g, "gremlin-groovy", "g.V.out('followedBy').group.by('songType').by(bothE().group.by(label).by(values('weight').sum))")
         }
+
+        @Override
+        public Traversal<Vertex, Map<String, String>> get_g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX() {
+            new ScriptTraversal<>(g, "gremlin-groovy", "g.V.group('m').by('name').by(__.in('knows').name).cap('m')")
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d70c3d1/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
index 356eb58..036c8c8 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupTest.java
@@ -88,6 +88,8 @@ public abstract class GroupTest extends AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, Map<String, Map<String, Number>>> get_g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX();
 
+    public abstract Traversal<Vertex, Map<String, String>> get_g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_group_byXnameX() {
@@ -364,6 +366,7 @@ public abstract class GroupTest extends AbstractGremlinProcessTest {
     @LoadGraphWith(MODERN)
     public void g_V_group_byXbothE_countX_byXgroup_byXlabelXX() {
         final Traversal<Vertex, Map<Long, Map<String, List<Vertex>>>> traversal = get_g_V_group_byXbothE_countX_byXgroup_byXlabelXX();
+        printTraversalForm(traversal);
         final Map<Long, Map<String, List<Vertex>>> map = traversal.next();
         assertFalse(traversal.hasNext());
         assertEquals(2, map.size());
@@ -399,6 +402,7 @@ public abstract class GroupTest extends AbstractGremlinProcessTest {
     @LoadGraphWith(GRATEFUL)
     public void g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX() {
         final Traversal<Vertex, Map<String, Map<String, Number>>> traversal = get_g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX();
+        printTraversalForm(traversal);
         final Map<String, Map<String, Number>> map = traversal.next();
         assertFalse(traversal.hasNext());
         assertEquals(3, map.size());
@@ -423,6 +427,20 @@ public abstract class GroupTest extends AbstractGremlinProcessTest {
         assertEquals(0, subMap.get("sungBy").intValue());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX() {
+        final Traversal<Vertex, Map<String, String>> traversal = get_g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX();
+        printTraversalForm(traversal);
+        final Map<String, String> map = traversal.next();
+        assertFalse(traversal.hasNext());
+        assertEquals(2, map.size());
+        assertEquals("marko", map.get("vadas"));
+        assertEquals("marko", map.get("josh"));
+
+        checkSideEffects(traversal.asAdmin().getSideEffects(), "m", HashMap.class);
+    }
+
     public static class Traversals extends GroupTest {
 
         @Override
@@ -514,5 +532,10 @@ public abstract class GroupTest extends AbstractGremlinProcessTest {
         public Traversal<Vertex, Map<String, Map<String, Number>>> get_g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX() {
             return g.V().out("followedBy").<String, Map<String, Number>>group().by("songType").by(__.bothE().group().by(T.label).by(__.values("weight").sum()));
         }
+
+        @Override
+        public Traversal<Vertex, Map<String, String>> get_g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX() {
+            return g.V().group("m").by("name").by(__.in("knows").values("name")).cap("m");
+        }
     }
 }


[04/17] tinkerpop git commit: removed null initialization of fields and removed a stream() usage.

Posted by sp...@apache.org.
removed null initialization of fields and removed a stream() usage.


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

Branch: refs/heads/TINKERPOP-1490
Commit: 525d8ea38863f912eb3f2dce515cf7a8d4b7003c
Parents: b644435
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 3 11:17:38 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 3 11:17:38 2016 -0600

----------------------------------------------------------------------
 .../gremlin/process/traversal/step/map/GroupStep.java     | 10 ++++++----
 .../traversal/step/sideEffect/GroupSideEffectStep.java    | 10 ++++++----
 2 files changed, 12 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/525d8ea3/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
index 737c5f9..174c1ad 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java
@@ -59,9 +59,9 @@ import java.util.function.BinaryOperator;
 public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>> implements ByModulating, TraversalParent {
 
     private char state = 'k';
-    private Traversal.Admin<S, K> keyTraversal = null;
-    private Traversal.Admin<S, ?> preTraversal = null;
-    private Traversal.Admin<S, V> valueTraversal = null;
+    private Traversal.Admin<S, K> keyTraversal;
+    private Traversal.Admin<S, ?> preTraversal;
+    private Traversal.Admin<S, V> valueTraversal;
 
     public GroupStep(final Traversal.Admin traversal) {
         super(traversal);
@@ -95,7 +95,9 @@ public final class GroupStep<S, K, V> extends ReducingBarrierStep<S, Map<K, V>>
             final TraverserSet traverserSet = new TraverserSet<>();
             this.preTraversal.reset();
             this.preTraversal.addStart(traverser);
-            this.preTraversal.getEndStep().forEachRemaining(traverserSet::add);
+            while(this.preTraversal.hasNext()) {
+                traverserSet.add(this.preTraversal.nextTraverser());
+            }
             map.put(TraversalUtil.applyNullable(traverser, this.keyTraversal), (V) traverserSet);
         }
         return map;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/525d8ea3/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
index f2699e0..cf69c4c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java
@@ -43,9 +43,9 @@ import java.util.Set;
 public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S> implements SideEffectCapable<Map<K, ?>, Map<K, V>>, TraversalParent, ByModulating {
 
     private char state = 'k';
-    private Traversal.Admin<S, K> keyTraversal = null;
-    private Traversal.Admin<S, ?> preTraversal = null;
-    private Traversal.Admin<S, V> valueTraversal = null;
+    private Traversal.Admin<S, K> keyTraversal;
+    private Traversal.Admin<S, ?> preTraversal;
+    private Traversal.Admin<S, V> valueTraversal;
     ///
     private String sideEffectKey;
 
@@ -81,7 +81,9 @@ public final class GroupSideEffectStep<S, K, V> extends SideEffectStep<S> implem
             final TraverserSet traverserSet = new TraverserSet<>();
             this.preTraversal.reset();
             this.preTraversal.addStart(traverser.split());
-            this.preTraversal.getEndStep().forEachRemaining(traverserSet::add);
+            while(this.preTraversal.hasNext()) {
+                traverserSet.add(this.preTraversal.nextTraverser());
+            }
             map.put(TraversalUtil.applyNullable(traverser, this.keyTraversal), (V) traverserSet);
         }
         this.getTraversal().getSideEffects().add(this.sideEffectKey, map);


[16/17] tinkerpop git commit: TINKERPOP-1490 Restructured Traversal.promise()

Posted by sp...@apache.org.
TINKERPOP-1490 Restructured Traversal.promise()

No longer uses an ExecutorService and is only applicable to "remote" traversals. Moved the commons-lang dependency back to gremlin-groovy for now.


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

Branch: refs/heads/TINKERPOP-1490
Commit: a9e5e99a352ac3b9899dffc6f17762f3c12dcc01
Parents: 94cc911
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 12:51:40 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Nov 11 15:09:04 2016 -0500

----------------------------------------------------------------------
 gremlin-core/pom.xml                            |   5 -
 .../process/remote/RemoteConnection.java        |  12 +-
 .../remote/traversal/RemoteTraversal.java       |   2 +-
 .../remote/traversal/step/map/RemoteStep.java   |  32 +++-
 .../gremlin/process/traversal/Traversal.java    |  57 ++------
 .../traversal/util/DefaultTraversal.java        |  37 -----
 .../process/traversal/TraversalTest.java        | 145 -------------------
 .../tinkerpop/gremlin/driver/Connection.java    |   6 +-
 .../driver/remote/DriverRemoteConnection.java   |  14 ++
 .../driver/remote/DriverRemoteTraversal.java    |  16 +-
 .../DriverRemoteTraversalSideEffects.java       |  24 ++-
 .../DriverRemoteTraversalSideEffectsTest.java   |  12 +-
 gremlin-groovy/pom.xml                          |   5 +
 .../server/GremlinServerIntegrateTest.java      |  26 +++-
 .../process/traversal/CoreTraversalTest.java    |  42 ------
 15 files changed, 131 insertions(+), 304 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-core/pom.xml b/gremlin-core/pom.xml
index 0594448..e8f3a34 100644
--- a/gremlin-core/pom.xml
+++ b/gremlin-core/pom.xml
@@ -61,11 +61,6 @@ limitations under the License.
                 </exclusion>
             </exclusions>
         </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-            <version>3.3.1</version>
-        </dependency>
         <!-- LOGGING -->
         <dependency>
             <groupId>org.slf4j</groupId>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
index 8506ad7..f4e3976 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/RemoteConnection.java
@@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 
 import java.util.Iterator;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * A simple abstraction of a "connection" to a "server" that is capable of processing a {@link Traversal} and
@@ -43,9 +44,16 @@ public interface RemoteConnection extends AutoCloseable {
     public <E> Iterator<Traverser.Admin<E>> submit(final Traversal<?, E> traversal) throws RemoteConnectionException;
 
     /**
-     * Submits {@link Traversal} {@link Bytecode} to a server and returns a {@link Traversal}.
-     * The {@link Traversal} is an abstraction over two types of results that can be returned as part of the
+     * Submits {@link Traversal} {@link Bytecode} to a server and returns a {@link RemoteTraversal}.
+     * The {@link RemoteTraversal} is an abstraction over two types of results that can be returned as part of the
      * response from the server: the results of the {@link Traversal} itself and the side-effects that it produced.
      */
     public <E> RemoteTraversal<?,E> submit(final Bytecode bytecode) throws RemoteConnectionException;
+
+    /**
+     * Submits {@link Traversal} {@link Bytecode} to a server and returns a promise of a {@link RemoteTraversal}.
+     * The {@link RemoteTraversal} is an abstraction over two types of results that can be returned as part of the
+     * response from the server: the results of the {@link Traversal} itself and the side-effects that it produced.
+     */
+    public <E> CompletableFuture<RemoteTraversal<?, E>> submitAsync(final Bytecode bytecode) throws RemoteConnectionException;
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
index 9c893c2..57b0cda 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversal.java
@@ -39,7 +39,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
 public interface RemoteTraversal<S,E> extends Traversal.Admin<S,E> {
 
     /**
-     * Returns remote side-effects generated by the traversal so that they can accessible to the client. Note that
+     * Returns remote side-effects generated by the traversal so that they can be accessible to the client. Note that
      * "side-effect" refers to the value in "a" in the traversal {@code g.V().aggregate('a').values('name')}.
      */
     @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
index 6b2be96..3e19097 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/step/map/RemoteStep.java
@@ -21,12 +21,17 @@ package org.apache.tinkerpop.gremlin.process.remote.traversal.step.map;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnectionException;
 import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.NoSuchElementException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Sends a {@link Traversal} to a {@link RemoteConnection} and iterates back the results.
@@ -38,6 +43,7 @@ public final class RemoteStep<S, E> extends AbstractStep<S, E> {
 
     private transient RemoteConnection remoteConnection;
     private RemoteTraversal<?, E> remoteTraversal;
+    private final AtomicReference<CompletableFuture<Traversal<?, E>>> traversalFuture = new AtomicReference<>(null);
 
     public RemoteStep(final Traversal.Admin traversal, final RemoteConnection remoteConnection) {
         super(traversal);
@@ -51,14 +57,26 @@ public final class RemoteStep<S, E> extends AbstractStep<S, E> {
 
     @Override
     protected Traverser.Admin<E> processNextStart() throws NoSuchElementException {
-        if (null == this.remoteTraversal) {
-            try {
-                this.remoteTraversal = this.remoteConnection.submit(this.traversal.getBytecode());
-                this.traversal.setSideEffects(this.remoteTraversal.getSideEffects());
-            } catch (final RemoteConnectionException sce) {
-                throw new IllegalStateException(sce);
+        if (null == this.remoteTraversal) promise().join();
+        return this.remoteTraversal.nextTraverser();
+    }
+
+    /**
+     * Submits the traversal asynchronously to a "remote" using {@link RemoteConnection#submitAsync(Bytecode)}.
+     */
+    public CompletableFuture<Traversal<?, E>> promise() {
+        try {
+            if (null == traversalFuture.get()) {
+                traversalFuture.set(this.remoteConnection.submitAsync(this.traversal.getBytecode()).<Traversal<?, E>>thenApply(t -> {
+                    this.remoteTraversal = (RemoteTraversal<?, E>) t;
+                    this.traversal.setSideEffects(this.remoteTraversal.getSideEffects());
+                    return traversal;
+                }));
             }
+
+            return traversalFuture.get();
+        } catch (RemoteConnectionException rce) {
+            throw new IllegalStateException(rce);
         }
-        return this.remoteTraversal.nextTraverser();
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
index e4ba5a6..04f5127 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
@@ -18,8 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.commons.configuration.Configuration;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
+import org.apache.tinkerpop.gremlin.process.remote.traversal.step.map.RemoteStep;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileSideEffectStep;
@@ -43,11 +44,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.Spliterators;
-import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Stream;
@@ -148,39 +145,21 @@ public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable, A
 
     /**
      * Starts a promise to execute a function on the current {@code Traversal} that will be completed in the future.
-     * This implementation uses {@link Admin#traversalExecutorService} to execute the supplied
-     * {@code traversalFunction}.
+     * Note that this method can only be used if the {@code Traversal} is constructed using
+     * {@link TraversalSource#withRemote(Configuration)}. Calling this method otherwise will yield an
+     * {@code IllegalStateException}.
      */
     public default <T> CompletableFuture<T> promise(final Function<Traversal, T> traversalFunction) {
-        return promise(traversalFunction, Admin.traversalExecutorService);
-    }
-
-    /**
-     * Starts a promise to execute a function on the current {@code Traversal} that will be completed in the future.
-     * This implementation uses the caller supplied {@code ExecutorService} to execute the {@code traversalFunction}.
-     */
-    public default <T> CompletableFuture<T> promise(final Function<Traversal, T> traversalFunction, final ExecutorService service) {
-        final CompletableFuture<T> promise = new CompletableFuture<>();
-        final Future iterationFuture = service.submit(() -> {
-            try {
-                promise.complete(traversalFunction.apply(this));
-            } catch (Exception ex) {
-                // the promise may have been cancelled by the caller, in which case, there is no need to attempt
-                // another write on completion
-                if (!promise.isDone()) promise.completeExceptionally(ex);
-            }
-        });
-
-        // if the user cancels the promise then attempt to kill the iteration.
-        promise.exceptionally(t -> {
-            if (t instanceof CancellationException) {
-                iterationFuture.cancel(true);
-            }
-
-            return null;
-        });
-
-        return promise;
+        // apply strategies to see if RemoteStrategy has any effect (i.e. add RemoteStep)
+        if (!this.asAdmin().isLocked()) this.asAdmin().applyStrategies();
+
+        // use the end step so the results are bulked
+        final Step<?, E> endStep = this.asAdmin().getEndStep();
+        if (endStep instanceof RemoteStep) {
+            return ((RemoteStep) endStep).promise().thenApply(traversalFunction);
+        } else {
+            throw new IllegalStateException("Only traversals created using withRemote() can be used in an async way");
+        }
     }
 
     /**
@@ -297,12 +276,6 @@ public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable, A
     public interface Admin<S, E> extends Traversal<S, E> {
 
         /**
-         * Service that handles promises.
-         */
-        static final ExecutorService traversalExecutorService = Executors.newCachedThreadPool(
-                new BasicThreadFactory.Builder().namingPattern("traversal-executor-%d").build());
-
-        /**
          * Get the {@link Bytecode} associated with the construction of this traversal.
          *
          * @return the byte code representation of the traversal

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
index 6ce6dfe..3c21e37 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
@@ -43,9 +43,6 @@ import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.function.Function;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -328,40 +325,6 @@ public class DefaultTraversal<S, E> implements Traversal.Admin<S, E> {
         this.graph = graph;
     }
 
-    /**
-     * Override of {@link Traversal#promise(Function)} that is aware of graph transactions.
-     */
-    @Override
-    public <T2> CompletableFuture<T2> promise(final Function<Traversal, T2> traversalFunction) {
-        return this.promise(traversalFunction, Traversal.Admin.traversalExecutorService);
-    }
-
-    /**
-     * Override of {@link Traversal#promise(Function)} that is aware of graph transactions. In a transactional graph
-     * a promise represents the full scope of a transaction, even if the graph is only partially iterated.
-     */
-    @Override
-    public <T2> CompletableFuture<T2> promise(final Function<Traversal, T2> traversalFunction, final ExecutorService service) {
-        if (graph != null && graph.features().graph().supportsTransactions()) {
-            final Function<Traversal, T2> transactionAware = traversal -> {
-
-                try {
-                    if (graph.tx().isOpen()) graph.tx().rollback();
-                    final T2 obj = traversalFunction.apply(traversal);
-                    if (graph.tx().isOpen()) graph.tx().commit();
-                    return obj;
-                } catch (Exception ex) {
-                    if (graph.tx().isOpen()) graph.tx().rollback();
-                    throw ex;
-                }
-            };
-
-            return Traversal.Admin.super.promise(transactionAware, service);
-        } else {
-            return Traversal.Admin.super.promise(traversalFunction, service);
-        }
-    }
-
     @Override
     public boolean equals(final Object other) {
         return other != null && other.getClass().equals(this.getClass()) && this.equals(((Traversal.Admin) other));

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
index aa1b99b..c427d8e 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
@@ -30,34 +30,22 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.util.NoSuchElementException;
 import java.util.Optional;
-import java.util.Random;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsCollectionContaining.hasItems;
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class TraversalTest {
 
-    private final ExecutorService service = Executors.newFixedThreadPool(2);
-
     @Test
     public void shouldTryNext() {
         final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3);
@@ -117,139 +105,6 @@ public class TraversalTest {
     }
 
     @Test
-    public void shouldPromiseNextThreeUsingForkJoin() throws Exception {
-        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
-        final CompletableFuture<List<Integer>> promiseFirst = t.promise(traversal -> traversal.next(3));
-        final List<Integer> listFirst = promiseFirst.get();
-        assertEquals(3, listFirst.size());
-        assertThat(listFirst, hasItems(1 ,2, 3));
-        assertThat(t.hasNext(), is(true));
-        assertThat(promiseFirst.isDone(), is(true));
-
-        final CompletableFuture<List<Integer>> promiseSecond = t.promise(traversal -> traversal.next(3));
-        final List<Integer> listSecond = promiseSecond.get();
-        assertEquals(3, listSecond.size());
-        assertThat(listSecond, hasItems(4, 5, 6));
-        assertThat(t.hasNext(), is(true));
-        assertThat(promiseSecond.isDone(), is(true));
-
-        final CompletableFuture<List<Integer>> promiseThird = t.promise(traversal -> traversal.next(3));
-        final List<Integer> listThird = promiseThird.get();
-        assertEquals(1, listThird.size());
-        assertThat(listThird, hasItems(7));
-        assertThat(t.hasNext(), is(false));
-        assertThat(promiseThird.isDone(), is(true));
-
-        final CompletableFuture<Integer> promiseDead = t.promise(traversal -> (Integer) traversal.next());
-        final AtomicBoolean dead = new AtomicBoolean(false);
-        promiseDead.exceptionally(tossed -> {
-            dead.set(tossed instanceof NoSuchElementException);
-            return null;
-        });
-
-        try {
-            promiseDead.get(10000, TimeUnit.MILLISECONDS);
-            fail("Should have gotten an exception");
-        } catch (Exception ex) {
-            if (ex instanceof TimeoutException) {
-                fail("This should not have timed out but should have gotten an exception caught above in the exceptionally() clause");
-            }
-
-            assertThat(ex.getCause(), instanceOf(NoSuchElementException.class));
-        }
-
-        assertThat(dead.get(), is(true));
-        assertThat(t.hasNext(), is(false));
-        assertThat(promiseDead.isDone(), is(true));
-    }
-
-    @Test
-    public void shouldPromiseNextThreeUsingSpecificExecutor() throws Exception {
-        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
-        final CompletableFuture<List<Integer>> promiseFirst = t.promise(traversal -> traversal.next(3), service);
-        final List<Integer> listFirst = promiseFirst.get();
-        assertEquals(3, listFirst.size());
-        assertThat(listFirst, hasItems(1 ,2, 3));
-        assertThat(t.hasNext(), is(true));
-        assertThat(promiseFirst.isDone(), is(true));
-
-        final CompletableFuture<List<Integer>> promiseSecond = t.promise(traversal -> traversal.next(3), service);
-        final List<Integer> listSecond = promiseSecond.get();
-        assertEquals(3, listSecond.size());
-        assertThat(listSecond, hasItems(4, 5, 6));
-        assertThat(t.hasNext(), is(true));
-        assertThat(promiseSecond.isDone(), is(true));
-
-        final CompletableFuture<List<Integer>> promiseThird = t.promise(traversal -> traversal.next(3), service);
-        final List<Integer> listThird = promiseThird.get();
-        assertEquals(1, listThird.size());
-        assertThat(listThird, hasItems(7));
-        assertThat(t.hasNext(), is(false));
-        assertThat(promiseThird.isDone(), is(true));
-
-        final CompletableFuture<Integer> promiseDead = t.promise(traversal -> (Integer) traversal.next(), service);
-        final AtomicBoolean dead = new AtomicBoolean(false);
-        promiseDead.exceptionally(tossed -> {
-            dead.set(tossed instanceof NoSuchElementException);
-            return null;
-        });
-
-        try {
-            promiseDead.get(10000, TimeUnit.MILLISECONDS);
-            fail("Should have gotten an exception");
-        } catch (Exception ex) {
-            if (ex instanceof TimeoutException) {
-                fail("This should not have timed out but should have gotten an exception caught above in the exceptionally() clause");
-            }
-
-            assertThat(ex.getCause(), instanceOf(NoSuchElementException.class));
-        }
-
-        assertThat(dead.get(), is(true));
-        assertThat(t.hasNext(), is(false));
-        assertThat(promiseDead.isDone(), is(true));
-    }
-
-    @Test
-    public void shouldInterruptTraversalFunction() throws Exception {
-        final Random rand = new Random(1234567890);
-
-        // infinite traversal
-        final MockTraversal<Integer> t = new MockTraversal<>(IntStream.generate(rand::nextInt).iterator());
-
-        // iterate a bunch of it
-        final CompletableFuture<List<Integer>> promise10 = t.promise(traversal -> traversal.next(10), service);
-        assertEquals(10, promise10.get(10000, TimeUnit.MILLISECONDS).size());
-        final CompletableFuture<List<Integer>> promise100 = t.promise(traversal -> traversal.next(100), service);
-        assertEquals(100, promise100.get(10000, TimeUnit.MILLISECONDS).size());
-        final CompletableFuture<List<Integer>> promise1000 = t.promise(traversal -> traversal.next(1000), service);
-        assertEquals(1000, promise1000.get(10000, TimeUnit.MILLISECONDS).size());
-
-        // this is endless, so let's cancel
-        final CompletableFuture<List<Integer>> promiseForevers = t.promise(traversal -> traversal.next(Integer.MAX_VALUE), service);
-
-        // specify what to do on exception
-        final AtomicBoolean failed = new AtomicBoolean(false);
-        promiseForevers.exceptionally(ex -> {
-            failed.set(true);
-            return null;
-        });
-
-        try {
-            // let it actually iterate a moment
-            promiseForevers.get(500, TimeUnit.MILLISECONDS);
-            fail("This should have timed out because the traversal has infinite items in it");
-        } catch (TimeoutException tex) {
-
-        }
-
-        assertThat(promiseForevers.isDone(), is(false));
-        promiseForevers.cancel(true);
-        assertThat(failed.get(), is(true));
-        assertThat(promiseForevers.isDone(), is(true));
-    }
-
-    @Test
     public void shouldIterate() {
         final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
         assertThat(t.hasNext(), is(true));

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
index 972e838..9a2180e 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
@@ -208,7 +208,7 @@ final class Connection {
                             logger.debug(String.format("Write on connection %s failed", thisConnection.getConnectionInfo()), f.cause());
                         thisConnection.isDead = true;
                         thisConnection.returnToPool();
-                        future.completeExceptionally(f.cause());
+                        cluster.executor().submit(() -> future.completeExceptionally(f.cause()));
                     } else {
                         final LinkedBlockingQueue<Result> resultLinkedBlockingQueue = new LinkedBlockingQueue<>();
                         final CompletableFuture<Void> readCompleted = new CompletableFuture<>();
@@ -250,8 +250,8 @@ final class Connection {
 
                         final ResultQueue handler = new ResultQueue(resultLinkedBlockingQueue, readCompleted);
                         pending.put(requestMessage.getRequestId(), handler);
-                        future.complete(new ResultSet(handler, cluster.executor(), readCompleted,
-                                requestMessage, pool.host));
+                        cluster.executor().submit(() -> future.complete(
+                                new ResultSet(handler, cluster.executor(), readCompleted, requestMessage, pool.host)));
                     }
                 });
         channel.writeAndFlush(requestMessage, requestPromise);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
index c1eba34..6d8c8e4 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java
@@ -36,6 +36,7 @@ import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
 
 import java.util.Iterator;
 import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
 
 /**
@@ -161,6 +162,10 @@ public class DriverRemoteConnection implements RemoteConnection {
         }
     }
 
+    /**
+     * @deprecated As of release 3.2.2, replaced by {@link #submit(Bytecode)}.
+     */
+    @Deprecated
     @Override
     public <E> Iterator<Traverser.Admin<E>> submit(final Traversal<?, E> t) throws RemoteConnectionException {
         try {
@@ -187,6 +192,15 @@ public class DriverRemoteConnection implements RemoteConnection {
     }
 
     @Override
+    public <E> CompletableFuture<RemoteTraversal<?, E>> submitAsync(final Bytecode bytecode) throws RemoteConnectionException {
+        try {
+            return client.submitAsync(bytecode).thenApply(rs -> new DriverRemoteTraversal<>(rs, client, attachElements, conf));
+        } catch (Exception ex) {
+            throw new RemoteConnectionException(ex);
+        }
+    }
+
+    @Override
     public void close() throws Exception {
         try {
             client.close();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
index 88ee794..d3f290c 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
@@ -66,28 +66,18 @@ public class DriverRemoteTraversal<S, E> extends AbstractRemoteTraversal<S, E> {
         }
 
         this.rs = rs;
-        this.sideEffects = new DriverRemoteTraversalSideEffects(
-                client,
+        this.sideEffects = new DriverRemoteTraversalSideEffects(client,
                 rs.getOriginalRequestMessage().getRequestId(),
-                rs.getHost());
+                rs.getHost(), rs.allItemsAvailableAsync());
     }
 
     /**
      * Gets a side-effect from the server. Do not call this method prior to completing the iteration of the
-     * {@link DriverRemoteTraversal} that spawned this as the side-effect will not be ready. If this method is called
-     * prior to iteration being complete, then it will block until the traversal notifies it of completion. Generally
+     * {@link DriverRemoteTraversal} that spawned this as the side-effect will not be ready. Generally
      * speaking, the common user would not get side-effects this way - they would use a call to {@code cap()}.
      */
     @Override
     public RemoteTraversalSideEffects getSideEffects() {
-        // wait for the read to complete (i.e. iteration on the server) before allowing the caller to get the
-        // side-effect. calling prior to this will result in the side-effect not being found. of course, the
-        // bad part here is that the method blocks indefinitely waiting for the result, but it prevents the
-        // test failure problems that happen on slower systems. in practice, it's unlikely that a user would
-        // try to get a side-effect prior to iteration, but since the API allows it, this at least prevents
-        // the error.
-        rs.allItemsAvailableAsync().join();
-
         return this.sideEffects;
     }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
index e13c33e..149db25 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
@@ -33,7 +33,7 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * Java driver implementation of {@link TraversalSideEffects}. This class is not thread safe.
@@ -51,16 +51,26 @@ public class DriverRemoteTraversalSideEffects extends AbstractRemoteTraversalSid
 
     private boolean closed = false;
     private boolean retrievedAllKeys = false;
-    private final AtomicInteger counter = new AtomicInteger(0);
+    private final CompletableFuture<Void> ready;
 
-    public DriverRemoteTraversalSideEffects(final Client client, final UUID serverSideEffect, final Host host) {
+    public DriverRemoteTraversalSideEffects(final Client client, final UUID serverSideEffect, final Host host,
+                                            final CompletableFuture<Void> ready) {
         this.client = client;
         this.serverSideEffect = serverSideEffect;
         this.host = host;
+        this.ready = ready;
     }
 
     @Override
     public <V> V get(final String key) throws IllegalArgumentException {
+        // wait for the read to complete (i.e. iteration on the server) before allowing the caller to get the
+        // side-effect. calling prior to this will result in the side-effect not being found. of course, the
+        // bad part here is that the method blocks indefinitely waiting for the result, but it prevents the
+        // test failure problems that happen on slower systems. in practice, it's unlikely that a user would
+        // try to get a side-effect prior to iteration, but since the API allows it, this at least prevents
+        // the error.
+        ready.join();
+
         if (!keys().contains(key)) throw TraversalSideEffects.Exceptions.sideEffectKeyDoesNotExist(key);
 
         if (!sideEffects.containsKey(key)) {
@@ -92,6 +102,14 @@ public class DriverRemoteTraversalSideEffects extends AbstractRemoteTraversalSid
 
     @Override
     public Set<String> keys() {
+        // wait for the read to complete (i.e. iteration on the server) before allowing the caller to get the
+        // side-effect. calling prior to this will result in the side-effect not being found. of course, the
+        // bad part here is that the method blocks indefinitely waiting for the result, but it prevents the
+        // test failure problems that happen on slower systems. in practice, it's unlikely that a user would
+        // try to get a side-effect prior to iteration, but since the API allows it, this at least prevents
+        // the error.
+        ready.join();
+
         if (closed && !retrievedAllKeys) throw new IllegalStateException("Traversal has been closed - side-effect keys cannot be retrieved");
 
         if (!retrievedAllKeys) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java
index c589733..076031a 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffectsTest.java
@@ -53,7 +53,9 @@ public class DriverRemoteTraversalSideEffectsTest extends AbstractResultQueueTes
         mockClientForCall(client);
 
         final UUID sideEffectKey = UUID.fromString("31dec2c6-b214-4a6f-a68b-996608dce0d9");
-        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null);
+        final CompletableFuture<Void> ready = new CompletableFuture<>();
+        ready.complete(null);
+        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null, ready);
 
         assertEquals(1, sideEffects.keys().size());
         sideEffects.close();
@@ -74,7 +76,9 @@ public class DriverRemoteTraversalSideEffectsTest extends AbstractResultQueueTes
         mockClientForCall(client);
         mockClientForCall(client);
         final UUID sideEffectKey = UUID.fromString("31dec2c6-b214-4a6f-a68b-996608dce0d9");
-        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null);
+        final CompletableFuture<Void> ready = new CompletableFuture<>();
+        ready.complete(null);
+        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null, ready);
 
         assertNotNull(sideEffects.get("test-0"));
         sideEffects.close();
@@ -94,7 +98,9 @@ public class DriverRemoteTraversalSideEffectsTest extends AbstractResultQueueTes
         mockClientForCall(client);
 
         final UUID sideEffectKey = UUID.fromString("31dec2c6-b214-4a6f-a68b-996608dce0d9");
-        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null);
+        final CompletableFuture<Void> ready = new CompletableFuture<>();
+        ready.complete(null);
+        final TraversalSideEffects sideEffects = new DriverRemoteTraversalSideEffects(client, sideEffectKey, null, ready);
 
         sideEffects.close();
         sideEffects.close();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-groovy/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-groovy/pom.xml b/gremlin-groovy/pom.xml
index dae5e8a..b82c986 100644
--- a/gremlin-groovy/pom.xml
+++ b/gremlin-groovy/pom.xml
@@ -65,6 +65,11 @@ limitations under the License.
             <artifactId>jBCrypt</artifactId>
             <version>jbcrypt-0.4</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.3.1</version>
+        </dependency>
         <!-- TEST -->
         <dependency>
             <groupId>org.slf4j</groupId>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 15db36d..343a711 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -48,19 +48,20 @@ import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.InterpreterModeCust
 import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.SimpleSandboxExtension;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.TimedInterruptCustomizerProvider;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteGraph;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.server.channel.NioChannelizer;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.hamcrest.CoreMatchers;
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -79,6 +80,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -988,4 +990,26 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
         final BulkSet localBSideEffects = se.get("b");
         assertThat(localBSideEffects.isEmpty(), is(false));
     }
+
+    @Test
+    public void shouldDoNonBlockingPromiseWithRemote() throws Exception {
+        final Graph graph = EmptyGraph.instance();
+        final GraphTraversalSource g = graph.traversal().withRemote(conf);
+        g.addV("person").property("age", 20).promise(Traversal::iterate).join();
+        g.addV("person").property("age", 10).promise(Traversal::iterate).join();
+        assertEquals(50L, g.V().hasLabel("person").map(Lambda.function("it.get().value('age') + 10")).sum().promise(t -> t.next()).join());
+        g.addV("person").property("age", 20).promise(Traversal::iterate).join();
+
+        final Traversal traversal = g.V().hasLabel("person").has("age", 20).values("age");
+        assertEquals(20, traversal.promise(t -> ((Traversal) t).next(1).get(0)).join());
+        assertEquals(20, traversal.next());
+        assertThat(traversal.hasNext(), is(false));
+
+        final Traversal traversalCloned = g.V().hasLabel("person").has("age", 20).values("age");
+        assertEquals(20, traversalCloned.next());
+        assertEquals(20, traversalCloned.promise(t -> ((Traversal) t).next(1).get(0)).join());
+        assertThat(traversalCloned.promise(t -> ((Traversal) t).hasNext()).join(), is(false));
+
+        assertEquals(3, g.V().promise(Traversal::toList).join().size());
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a9e5e99a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
index 050f9de..68f8217 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
@@ -20,7 +20,6 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.ExceptionCoverage;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
-import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
@@ -41,9 +40,6 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Random;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
@@ -311,42 +307,4 @@ public class CoreTraversalTest extends AbstractGremlinProcessTest {
         }
 
     }
-
-    @Test
-    @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
-    public void shouldUsePromiseAndControlTransactionsIfAvailable() throws Exception {
-        // this test will validate that transactional graphs can properly open/close transactions within a promise.
-        // as there is a feature check, non-transactional graphs can use this to simply exercise the promise API
-        final Vertex vAdded = g.addV("person").property("name", "stephen").promise(t -> (Vertex) t.next()).get(10000, TimeUnit.MILLISECONDS);
-        final Vertex vRead = g.V().has("name", "stephen").next();
-        assertEquals(vAdded.id(), vRead.id());
-
-        // transaction should have been committed at this point so test the count in this thread to validate persistence
-        assertVertexEdgeCounts(graph, 1, 0);
-
-        // cancel a promise and ensure the transaction ended in failure. hold the traversal in park until it can be
-        // interrupted, then the promise will have to rollback the transaction.
-        final CompletableFuture promiseToCancel = g.addV("person").property("name", "marko").sideEffect(traverser -> {
-            try {
-                Thread.sleep(100000);
-            } catch (Exception ignored) {
-
-            }
-        }).promise(t -> (Vertex) t.next());
-
-        try {
-            promiseToCancel.get(500, TimeUnit.MILLISECONDS);
-            fail("Should have timed out");
-        } catch (TimeoutException te) {
-
-        }
-
-        promiseToCancel.cancel(true);
-
-        // graphs that support transactions will rollback the transaction
-        if (graph.features().graph().supportsTransactions())
-            assertVertexEdgeCounts(graph, 1, 0);
-        else
-            assertVertexEdgeCounts(graph, 2, 0);
-    }
 }


[03/17] tinkerpop git commit: updated CHANGELOG with bug fix around GroupXXXStep and empty reductions.

Posted by sp...@apache.org.
updated CHANGELOG with bug fix around GroupXXXStep and empty reductions.


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

Branch: refs/heads/TINKERPOP-1490
Commit: b6444354039f7b4e94b50b9c82d670713ee76118
Parents: 1d715d3
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 3 10:39:28 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 3 10:39:28 2016 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b6444354/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 766b135..40f3f3a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Fixed a `NoSuchElementException` bug with `GroupXXXStep` where if the reduced `TraverserSet` is empty, don't add the key/value.
 * Fixed a `NullPointerException` bug with profiling `GroupSideEffectStep` in OLTP.
 * Improved ability to release resources in `GraphProvider` instances in the test suite.
 * Added a `force` option for killing sessions without waiting for transaction close or timeout of a currently running job or multiple jobs.


[09/17] tinkerpop git commit: Merge branch 'TINKERPOP-1547' into tp32

Posted by sp...@apache.org.
Merge branch 'TINKERPOP-1547' into tp32


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

Branch: refs/heads/TINKERPOP-1490
Commit: f23a47b345c49204b2c07fd7593b15c3933a3b9e
Parents: 398e834 56e113d
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 10 17:26:07 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 10 17:26:07 2016 -0700

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   3 +
 .../process/traversal/step/map/MatchStep.java   |  22 +--
 .../optimization/RangeByIsCountStrategy.java    | 137 ++++++++++---------
 .../RangeByIsCountStrategyTest.java             |   2 +
 .../traversal/step/map/GroovyMatchTest.groovy   |  15 +-
 .../process/traversal/step/map/MatchTest.java   |  46 ++++---
 .../neo4j/process/NativeNeo4jCypherCheck.java   |  16 +--
 7 files changed, 140 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f23a47b3/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index b7574fa,3c44f0f..229bcef
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -26,10 -26,11 +26,13 @@@ image::https://raw.githubusercontent.co
  TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
+ * Fixed a OLAP `MatchStep.clone()`-bug that occurs when the `match()` is in a local child.
+ * Fixed a bug in `RangeByIsCountStrategy` where labeled parents shouldn't have the strategy applied to their children.
+ * Fixed a bug in `PathRetractionStrategy` where `MatchEndStep` labels were being dropped when they shouldn't be.
  * Added `TinkerGraphCountStrategy` which translates `g.V().map*.count()` patterns into direct `Map.size()` calls in `TinkerGraph`.
  * Added `Path.head()` and `Path.isEmpty()` with default method implementations.
 +* Fixed a `NoSuchElementException` bug with `GroupXXXStep` where if the reduced `TraverserSet` is empty, don't add the key/value.
 +* Fixed a `NullPointerException` bug with profiling `GroupSideEffectStep` in OLTP.
  * Improved ability to release resources in `GraphProvider` instances in the test suite.
  * Added a `force` option for killing sessions without waiting for transaction close or timeout of a currently running job or multiple jobs.
  * Deprecated `Session.kill()` and `Session.manualKill()`.


[07/17] tinkerpop git commit: Merge branch 'TINKERPOP-1428' into tp32

Posted by sp...@apache.org.
Merge branch 'TINKERPOP-1428' into tp32


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

Branch: refs/heads/TINKERPOP-1490
Commit: 398e834c4f1a082fc541f87eaf2b90bdfab07b6b
Parents: fbefd8c 525d8ea
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 10 07:12:33 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 10 07:12:33 2016 -0700

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  2 +
 .../process/traversal/step/map/GroupStep.java   | 35 +++++----
 .../step/sideEffect/GroupSideEffectStep.java    | 19 +++--
 .../traversal/util/DefaultTraversalMetrics.java | 76 ++++++++++----------
 .../traversal/step/map/GroovyProfileTest.groovy |  5 ++
 .../step/sideEffect/GroovyGroupTest.groovy      |  5 ++
 .../process/traversal/step/map/ProfileTest.java | 17 +++++
 .../traversal/step/sideEffect/GroupTest.java    | 23 ++++++
 8 files changed, 125 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/398e834c/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index 43e4450,40f3f3a..b7574fa
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -26,8 -26,8 +26,10 @@@ image::https://raw.githubusercontent.co
  TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
 +* Added `TinkerGraphCountStrategy` which translates `g.V().map*.count()` patterns into direct `Map.size()` calls in `TinkerGraph`.
 +* Added `Path.head()` and `Path.isEmpty()` with default method implementations.
+ * Fixed a `NoSuchElementException` bug with `GroupXXXStep` where if the reduced `TraverserSet` is empty, don't add the key/value.
+ * Fixed a `NullPointerException` bug with profiling `GroupSideEffectStep` in OLTP.
  * Improved ability to release resources in `GraphProvider` instances in the test suite.
  * Added a `force` option for killing sessions without waiting for transaction close or timeout of a currently running job or multiple jobs.
  * Deprecated `Session.kill()` and `Session.manualKill()`.


[06/17] tinkerpop git commit: updated CHANGELOG and fixed a MatchStep.clone() bug that exposes itself in OLAP traversals with OLTP match() children.

Posted by sp...@apache.org.
updated CHANGELOG and fixed a MatchStep.clone() bug that exposes itself in OLAP traversals with OLTP match() children.


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

Branch: refs/heads/TINKERPOP-1490
Commit: 56e113da4878eb4e082b8589d323cbfa4efd31ac
Parents: e6266b1
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Tue Nov 8 11:56:30 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Tue Nov 8 11:56:30 2016 -0700

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                  |  3 +++
 .../process/traversal/step/map/MatchStep.java       |  3 ++-
 .../process/traversal/step/map/MatchTest.java       | 16 ++--------------
 3 files changed, 7 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56e113da/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 43e4450..3c44f0f 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,9 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Fixed a OLAP `MatchStep.clone()`-bug that occurs when the `match()` is in a local child.
+* Fixed a bug in `RangeByIsCountStrategy` where labeled parents shouldn't have the strategy applied to their children.
+* Fixed a bug in `PathRetractionStrategy` where `MatchEndStep` labels were being dropped when they shouldn't be.
 * Added `TinkerGraphCountStrategy` which translates `g.V().map*.count()` patterns into direct `Map.size()` calls in `TinkerGraph`.
 * Added `Path.head()` and `Path.isEmpty()` with default method implementations.
 * Improved ability to release resources in `GraphProvider` instances in the test suite.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56e113da/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
index d17a3ea..8a8237a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
@@ -246,6 +246,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
             clone.matchTraversals.add(traversal.clone());
         }
         if (this.dedups != null) clone.dedups = new HashSet<>();
+        clone.standardAlgorithmBarrier = new TraverserSet();
         return clone;
     }
 
@@ -352,7 +353,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
         return this.referencedLabelsMap;
     }
 
-    private final TraverserSet standardAlgorithmBarrier = new TraverserSet();
+    private TraverserSet standardAlgorithmBarrier = new TraverserSet();
 
     @Override
     protected Iterator<Traverser.Admin<Map<String, E>>> standardAlgorithm() throws NoSuchElementException {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56e113da/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
index e83bd0e..b8bf1b6 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
-import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
@@ -53,10 +52,8 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.repeat;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.where;
-import static org.hamcrest.core.StringStartsWith.startsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -304,7 +301,6 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
 
     // TODO: this test requires Traversal.reverse()
     @LoadGraphWith(MODERN)
-    @Test
     public void g_V_matchXa_knows_b__c_knows_bX() {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_knows_b__c_knows_bX();
         try {
@@ -330,7 +326,6 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     }
 
     // TODO: this test requires Traversal.reverse()
-    @Test
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_created_b__c_created_bX_selectXa_b_cX_byXnameX() throws Exception {
         final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_created_b__c_created_bX_selectXa_b_cX_byXnameX();
@@ -344,7 +339,6 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         }
     }
 
-    @Test
     @LoadGraphWith(MODERN)
     public void g_V_out_asXcX_matchXb_knows_a__c_created_eX_selectXcX() throws Exception {
         final Traversal<Vertex, String> traversal = get_g_V_out_asXcX_matchXb_knows_a__c_created_eX_selectXcX();
@@ -556,7 +550,6 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         assertFalse(traversal.hasNext());
     }
 
-
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
@@ -577,17 +570,12 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         @Before
         public void setupTest() {
             super.setupTest();
-            g = graphProvider.traversal(graph, MatchAlgorithmStrategy.build().algorithm(MatchStep.GreedyMatchAlgorithm.class).create());
+            g = g.withStrategies(MatchAlgorithmStrategy.build().algorithm(MatchStep.GreedyMatchAlgorithm.class).create());
         }
     }
 
     public static class CountMatchTraversals extends Traversals {
-        // make sure default works -- i.e. CountMatchAlgorithm
-        /*@Before
-        public void setupTest() {
-            super.setupTest();
-            g = graphProvider.traversal(graph, MatchAlgorithmStrategy.build().algorithm(MatchStep.CountMatchAlgorithm.class).create());
-        }*/
+
     }
 
     public abstract static class Traversals extends MatchTest {


[17/17] tinkerpop git commit: TINKERPOP-1490 Remove some dead tests from ignores.

Posted by sp...@apache.org.
TINKERPOP-1490 Remove some dead tests from ignores.


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

Branch: refs/heads/TINKERPOP-1490
Commit: e07cfd06e7fe5cf41406b45eadc1f0c289051440
Parents: a9e5e99
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 13:39:40 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Nov 11 15:09:04 2016 -0500

----------------------------------------------------------------------
 .../org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java  | 1 -
 .../process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java  | 1 -
 .../process/jsr223/TinkerGraphJavaTranslatorProvider.java           | 1 -
 3 files changed, 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e07cfd06/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
----------------------------------------------------------------------
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
index 3bf4239..fe04156 100644
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
+++ b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
@@ -72,7 +72,6 @@ public class PythonProvider extends AbstractGraphProvider {
             "shouldNeverPropagateANullValuedTraverser",
             "shouldHidePartitionKeyForValues",
             "g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack",
-            "shouldUsePromiseAndControlTransactionsIfAvailable",
             //
             ProgramTest.Traversals.class.getCanonicalName(),
             TraversalInterruptionTest.class.getCanonicalName(),

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e07cfd06/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
index a595c34..dd118d7 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
@@ -51,7 +51,6 @@ public class TinkerGraphGroovyTranslatorProvider extends TinkerGraphProvider {
             "g_VX1X_out_injectXv2X_name",
             "shouldNeverPropagateANoBulkTraverser",
             "shouldNeverPropagateANullValuedTraverser",
-            "shouldUsePromiseAndControlTransactionsIfAvailable",
             GraphComputerTest.class.getCanonicalName(),
             ProgramTest.Traversals.class.getCanonicalName(),
             TraversalInterruptionTest.class.getCanonicalName(),

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e07cfd06/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
index 15a6c0b..f40a8c7 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
@@ -49,7 +49,6 @@ public class TinkerGraphJavaTranslatorProvider extends TinkerGraphProvider {
             TraversalInterruptionComputerTest.class.getCanonicalName(),
             "shouldNeverPropagateANoBulkTraverser",
             "shouldNeverPropagateANullValuedTraverser",
-            "shouldUsePromiseAndControlTransactionsIfAvailable",
             ElementIdStrategyProcessTest.class.getCanonicalName(),
             EventStrategyProcessTest.class.getCanonicalName(),
             ProgramTest.Traversals.class.getCanonicalName()));


[15/17] tinkerpop git commit: TINKERPOP-1490 Implemented promise API for Traversal

Posted by sp...@apache.org.
TINKERPOP-1490 Implemented promise API for Traversal

Added two promise() methods that return CompletableFuture on Traversal. Provided an override on DefaultTraversal for those methods because the function that transforms the Traversal is executed in a different thread and therefore requires Graph transaction management (or else we would orphan transactions). Did not update gremlin-python with the promise API because it seemed to beg discussion on the "right" way to do that (i.e. what library to use to support promises?, just use futures from the core lib?, etc).


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

Branch: refs/heads/TINKERPOP-1490
Commit: 94cc9116275cf58f9077423b71dcdbec1255a17d
Parents: 7c9b47f
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Nov 1 09:30:28 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Nov 11 15:09:04 2016 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   1 +
 .../upgrade/release-3.2.x-incubating.asciidoc   |  20 +
 gremlin-core/pom.xml                            |   5 +
 .../gremlin/process/traversal/Traversal.java    |  50 ++
 .../traversal/util/DefaultTraversal.java        |  37 ++
 .../process/traversal/TraversalTest.java        | 473 +++++++++++++++++++
 gremlin-groovy/pom.xml                          |   5 -
 .../gremlin/python/jsr223/PythonProvider.java   |   1 +
 .../process/traversal/CoreTraversalTest.java    |  42 ++
 .../TinkerGraphGroovyTranslatorProvider.java    |   1 +
 .../TinkerGraphJavaTranslatorProvider.java      |   1 +
 11 files changed, 631 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index ccbbc89..6e66eea 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -38,6 +38,7 @@ TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Improved ability to release resources in `GraphProvider` instances in the test suite.
 * Added a `force` option for killing sessions without waiting for transaction close or timeout of a currently running job or multiple jobs.
 * Deprecated `Session.kill()` and `Session.manualKill()`.
+* Added `Traversal.promise()` methods to allow for asynchronous traversal processing.
 * Added `choose(predicate,traversal)` and `choose(traversal,traversal)` to effect if/then-semantics (no else). Equivalent to `choose(x,y,identity())`.
 * Removed `ImmutablePath.TailPath` as it is no longer required with new recursion model.
 * Removed call stack recursion in `ImmutablePath`.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
index 8574b88..04f3b79 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -32,6 +32,26 @@ Please see the link:https://github.com/apache/tinkerpop/blob/3.2.4/CHANGELOG.asc
 Upgrading for Users
 ~~~~~~~~~~~~~~~~~~~
 
+Traversal Promises
+^^^^^^^^^^^^^^^^^^
+
+The `Traversal` API now has two `promise()` method overloads. These methods return a promise in the form of a
+`CompleteableFuture`. Usage is as follows:
+
+[source,groovy]
+----
+gremlin> promise = g.V().out().promise{it.next()}
+==>java.util.concurrent.CompletableFuture@4aa3d36[Completed normally]
+gremlin> promise.join()
+==>v[3]
+gremlin> promise.isDone()
+==>true
+gremlin> g.V().out().promise{it.toList()}.thenApply{it.size()}.get()
+==>6
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1490[TINKERPOP-1490]
+
 If/Then-Semantics with Choose Step
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-core/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-core/pom.xml b/gremlin-core/pom.xml
index e8f3a34..0594448 100644
--- a/gremlin-core/pom.xml
+++ b/gremlin-core/pom.xml
@@ -61,6 +61,11 @@ limitations under the License.
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.3.1</version>
+        </dependency>
         <!-- LOGGING -->
         <dependency>
             <groupId>org.slf4j</groupId>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
index edc18e0..e4ba5a6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
@@ -42,7 +43,13 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
@@ -140,6 +147,43 @@ public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable, A
     }
 
     /**
+     * Starts a promise to execute a function on the current {@code Traversal} that will be completed in the future.
+     * This implementation uses {@link Admin#traversalExecutorService} to execute the supplied
+     * {@code traversalFunction}.
+     */
+    public default <T> CompletableFuture<T> promise(final Function<Traversal, T> traversalFunction) {
+        return promise(traversalFunction, Admin.traversalExecutorService);
+    }
+
+    /**
+     * Starts a promise to execute a function on the current {@code Traversal} that will be completed in the future.
+     * This implementation uses the caller supplied {@code ExecutorService} to execute the {@code traversalFunction}.
+     */
+    public default <T> CompletableFuture<T> promise(final Function<Traversal, T> traversalFunction, final ExecutorService service) {
+        final CompletableFuture<T> promise = new CompletableFuture<>();
+        final Future iterationFuture = service.submit(() -> {
+            try {
+                promise.complete(traversalFunction.apply(this));
+            } catch (Exception ex) {
+                // the promise may have been cancelled by the caller, in which case, there is no need to attempt
+                // another write on completion
+                if (!promise.isDone()) promise.completeExceptionally(ex);
+            }
+        });
+
+        // if the user cancels the promise then attempt to kill the iteration.
+        promise.exceptionally(t -> {
+            if (t instanceof CancellationException) {
+                iterationFuture.cancel(true);
+            }
+
+            return null;
+        });
+
+        return promise;
+    }
+
+    /**
      * Add all the results of the traversal to the provided collection.
      *
      * @param collection the collection to fill
@@ -253,6 +297,12 @@ public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable, A
     public interface Admin<S, E> extends Traversal<S, E> {
 
         /**
+         * Service that handles promises.
+         */
+        static final ExecutorService traversalExecutorService = Executors.newCachedThreadPool(
+                new BasicThreadFactory.Builder().namingPattern("traversal-executor-%d").build());
+
+        /**
          * Get the {@link Bytecode} associated with the construction of this traversal.
          *
          * @return the byte code representation of the traversal

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
index 3c21e37..6ce6dfe 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DefaultTraversal.java
@@ -43,6 +43,9 @@ import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Function;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -325,6 +328,40 @@ public class DefaultTraversal<S, E> implements Traversal.Admin<S, E> {
         this.graph = graph;
     }
 
+    /**
+     * Override of {@link Traversal#promise(Function)} that is aware of graph transactions.
+     */
+    @Override
+    public <T2> CompletableFuture<T2> promise(final Function<Traversal, T2> traversalFunction) {
+        return this.promise(traversalFunction, Traversal.Admin.traversalExecutorService);
+    }
+
+    /**
+     * Override of {@link Traversal#promise(Function)} that is aware of graph transactions. In a transactional graph
+     * a promise represents the full scope of a transaction, even if the graph is only partially iterated.
+     */
+    @Override
+    public <T2> CompletableFuture<T2> promise(final Function<Traversal, T2> traversalFunction, final ExecutorService service) {
+        if (graph != null && graph.features().graph().supportsTransactions()) {
+            final Function<Traversal, T2> transactionAware = traversal -> {
+
+                try {
+                    if (graph.tx().isOpen()) graph.tx().rollback();
+                    final T2 obj = traversalFunction.apply(traversal);
+                    if (graph.tx().isOpen()) graph.tx().commit();
+                    return obj;
+                } catch (Exception ex) {
+                    if (graph.tx().isOpen()) graph.tx().rollback();
+                    throw ex;
+                }
+            };
+
+            return Traversal.Admin.super.promise(transactionAware, service);
+        } else {
+            return Traversal.Admin.super.promise(traversalFunction, service);
+        }
+    }
+
     @Override
     public boolean equals(final Object other) {
         return other != null && other.getClass().equals(this.getClass()) && this.equals(((Traversal.Admin) other));

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
new file mode 100644
index 0000000..aa1b99b
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalTest.java
@@ -0,0 +1,473 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal;
+
+import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsCollectionContaining.hasItems;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class TraversalTest {
+
+    private final ExecutorService service = Executors.newFixedThreadPool(2);
+
+    @Test
+    public void shouldTryNext() {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3);
+        final Optional<Integer> optFirst = t.tryNext();
+        assertEquals(1, optFirst.get().intValue());
+        final Optional<Integer> optSecond = t.tryNext();
+        assertEquals(2, optSecond.get().intValue());
+        final Optional<Integer> optThird = t.tryNext();
+        assertEquals(3, optThird.get().intValue());
+
+        IntStream.range(0, 100).forEach(i -> {
+            assertThat(t.tryNext().isPresent(), is(false));
+        });
+    }
+
+    @Test
+    public void shouldGetTwoAtATime() {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
+        final List<Integer> batchOne = t.next(2);
+        assertEquals(2, batchOne.size());
+        assertThat(batchOne, hasItems(1 ,2));
+
+        final List<Integer> batchTwo = t.next(2);
+        assertEquals(2, batchTwo.size());
+        assertThat(batchTwo, hasItems(3 ,4));
+
+        final List<Integer> batchThree = t.next(2);
+        assertEquals(2, batchThree.size());
+        assertThat(batchThree, hasItems(5, 6));
+
+        final List<Integer> batchFour = t.next(2);
+        assertEquals(1, batchFour.size());
+        assertThat(batchFour, hasItems(7));
+
+        final List<Integer> batchFive = t.next(2);
+        assertEquals(0, batchFive.size());
+    }
+
+    @Test
+    public void shouldFillList() {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
+        final List<Integer> listToFill = new ArrayList<>();
+        final List<Integer> batch = t.fill(listToFill);
+        assertEquals(7, batch.size());
+        assertThat(batch, hasItems(1 ,2, 3, 4, 5, 6, 7));
+        assertThat(t.hasNext(), is(false));
+        assertSame(listToFill, batch);
+    }
+
+    @Test
+    public void shouldStream() {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
+        final List<Integer> batch = t.toStream().collect(Collectors.toList());
+        assertEquals(7, batch.size());
+        assertThat(batch, hasItems(1 ,2, 3, 4, 5, 6, 7));
+        assertThat(t.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldPromiseNextThreeUsingForkJoin() throws Exception {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
+        final CompletableFuture<List<Integer>> promiseFirst = t.promise(traversal -> traversal.next(3));
+        final List<Integer> listFirst = promiseFirst.get();
+        assertEquals(3, listFirst.size());
+        assertThat(listFirst, hasItems(1 ,2, 3));
+        assertThat(t.hasNext(), is(true));
+        assertThat(promiseFirst.isDone(), is(true));
+
+        final CompletableFuture<List<Integer>> promiseSecond = t.promise(traversal -> traversal.next(3));
+        final List<Integer> listSecond = promiseSecond.get();
+        assertEquals(3, listSecond.size());
+        assertThat(listSecond, hasItems(4, 5, 6));
+        assertThat(t.hasNext(), is(true));
+        assertThat(promiseSecond.isDone(), is(true));
+
+        final CompletableFuture<List<Integer>> promiseThird = t.promise(traversal -> traversal.next(3));
+        final List<Integer> listThird = promiseThird.get();
+        assertEquals(1, listThird.size());
+        assertThat(listThird, hasItems(7));
+        assertThat(t.hasNext(), is(false));
+        assertThat(promiseThird.isDone(), is(true));
+
+        final CompletableFuture<Integer> promiseDead = t.promise(traversal -> (Integer) traversal.next());
+        final AtomicBoolean dead = new AtomicBoolean(false);
+        promiseDead.exceptionally(tossed -> {
+            dead.set(tossed instanceof NoSuchElementException);
+            return null;
+        });
+
+        try {
+            promiseDead.get(10000, TimeUnit.MILLISECONDS);
+            fail("Should have gotten an exception");
+        } catch (Exception ex) {
+            if (ex instanceof TimeoutException) {
+                fail("This should not have timed out but should have gotten an exception caught above in the exceptionally() clause");
+            }
+
+            assertThat(ex.getCause(), instanceOf(NoSuchElementException.class));
+        }
+
+        assertThat(dead.get(), is(true));
+        assertThat(t.hasNext(), is(false));
+        assertThat(promiseDead.isDone(), is(true));
+    }
+
+    @Test
+    public void shouldPromiseNextThreeUsingSpecificExecutor() throws Exception {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
+        final CompletableFuture<List<Integer>> promiseFirst = t.promise(traversal -> traversal.next(3), service);
+        final List<Integer> listFirst = promiseFirst.get();
+        assertEquals(3, listFirst.size());
+        assertThat(listFirst, hasItems(1 ,2, 3));
+        assertThat(t.hasNext(), is(true));
+        assertThat(promiseFirst.isDone(), is(true));
+
+        final CompletableFuture<List<Integer>> promiseSecond = t.promise(traversal -> traversal.next(3), service);
+        final List<Integer> listSecond = promiseSecond.get();
+        assertEquals(3, listSecond.size());
+        assertThat(listSecond, hasItems(4, 5, 6));
+        assertThat(t.hasNext(), is(true));
+        assertThat(promiseSecond.isDone(), is(true));
+
+        final CompletableFuture<List<Integer>> promiseThird = t.promise(traversal -> traversal.next(3), service);
+        final List<Integer> listThird = promiseThird.get();
+        assertEquals(1, listThird.size());
+        assertThat(listThird, hasItems(7));
+        assertThat(t.hasNext(), is(false));
+        assertThat(promiseThird.isDone(), is(true));
+
+        final CompletableFuture<Integer> promiseDead = t.promise(traversal -> (Integer) traversal.next(), service);
+        final AtomicBoolean dead = new AtomicBoolean(false);
+        promiseDead.exceptionally(tossed -> {
+            dead.set(tossed instanceof NoSuchElementException);
+            return null;
+        });
+
+        try {
+            promiseDead.get(10000, TimeUnit.MILLISECONDS);
+            fail("Should have gotten an exception");
+        } catch (Exception ex) {
+            if (ex instanceof TimeoutException) {
+                fail("This should not have timed out but should have gotten an exception caught above in the exceptionally() clause");
+            }
+
+            assertThat(ex.getCause(), instanceOf(NoSuchElementException.class));
+        }
+
+        assertThat(dead.get(), is(true));
+        assertThat(t.hasNext(), is(false));
+        assertThat(promiseDead.isDone(), is(true));
+    }
+
+    @Test
+    public void shouldInterruptTraversalFunction() throws Exception {
+        final Random rand = new Random(1234567890);
+
+        // infinite traversal
+        final MockTraversal<Integer> t = new MockTraversal<>(IntStream.generate(rand::nextInt).iterator());
+
+        // iterate a bunch of it
+        final CompletableFuture<List<Integer>> promise10 = t.promise(traversal -> traversal.next(10), service);
+        assertEquals(10, promise10.get(10000, TimeUnit.MILLISECONDS).size());
+        final CompletableFuture<List<Integer>> promise100 = t.promise(traversal -> traversal.next(100), service);
+        assertEquals(100, promise100.get(10000, TimeUnit.MILLISECONDS).size());
+        final CompletableFuture<List<Integer>> promise1000 = t.promise(traversal -> traversal.next(1000), service);
+        assertEquals(1000, promise1000.get(10000, TimeUnit.MILLISECONDS).size());
+
+        // this is endless, so let's cancel
+        final CompletableFuture<List<Integer>> promiseForevers = t.promise(traversal -> traversal.next(Integer.MAX_VALUE), service);
+
+        // specify what to do on exception
+        final AtomicBoolean failed = new AtomicBoolean(false);
+        promiseForevers.exceptionally(ex -> {
+            failed.set(true);
+            return null;
+        });
+
+        try {
+            // let it actually iterate a moment
+            promiseForevers.get(500, TimeUnit.MILLISECONDS);
+            fail("This should have timed out because the traversal has infinite items in it");
+        } catch (TimeoutException tex) {
+
+        }
+
+        assertThat(promiseForevers.isDone(), is(false));
+        promiseForevers.cancel(true);
+        assertThat(failed.get(), is(true));
+        assertThat(promiseForevers.isDone(), is(true));
+    }
+
+    @Test
+    public void shouldIterate() {
+        final MockTraversal<Integer> t = new MockTraversal<>(1, 2, 3, 4, 5, 6, 7);
+        assertThat(t.hasNext(), is(true));
+        t.iterate();
+        assertThat(t.hasNext(), is(false));
+    }
+
+    private static class MockStep<E> implements Step<E,E> {
+
+        private final Iterator<E> itty;
+
+        MockStep(final Iterator<E> itty) {
+            this.itty = itty;
+        }
+
+        @Override
+        public void addStarts(final Iterator starts) {
+
+        }
+
+        @Override
+        public void addStart(final Traverser.Admin start) {
+
+        }
+
+        @Override
+        public void setPreviousStep(final Step step) {
+
+        }
+
+        @Override
+        public Step getPreviousStep() {
+            return null;
+        }
+
+        @Override
+        public void setNextStep(final Step step) {
+
+        }
+
+        @Override
+        public Step getNextStep() {
+            return null;
+        }
+
+        @Override
+        public Traversal.Admin getTraversal() {
+            return null;
+        }
+
+        @Override
+        public void setTraversal(final Traversal.Admin traversal) {
+
+        }
+
+        @Override
+        public void reset() {
+
+        }
+
+        @Override
+        public Step clone() {
+            return null;
+        }
+
+        @Override
+        public Set<String> getLabels() {
+            return null;
+        }
+
+        @Override
+        public void addLabel(final String label) {
+
+        }
+
+        @Override
+        public void removeLabel(final String label) {
+
+        }
+
+        @Override
+        public void setId(final String id) {
+
+        }
+
+        @Override
+        public String getId() {
+            return null;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return itty.hasNext();
+        }
+
+        @Override
+        public Traverser.Admin<E> next() {
+            return new DefaultRemoteTraverser<>(itty.next(), 1L);
+        }
+    }
+
+
+    private static class MockTraversal<T> implements Traversal.Admin<T,T> {
+
+        private Iterator<T> itty;
+
+        private Step mockEndStep;
+
+        private List<Step> steps;
+
+        MockTraversal(final T... objects) {
+            this(Arrays.asList(objects));
+        }
+
+        MockTraversal(final List<T> list) {
+            this(list.iterator());
+        }
+
+        MockTraversal(final Iterator<T> itty) {
+            this.itty = itty;
+            mockEndStep = new MockStep<>(itty);
+            steps = Collections.singletonList(mockEndStep);
+        }
+
+        @Override
+        public Bytecode getBytecode() {
+            return null;
+        }
+
+        @Override
+        public List<Step> getSteps() {
+            return steps;
+        }
+
+        @Override
+        public <S2, E2> Admin<S2, E2> addStep(final int index, final Step<?, ?> step) throws IllegalStateException {
+            return null;
+        }
+
+        @Override
+        public <S2, E2> Admin<S2, E2> removeStep(final int index) throws IllegalStateException {
+            return null;
+        }
+
+        @Override
+        public void applyStrategies() throws IllegalStateException {
+
+        }
+
+        @Override
+        public TraverserGenerator getTraverserGenerator() {
+            return null;
+        }
+
+        @Override
+        public Set<TraverserRequirement> getTraverserRequirements() {
+            return null;
+        }
+
+        @Override
+        public void setSideEffects(final TraversalSideEffects sideEffects) {
+
+        }
+
+        @Override
+        public TraversalSideEffects getSideEffects() {
+            return null;
+        }
+
+        @Override
+        public void setStrategies(final TraversalStrategies strategies) {
+
+        }
+
+        @Override
+        public TraversalStrategies getStrategies() {
+            return null;
+        }
+
+        @Override
+        public void setParent(final TraversalParent step) {
+
+        }
+
+        @Override
+        public TraversalParent getParent() {
+            return null;
+        }
+
+        @Override
+        public Admin<T, T> clone() {
+            return null;
+        }
+
+        @Override
+        public boolean isLocked() {
+            return false;
+        }
+
+        @Override
+        public Optional<Graph> getGraph() {
+            return null;
+        }
+
+        @Override
+        public void setGraph(final Graph graph) {
+
+        }
+
+        @Override
+        public boolean hasNext() {
+            return itty.hasNext();
+        }
+
+        @Override
+        public T next() {
+            if (Thread.interrupted()) throw new TraversalInterruptedException();
+            return itty.next();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-groovy/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-groovy/pom.xml b/gremlin-groovy/pom.xml
index acc51b7..dae5e8a 100644
--- a/gremlin-groovy/pom.xml
+++ b/gremlin-groovy/pom.xml
@@ -61,11 +61,6 @@ limitations under the License.
             <classifier>indy</classifier>
         </dependency>
         <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-            <version>3.3.1</version>
-        </dependency>
-        <dependency>
             <groupId>com.github.jeremyh</groupId>
             <artifactId>jBCrypt</artifactId>
             <version>jbcrypt-0.4</version>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
----------------------------------------------------------------------
diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
index fe04156..3bf4239 100644
--- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
+++ b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/PythonProvider.java
@@ -72,6 +72,7 @@ public class PythonProvider extends AbstractGraphProvider {
             "shouldNeverPropagateANullValuedTraverser",
             "shouldHidePartitionKeyForValues",
             "g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack",
+            "shouldUsePromiseAndControlTransactionsIfAvailable",
             //
             ProgramTest.Traversals.class.getCanonicalName(),
             TraversalInterruptionTest.class.getCanonicalName(),

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
index 68f8217..050f9de 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/CoreTraversalTest.java
@@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.ExceptionCoverage;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
+import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
 import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
@@ -40,6 +41,9 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
@@ -307,4 +311,42 @@ public class CoreTraversalTest extends AbstractGremlinProcessTest {
         }
 
     }
+
+    @Test
+    @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+    public void shouldUsePromiseAndControlTransactionsIfAvailable() throws Exception {
+        // this test will validate that transactional graphs can properly open/close transactions within a promise.
+        // as there is a feature check, non-transactional graphs can use this to simply exercise the promise API
+        final Vertex vAdded = g.addV("person").property("name", "stephen").promise(t -> (Vertex) t.next()).get(10000, TimeUnit.MILLISECONDS);
+        final Vertex vRead = g.V().has("name", "stephen").next();
+        assertEquals(vAdded.id(), vRead.id());
+
+        // transaction should have been committed at this point so test the count in this thread to validate persistence
+        assertVertexEdgeCounts(graph, 1, 0);
+
+        // cancel a promise and ensure the transaction ended in failure. hold the traversal in park until it can be
+        // interrupted, then the promise will have to rollback the transaction.
+        final CompletableFuture promiseToCancel = g.addV("person").property("name", "marko").sideEffect(traverser -> {
+            try {
+                Thread.sleep(100000);
+            } catch (Exception ignored) {
+
+            }
+        }).promise(t -> (Vertex) t.next());
+
+        try {
+            promiseToCancel.get(500, TimeUnit.MILLISECONDS);
+            fail("Should have timed out");
+        } catch (TimeoutException te) {
+
+        }
+
+        promiseToCancel.cancel(true);
+
+        // graphs that support transactions will rollback the transaction
+        if (graph.features().graph().supportsTransactions())
+            assertVertexEdgeCounts(graph, 1, 0);
+        else
+            assertVertexEdgeCounts(graph, 2, 0);
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
index dd118d7..a595c34 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/groovy/jsr223/TinkerGraphGroovyTranslatorProvider.java
@@ -51,6 +51,7 @@ public class TinkerGraphGroovyTranslatorProvider extends TinkerGraphProvider {
             "g_VX1X_out_injectXv2X_name",
             "shouldNeverPropagateANoBulkTraverser",
             "shouldNeverPropagateANullValuedTraverser",
+            "shouldUsePromiseAndControlTransactionsIfAvailable",
             GraphComputerTest.class.getCanonicalName(),
             ProgramTest.Traversals.class.getCanonicalName(),
             TraversalInterruptionTest.class.getCanonicalName(),

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/94cc9116/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
index f40a8c7..15a6c0b 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/jsr223/TinkerGraphJavaTranslatorProvider.java
@@ -49,6 +49,7 @@ public class TinkerGraphJavaTranslatorProvider extends TinkerGraphProvider {
             TraversalInterruptionComputerTest.class.getCanonicalName(),
             "shouldNeverPropagateANoBulkTraverser",
             "shouldNeverPropagateANullValuedTraverser",
+            "shouldUsePromiseAndControlTransactionsIfAvailable",
             ElementIdStrategyProcessTest.class.getCanonicalName(),
             EventStrategyProcessTest.class.getCanonicalName(),
             ProgramTest.Traversals.class.getCanonicalName()));


[11/17] tinkerpop git commit: Merge branch 'TINKERPOP-1547' into tp32

Posted by sp...@apache.org.
Merge branch 'TINKERPOP-1547' into tp32


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

Branch: refs/heads/TINKERPOP-1490
Commit: d0389168d14bf8ce56918d8c639f3ab66176029a
Parents: f448637 6bb8456
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 10 17:29:56 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 10 17:29:56 2016 -0700

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../optimization/RangeByIsCountStrategy.java    | 55 +++++++++++---------
 .../RangeByIsCountStrategyTest.java             | 30 ++++++-----
 3 files changed, 48 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/d0389168/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index 0b765db,1f4e4cf..ccbbc89
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -26,8 -26,8 +26,9 @@@ image::https://raw.githubusercontent.co
  TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
+ * Added another optimization in `RangeByIsCountStrategy`, that removes `count().is()` altogether if it's not needed.
  * Fixed a OLAP `MatchStep.clone()`-bug that occurs when the `match()` is in a local child.
 +* Added another optimization in `RangeByIsCountStrategy`, that removes `count().is()` altogether if it's not needed.
  * Fixed a bug in `RangeByIsCountStrategy` where labeled parents shouldn't have the strategy applied to their children.
  * Fixed a bug in `PathRetractionStrategy` where `MatchEndStep` labels were being dropped when they shouldn't be.
  * Added `TinkerGraphCountStrategy` which translates `g.V().map*.count()` patterns into direct `Map.size()` calls in `TinkerGraph`.


[08/17] tinkerpop git commit: Added another optimization in `RangeByIsCountStrategy` (covered by unit tests), that removes `count().is()` altogether if it's not needed.

Posted by sp...@apache.org.
Added another optimization in `RangeByIsCountStrategy` (covered by unit tests), that removes `count().is()` altogether if it's not needed.


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

Branch: refs/heads/TINKERPOP-1490
Commit: 6bb84563c912fc4f2ad5b8b1bcf2094bffed8738
Parents: 56e113d
Author: Daniel Kuppitz <da...@hotmail.com>
Authored: Thu Nov 10 19:06:50 2016 +0100
Committer: Daniel Kuppitz <da...@hotmail.com>
Committed: Thu Nov 10 19:06:50 2016 +0100

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../optimization/RangeByIsCountStrategy.java    | 55 +++++++++++---------
 .../RangeByIsCountStrategyTest.java             | 30 ++++++-----
 3 files changed, 48 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6bb84563/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 3c44f0f..1f4e4cf 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Added another optimization in `RangeByIsCountStrategy`, that removes `count().is()` altogether if it's not needed.
 * Fixed a OLAP `MatchStep.clone()`-bug that occurs when the `match()` is in a local child.
 * Fixed a bug in `RangeByIsCountStrategy` where labeled parents shouldn't have the strategy applied to their children.
 * Fixed a bug in `PathRetractionStrategy` where `MatchEndStep` labels were being dropped when they shouldn't be.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6bb84563/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
index b29ce47..efe7685 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
@@ -76,6 +76,10 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
     private RangeByIsCountStrategy() {
     }
 
+    public static RangeByIsCountStrategy instance() {
+        return INSTANCE;
+    }
+
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
         final TraversalParent parent = traversal.getParent();
@@ -87,7 +91,7 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
                 final IsStep isStep = (IsStep) traversal.getSteps().get(i + 1);
                 final P isStepPredicate = isStep.getPredicate();
                 Long highRange = null;
-                boolean useNotStep = false;
+                boolean useNotStep = false, dismissCountIs = false;
                 for (P p : isStepPredicate instanceof ConnectiveP ? ((ConnectiveP<?>) isStepPredicate).getPredicates() : Collections.singletonList(isStepPredicate)) {
                     final Object value = p.getValue();
                     final BiPredicate predicate = p.getBiPredicate();
@@ -101,10 +105,10 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
                             } else {
                                 if (parent instanceof RepeatStep) {
                                     final RepeatStep repeatStep = (RepeatStep) parent;
-                                    useNotStep = Objects.equals(traversal, repeatStep.getUntilTraversal())
+                                    dismissCountIs = useNotStep = Objects.equals(traversal, repeatStep.getUntilTraversal())
                                             || Objects.equals(traversal, repeatStep.getEmitTraversal());
                                 } else {
-                                    useNotStep = parent instanceof FilterStep || parent instanceof SideEffectStep;
+                                    dismissCountIs = useNotStep = parent instanceof FilterStep || parent instanceof SideEffectStep;
                                 }
                             }
                             highRange = highRangeCandidate;
@@ -112,6 +116,9 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
                                     && isStep.getNextStep() instanceof EmptyStep
                                     && ((highRange <= 1L && predicate.equals(Compare.lt))
                                     || (highRange == 1L && (predicate.equals(Compare.eq) || predicate.equals(Compare.lte))));
+                            dismissCountIs &= curr.getLabels().isEmpty() && isStep.getLabels().isEmpty()
+                                    && isStep.getNextStep() instanceof EmptyStep
+                                    && (highRange == 1L && (predicate.equals(Compare.gt) || predicate.equals(Compare.gte)));
                         }
                     } else {
                         final Long highRangeOffset = RANGE_PREDICATES.get(predicate);
@@ -126,29 +133,31 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
                     }
                 }
                 if (highRange != null) {
-                    if (useNotStep) {
+                    if (useNotStep || dismissCountIs) {
                         traversal.asAdmin().removeStep(isStep); // IsStep
                         traversal.asAdmin().removeStep(curr); // CountStep
                         size -= 2;
-                        final Traversal.Admin inner;
-                        if (prev != null) {
-                            inner = __.start().asAdmin();
-                            for (; ; ) {
-                                final Step pp = prev.getPreviousStep();
-                                inner.addStep(0, prev);
-                                if (pp instanceof EmptyStep || pp instanceof GraphStep ||
-                                        !(prev instanceof FilterStep || prev instanceof SideEffectStep)) break;
-                                traversal.removeStep(prev);
-                                prev = pp;
-                                size--;
+                        if (!dismissCountIs) {
+                            final Traversal.Admin inner;
+                            if (prev != null) {
+                                inner = __.start().asAdmin();
+                                for (; ; ) {
+                                    final Step pp = prev.getPreviousStep();
+                                    inner.addStep(0, prev);
+                                    if (pp instanceof EmptyStep || pp instanceof GraphStep ||
+                                            !(prev instanceof FilterStep || prev instanceof SideEffectStep)) break;
+                                    traversal.removeStep(prev);
+                                    prev = pp;
+                                    size--;
+                                }
+                            } else {
+                                inner = __.identity().asAdmin();
                             }
-                        } else {
-                            inner = __.identity().asAdmin();
+                            if (prev != null)
+                                TraversalHelper.replaceStep(prev, new NotStep<>(traversal, inner), traversal);
+                            else
+                                traversal.asAdmin().addStep(new NotStep<>(traversal, inner));
                         }
-                        if (prev != null)
-                            TraversalHelper.replaceStep(prev, new NotStep<>(traversal, inner), traversal);
-                        else
-                            traversal.asAdmin().addStep(new NotStep<>(traversal, inner));
                     } else {
                         TraversalHelper.insertBeforeStep(new RangeGlobalStep<>(traversal, 0L, highRange), curr, traversal);
                     }
@@ -170,8 +179,4 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
                 !(parent.getNextStep() instanceof MatchStep.MatchEndStep && // if this is in a pattern match, then don't do it.
                         ((MatchStep.MatchEndStep) parent.getNextStep()).getMatchKey().isPresent());
     }
-
-    public static RangeByIsCountStrategy instance() {
-        return INSTANCE;
-    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6bb84563/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
index 51ad112..55eb840 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
@@ -52,19 +52,6 @@ public class RangeByIsCountStrategyTest {
     @Parameterized.Parameter(value = 1)
     public Traversal optimized;
 
-    void applyRangeByIsCountStrategy(final Traversal traversal) {
-        final TraversalStrategies strategies = new DefaultTraversalStrategies();
-        strategies.addStrategies(RangeByIsCountStrategy.instance());
-        traversal.asAdmin().setStrategies(strategies);
-        traversal.asAdmin().applyStrategies();
-    }
-
-    @Test
-    public void doTest() {
-        applyRangeByIsCountStrategy(original);
-        assertEquals(optimized, original);
-    }
-
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> generateTestParameters() {
 
@@ -97,6 +84,23 @@ public class RangeByIsCountStrategyTest {
                 {__.repeat(__.out()).emit(__.outE().count().is(0)), __.repeat(__.out()).emit(__.not(__.outE()))},
                 {__.where(__.outE().hasLabel("created").count().is(0)), __.where(__.not(__.outE().hasLabel("created")))},
                 {__.where(__.out().outE().hasLabel("created").count().is(0)), __.where(__.out().not(__.outE().hasLabel("created")))},
+                {__.filter(__.bothE().count().is(gt(0))), __.filter(__.bothE())},
+                {__.filter(__.bothE().count().is(gte(1))), __.filter(__.bothE())},
+                {__.filter(__.bothE().count().is(gt(1))), __.filter(__.bothE().limit(2).count().is(gt(1)))},
+                {__.filter(__.bothE().count().is(gte(2))), __.filter(__.bothE().limit(2).count().is(gte(2)))},
         });
     }
+
+    void applyRangeByIsCountStrategy(final Traversal traversal) {
+        final TraversalStrategies strategies = new DefaultTraversalStrategies();
+        strategies.addStrategies(RangeByIsCountStrategy.instance());
+        traversal.asAdmin().setStrategies(strategies);
+        traversal.asAdmin().applyStrategies();
+    }
+
+    @Test
+    public void doTest() {
+        applyRangeByIsCountStrategy(original);
+        assertEquals(optimized, original);
+    }
 }


[13/17] tinkerpop git commit: Set TinkerIoRegistryV2 in cofig files directly.

Posted by sp...@apache.org.
Set TinkerIoRegistryV2 in cofig files directly.

This should have been this way when we added GraphSON 2.0 as the default for TinkerGraph is to still use GraphSON 1.0. CTR


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

Branch: refs/heads/TINKERPOP-1490
Commit: b697b256dafca755c2d5d60393c5cd7c23125735
Parents: 80850e4
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 14:16:45 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Nov 11 14:16:45 2016 -0500

----------------------------------------------------------------------
 gremlin-server/conf/gremlin-server-classic.yaml                    | 2 +-
 gremlin-server/conf/gremlin-server-modern-py.yaml                  | 2 +-
 gremlin-server/conf/gremlin-server-modern-readonly.yaml            | 2 +-
 gremlin-server/conf/gremlin-server-modern.yaml                     | 2 +-
 gremlin-server/conf/gremlin-server-neo4j.yaml                      | 2 +-
 gremlin-server/conf/gremlin-server-rest-modern.yaml                | 2 +-
 gremlin-server/conf/gremlin-server-rest-secure.yaml                | 2 +-
 gremlin-server/conf/gremlin-server-secure.yaml                     | 2 +-
 gremlin-server/conf/gremlin-server-spark.yaml                      | 2 +-
 gremlin-server/conf/gremlin-server.yaml                            | 2 +-
 .../gremlin/driver/remote/gremlin-server-integration.yaml          | 2 +-
 .../tinkerpop/gremlin/server/gremlin-server-integration.yaml       | 2 +-
 12 files changed, 12 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-classic.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-classic.yaml b/gremlin-server/conf/gremlin-server-classic.yaml
index 6519c1e..ac78da0 100644
--- a/gremlin-server/conf/gremlin-server-classic.yaml
+++ b/gremlin-server/conf/gremlin-server-classic.yaml
@@ -32,7 +32,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-modern-py.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-modern-py.yaml b/gremlin-server/conf/gremlin-server-modern-py.yaml
index 8965534..e00eb1d 100644
--- a/gremlin-server/conf/gremlin-server-modern-py.yaml
+++ b/gremlin-server/conf/gremlin-server-modern-py.yaml
@@ -47,7 +47,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-modern-readonly.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-modern-readonly.yaml b/gremlin-server/conf/gremlin-server-modern-readonly.yaml
index 779c0df..379b358 100644
--- a/gremlin-server/conf/gremlin-server-modern-readonly.yaml
+++ b/gremlin-server/conf/gremlin-server-modern-readonly.yaml
@@ -32,7 +32,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-modern.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-modern.yaml b/gremlin-server/conf/gremlin-server-modern.yaml
index e1a1a96..4ac5587 100644
--- a/gremlin-server/conf/gremlin-server-modern.yaml
+++ b/gremlin-server/conf/gremlin-server-modern.yaml
@@ -32,7 +32,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-neo4j.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-neo4j.yaml b/gremlin-server/conf/gremlin-server-neo4j.yaml
index caae71e..8d68c7f 100644
--- a/gremlin-server/conf/gremlin-server-neo4j.yaml
+++ b/gremlin-server/conf/gremlin-server-neo4j.yaml
@@ -43,7 +43,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-rest-modern.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-rest-modern.yaml b/gremlin-server/conf/gremlin-server-rest-modern.yaml
index 0fdcb69..8c41ee7 100644
--- a/gremlin-server/conf/gremlin-server-rest-modern.yaml
+++ b/gremlin-server/conf/gremlin-server-rest-modern.yaml
@@ -30,7 +30,7 @@ scriptEngines: {
     scripts: [scripts/generate-modern.groovy]}}
 serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }}  # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }}  # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}         # application/json
 metrics: {
   slf4jReporter: {enabled: true, interval: 180000}}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-rest-secure.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-rest-secure.yaml b/gremlin-server/conf/gremlin-server-rest-secure.yaml
index 1485f10..646a1e5 100644
--- a/gremlin-server/conf/gremlin-server-rest-secure.yaml
+++ b/gremlin-server/conf/gremlin-server-rest-secure.yaml
@@ -43,7 +43,7 @@ scriptEngines: {
               "org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.CompileStaticCustomizerProvider":["org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.SimpleSandboxExtension"]}}}}
 serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-secure.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-secure.yaml b/gremlin-server/conf/gremlin-server-secure.yaml
index d6ce87e..5b5e91e 100644
--- a/gremlin-server/conf/gremlin-server-secure.yaml
+++ b/gremlin-server/conf/gremlin-server-secure.yaml
@@ -46,7 +46,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server-spark.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-spark.yaml b/gremlin-server/conf/gremlin-server-spark.yaml
index 512297d..d79185f 100644
--- a/gremlin-server/conf/gremlin-server-spark.yaml
+++ b/gremlin-server/conf/gremlin-server-spark.yaml
@@ -56,7 +56,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/conf/gremlin-server.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server.yaml b/gremlin-server/conf/gremlin-server.yaml
index 5b17711..8cf2947 100644
--- a/gremlin-server/conf/gremlin-server.yaml
+++ b/gremlin-server/conf/gremlin-server.yaml
@@ -33,7 +33,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/vnd.gremlin-v1.0+gryo-lite
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}        # application/vnd.gremlin-v1.0+gryo-stringd
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v1.0+json
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }} # application/vnd.gremlin-v2.0+json
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }} # application/vnd.gremlin-v2.0+json
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}        # application/json
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/driver/remote/gremlin-server-integration.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/driver/remote/gremlin-server-integration.yaml b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/driver/remote/gremlin-server-integration.yaml
index b87fc0f..552b2ea 100644
--- a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/driver/remote/gremlin-server-integration.yaml
+++ b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/driver/remote/gremlin-server-integration.yaml
@@ -36,7 +36,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph, custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true}}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }}
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b697b256/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
index 91a94a4..3d5c154 100644
--- a/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
+++ b/gremlin-server/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml
@@ -32,7 +32,7 @@ serializers:
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: { useMapperFromGraph: graph, custom: [groovy.json.JsonBuilder;org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer]}}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true}}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { useMapperFromGraph: graph }}
-  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { useMapperFromGraph: graph }}
+  - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerIoRegistryV2d0] }}
   - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { useMapperFromGraph: graph }}
 processors:
   - { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}


[10/17] tinkerpop git commit: CHANGELOG lost its addition

Posted by sp...@apache.org.
CHANGELOG lost its addition


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

Branch: refs/heads/TINKERPOP-1490
Commit: f4486376809eec08f73fb4928760624a4fc3ee85
Parents: f23a47b
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 10 17:27:21 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 10 17:27:21 2016 -0700

----------------------------------------------------------------------
 CHANGELOG.asciidoc | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f4486376/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 229bcef..0b765db 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -27,6 +27,7 @@ TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 * Fixed a OLAP `MatchStep.clone()`-bug that occurs when the `match()` is in a local child.
+* Added another optimization in `RangeByIsCountStrategy`, that removes `count().is()` altogether if it's not needed.
 * Fixed a bug in `RangeByIsCountStrategy` where labeled parents shouldn't have the strategy applied to their children.
 * Fixed a bug in `PathRetractionStrategy` where `MatchEndStep` labels were being dropped when they shouldn't be.
 * Added `TinkerGraphCountStrategy` which translates `g.V().map*.count()` patterns into direct `Map.size()` calls in `TinkerGraph`.


[02/17] tinkerpop git commit: added a group().profile() test to ProfileTest to verify no NPE.

Posted by sp...@apache.org.
added a group().profile() test to ProfileTest to verify no NPE.


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

Branch: refs/heads/TINKERPOP-1490
Commit: 1d715d3d7e9d532e7ea3713f4c4c20e0472b88ba
Parents: 3d70c3d
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Nov 3 10:31:36 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Nov 3 10:31:36 2016 -0600

----------------------------------------------------------------------
 .../traversal/step/map/GroovyProfileTest.groovy    |  5 +++++
 .../process/traversal/step/map/ProfileTest.java    | 17 +++++++++++++++++
 2 files changed, 22 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/1d715d3d/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyProfileTest.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyProfileTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyProfileTest.groovy
index 0987ee5..f2dbfbf 100644
--- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyProfileTest.groovy
+++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyProfileTest.groovy
@@ -84,6 +84,11 @@ public abstract class GroovyProfileTest {
         public Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile() {
             new ScriptTraversal<>(g, "gremlin-groovy", "g.V.hasLabel('person').pageRank.by('rank').by(bothE()).rank.profile()")
         }
+
+        @Override
+        public Traversal<Vertex, TraversalMetrics> get_g_V_groupXmX_profile() {
+            new ScriptTraversal<>(g, "gremlin-groovy", "g.V.group('m').profile")
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/1d715d3d/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
index 548e7ab..1af6ba3 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProfileTest.java
@@ -54,6 +54,7 @@ import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -88,6 +89,8 @@ public abstract class ProfileTest extends AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile();
 
+    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_groupXmX_profile();
+
     @Test
     @LoadGraphWith(MODERN)
     public void modern_V_out_out_profile() {
@@ -409,6 +412,15 @@ public abstract class ProfileTest extends AbstractGremlinProcessTest {
         }
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_groupXmX_profile() {
+        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_groupXmX_profile();
+        printTraversalForm(traversal);
+        traversal.next();
+        assertFalse(traversal.hasNext());
+    }
+
     private static boolean onGraphComputer(final Traversal.Admin<?, ?> traversal) {
         return !TraversalHelper.getStepsOfClass(TraversalVertexProgramStep.class, TraversalHelper.getRootTraversal(traversal)).isEmpty();
     }
@@ -496,5 +508,10 @@ public abstract class ProfileTest extends AbstractGremlinProcessTest {
         public Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_byXrankX_byXbothEX_rank_profile() {
             return g.V().hasLabel("person").pageRank().by("rank").by(__.bothE()).values("rank").profile();
         }
+
+        @Override
+        public Traversal<Vertex, TraversalMetrics> get_g_V_groupXmX_profile() {
+            return g.V().group("m").profile();
+        }
     }
 }


[05/17] tinkerpop git commit: fixed a bug in MatchStep that I forgot we had. Because of it, we had 3 tests commented out. Doh. The tests were a combination of problems in PathRetractionsStrategy and RangeByIsCountStratyegy. Because of the fix in PathRetr

Posted by sp...@apache.org.
fixed a bug in MatchStep that I forgot we had. Because of it, we had 3 tests commented out. Doh. The tests were a combination of problems in PathRetractionsStrategy and RangeByIsCountStratyegy. Because of the fix in PathRetractionStrategy, some match benchmarks got significantly faster.


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

Branch: refs/heads/TINKERPOP-1490
Commit: e6266b12a0c90a7283231d2d435d1d677baccbfa
Parents: fbefd8c
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Tue Nov 8 10:02:37 2016 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Tue Nov 8 10:02:37 2016 -0700

----------------------------------------------------------------------
 .../process/traversal/step/map/MatchStep.java   |  19 ++-
 .../optimization/RangeByIsCountStrategy.java    | 137 ++++++++++---------
 .../RangeByIsCountStrategyTest.java             |   2 +
 .../traversal/step/map/GroovyMatchTest.groovy   |  15 +-
 .../process/traversal/step/map/MatchTest.java   |  36 ++++-
 .../neo4j/process/NativeNeo4jCypherCheck.java   |  16 +--
 6 files changed, 136 insertions(+), 89 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e6266b12/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
index c075d0a..d17a3ea 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
@@ -470,8 +470,8 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
     public static final class MatchStartStep extends AbstractStep<Object, Object> implements Scoping {
 
         private final String selectKey;
-        private Set<String> scopeKeys = null;
-        private MatchStep<?, ?> parent = null;
+        private Set<String> scopeKeys;
+        private MatchStep<?, ?> parent;
 
         public MatchStartStep(final Traversal.Admin traversal, final String selectKey) {
             super(traversal);
@@ -508,7 +508,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
 
         @Override
         public Set<String> getScopeKeys() {
-            if (null == this.scopeKeys) {
+            if (null == this.scopeKeys) { // computer the first time and then save resultant keys
                 this.scopeKeys = new HashSet<>();
                 if (null != this.selectKey)
                     this.scopeKeys.add(this.selectKey);
@@ -520,16 +520,16 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
         }
     }
 
-    public static final class MatchEndStep extends EndStep<Object> {
+    public static final class MatchEndStep extends EndStep<Object> implements Scoping {
 
         private final String matchKey;
         private final Set<String> matchKeyCollection;
-        private MatchStep<?, ?> parent = null;
+        private MatchStep<?, ?> parent;
 
         public MatchEndStep(final Traversal.Admin traversal, final String matchKey) {
             super(traversal);
             this.matchKey = matchKey;
-            this.matchKeyCollection = Collections.singleton(this.matchKey);
+            this.matchKeyCollection = null == matchKey ? Collections.emptySet() : Collections.singleton(this.matchKey);
         }
 
 
@@ -539,7 +539,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
 
             final Set<String> keepers = new HashSet<>(this.parent.getKeepLabels());
             final Set<String> tags = traverser.getTags();
-            for (final Traversal.Admin<?, ?> matchTraversal : this.parent.getGlobalChildren()) { // get remaining traversal patterns for the traverser
+            for (final Traversal.Admin<?, ?> matchTraversal : this.parent.matchTraversals) { // get remaining traversal patterns for the traverser
                 final String startStepId = matchTraversal.getStartStep().getId();
                 if (!tags.contains(startStepId)) {
                     keepers.addAll(this.parent.getReferencedLabelsMap().get(startStepId)); // get the reference labels required for those remaining traversals
@@ -591,6 +591,11 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
                 result ^= this.matchKey.hashCode();
             return result;
         }
+
+        @Override
+        public Set<String> getScopeKeys() {
+            return this.matchKeyCollection;
+        }
     }
 
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e6266b12/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
index 6957abe..b29ce47 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategy.java
@@ -33,6 +33,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NotStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchStep;
 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;
@@ -82,86 +83,94 @@ public final class RangeByIsCountStrategy extends AbstractTraversalStrategy<Trav
         Step prev = null;
         for (int i = 0; i < size; i++) {
             final Step curr = traversal.getSteps().get(i);
-            if (curr instanceof CountGlobalStep && i < size - 1) {
-                final Step next = traversal.getSteps().get(i + 1);
-                if (next instanceof IsStep && !(prev instanceof RangeGlobalStep)) { // if a RangeStep was provided, assume that the user knows what he's doing
-                    final IsStep isStep = (IsStep) next;
-                    final P isStepPredicate = isStep.getPredicate();
-                    Long highRange = null;
-                    boolean useNotStep = false;
-                    for (P p : isStepPredicate instanceof ConnectiveP ? ((ConnectiveP<?>) isStepPredicate).getPredicates() : Collections.singletonList(isStepPredicate)) {
-                        final Object value = p.getValue();
-                        final BiPredicate predicate = p.getBiPredicate();
-                        if (value instanceof Number) {
-                            final long highRangeOffset = INCREASED_OFFSET_SCALAR_PREDICATES.contains(predicate) ? 1L : 0L;
-                            final Long highRangeCandidate = ((Number) value).longValue() + highRangeOffset;
-                            final boolean update = highRange == null || highRangeCandidate > highRange;
-                            if (update) {
-                                if (parent instanceof EmptyStep) {
-                                    useNotStep = true;
+            if (i < size - 1 && doStrategy(curr)) {
+                final IsStep isStep = (IsStep) traversal.getSteps().get(i + 1);
+                final P isStepPredicate = isStep.getPredicate();
+                Long highRange = null;
+                boolean useNotStep = false;
+                for (P p : isStepPredicate instanceof ConnectiveP ? ((ConnectiveP<?>) isStepPredicate).getPredicates() : Collections.singletonList(isStepPredicate)) {
+                    final Object value = p.getValue();
+                    final BiPredicate predicate = p.getBiPredicate();
+                    if (value instanceof Number) {
+                        final long highRangeOffset = INCREASED_OFFSET_SCALAR_PREDICATES.contains(predicate) ? 1L : 0L;
+                        final Long highRangeCandidate = ((Number) value).longValue() + highRangeOffset;
+                        final boolean update = highRange == null || highRangeCandidate > highRange;
+                        if (update) {
+                            if (parent instanceof EmptyStep) {
+                                useNotStep = true;
+                            } else {
+                                if (parent instanceof RepeatStep) {
+                                    final RepeatStep repeatStep = (RepeatStep) parent;
+                                    useNotStep = Objects.equals(traversal, repeatStep.getUntilTraversal())
+                                            || Objects.equals(traversal, repeatStep.getEmitTraversal());
                                 } else {
-                                    if (parent instanceof RepeatStep) {
-                                        final RepeatStep repeatStep = (RepeatStep) parent;
-                                        useNotStep = Objects.equals(traversal, repeatStep.getUntilTraversal())
-                                                || Objects.equals(traversal, repeatStep.getEmitTraversal());
-                                    } else {
-                                        useNotStep = parent instanceof FilterStep || parent instanceof SideEffectStep;
-                                    }
+                                    useNotStep = parent instanceof FilterStep || parent instanceof SideEffectStep;
                                 }
-                                highRange = highRangeCandidate;
-                                useNotStep &= curr.getLabels().isEmpty() && next.getLabels().isEmpty()
-                                        && next.getNextStep() instanceof EmptyStep
-                                        && ((highRange <= 1L && predicate.equals(Compare.lt))
-                                        || (highRange == 1L && (predicate.equals(Compare.eq) || predicate.equals(Compare.lte))));
                             }
-                        } else {
-                            final Long highRangeOffset = RANGE_PREDICATES.get(predicate);
-                            if (value instanceof Collection && highRangeOffset != null) {
-                                final Object high = Collections.max((Collection) value);
-                                if (high instanceof Number) {
-                                    final Long highRangeCandidate = ((Number) high).longValue() + highRangeOffset;
-                                    final boolean update = highRange == null || highRangeCandidate > highRange;
-                                    if (update) highRange = highRangeCandidate;
-                                }
+                            highRange = highRangeCandidate;
+                            useNotStep &= curr.getLabels().isEmpty() && isStep.getLabels().isEmpty()
+                                    && isStep.getNextStep() instanceof EmptyStep
+                                    && ((highRange <= 1L && predicate.equals(Compare.lt))
+                                    || (highRange == 1L && (predicate.equals(Compare.eq) || predicate.equals(Compare.lte))));
+                        }
+                    } else {
+                        final Long highRangeOffset = RANGE_PREDICATES.get(predicate);
+                        if (value instanceof Collection && highRangeOffset != null) {
+                            final Object high = Collections.max((Collection) value);
+                            if (high instanceof Number) {
+                                final Long highRangeCandidate = ((Number) high).longValue() + highRangeOffset;
+                                final boolean update = highRange == null || highRangeCandidate > highRange;
+                                if (update) highRange = highRangeCandidate;
                             }
                         }
                     }
-                    if (highRange != null) {
-                        if (useNotStep) {
-                            traversal.asAdmin().removeStep(next); // IsStep
-                            traversal.asAdmin().removeStep(curr); // CountStep
-                            size -= 2;
-                            final Traversal.Admin inner;
-                            if (prev != null) {
-                                inner = __.start().asAdmin();
-                                for (; ; ) {
-                                    final Step pp = prev.getPreviousStep();
-                                    inner.addStep(0, prev);
-                                    if (pp instanceof EmptyStep || pp instanceof GraphStep ||
-                                            !(prev instanceof FilterStep || prev instanceof SideEffectStep)) break;
-                                    traversal.removeStep(prev);
-                                    prev = pp;
-                                    size--;
-                                }
-                            } else {
-                                inner = __.identity().asAdmin();
-                            }
-                            if (prev != null) {
-                                TraversalHelper.replaceStep(prev, new NotStep<>(traversal, inner), traversal);
-                            } else {
-                                traversal.asAdmin().addStep(new NotStep<>(traversal, inner));
+                }
+                if (highRange != null) {
+                    if (useNotStep) {
+                        traversal.asAdmin().removeStep(isStep); // IsStep
+                        traversal.asAdmin().removeStep(curr); // CountStep
+                        size -= 2;
+                        final Traversal.Admin inner;
+                        if (prev != null) {
+                            inner = __.start().asAdmin();
+                            for (; ; ) {
+                                final Step pp = prev.getPreviousStep();
+                                inner.addStep(0, prev);
+                                if (pp instanceof EmptyStep || pp instanceof GraphStep ||
+                                        !(prev instanceof FilterStep || prev instanceof SideEffectStep)) break;
+                                traversal.removeStep(prev);
+                                prev = pp;
+                                size--;
                             }
                         } else {
-                            TraversalHelper.insertBeforeStep(new RangeGlobalStep<>(traversal, 0L, highRange), curr, traversal);
+                            inner = __.identity().asAdmin();
                         }
-                        i++;
+                        if (prev != null)
+                            TraversalHelper.replaceStep(prev, new NotStep<>(traversal, inner), traversal);
+                        else
+                            traversal.asAdmin().addStep(new NotStep<>(traversal, inner));
+                    } else {
+                        TraversalHelper.insertBeforeStep(new RangeGlobalStep<>(traversal, 0L, highRange), curr, traversal);
                     }
+                    i++;
                 }
             }
             prev = curr;
         }
     }
 
+    private boolean doStrategy(final Step step) {
+        if (!(step instanceof CountGlobalStep) ||
+                !(step.getNextStep() instanceof IsStep) ||
+                step.getPreviousStep() instanceof RangeGlobalStep) // if a RangeStep was provided, assume that the user knows what he's doing
+            return false;
+
+        final Step parent = step.getTraversal().getParent().asStep();
+        return (parent instanceof FilterStep || parent.getLabels().isEmpty()) && // if the parent is labeled, then the count matters
+                !(parent.getNextStep() instanceof MatchStep.MatchEndStep && // if this is in a pattern match, then don't do it.
+                        ((MatchStep.MatchEndStep) parent.getNextStep()).getMatchKey().isPresent());
+    }
+
     public static RangeByIsCountStrategy instance() {
         return INSTANCE;
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e6266b12/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
index 99d2f75..51ad112 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RangeByIsCountStrategyTest.java
@@ -87,6 +87,8 @@ public class RangeByIsCountStrategyTest {
                 {__.out().count().is(without(2, 6, 4)), __.out().limit(6).count().is(without(2, 6, 4))},
                 {__.map(__.count().is(0)), __.map(__.limit(1).count().is(0))},
                 {__.flatMap(__.count().is(0)), __.flatMap(__.limit(1).count().is(0))},
+                {__.flatMap(__.count().is(0)).as("a"), __.flatMap(__.count().is(0)).as("a")},
+                {__.filter(__.count().is(0)).as("a"), __.filter(__.not(__.identity())).as("a")},
                 {__.filter(__.count().is(0)), __.filter(__.not(__.identity()))},
                 {__.sideEffect(__.count().is(0)), __.sideEffect(__.not(__.identity()))},
                 {__.branch(__.count().is(0)), __.branch(__.limit(1).count().is(0))},

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e6266b12/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
index f953e91..8c36d26 100644
--- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
+++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
@@ -231,8 +231,8 @@ public abstract class GroovyMatchTest {
         public Traversal<Vertex, String> get_g_V_out_asXcX_matchXb_knows_a__c_created_eX_selectXcX() {
             new ScriptTraversal<>(g, "gremlin-groovy", """
                 g.V().out().as("c").match(
-                    as("b").out("knows").as("a"),
-                    as("c").out("created").as("e")).select("c")
+                    __.as("b").out("knows").as("a"),
+                    __.as("c").out("created").as("e")).select("c")
             """)
         }
 
@@ -366,7 +366,16 @@ public abstract class GroovyMatchTest {
                             __.as('a').age.as('b'),
                             __.as('a').name.as('c')).
                         where('b', eq('c')).select('a')).name
-            """, g)
+            """)
+        }
+
+        @Override
+        public Traversal<Vertex, Long> get_g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count() {
+            new ScriptTraversal<>(g, "gremlin-groovy", """
+             g.V.match(
+                    __.as("a").out("followedBy").count.is(gt(10)).as("b"),
+                    __.as("a").in("followedBy").count().is(gt(10)).as("b")).count;
+            """)
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e6266b12/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
index ce60734..e83bd0e 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
@@ -34,6 +34,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -158,9 +159,11 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     // test not(match)
     public abstract Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name();
 
+    // test inline counts
+    public abstract Traversal<Vertex, Long> get_g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count();
+
     @Test
     @LoadGraphWith(MODERN)
-
     public void g_V_valueMap_matchXa_selectXnameX_bX() {
         final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_valueMap_matchXa_selectXnameX_bX();
         printTraversalForm(traversal);
@@ -301,6 +304,7 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
 
     // TODO: this test requires Traversal.reverse()
     @LoadGraphWith(MODERN)
+    @Test
     public void g_V_matchXa_knows_b__c_knows_bX() {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_knows_b__c_knows_bX();
         try {
@@ -308,8 +312,8 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
             traversal.iterate();
             fail("Should have tossed an exception because match pattern is not solvable");
         } catch (Exception ex) {
-            final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root.getMessage(), startsWith("The provided match pattern is unsolvable:"));
+            //final Throwable root = ExceptionUtils.getRootCause(ex);
+            //assertThat(root.getMessage(), startsWith("The provided match pattern is unsolvable:"));
         }
     }
 
@@ -326,6 +330,7 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     }
 
     // TODO: this test requires Traversal.reverse()
+    @Test
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_created_b__c_created_bX_selectXa_b_cX_byXnameX() throws Exception {
         final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_created_b__c_created_bX_selectXa_b_cX_byXnameX();
@@ -334,11 +339,12 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
             traversal.iterate();
             fail("Should have tossed an exception because match pattern is not solvable");
         } catch (Exception ex) {
-            final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root.getMessage(), startsWith("The provided match pattern is unsolvable:"));
+            //final Throwable root = ExceptionUtils.getRootCause(ex);
+            //assertThat(root.getMessage(), startsWith("The provided match pattern is unsolvable:"));
         }
     }
 
+    @Test
     @LoadGraphWith(MODERN)
     public void g_V_out_asXcX_matchXb_knows_a__c_created_eX_selectXcX() throws Exception {
         final Traversal<Vertex, String> traversal = get_g_V_out_asXcX_matchXb_knows_a__c_created_eX_selectXcX();
@@ -347,8 +353,8 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
             traversal.iterate();
             fail("Should have tossed an exception because match pattern is not solvable");
         } catch (Exception ex) {
-            final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root.getMessage(), startsWith("The provided match pattern is unsolvable:"));
+            //final Throwable root = ExceptionUtils.getRootCause(ex);
+            //assertThat(root.getMessage(), startsWith("The provided match pattern is unsolvable:"));
         }
     }
 
@@ -551,6 +557,7 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     }
 
 
+    @Test
     @LoadGraphWith(MODERN)
     public void g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
         final Traversal<Vertex, String> traversal = get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name();
@@ -558,6 +565,14 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         checkResults(Arrays.asList("marko", "peter", "josh", "vadas", "lop", "ripple"), traversal);
     }
 
+    @Test
+    @LoadGraphWith(GRATEFUL)
+    public void g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count() {
+        final Traversal<Vertex, Long> traversal = get_g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count();
+        printTraversalForm(traversal);
+        checkResults(Collections.singletonList(6L), traversal);
+    }
+
     public static class GreedyMatchTraversals extends Traversals {
         @Before
         public void setupTest() {
@@ -840,5 +855,12 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         public Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
             return g.V().not(match(__.as("a").values("age").as("b"), __.as("a").values("name").as("c")).where("b", eq("c")).select("a")).values("name");
         }
+
+        @Override
+        public Traversal<Vertex, Long> get_g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count() {
+            return g.V().match(
+                    as("a").out("followedBy").count().is(P.gt(10)).as("b"),
+                    as("a").in("followedBy").count().is(P.gt(10)).as("b")).count();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e6266b12/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
index c98e8f9..7ac3d89 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
@@ -153,12 +153,12 @@ public class NativeNeo4jCypherCheck extends AbstractNeo4jGremlinTest {
                 () -> n.cypher("MATCH (a)-[:followedBy]->(b), (b)-[:followedBy]->(a) RETURN a.name, b.name"),
                 ///
                 () -> g.V().match(
-                        as("a").out("followedBy").count().as("b"),
-                        as("a").in("followedBy").count().as("b"),
-                        as("b").is(P.gt(10))).select("a").by("name"),
+                        as("a").out("followedBy").count().is(P.gt(10)).as("b"),
+                        as("a").in("followedBy").count().is(P.gt(10)).as("b")).
+                        select("a").by("name"),
                 () -> n.cypher("MATCH (a)-[:followedBy]->(b) WITH a, COUNT(b) AS bc WHERE bc > 10 MATCH (a)<-[:followedBy]-(c) WITH a, bc, COUNT(c) AS cc WHERE bc = cc RETURN a.name"),
                 ///
-                /*() -> g.V().match(
+                () -> g.V().match(
                         as("a").in("sungBy").count().as("b"),
                         as("a").in("sungBy").as("c"),
                         as("c").out("followedBy").as("d"),
@@ -166,7 +166,7 @@ public class NativeNeo4jCypherCheck extends AbstractNeo4jGremlinTest {
                         as("e").in("sungBy").count().as("b"),
                         where("a", P.neq("e"))).select("a", "e").by("name"),
                 () -> n.cypher("MATCH (a)<-[:sungBy]-()-[:followedBy]->()-[:sungBy]->(e) WHERE a <> e WITH a, e MATCH (a)<-[:sungBy]-(b) WITH a, e, COUNT(DISTINCT b) as bc MATCH (e)<-[:sungBy]-(f) WITH a, e, bc, COUNT(DISTINCT f) as fc WHERE bc = fc RETURN a.name, e.name"),
-                *////
+                ///
                 () -> g.V().match(
                         as("a").in("followedBy").as("b"),
                         as("a").out("sungBy").as("c"),
@@ -201,14 +201,14 @@ public class NativeNeo4jCypherCheck extends AbstractNeo4jGremlinTest {
                 () -> g.V().match(
                         as("a").out("followedBy").as("b"),
                         as("b").out("followedBy").as("c")).select("a").by("name"),
-                () -> n.cypher("MATCH (a)-[:followedBy]->(b), (b)-[:followedBy]->(c) RETURN a.name")
+                () -> n.cypher("MATCH (a)-[:followedBy]->(b), (b)-[:followedBy]->(c) RETURN a.name"),
                 ///
-                /*() -> g.V().match(
+                () -> g.V().match(
                         as("a").out("followedBy").as("b"),
                         as("a").has(T.label, "song").has("performances", P.gt(10)),
                         as("a").out("writtenBy").as("c"),
                         as("b").out("writtenBy").as("c")).select("a", "b", "c").by("name"),
-                () -> n.cypher("MATCH (a)-[:followedBy]->(b), (a)-[:writtenBy]->(c), (b)-[:writtenBy]->(c) WHERE a.performances > 10 AND 'song' IN labels(a) RETURN a, b, c").select("a","b","c").by("name")*/
+                () -> n.cypher("MATCH (a)-[:followedBy]->(b), (a)-[:writtenBy]->(c), (b)-[:writtenBy]->(c) WHERE a.performances > 10 AND 'song' IN labels(a) RETURN a, b, c").select("a", "b", "c").by("name")
         );
 
         for (int i = 0; i < traversals.size(); i = i + 2) {


[12/17] tinkerpop git commit: CTR: added HadoopGtaph OPT_OUTs for MatchTests that were way too slow and made Travis CI fail

Posted by sp...@apache.org.
CTR: added HadoopGtaph OPT_OUTs for MatchTests that were way too slow and made Travis CI fail


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

Branch: refs/heads/TINKERPOP-1490
Commit: 80850e4d82a0bb2d42df401f4e217aeab0e775b8
Parents: d038916
Author: Daniel Kuppitz <da...@hotmail.com>
Authored: Fri Nov 11 18:36:07 2016 +0100
Committer: Daniel Kuppitz <da...@hotmail.com>
Committed: Fri Nov 11 18:36:07 2016 +0100

----------------------------------------------------------------------
 .../gremlin/hadoop/structure/HadoopGraph.java   | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/80850e4d/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
----------------------------------------------------------------------
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
index d0f50d0..665d21f 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
@@ -250,6 +250,26 @@ import java.util.stream.Stream;
         method = "*",
         reason = "This test makes use of a sideEffect to enforce when a thread interruption is triggered and thus isn't applicable to HadoopGraph",
         computers = {"org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer", "org.apache.tinkerpop.gremlin.giraph.process.computer.GiraphGraphComputer"})
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchTest$CountMatchTraversals",
+        method = "g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count",
+        reason = "Hadoop-Gremlin is OLAP-oriented and for OLTP operations, linear-scan joins are required. This particular tests takes many minutes to execute.",
+        computers = {"ALL"})
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchTest$GreedyMatchTraversals",
+        method = "g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count",
+        reason = "Hadoop-Gremlin is OLAP-oriented and for OLTP operations, linear-scan joins are required. This particular tests takes many minutes to execute.",
+        computers = {"ALL"})
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.GroovyMatchTest$CountMatchTraversals",
+        method = "g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count",
+        reason = "Hadoop-Gremlin is OLAP-oriented and for OLTP operations, linear-scan joins are required. This particular tests takes many minutes to execute.",
+        computers = {"ALL"})
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.GroovyMatchTest$GreedyMatchTraversals",
+        method = "g_V_matchXa_followedBy_count_isXgtX10XX_b__a_0followedBy_count_isXgtX10XX_bX_count",
+        reason = "Hadoop-Gremlin is OLAP-oriented and for OLTP operations, linear-scan joins are required. This particular tests takes many minutes to execute.",
+        computers = {"ALL"})
 public final class HadoopGraph implements Graph {
 
     public static final Logger LOGGER = LoggerFactory.getLogger(HadoopGraph.class);


[14/17] tinkerpop git commit: Added an exercise mode to the profiling app

Posted by sp...@apache.org.
Added an exercise mode to the profiling app

Just provides a simple way to do some traversals against a graph without having to do a lot of extra setup. CTR


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

Branch: refs/heads/TINKERPOP-1490
Commit: 7c9b47fb8ce42b9d6be23c076e6058df50d1b8d4
Parents: b697b25
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 15:06:01 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Nov 11 15:06:01 2016 -0500

----------------------------------------------------------------------
 .../driver/util/ProfilingApplication.java       | 58 +++++++++++++++++---
 1 file changed, 49 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/7c9b47fb/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
index 5e640c9..b3d20d7 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/util/ProfilingApplication.java
@@ -31,6 +31,7 @@ import java.io.File;
 import java.io.FileWriter;
 import java.io.PrintWriter;
 import java.util.Map;
+import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -47,22 +48,43 @@ import java.util.stream.IntStream;
  */
 public class ProfilingApplication {
 
+    private static final Random random = new Random();
+    private static final String[] scripts = new String[]{
+            "g.V()",
+            "g.V(1).out('knows')",
+            "g.V(1).out('knows').has('name','josh')",
+            "g.V(1).as(\"a\").out(\"knows\").as(\"b\").select(\"a\", \"b\")",
+            "g.V(1).as(\"a\").out(\"knows\").as(\"b\").select(\"a\", \"b\").by(\"name\")",
+            "g.V().hasLabel(\"person\").as(\"p\").map(__.bothE().label().groupCount()).as(\"r\").select(\"p\", \"r\")",
+            "g.V().choose(__.outE().count().is(0L), __.as(\"a\"), __.as(\"b\")).choose(__.select(\"a\"), __.select(\"a\"), __.select(\"b\"))",
+            "g.V().group(\"a\").by(T.label).by(outE().values(\"weight\").sum()).cap(\"a\")",
+            "g.V().repeat(__.union(__.out(\"knows\").group(\"a\").by(\"age\"), __.out(\"created\").group(\"b\").by(\"name\").by(count())).group(\"a\").by(\"name\")).times(2).cap(\"a\", \"b\")",
+            "g.V().match(\n" +
+            "  as(\"a\").out(\"knows\").as(\"b\"),\n" +
+            "  as(\"b\").out(\"created\").has(\"name\", \"lop\"),\n" +
+            "  as(\"b\").match(\n" +
+            "  as(\"b\").out(\"created\").as(\"d\"),\n" +
+            "  as(\"d\").in(\"created\").as(\"c\")).select(\"c\").as(\"c\")).<Vertex>select(\"a\", \"b\", \"c\")"
+    };
+
     private final Cluster cluster;
     private final int requests;
     private final String executionName;
     private final String script;
     private final int tooSlowThreshold;
+    private final boolean exercise;
 
     private final ExecutorService executor;
 
     public ProfilingApplication(final String executionName, final Cluster cluster, final int requests, final ExecutorService executor,
-                                final String script, final int tooSlowThreshold) {
+                                final String script, final int tooSlowThreshold, final boolean exercise) {
         this.executionName = executionName;
         this.cluster = cluster;
         this.requests = requests;
         this.executor = executor;
         this.script = script;
         this.tooSlowThreshold = tooSlowThreshold;
+        this.exercise = exercise;
     }
 
     public long execute() throws Exception {
@@ -75,8 +97,9 @@ public class ProfilingApplication {
             client.init();
 
             final long start = System.nanoTime();
-            IntStream.range(0, requests).forEach(i ->
-                client.submitAsync(script).thenAcceptAsync(r -> {
+            IntStream.range(0, requests).forEach(i -> {
+                final String s = exercise ? chooseScript() : script;
+                client.submitAsync(s).thenAcceptAsync(r -> {
                     try {
                         r.all().get(tooSlowThreshold, TimeUnit.MILLISECONDS);
                     } catch (TimeoutException ex) {
@@ -86,8 +109,8 @@ public class ProfilingApplication {
                     } finally {
                         latch.countDown();
                     }
-                }, executor)
-            );
+                }, executor);
+            });
 
             // finish once all requests are accounted for
             latch.await();
@@ -97,7 +120,7 @@ public class ProfilingApplication {
             final double totalSeconds = total / 1000000000d;
             final long requestCount = requests;
             final long reqSec = Math.round(requestCount / totalSeconds);
-            System.out.println(String.format(StringUtils.rightPad(executionId, 10) + " requests: %s | time(s): %s | req/sec: %s | too slow: %s", requestCount, StringUtils.rightPad(String.valueOf(totalSeconds), 14), StringUtils.rightPad(String.valueOf(reqSec), 7), tooSlow.get()));
+            System.out.println(String.format(StringUtils.rightPad(executionId, 10) + " requests: %s | time(s): %s | req/sec: %s | too slow: %s", requestCount, StringUtils.rightPad(String.valueOf(totalSeconds), 14), StringUtils.rightPad(String.valueOf(reqSec), 7), exercise ? "N/A" : tooSlow.get()));
             return reqSec;
         } catch (Exception ex) {
             ex.printStackTrace();
@@ -107,6 +130,10 @@ public class ProfilingApplication {
         }
     }
 
+    private String chooseScript() {
+        return scripts[random.nextInt(scripts.length - 1)];
+    }
+
     public static void main(final String[] args) {
         final Map<String,Object> options = ElementHelper.asMap(args);
         final boolean noExit = Boolean.parseBoolean(options.getOrDefault("noExit", "false").toString());
@@ -133,6 +160,7 @@ public class ProfilingApplication {
         final String channelizer = options.getOrDefault("channelizer", Channelizer.WebSocketChannelizer.class.getName()).toString();
         final String serializer = options.getOrDefault("serializer", Serializers.GRYO_V1D0.name()).toString();
 
+        final boolean exercise = Boolean.parseBoolean(options.getOrDefault("exercise", "false").toString());
         final String script = options.getOrDefault("script", "1+1").toString();
 
         final Cluster cluster = Cluster.build(host)
@@ -149,6 +177,18 @@ public class ProfilingApplication {
                 .workerPoolSize(workerPoolSize).create();
 
         try {
+            if (exercise) {
+                System.out.println("--------------------------INITIALIZATION--------------------------");
+                final Client client = cluster.connect();
+                client.submit("graph.clear()").all().join();
+                System.out.println("Cleared existing 'graph'");
+
+                client.submit("TinkerFactory.generateModern(graph)").all().join();
+                client.close();
+
+                System.out.println("Modern graph loaded");
+            }
+
             final Object fileName = options.get("store");
             final File f = null == fileName ? null : new File(fileName.toString());
             if (f != null && f.length() == 0) {
@@ -161,7 +201,7 @@ public class ProfilingApplication {
             final AtomicBoolean meetsRpsExpectation = new AtomicBoolean(true);
             System.out.println("---------------------------WARMUP CYCLE---------------------------");
             for (int ix = 0; ix < warmups && meetsRpsExpectation.get(); ix++) {
-                final long averageRequestsPerSecond = new ProfilingApplication("warmup-" + (ix + 1), cluster, 1000, executor, script, tooSlowThreshold).execute();
+                final long averageRequestsPerSecond = new ProfilingApplication("warmup-" + (ix + 1), cluster, 1000, executor, script, tooSlowThreshold, exercise).execute();
                 meetsRpsExpectation.set(averageRequestsPerSecond > minExpectedRps);
                 TimeUnit.SECONDS.sleep(1); // pause between executions
             }
@@ -170,11 +210,11 @@ public class ProfilingApplication {
             long totalRequestsPerSecond = 0;
 
             // no need to execute this if we didn't pass the basic expectation in the warmups
-            if (meetsRpsExpectation.get()) {
+            if (exercise || meetsRpsExpectation.get()) {
                 final long start = System.nanoTime();
                 System.out.println("----------------------------TEST CYCLE----------------------------");
                 for (int ix = 0; ix < executions && !exceededTimeout.get(); ix++) {
-                    totalRequestsPerSecond += new ProfilingApplication("test-" + (ix + 1), cluster, requests, executor, script, tooSlowThreshold).execute();
+                    totalRequestsPerSecond += new ProfilingApplication("test-" + (ix + 1), cluster, requests, executor, script, tooSlowThreshold, exercise).execute();
                     exceededTimeout.set((System.nanoTime() - start) > TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS));
                     TimeUnit.SECONDS.sleep(1); // pause between executions
                 }