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/12/16 17:19:27 UTC

[01/13] tinkerpop git commit: TINKERPOP-1490 Deprecated the old RemoteConnection submit method.

Repository: tinkerpop
Updated Branches:
  refs/heads/tp32 347a0a960 -> 79dac23b2


TINKERPOP-1490 Deprecated the old RemoteConnection submit method.

That method isn't called at all anymore - needs to be removed completely for 3.3.x.


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

Branch: refs/heads/tp32
Commit: f02e18336aefd540000ecaacd157349537f1f94f
Parents: 460f124
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Mon Nov 14 10:08:48 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:00:40 2016 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                |  1 +
 .../gremlin/process/remote/RemoteConnection.java  | 18 ++++++++++++++++--
 .../process/remote/traversal/RemoteTraversal.java |  6 +++---
 .../driver/remote/DriverRemoteConnection.java     |  6 +++++-
 4 files changed, 25 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f02e1833/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index b637552..60e1bb1 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -53,6 +53,7 @@ TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 * 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()` method to allow for asynchronous traversal processing on "remote" traversals.
+* Deprecated `RemoteConnection.submit(Bytecode)` in favor of `submitAsync(Bytecode)`.
 * 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/f02e1833/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 f4e3976..1831276 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
@@ -38,7 +38,7 @@ import java.util.concurrent.CompletableFuture;
 public interface RemoteConnection extends AutoCloseable {
 
     /**
-     * @deprecated As of release 3.2.2, replaced by {@link #submit(Bytecode)}.
+     * @deprecated As of release 3.2.2, replaced by {@link #submitAsync(Bytecode)}.
      */
     @Deprecated
     public <E> Iterator<Traverser.Admin<E>> submit(final Traversal<?, E> traversal) throws RemoteConnectionException;
@@ -47,13 +47,27 @@ public interface RemoteConnection extends AutoCloseable {
      * 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.
+     *
+     * @deprecated As of release 3.2.4, replaced by {@link #submitAsync(Bytecode)}.
      */
+    @Deprecated
     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.
+     * <p/>
+     * The default implementation calls the {@link #submit(Bytecode)} method for backward compatibility, but generally
+     * speaking this method should be implemented directly as {@link #submit(Bytecode)} is not called directly by
+     * any part of TinkerPop. Even if the {@code RemoteConnection} itself is not capable of asynchronous behaviour, it
+     * should simply implement this method in a blocking form.
      */
-    public <E> CompletableFuture<RemoteTraversal<?, E>> submitAsync(final Bytecode bytecode) throws RemoteConnectionException;
+    public default <E> CompletableFuture<RemoteTraversal<?, E>> submitAsync(final Bytecode bytecode) throws RemoteConnectionException {
+        // default implementation for backward compatibility to 3.2.4 - this method will probably just become
+        // the new submit() in 3.3.x when the deprecation is removed
+        final CompletableFuture<RemoteTraversal<?, E>> promise = new CompletableFuture<>();
+        promise.complete(submit(bytecode));
+        return promise;
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f02e1833/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 57b0cda..70ec27f 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
@@ -25,9 +25,9 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
 
 /**
- * A {@link RemoteTraversal} is returned from {@link RemoteConnection#submit(Bytecode)}. It is iterated from within
- * {@link RemoteStep} using {@link #nextTraverser()}. Implementations should typically be given a "result" from a
- * remote source where the traversal was executed. The "result" should be an iterator which preferably has its data
+ * A {@link RemoteTraversal} is returned from {@link RemoteConnection#submitAsync(Bytecode)}. It is iterated from
+ * within {@link RemoteStep} using {@link #nextTraverser()}. Implementations should typically be given a "result" from
+ * a remote source where the traversal was executed. The "result" should be an iterator which preferably has its data
  * bulked.
  * <p/>
  * Note that internally {@link #nextTraverser()} is called from within a loop (specifically in

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f02e1833/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 be3fa28..d6415de 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
@@ -165,7 +165,7 @@ public class DriverRemoteConnection implements RemoteConnection {
     }
 
     /**
-     * @deprecated As of release 3.2.2, replaced by {@link #submit(Bytecode)}.
+     * @deprecated As of release 3.2.2, replaced by {@link #submitAsync(Bytecode)}.
      */
     @Deprecated
     @Override
@@ -183,6 +183,10 @@ public class DriverRemoteConnection implements RemoteConnection {
         }
     }
 
+    /**
+     * @deprecated As of release 3.2.4, replaced by {@link #submitAsync(Bytecode)}.
+     */
+    @Deprecated
     @Override
     public <E> RemoteTraversal<?,E> submit(final Bytecode bytecode) throws RemoteConnectionException {
         try {


[08/13] 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/6c4cbc84
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/6c4cbc84
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/6c4cbc84

Branch: refs/heads/tp32
Commit: 6c4cbc849f83b9ed44d3c5bbef5e59d67b702593
Parents: b0b9330
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Nov 1 09:30:28 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:10:14 2016 -0500

----------------------------------------------------------------------
 gremlin-core/pom.xml                            |  5 +++
 .../traversal/util/DefaultTraversal.java        | 37 +++++++++++++++++
 .../gremlin/python/jsr223/PythonProvider.java   |  1 +
 .../process/traversal/CoreTraversalTest.java    | 42 ++++++++++++++++++++
 .../TinkerGraphGroovyTranslatorProvider.java    |  1 +
 .../TinkerGraphJavaTranslatorProvider.java      |  1 +
 6 files changed, 87 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6c4cbc84/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/6c4cbc84/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/6c4cbc84/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 9e03884..5dd9c28 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
@@ -69,6 +69,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/6c4cbc84/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/6c4cbc84/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/6c4cbc84/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()));


[09/13] 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/f4bc29c0
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/f4bc29c0
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/f4bc29c0

Branch: refs/heads/tp32
Commit: f4bc29c0a5a5ef26e182765bd3d8d6d2780925d0
Parents: 9bbf025
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 13:39:40 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:12:08 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/f4bc29c0/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 5dd9c28..9e03884 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
@@ -69,7 +69,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/f4bc29c0/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/f4bc29c0/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()));


[13/13] tinkerpop git commit: raise error if side effect method called while loop is running

Posted by sp...@apache.org.
raise error if side effect method called while loop is running


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

Branch: refs/heads/tp32
Commit: 79dac23b2f305911e651648c5b43fb3fe59d94c8
Parents: a8c8b65
Author: davebshow <da...@gmail.com>
Authored: Wed Dec 7 16:37:05 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:14:20 2016 -0500

----------------------------------------------------------------------
 .../driver/driver_remote_connection.py          |  4 ++--
 .../gremlin_python/driver/remote_connection.py  | 12 +++++++++-
 .../driver/test_driver_remote_connection.py     | 24 +++++++++++---------
 3 files changed, 26 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/79dac23b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
index babb113..b951cdf 100644
--- a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
+++ b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
@@ -54,13 +54,13 @@ class DriverRemoteConnection(RemoteConnection):
         request_id = str(uuid.uuid4())
         traversers = self._loop.run_sync(lambda: self.submit_traversal_bytecode(request_id, bytecode))
         keys, value, close = self._get_side_effect_lambdas(request_id)
-        return RemoteTraversal(iter(traversers), RemoteTraversalSideEffects(keys, value, close))
+        return RemoteTraversal(iter(traversers), RemoteTraversalSideEffects(keys, value, close, self._loop))
 
     def submit_async(self, bytecode):
         request_id = str(uuid.uuid4())
         future_traversers = self.submit_traversal_bytecode(request_id, bytecode)
         keys, value, close = self._get_side_effect_lambdas(request_id)
-        side_effects = RemoteTraversalSideEffects(keys, value, close)
+        side_effects = RemoteTraversalSideEffects(keys, value, close, self._loop)
         return RemoteTraversal(future_traversers, side_effects)
 
     @gen.coroutine

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/79dac23b/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
index 93c92b7..f7ed48e 100644
--- a/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
+++ b/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
@@ -57,20 +57,27 @@ class RemoteTraversal(Traversal):
 
 
 class RemoteTraversalSideEffects(TraversalSideEffects):
-    def __init__(self, keys_lambda, value_lambda, close_lambda):
+    def __init__(self, keys_lambda, value_lambda, close_lambda, loop):
         self._keys_lambda = keys_lambda
         self._value_lambda = value_lambda
         self._close_lambda = close_lambda
+        self._loop = loop
         self._keys = set()
         self._side_effects = {}
         self._closed = False
 
     def keys(self):
+        if self._loop._running:
+            raise RuntimeError("Cannot call side effect methods"
+                               "while event loop is running")
         if not self._closed:
             self._keys = self._keys_lambda()
         return self._keys
 
     def get(self, key):
+        if self._loop._running:
+            raise RuntimeError("Cannot call side effect methods"
+                               "while event loop is running")
         if not self._side_effects.get(key):
             if not self._closed:
                 results = self._value_lambda(key)
@@ -81,6 +88,9 @@ class RemoteTraversalSideEffects(TraversalSideEffects):
         return self._side_effects[key]
 
     def close(self):
+        if self._loop._running:
+            raise RuntimeError("Cannot call side effect methods"
+                               "while event loop is running")
         results = self._close_lambda()
         self._closed = True
         return results

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/79dac23b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
index c9e64c5..783cf7e 100644
--- a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
+++ b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
@@ -211,6 +211,7 @@ class TestDriverRemoteConnection(TestCase):
             assert count == 6
 
         loop.run_sync(go)
+        connection.close()
 
     def test_promise_side_effects(self):
         loop = ioloop.IOLoop.current()
@@ -224,22 +225,17 @@ class TestDriverRemoteConnection(TestCase):
         @gen.coroutine
         def go():
             traversal = yield g.V().aggregate('a').promise()
-            # Trying to get side effect keys throws error - BAD
+            # Calling synchronous side effect methods from coroutine raises.
             with pytest.raises(RuntimeError):
                 keys = traversal.side_effects.keys()
-                # IOLoop is now hosed.
 
-        loop.run_sync(go)
+            with pytest.raises(RuntimeError):
+                keys = traversal.side_effects.get('a')
 
-        # Get a new IOLoop - this should happen for each test case.
-        connection.close()
-        ioloop.IOLoop.clear_instance()
-        loop.close()
-        loop = ioloop.IOLoop()
-        loop.make_current()
+            with pytest.raises(RuntimeError):
+                keys = traversal.side_effects.close()
 
-        connection = DriverRemoteConnection('ws://localhost:45940/gremlin', 'g')
-        g = Graph().traversal().withRemote(connection)
+        loop.run_sync(go)
 
         # If we return the traversal though, we can use side effects per usual.
         @gen.coroutine
@@ -251,6 +247,12 @@ class TestDriverRemoteConnection(TestCase):
         traversal = loop.run_sync(go)
         a, = traversal.side_effects.keys()
         assert  a == 'a'
+        results = traversal.side_effects.get('a')
+        assert results
+        results = traversal.side_effects.close()
+        assert not results
+
+        connection.close()
 
 
 if __name__ == '__main__':


[04/13] tinkerpop git commit: TINKERPOP-1490 Updated dev docs on RemoteConnection API

Posted by sp...@apache.org.
TINKERPOP-1490 Updated dev docs on RemoteConnection API


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

Branch: refs/heads/tp32
Commit: 460f1243b7b0cddb52fc687b370158c1860c9cb7
Parents: 81fa7e0
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Mon Nov 14 10:08:17 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:00:40 2016 -0500

----------------------------------------------------------------------
 docs/src/dev/provider/index.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/460f1243/docs/src/dev/provider/index.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/provider/index.asciidoc b/docs/src/dev/provider/index.asciidoc
index 8760d01..71d071f 100644
--- a/docs/src/dev/provider/index.asciidoc
+++ b/docs/src/dev/provider/index.asciidoc
@@ -427,7 +427,7 @@ iterate.
 There is one method to implement on `RemoteConnection`:
 
 [source,java]
-public <E> RemoteTraversal<?,E> submit(final Bytecode bytecode) throws RemoteConnectionException;
+public <E> CompletableFuture<RemoteTraversal<?, E>> submitAsync(final Bytecode bytecode) throws RemoteConnectionException;
 
 Note that it returns a `RemoteTraversal`. This interface should also be implemented and in most cases implementers can
 simply extend the `AbstractRemoteTraversal`, which provides default implementations for all the `Traversal` methods


[02/13] 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/ee6a3589
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/ee6a3589
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/ee6a3589

Branch: refs/heads/tp32
Commit: ee6a35893661b015dbb827463f175ddcecf1bcb8
Parents: eb08976
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 12:51:40 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:00:40 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       |  22 ++-
 .../DriverRemoteTraversalSideEffectsTest.java   |  12 +-
 gremlin-groovy/pom.xml                          |   5 +
 .../server/GremlinServerIntegrateTest.java      |  25 ++++
 .../process/traversal/CoreTraversalTest.java    |  42 ------
 15 files changed, 131 insertions(+), 301 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ee6a3589/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/ee6a3589/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/ee6a3589/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/ee6a3589/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/ee6a3589/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/ee6a3589/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/ee6a3589/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/ee6a3589/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/ee6a3589/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 bb2d33d..be3fa28 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
@@ -37,6 +37,7 @@ import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.Iterator;
 import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
 
 /**
@@ -163,6 +164,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 {
@@ -189,6 +194,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/ee6a3589/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/ee6a3589/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 8d6fa98..4305567 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,6 +33,7 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * Java driver implementation of {@link TraversalSideEffects}. This class is not thread safe.
@@ -50,15 +51,26 @@ public class DriverRemoteTraversalSideEffects extends AbstractRemoteTraversalSid
 
     private boolean closed = false;
     private boolean retrievedAllKeys = false;
+    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)) {
@@ -91,6 +103,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/ee6a3589/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 27d0079..4e6df93 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
@@ -52,7 +52,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();
@@ -73,7 +75,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();
@@ -93,7 +97,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/ee6a3589/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/ee6a3589/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 b3dbe29..420bd05 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
@@ -46,12 +46,14 @@ 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;
@@ -76,6 +78,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;
@@ -990,4 +993,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/ee6a3589/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);
-    }
 }


[06/13] 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/42e85883
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/42e85883
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/42e85883

Branch: refs/heads/tp32
Commit: 42e858832c294e4cd38e15bdc7c43960217ae094
Parents: ee6a358
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 13:39:40 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:00:40 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/42e85883/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 5dd9c28..9e03884 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
@@ -69,7 +69,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/42e85883/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/42e85883/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()));


[03/13] 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/eb089764
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/eb089764
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/eb089764

Branch: refs/heads/tp32
Commit: eb089764acb91c24023353a2220e7c84febdec8d
Parents: 347a0a9
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Nov 1 09:30:28 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:00:40 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/eb089764/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 8e01ce0..24c75a7 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -52,6 +52,7 @@ TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Factored `GremlinPlugin` functionality out of gremlin-groovy and into gremlin-core - related classes were deprecated.
 * 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/eb089764/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 8a184b4..34ff427 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/eb089764/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/eb089764/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/eb089764/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/eb089764/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/eb089764/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/eb089764/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 9e03884..5dd9c28 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
@@ -69,6 +69,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/eb089764/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/eb089764/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/eb089764/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()));


[12/13] tinkerpop git commit: TINKERPOP-1490 Merge fixes after rebase on tp32

Posted by sp...@apache.org.
TINKERPOP-1490 Merge fixes after rebase on tp32


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

Branch: refs/heads/tp32
Commit: a8c8b6553a0bd0b41c292822f41e2e0d8e073cf1
Parents: 21663f4
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Dec 7 15:01:28 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:14:20 2016 -0500

----------------------------------------------------------------------
 gremlin-python/src/main/jython/gremlin_python/process/traversal.py | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a8c8b655/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
index 2c2db59..07afeac 100644
--- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
+++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
@@ -406,3 +406,4 @@ class Binding(object):
         return hash(self.key) + hash(self.value)
     def __repr__(self):
         return "binding[" + self.key + "=" + str(self.value) + "]"
+


[05/13] tinkerpop git commit: TINKERPOP-1490 Cleaned up documentation based on latest changes to promise API

Posted by sp...@apache.org.
TINKERPOP-1490 Cleaned up documentation based on latest changes to promise API


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

Branch: refs/heads/tp32
Commit: 81fa7e0e19ad337d764f6bcb7c36c286ca33396d
Parents: 42e8588
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Mon Nov 14 06:38:18 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:00:40 2016 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                 | 2 +-
 docs/src/upgrade/release-3.2.x-incubating.asciidoc | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/81fa7e0e/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 24c75a7..b637552 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -52,7 +52,7 @@ TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Factored `GremlinPlugin` functionality out of gremlin-groovy and into gremlin-core - related classes were deprecated.
 * 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 `Traversal.promise()` method to allow for asynchronous traversal processing on "remote" traversals.
 * 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/81fa7e0e/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 34ff427..428b0c6 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -35,7 +35,7 @@ Upgrading for Users
 Traversal Promises
 ^^^^^^^^^^^^^^^^^^
 
-The `Traversal` API now has two `promise()` method overloads. These methods return a promise in the form of a
+The `Traversal` API now has a new `promise()` method. These methods return a promise in the form of a
 `CompleteableFuture`. Usage is as follows:
 
 [source,groovy]
@@ -50,6 +50,8 @@ gremlin> g.V().out().promise{it.toList()}.thenApply{it.size()}.get()
 ==>6
 ----
 
+At this time, this method is only used for traversals that are configured using `withRemote()`.
+
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-1490[TINKERPOP-1490]
 
 If/Then-Semantics with Choose Step


[11/13] tinkerpop git commit: TINKERPOP-1490 Deprecated the old RemoteConnection submit method.

Posted by sp...@apache.org.
TINKERPOP-1490 Deprecated the old RemoteConnection submit method.

That method isn't called at all anymore - needs to be removed completely for 3.3.x.


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

Branch: refs/heads/tp32
Commit: 21663f400e9a808b136ef6384a2ad694c20f5da4
Parents: f4bc29c
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Mon Nov 14 10:08:48 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:14:20 2016 -0500

----------------------------------------------------------------------
 .../tinkerpop/gremlin/driver/remote/DriverRemoteConnection.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/21663f40/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 ef3a0a9..d6415de 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
@@ -165,7 +165,7 @@ public class DriverRemoteConnection implements RemoteConnection {
     }
 
     /**
-     * @deprecated As of release 3.2.2, replaced by {@link #submit(Bytecode)}.
+     * @deprecated As of release 3.2.2, replaced by {@link #submitAsync(Bytecode)}.
      */
     @Deprecated
     @Override


[07/13] tinkerpop git commit: implemented promise API for gremlin-python. side effect retrieval is problematic

Posted by sp...@apache.org.
implemented promise API for gremlin-python. side effect retrieval is problematic


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

Branch: refs/heads/tp32
Commit: b0b933084b38f77fcd4843796980cabe313ed1e4
Parents: f02e183
Author: davebshow <da...@gmail.com>
Authored: Wed Dec 7 13:35:42 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:03:41 2016 -0500

----------------------------------------------------------------------
 .../python/TraversalSourceGenerator.groovy      | 27 +++++++++
 .../driver/driver_remote_connection.py          | 21 +++++--
 .../gremlin_python/driver/remote_connection.py  |  7 +++
 .../jython/gremlin_python/process/traversal.py  | 28 +++++++++-
 .../driver/test_driver_remote_connection.py     | 59 ++++++++++++++++++++
 5 files changed, 137 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b0b93308/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
index 73ffcb6..fc76b71 100644
--- a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
+++ b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
@@ -114,6 +114,28 @@ class Traversal(object):
                 except StopIteration: return tempList
                 tempList.append(temp)
             return tempList
+    def promise(self, cb=None):
+        self.traversal_strategies.apply_async_strategies(self)
+        future_traversers = self.traversers
+        future = type(future_traversers)()
+        def process(f):
+            try:
+                traversers = f.result()
+            except Exception as e:
+                future.set_exception(e)
+            else:
+                self.traversers = iter(traversers)
+                if cb:
+                    try:
+                        result = cb(self)
+                    except Exception as e:
+                        future.set_exception(e)
+                    else:
+                        future.set_result(result)
+                else:
+                    future.set_result(self)
+        future_traversers.add_done_callback(process)
+        return future
 
 
 """)
@@ -223,6 +245,9 @@ class TraversalStrategies(object):
     def apply_strategies(self, traversal):
         for traversal_strategy in self.traversal_strategies:
             traversal_strategy.apply(traversal)
+    def apply_async_strategies(self, traversal):
+        for traversal_strategy in self.traversal_strategies:
+            traversal_strategy.apply_async(traversal)
     def __repr__(self):
         return str(self.traversal_strategies)
 
@@ -233,6 +258,8 @@ class TraversalStrategy(object):
         self.configuration = {} if configuration is None else configuration
     def apply(self, traversal):
         return
+    def apply_async(self, traversal):
+        return
     def __eq__(self, other):
         return isinstance(other, self.__class__)
     def __hash__(self):

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b0b93308/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
index d975f60..babb113 100644
--- a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
+++ b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
@@ -17,9 +17,11 @@ specific language governing permissions and limitations
 under the License.
 """
 import base64
+import functools
 import json
 import uuid
 from tornado import gen
+from tornado import concurrent
 from tornado import ioloop
 from tornado import websocket
 
@@ -51,10 +53,15 @@ class DriverRemoteConnection(RemoteConnection):
         '''
         request_id = str(uuid.uuid4())
         traversers = self._loop.run_sync(lambda: self.submit_traversal_bytecode(request_id, bytecode))
-        side_effect_keys = lambda: self._loop.run_sync(lambda: self.submit_sideEffect_keys(request_id))
-        side_effect_value = lambda key: self._loop.run_sync(lambda: self.submit_sideEffect_value(request_id, key))
-        side_effect_close = lambda: self._loop.run_sync(lambda: self.submit_sideEffect_close(request_id))
-        return RemoteTraversal(iter(traversers), RemoteTraversalSideEffects(side_effect_keys, side_effect_value, side_effect_close))
+        keys, value, close = self._get_side_effect_lambdas(request_id)
+        return RemoteTraversal(iter(traversers), RemoteTraversalSideEffects(keys, value, close))
+
+    def submit_async(self, bytecode):
+        request_id = str(uuid.uuid4())
+        future_traversers = self.submit_traversal_bytecode(request_id, bytecode)
+        keys, value, close = self._get_side_effect_lambdas(request_id)
+        side_effects = RemoteTraversalSideEffects(keys, value, close)
+        return RemoteTraversal(future_traversers, side_effects)
 
     @gen.coroutine
     def submit_traversal_bytecode(self, request_id, bytecode):
@@ -135,6 +142,12 @@ class DriverRemoteConnection(RemoteConnection):
         result = yield self._execute_message(message)
         raise gen.Return(result)
 
+    def _get_side_effect_lambdas(self, request_id):
+        side_effect_keys = lambda: self._loop.run_sync(lambda: self.submit_sideEffect_keys(request_id))
+        side_effect_value = lambda key: self._loop.run_sync(lambda: self.submit_sideEffect_value(request_id, key))
+        side_effect_close = lambda: self._loop.run_sync(lambda: self.submit_sideEffect_close(request_id))
+        return side_effect_keys, side_effect_value, side_effect_close
+
     @gen.coroutine
     def _execute_message(self, send_message):
         send_message = b"".join([b"\x21",

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b0b93308/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
index 46fb760..93c92b7 100644
--- a/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
+++ b/gremlin-python/src/main/jython/gremlin_python/driver/remote_connection.py
@@ -95,3 +95,10 @@ class RemoteStrategy(TraversalStrategy):
             remote_traversal = self.remote_connection.submit(traversal.bytecode)
             traversal.side_effects = remote_traversal.side_effects
             traversal.traversers = remote_traversal.traversers
+
+    def apply_async(self, traversal):
+        if traversal.traversers is None:
+            remote_traversal = self.remote_connection.submit_async(
+                traversal.bytecode)
+            traversal.side_effects = remote_traversal.side_effects
+            traversal.traversers = remote_traversal.traversers

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b0b93308/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
index a7b6118..2c2db59 100644
--- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
+++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
@@ -77,6 +77,28 @@ class Traversal(object):
                 except StopIteration: return tempList
                 tempList.append(temp)
             return tempList
+    def promise(self, cb=None):
+        self.traversal_strategies.apply_async_strategies(self)
+        future_traversers = self.traversers
+        future = type(future_traversers)()
+        def process(f):
+            try:
+                traversers = f.result()
+            except Exception as e:
+                future.set_exception(e)
+            else:
+                self.traversers = iter(traversers)
+                if cb:
+                    try:
+                        result = cb(self)
+                    except Exception as e:
+                        future.set_exception(e)
+                    else:
+                        future.set_result(result)
+                else:
+                    future.set_result(self)
+        future_traversers.add_done_callback(process)
+        return future
 
 
 Barrier = Enum('Barrier', 'normSack')
@@ -286,6 +308,9 @@ class TraversalStrategies(object):
     def apply_strategies(self, traversal):
         for traversal_strategy in self.traversal_strategies:
             traversal_strategy.apply(traversal)
+    def apply_async_strategies(self, traversal):
+        for traversal_strategy in self.traversal_strategies:
+            traversal_strategy.apply_async(traversal)
     def __repr__(self):
         return str(self.traversal_strategies)
 
@@ -296,6 +321,8 @@ class TraversalStrategy(object):
         self.configuration = {} if configuration is None else configuration
     def apply(self, traversal):
         return
+    def apply_async(self, traversal):
+        return
     def __eq__(self, other):
         return isinstance(other, self.__class__)
     def __hash__(self):
@@ -379,4 +406,3 @@ class Binding(object):
         return hash(self.key) + hash(self.value)
     def __repr__(self):
         return "binding[" + self.key + "=" + str(self.value) + "]"
-

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b0b93308/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
index 6b057d5..c9e64c5 100644
--- a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
+++ b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py
@@ -24,6 +24,8 @@ from unittest import TestCase
 
 import pytest
 
+from tornado import ioloop, gen
+
 from gremlin_python import statics
 from gremlin_python.statics import long
 from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
@@ -193,6 +195,63 @@ class TestDriverRemoteConnection(TestCase):
             t.side_effects.value_lambda('b')
         connection.close()
 
+    def test_promise(self):
+        loop = ioloop.IOLoop.current()
+        connection = DriverRemoteConnection('ws://localhost:45940/gremlin', 'g')
+        g = Graph().traversal().withRemote(connection)
+
+        @gen.coroutine
+        def go():
+            future_traversal = g.V().promise(lambda x: x.toList())
+            assert not future_traversal.done()
+            resp = yield future_traversal
+            assert future_traversal.done()
+            assert len(resp) == 6
+            count = yield g.V().count().promise(lambda x: x.next())
+            assert count == 6
+
+        loop.run_sync(go)
+
+    def test_promise_side_effects(self):
+        loop = ioloop.IOLoop.current()
+        connection = DriverRemoteConnection('ws://localhost:45940/gremlin', 'g')
+        g = Graph().traversal().withRemote(connection)
+
+        # Side effects are problematic in coroutines.
+        # Because they are designed to be synchronous (calling `run_sync`)
+        # they result in an error if called from a coroutine because
+        # the event loop is already running
+        @gen.coroutine
+        def go():
+            traversal = yield g.V().aggregate('a').promise()
+            # Trying to get side effect keys throws error - BAD
+            with pytest.raises(RuntimeError):
+                keys = traversal.side_effects.keys()
+                # IOLoop is now hosed.
+
+        loop.run_sync(go)
+
+        # Get a new IOLoop - this should happen for each test case.
+        connection.close()
+        ioloop.IOLoop.clear_instance()
+        loop.close()
+        loop = ioloop.IOLoop()
+        loop.make_current()
+
+        connection = DriverRemoteConnection('ws://localhost:45940/gremlin', 'g')
+        g = Graph().traversal().withRemote(connection)
+
+        # If we return the traversal though, we can use side effects per usual.
+        @gen.coroutine
+        def go():
+            traversal = yield g.V().aggregate('a').promise()
+            raise gen.Return(traversal)  # Weird legacy Python compatible idiom
+
+        # See, normal side effects.
+        traversal = loop.run_sync(go)
+        a, = traversal.side_effects.keys()
+        assert  a == 'a'
+
 
 if __name__ == '__main__':
     test = False


[10/13] 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/9bbf0252
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/9bbf0252
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/9bbf0252

Branch: refs/heads/tp32
Commit: 9bbf0252572201b305236b21f6d4fc60c4db2294
Parents: 6c4cbc8
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 11 12:51:40 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Dec 16 10:12:08 2016 -0500

----------------------------------------------------------------------
 gremlin-core/pom.xml                            |  5 ---
 .../traversal/util/DefaultTraversal.java        | 37 -----------------
 .../driver/remote/DriverRemoteConnection.java   |  2 +-
 .../process/traversal/CoreTraversalTest.java    | 42 --------------------
 4 files changed, 1 insertion(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9bbf0252/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/9bbf0252/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/9bbf0252/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 d6415de..ef3a0a9 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
@@ -165,7 +165,7 @@ public class DriverRemoteConnection implements RemoteConnection {
     }
 
     /**
-     * @deprecated As of release 3.2.2, replaced by {@link #submitAsync(Bytecode)}.
+     * @deprecated As of release 3.2.2, replaced by {@link #submit(Bytecode)}.
      */
     @Deprecated
     @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9bbf0252/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);
-    }
 }