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/10/04 18:29:40 UTC

[01/20] tinkerpop git commit: Corrected a number of problems in close() operations for the driver. [Forced Update!]

Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1487 f04807b94 -> 6f481b0ba (forced update)


Corrected a number of problems in close() operations for the driver.

This was more of a commit than I wanted for tp31, but close() was really messed up. Fixed a number of race conditions and other logic that would allow the driver to hang on close. Also made it so that the Cluster makes an attempt to clean up any Client instances that it spawns.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 6d14adb0819e2ede0b1e7794f384af2910fdbc84
Parents: 0070d3d
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Sep 29 08:40:07 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 06:53:53 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 17 +++++
 .../tinkerpop/gremlin/driver/Channelizer.java   |  6 +-
 .../apache/tinkerpop/gremlin/driver/Client.java | 42 +++++++++--
 .../tinkerpop/gremlin/driver/Cluster.java       | 22 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 68 +++++++++++++++--
 .../gremlin/driver/ConnectionPool.java          | 21 +++---
 .../tinkerpop/gremlin/driver/Handler.java       | 27 +++++--
 .../tinkerpop/gremlin/driver/ResultQueue.java   |  4 +
 .../driver/handler/WebSocketClientHandler.java  |  4 +-
 .../server/GremlinDriverIntegrateTest.java      | 79 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 255 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d0aa8e8..9f45477 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.1.5 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Improved handling of `Cluster.close()` and `Client.close()` to prevent the methods from hanging.
 * Fixed output redirection and potential memory leak in `GremlinGroovyScriptEngine`.
 * Corrected naming of `g_withPath_V_asXaX_out_out_mapXa_name_it_nameX` and `g_withPath_V_asXaX_out_mapXa_nameX` in `MapTest`.
 * Improved session cleanup when a close is triggered by the client.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/docs/src/upgrade/release-3.1.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.1.x-incubating.asciidoc b/docs/src/upgrade/release-3.1.x-incubating.asciidoc
index 400ea10..6cf9fb2 100644
--- a/docs/src/upgrade/release-3.1.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.1.x-incubating.asciidoc
@@ -27,6 +27,23 @@ TinkerPop 3.1.5
 
 *Release Date: NOT OFFICIALLY RELEASED YET*
 
+Please see the link:https://github.com/apache/tinkerpop/blob/3.1.4/CHANGELOG.asciidoc#tinkerpop-315-release-date-XXXXXXXXXXXX[changelog] for a complete list of all the modifications that are part of this release.
+
+Upgrading for Users
+~~~~~~~~~~~~~~~~~~~
+
+Java Driver and close()
+^^^^^^^^^^^^^^^^^^^^^^^
+
+There were a few problems noted around the `close()` of `Cluster` and `Client` instances, including issues that
+presented as system hangs. These issues have been resolved, however, it is worth noting that an unchecked exception
+that was thrown under a certain situation has changed as part of the bug fixes. When submitting an in-session request
+on a `Client` that was closed (or closing) an `IllegalStateException` is thrown. This replaces older functionality
+that threw a `ConnectionException` and relied logic far deeper in the driver to produce that error and had the
+potential to open additional resources despite the intention of the user to "close".
+
+See: https://issues.apache.org/jira/browse/TINKERPOP-1467[TINKERPOP-1467]
+
 TinkerPop 3.1.4
 ---------------
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
index 40be11c..b3761b7 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
@@ -20,9 +20,6 @@ package org.apache.tinkerpop.gremlin.driver;
 
 import io.netty.channel.Channel;
 import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
-import io.netty.handler.ssl.SslContextBuilder;
-import io.netty.handler.ssl.SslProvider;
-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
 import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinRequestEncoder;
 import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinResponseDecoder;
@@ -42,7 +39,6 @@ import io.netty.handler.ssl.SslContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentMap;
@@ -156,7 +152,7 @@ public interface Channelizer extends ChannelHandler {
          */
         @Override
         public void close(final Channel channel) {
-            channel.writeAndFlush(new CloseWebSocketFrame());
+            if (channel.isOpen()) channel.writeAndFlush(new CloseWebSocketFrame());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index 4aca9ca..3a03141 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
@@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 /**
@@ -245,6 +246,8 @@ public abstract class Client {
      * A low-level method that allows the submission of a manually constructed {@link RequestMessage}.
      */
     public CompletableFuture<ResultSet> submitAsync(final RequestMessage msg) {
+        if (isClosing()) throw new IllegalStateException("Client has been closed");
+
         if (!initialized)
             init();
 
@@ -269,6 +272,8 @@ public abstract class Client {
         }
     }
 
+    public abstract boolean isClosing();
+
     /**
      * Closes the client by making a synchronous call to {@link #closeAsync()}.
      */
@@ -290,11 +295,17 @@ public abstract class Client {
     public final static class ClusteredClient extends Client {
 
         private ConcurrentMap<Host, ConnectionPool> hostConnectionPools = new ConcurrentHashMap<>();
+        private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
 
         ClusteredClient(final Cluster cluster) {
             super(cluster);
         }
 
+        @Override
+        public boolean isClosing() {
+            return closing.get() != null;
+        }
+
         /**
          * Submits a Gremlin script to the server and returns a {@link ResultSet} once the write of the request is
          * complete.
@@ -364,10 +375,14 @@ public abstract class Client {
          * Closes all the connection pools on all hosts.
          */
         @Override
-        public CompletableFuture<Void> closeAsync() {
+        public synchronized CompletableFuture<Void> closeAsync() {
+            if (closing.get() != null)
+                return closing.get();
+
             final CompletableFuture[] poolCloseFutures = new CompletableFuture[hostConnectionPools.size()];
             hostConnectionPools.values().stream().map(ConnectionPool::closeAsync).collect(Collectors.toList()).toArray(poolCloseFutures);
-            return CompletableFuture.allOf(poolCloseFutures);
+            closing.set(CompletableFuture.allOf(poolCloseFutures));
+            return closing.get();
         }
     }
 
@@ -448,11 +463,16 @@ public abstract class Client {
          * close on the {@code Client} that created it.
          */
         @Override
-        public CompletableFuture<Void> closeAsync() {
+        public synchronized CompletableFuture<Void> closeAsync() {
             close.complete(null);
             return close;
         }
 
+        @Override
+        public boolean isClosing() {
+            return close.isDone();
+        }
+
         /**
          * {@inheritDoc}
          */
@@ -483,6 +503,8 @@ public abstract class Client {
 
         private ConnectionPool connectionPool;
 
+        private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
+
         SessionedClient(final Cluster cluster, final String sessionId, final boolean manageTransactions) {
             super(cluster);
             this.sessionId = sessionId;
@@ -526,12 +548,22 @@ public abstract class Client {
             connectionPool = new ConnectionPool(host, this, Optional.of(1), Optional.of(1));
         }
 
+        @Override
+        public boolean isClosing() {
+            return closing.get() != null;
+        }
+
         /**
          * Close the bound {@link ConnectionPool}.
          */
         @Override
-        public CompletableFuture<Void> closeAsync() {
-            return connectionPool.closeAsync();
+        public synchronized CompletableFuture<Void> closeAsync() {
+            if (closing.get() != null)
+                return closing.get();
+
+            final CompletableFuture<Void> connectionPoolClose = connectionPool.closeAsync();
+            closing.set(connectionPoolClose);
+            return connectionPoolClose;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
index 6a6a2e3..473991a 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
@@ -36,6 +36,7 @@ import javax.net.ssl.TrustManager;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.lang.ref.WeakReference;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.URI;
@@ -83,7 +84,9 @@ public final class Cluster {
      * submitted or can be directly initialized via {@link Client#init()}.
      */
     public <T extends Client> T connect() {
-        return (T) new Client.ClusteredClient(this);
+        final Client client = new Client.ClusteredClient(this);
+        manager.trackClient(client);
+        return (T) client;
     }
 
     /**
@@ -122,7 +125,9 @@ public final class Cluster {
     public <T extends Client> T connect(final String sessionId, final boolean manageTransactions) {
         if (null == sessionId || sessionId.isEmpty())
             throw new IllegalArgumentException("sessionId cannot be null or empty");
-        return (T) new Client.SessionedClient(this, sessionId, manageTransactions);
+        final Client client = new Client.SessionedClient(this, sessionId, manageTransactions);
+        manager.trackClient(client);
+        return (T) client;
     }
 
     @Override
@@ -684,6 +689,8 @@ public final class Cluster {
 
         private final AtomicReference<CompletableFuture<Void>> closeFuture = new AtomicReference<>();
 
+        private final List<WeakReference<Client>> openedClients = new ArrayList<>();
+
         private Manager(final Builder builder) {
             this.loadBalancingStrategy = builder.loadBalancingStrategy;
             this.authProps = builder.authProps;
@@ -730,6 +737,10 @@ public final class Cluster {
             });
         }
 
+        void trackClient(final Client client) {
+            openedClients.add(new WeakReference<>(client));
+        }
+
         public Host add(final InetSocketAddress address) {
             final Host newHost = new Host(address, Cluster.this);
             final Host previous = hosts.putIfAbsent(address, newHost);
@@ -745,6 +756,13 @@ public final class Cluster {
             if (closeFuture.get() != null)
                 return closeFuture.get();
 
+            for (WeakReference<Client> openedClient : openedClients) {
+                final Client client = openedClient.get();
+                if (client != null && !client.isClosing()) {
+                    client.close();
+                }
+            }
+
             final CompletableFuture<Void> closeIt = new CompletableFuture<>();
             closeFuture.set(closeIt);
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/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 220ad42..660ad0d 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
@@ -35,6 +35,8 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -128,7 +130,7 @@ final class Connection {
         return isDead;
     }
 
-    public boolean isClosed() {
+    boolean isClosing() {
         return closeFuture.get() != null;
     }
 
@@ -148,22 +150,26 @@ final class Connection {
         return pending;
     }
 
-    public CompletableFuture<Void> closeAsync() {
+    public synchronized CompletableFuture<Void> closeAsync() {
+        if (isClosing()) return closeFuture.get();
+
         final CompletableFuture<Void> future = new CompletableFuture<>();
-        if (!closeFuture.compareAndSet(null, future))
-            return closeFuture.get();
+        closeFuture.set(future);
 
         // make sure all requests in the queue are fully processed before killing.  if they are then shutdown
         // can be immediate.  if not this method will signal the readCompleted future defined in the write()
         // operation to check if it can close.  in this way the connection no longer receives writes, but
         // can continue to read. If a request never comes back the future won't get fulfilled and the connection
         // will maintain a "pending" request, that won't quite ever go away.  The build up of such a dead requests
-        // on a connection in the connection pool will force the pool to replace the connection for a fresh one
-        if (pending.isEmpty()) {
+        // on a connection in the connection pool will force the pool to replace the connection for a fresh one.
+        if (isOkToClose()) {
             if (null == channel)
                 future.complete(null);
             else
                 shutdown(future);
+        } else {
+            // there may be some pending requests. schedule a job to wait for those to complete and then shutdown
+            new CheckForPending(future).runUntilDone(cluster.executor(), 1000, TimeUnit.MILLISECONDS);
         }
 
         return future;
@@ -247,16 +253,20 @@ final class Connection {
         }
     }
 
+    private boolean isOkToClose() {
+        return pending.isEmpty() || (channel !=null && !channel.isOpen()) || !pool.host.isAvailable();
+    }
+
     /**
      * Close was signaled in closeAsync() but there were pending messages at that time. This method attempts the
      * shutdown if the returned result cleared up the last pending message.
      */
     private void tryShutdown() {
-        if (isClosed() && pending.isEmpty())
+        if (isClosing() && isOkToClose())
             shutdown(closeFuture.get());
     }
 
-    private void shutdown(final CompletableFuture<Void> future) {
+    private synchronized void shutdown(final CompletableFuture<Void> future) {
         // shutdown can be called directly from closeAsync() or after write() and therefore this method should only
         // be called once. once shutdown is initiated, it shouldn't be executed a second time or else it sends more
         // messages at the server and leads to ugly log messages over there.
@@ -286,6 +296,7 @@ final class Connection {
             }
 
             channelizer.close(channel);
+
             final ChannelPromise promise = channel.newPromise();
             promise.addListener(f -> {
                 if (f.cause() != null)
@@ -307,4 +318,45 @@ final class Connection {
     public String toString() {
         return connectionLabel;
     }
+
+    /**
+     * Self-cancelling tasks that periodically checks for the pending queue to clear before shutting down the
+     * {@code Connection}. Once it does that, it self cancels the scheduled job in the executor.
+     */
+    private final class CheckForPending implements Runnable {
+        private volatile ScheduledFuture<?> self;
+        private final CompletableFuture<Void> future;
+
+        CheckForPending(final CompletableFuture<Void> future) {
+            this.future = future;
+        }
+
+        @Override
+        public void run() {
+            logger.info("Checking for pending messages to complete before close on {}", this);
+
+            if (isOkToClose()) {
+                shutdown(future);
+                boolean interrupted = false;
+                try {
+                    while(null == self) {
+                        try {
+                            Thread.sleep(1);
+                        } catch (InterruptedException e) {
+                            interrupted = true;
+                        }
+                    }
+                    self.cancel(false);
+                } finally {
+                    if(interrupted) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        }
+
+        void runUntilDone(final ScheduledExecutorService executor, final long period, final TimeUnit unit) {
+            self = executor.scheduleAtFixedRate(this, period, period, unit);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
index 9955e82..4691b1b 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
@@ -219,27 +219,26 @@ final class ConnectionPool {
     /**
      * Permanently kills the pool.
      */
-    public CompletableFuture<Void> closeAsync() {
-        logger.info("Signalled closing of connection pool on {} with core size of {}", host, minPoolSize);
+    public synchronized CompletableFuture<Void> closeAsync() {
+        if (closeFuture.get() != null) return closeFuture.get();
 
-        CompletableFuture<Void> future = closeFuture.get();
-        if (future != null)
-            return future;
+        logger.info("Signalled closing of connection pool on {} with core size of {}", host, minPoolSize);
 
         announceAllAvailableConnection();
-        future = CompletableFuture.allOf(killAvailableConnections());
-
-        return closeFuture.compareAndSet(null, future) ? future : closeFuture.get();
+        final CompletableFuture<Void> future = killAvailableConnections();
+        closeFuture.set(future);
+        return future;
     }
 
-    private CompletableFuture[] killAvailableConnections() {
+    private CompletableFuture<Void> killAvailableConnections() {
         final List<CompletableFuture<Void>> futures = new ArrayList<>(connections.size());
         for (Connection connection : connections) {
             final CompletableFuture<Void> future = connection.closeAsync();
-            future.thenRunAsync(open::decrementAndGet, cluster.executor());
+            future.thenRun(open::decrementAndGet);
             futures.add(future);
         }
-        return futures.toArray(new CompletableFuture[futures.size()]);
+
+        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
     }
 
     void replaceConnection(final Connection connection) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
index 773322a..65eb662 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
@@ -29,11 +29,11 @@ import io.netty.util.Attribute;
 import io.netty.util.AttributeKey;
 import io.netty.util.ReferenceCountUtil;
 import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
 import java.util.HashMap;
@@ -83,11 +83,24 @@ final class Handler {
             if (response.getStatus().getCode() == ResponseStatusCode.AUTHENTICATE) {
                 final Attribute<SaslClient> saslClient = channelHandlerContext.attr(saslClientKey);
                 final Attribute<Subject> subject = channelHandlerContext.attr(subjectKey);
-                RequestMessage.Builder messageBuilder = RequestMessage.build(Tokens.OPS_AUTHENTICATION);
+                final RequestMessage.Builder messageBuilder = RequestMessage.build(Tokens.OPS_AUTHENTICATION);
                 // First time through we don't have a sasl client
                 if (saslClient.get() == null) {
                     subject.set(login());
-                    saslClient.set(saslClient(getHostName(channelHandlerContext)));
+                    try {
+                        saslClient.set(saslClient(getHostName(channelHandlerContext)));
+                    } catch (SaslException saslException) {
+                        // push the sasl error into a failure response from the server. this ensures that standard
+                        // processing for the ResultQueue is kept. without this SaslException trap and subsequent
+                        // conversion to an authentication failure, the close() of the connection might not
+                        // succeed as it will appear as though pending messages remain present in the queue on the
+                        // connection and the shutdown won't proceed
+                        final ResponseMessage clientSideError = ResponseMessage.build(response.getRequestId())
+                                .code(ResponseStatusCode.FORBIDDEN).statusMessage(saslException.getMessage()).create();
+                        channelHandlerContext.fireChannelRead(clientSideError);
+                        return;
+                    }
+
                     messageBuilder.addArg(Tokens.ARGS_SASL_MECHANISM, getMechanism());
                     messageBuilder.addArg(Tokens.ARGS_SASL, saslClient.get().hasInitialResponse() ?
                                                                 evaluateChallenge(subject, saslClient, NULL_CHALLENGE) : null);
@@ -214,12 +227,12 @@ final class Handler {
             // there are that many failures someone would take notice and hopefully stop the client.
             logger.error("Could not process the response", cause);
 
-            // the channel took an error because of something pretty bad so release all the completeable
-            // futures out there
-            pending.entrySet().stream().forEach(kv -> kv.getValue().markError(cause));
+            // the channel took an error because of something pretty bad so release all the futures out there
+            pending.values().forEach(val -> val.markError(cause));
+            pending.clear();
 
             // serialization exceptions should not close the channel - that's worth a retry
-            if (!ExceptionUtils.getThrowableList(cause).stream().anyMatch(t -> t instanceof SerializationException))
+            if (!IteratorUtils.anyMatch(ExceptionUtils.getThrowableList(cause).iterator(), t -> t instanceof SerializationException))
                 ctx.close();
         }
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
index 89a0225..e55456e 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
@@ -76,6 +76,10 @@ final class ResultQueue {
         return this.size() == 0;
     }
 
+    public boolean isComplete() {
+        return readComplete.isDone();
+    }
+
     void drainTo(final Collection<Result> collection) {
         if (error.get() != null) throw new RuntimeException(error.get());
         resultLinkedBlockingQueue.drainTo(collection);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
index 922775e..e2a5668 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
@@ -95,9 +95,9 @@ public final class WebSocketClientHandler extends SimpleChannelInboundHandler<Ob
 
     @Override
     public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
-        logger.warn("Exception caught during WebSocket processing - closing connection", cause);
         if (!handshakeFuture.isDone()) handshakeFuture.setFailure(cause);
-        ctx.close();
+
+        // let the GremlinResponseHandler take care of exception logging, channel closing, and cleanup
         ctx.fireExceptionCaught(cause);
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 1a04b6b..bf66b0d 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@ -25,7 +25,6 @@ import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.Result;
 import org.apache.tinkerpop.gremlin.driver.ResultSet;
-import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer;
@@ -746,11 +745,13 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
         client.close();
 
         try {
-            client.submit("x[0]+1");
+            client.submit("x[0]+1").all().get();
             fail("Should have thrown an exception because the connection is closed");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root, instanceOf(ConnectionException.class));
+            assertThat(root, instanceOf(IllegalStateException.class));
+        } finally {
+            cluster.close();
         }
     }
 
@@ -1248,6 +1249,78 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
         }
     }
 
+    @Test
+    public void shouldCloseAllClientsOnCloseOfCluster() throws Exception {
+        final Cluster cluster = Cluster.open();
+        final Client sessionlessOne = cluster.connect();
+        final Client session = cluster.connect("session");
+        final Client sessionlessTwo = cluster.connect();
+        final Client sessionlessThree = cluster.connect();
+        final Client sessionlessFour = cluster.connect();
+
+        assertEquals(2, sessionlessOne.submit("1+1").all().get().get(0).getInt());
+        assertEquals(2, session.submit("1+1").all().get().get(0).getInt());
+        assertEquals(2, sessionlessTwo.submit("1+1").all().get().get(0).getInt());
+        assertEquals(2, sessionlessThree.submit("1+1").all().get().get(0).getInt());
+        // dont' send anything on the 4th client
+
+        // close one of these Clients before the Cluster
+        sessionlessThree.close();
+        cluster.close();
+
+        try {
+            sessionlessOne.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            session.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            sessionlessTwo.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            sessionlessThree.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            sessionlessFour.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        // allow call to close() even though closed through cluster
+        sessionlessOne.close();
+        session.close();
+        sessionlessTwo.close();
+
+        cluster.close();
+    }
+
     private void assertFutureTimeout(final CompletableFuture<List<Result>> futureFirst) {
         try
         {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
index 3e1b7e9..887d408 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
@@ -23,7 +23,6 @@ import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
-import org.ietf.jgss.GSSException;
 import org.junit.Test;
 
 import java.util.HashMap;
@@ -128,7 +127,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
             fail("This should not succeed as the client did not provide credentials");
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertEquals(GSSException.class, root.getClass());
+            assertEquals(ResponseException.class, root.getClass());
         } finally {
             cluster.close();
         }
@@ -157,7 +156,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
         final Client client = cluster.connect();
 
         try {
-            client.submit("1+1").all();
+            client.submit("1+1").all().get();
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertEquals(ResponseException.class, root.getClass());

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
index f2e5622..2f332be 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
@@ -131,7 +131,7 @@ public class GremlinServerAuthOldIntegrateTest extends AbstractGremlinServerInte
             fail("This should not succeed as the client did not provide credentials");
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertEquals(GSSException.class, root.getClass());
+            assertEquals(ResponseException.class, root.getClass());
 
             // removed this assert as the text of the message changes based on kerberos config - stupid kerberos
             // assertThat(root.getMessage(), startsWith("Invalid name provided"));
@@ -163,7 +163,7 @@ public class GremlinServerAuthOldIntegrateTest extends AbstractGremlinServerInte
         final Client client = cluster.connect();
 
         try {
-            client.submit("1+1").all();
+            client.submit("1+1").all().get();
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertEquals(ResponseException.class, root.getClass());

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
index 99b3a1b..3c1fef9 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
@@ -26,7 +26,6 @@ import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.Result;
 import org.apache.tinkerpop.gremlin.driver.ResultSet;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
-import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
@@ -189,7 +188,7 @@ public class GremlinServerSessionIntegrateTest  extends AbstractGremlinServerInt
             fail("Session should be dead");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root, instanceOf(ConnectionException.class));
+            assertThat(root, instanceOf(IllegalStateException.class));
         } finally {
             cluster.close();
         }
@@ -229,7 +228,8 @@ public class GremlinServerSessionIntegrateTest  extends AbstractGremlinServerInt
             cluster.close();
         }
 
-        assertEquals(1, recordingAppender.getMessages().stream()
+        // there will be on for the timeout and a second for closing the cluster
+        assertEquals(2, recordingAppender.getMessages().stream()
                 .filter(msg -> msg.equals("INFO - Session shouldHaveTheSessionTimeout closed\n")).count());
     }
 


[19/20] tinkerpop git commit: Add IO Reference docs

Posted by sp...@apache.org.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/src/dev/io/graphson.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/io/graphson.asciidoc b/docs/src/dev/io/graphson.asciidoc
new file mode 100644
index 0000000..8fa5eee
--- /dev/null
+++ b/docs/src/dev/io/graphson.asciidoc
@@ -0,0 +1,4586 @@
+////
+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.
+
+*******************************************************************************
+* The following groovy script generates the data samples for GraphSON.
+*******************************************************************************
+import java.time.*
+mapper = GraphSONMapper.build().
+                        addRegistry(TinkerIoRegistry.getInstance()).
+                        addCustomModule(new org.apache.tinkerpop.gremlin.driver.ser.AbstractGraphSONMessageSerializerV1d0.GremlinServerModule()).
+                        version(GraphSONVersion.V1_0).create().createMapper()
+graph = TinkerFactory.createTheCrew()
+g = graph.traversal()
+
+toJson = { o, type, comment = "" ->
+  println "Writing ${type}"
+  "${type}\n" +
+  "^".multiply(type.length()) + "\n\n" +
+  (comment.isEmpty() ? "" : comment + "\n\n") +
+  "[source,json]\n" +
+  "----\n" +
+  mapper.writerWithDefaultPrettyPrinter().writeValueAsString(o) + "\n" +
+  "----\n" +
+  "\n"
+}
+
+file = new File("out-graphson-1d0.txt")
+file.withWriter { writer ->
+
+  writer.write("Graph Structure\n")
+  writer.write("~~~~~~~~~~~~~~~\n\n")
+  writer.write(toJson(graph.edges().next(), "Edge"))
+  writer.write(toJson(g.V().out().out().path().next(), "Path"))
+  writer.write(toJson(graph.edges().next().properties().next(), "Property"))
+  writer.write(toJson(new org.apache.tinkerpop.gremlin.structure.util.star.DirectionalStarGraph(org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.of(graph.vertices().next()), Direction.BOTH), "StarGraph"))
+  writer.write(toJson(graph, "TinkerGraph", "`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`."))
+  writer.write(toJson(g.V().out().out().tree().next(), "Tree"))
+  writer.write(toJson(graph.vertices().next(), "Vertex"))
+  writer.write(toJson(graph.vertices().next().properties().next(), "VertexProperty"))
+
+  writer.write("\n")
+  writer.write("RequestMessage\n")
+  writer.write("~~~~~~~~~~~~~~\n\n")
+  def msg = null
+  msg = RequestMessage.build("authentication").
+                       add("saslMechanism", "PLAIN", "sasl", "AHN0ZXBocGhlbgBwYXNzd29yZA==").create()
+  writer.write(toJson(msg, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge."))
+  msg = RequestMessage.build("eval").processor("session").
+                           add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create()
+  writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters."))
+  msg = RequestMessage.build("eval").processor("session").
+                       add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"], "session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create()
+  writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\"."))
+  msg = RequestMessage.build("close").processor("session").
+                       add("session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create()
+  writer.write(toJson(msg, "Session Close", "The following `RequestMessage` is an example of a request to close a session."))
+  msg = RequestMessage.build("eval").
+                           add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy").create()
+  writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters."))
+  msg = RequestMessage.build("eval").
+                       add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"]).create()
+  writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\"."))
+
+  writer.write("\n")
+  writer.write("ResponseMessage\n")
+  writer.write("~~~~~~~~~~~~~~~\n\n")
+  msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
+                        code(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode.AUTHENTICATE).create()
+  writer.write(toJson(msg, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server)."))
+  msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
+                        code(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode.SUCCESS).
+                        result(Arrays.asList(graph.vertices().next())).create()
+  writer.write(toJson(msg, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script."))
+
+  writer.write("\n")
+  writer.write("Time\n")
+  writer.write("~~~~\n\n")
+  writer.write(toJson(Duration.ofDays(5), "Duration", "The following example is a `Duration` of five days."))
+  writer.write(toJson(Instant.now(), "Instant"))
+  writer.write(toJson(LocalDate.of(2016, 1, 1), "LocalDate"))
+  writer.write(toJson(LocalDateTime.of(2016, 1, 1, 12, 30), "LocalDateTime"))
+  writer.write(toJson(LocalTime.of(12, 30, 45), "LocalTime"))
+  writer.write(toJson(MonthDay.of(1, 1), "MonthDay"))
+  writer.write(toJson(OffsetDateTime.now(), "OffsetDateTime"))
+  writer.write(toJson(OffsetTime.now(), "OffsetTime"))
+  writer.write(toJson(Period.of(1, 6, 15), "Period", "The following example is a `Period` of one year, six months and fifteen days."))
+  writer.write(toJson(Year.of(2016), "Year", "The following example is of the `Year` \"2016\"."))
+  writer.write(toJson(YearMonth.of(2016, 6), "YearMonth", "The following example is a `YearMonth` of \"June 2016\""))
+  writer.write(toJson(ZonedDateTime.now(), "ZonedDateTime"))
+  writer.write(toJson(ZoneOffset.ofHoursMinutesSeconds(3, 6, 9), "ZoneOffset", "The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds."))
+
+}
+
+mapper = GraphSONMapper.build().
+                        addRegistry(TinkerIoRegistryV2d0.getInstance()).
+                        typeInfo(TypeInfo.PARTIAL_TYPES).
+                        addCustomModule(GraphSONXModuleV2d0.build().create(false)).
+                        addCustomModule(new org.apache.tinkerpop.gremlin.driver.ser.AbstractGraphSONMessageSerializerV2d0.GremlinServerModule()).
+                        version(GraphSONVersion.V2_0).create().createMapper()
+
+file = new File("out-graphson-2d0.txt")
+file.withWriter { writer ->
+
+  writer.write("Core\n")
+  writer.write("~~~~\n\n")
+  writer.write(toJson(File, "Class"))
+  writer.write(toJson(new Date(), "Date"))
+  writer.write(toJson(100.00d, "Double"))
+  writer.write(toJson(100.00f, "Float"))
+  writer.write(toJson(100, "Integer"))
+  writer.write(toJson(100L, "Long"))
+  writer.write(toJson(new java.sql.Timestamp(System.currentTimeMillis()), "Timestamp"))
+  writer.write(toJson(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786"), "UUID"))
+
+  writer.write("\n")
+  writer.write("Graph Structure\n")
+  writer.write("~~~~~~~~~~~~~~~\n\n")
+  writer.write(toJson(graph.edges().next(), "Edge"))
+  writer.write(toJson(g.V().out().out().path().next(), "Path"))
+  writer.write(toJson(graph.edges().next().properties().next(), "Property"))
+  writer.write(toJson(new org.apache.tinkerpop.gremlin.structure.util.star.DirectionalStarGraph(org.apache.tinkerpop.gremlin.structure.util.star.StarGraph.of(graph.vertices().next()), Direction.BOTH), "StarGraph"))
+  writer.write(toJson(graph, "TinkerGraph", "`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`."))
+  writer.write(toJson(g.V().out().out().tree().next(), "Tree"))
+  writer.write(toJson(graph.vertices().next(), "Vertex"))
+  writer.write(toJson(graph.vertices().next().properties().next(), "VertexProperty"))
+
+  writer.write("\n")
+  writer.write("Graph Process\n")
+  writer.write("~~~~~~~~~~~~~\n\n")
+  writer.write(toJson(SackFunctions.Barrier.normSack, "Barrier"))
+  writer.write(toJson(new Bytecode.Binding("x", 1), "Binding", "A \"Binding\" refers to a `Bytecode.Binding`."))
+  writer.write(toJson(g.V().hasLabel('person').out().in().tree(), "Bytecode", "The following `Bytecode` example represents the traversal of `g.V().hasLabel('person').out().in().tree()`. Obviously the serialized `Bytecode` woudl be quite different for the endless variations of commands that could be used together in the Gremlin language."))
+  writer.write(toJson(VertexProperty.Cardinality.list, "Cardinality"))
+  writer.write(toJson(Column.keys, "Column"))
+  writer.write(toJson(Direction.OUT, "Direction"))
+  writer.write(toJson(Operator.sum, "Operator"))
+  writer.write(toJson(Order.incr, "Order"))
+  writer.write(toJson(Pop.all, "Pop"))
+  writer.write(toJson(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda"))
+  writer.write(toJson(P.gt(0), "P"))
+  writer.write(toJson(P.gt(0).and(P.lt(10)), "P and"))
+  writer.write(toJson(P.gt(0).or(P.within(-1, -10, -100)), "P or"))
+  writer.write(toJson(Scope.local, "Scope"))
+  writer.write(toJson(T.label, "T"))
+  writer.write(toJson(g.V().hasLabel('person').out().out().tree().profile().next(), "TraversalMetrics"))
+  writer.write(toJson(g.V().hasLabel('person').nextTraverser(), "Traverser"))
+
+  writer.write("\n")
+  writer.write("RequestMessage\n")
+  writer.write("~~~~~~~~~~~~~~\n\n")
+  def msg = null
+  msg = RequestMessage.build("authentication").
+                       add("saslMechanism", "PLAIN", "sasl", "AHN0ZXBocGhlbgBwYXNzd29yZA==").create()
+  writer.write(toJson(msg, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge."))
+  msg = RequestMessage.build("eval").processor("session").
+                           add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create()
+  writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters."))
+  msg = RequestMessage.build("eval").processor("session").
+                       add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"], "session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create()
+  writer.write(toJson(msg, "Session Eval", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\"."))
+  msg = RequestMessage.build("close").processor("session").
+                       add("session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create()
+  writer.write(toJson(msg, "Session Close", "The following `RequestMessage` is an example of a request to close a session."))
+  msg = RequestMessage.build("eval").
+                           add("gremlin", "g.V(x)", "bindings", [x: 1], "language", "gremlin-groovy").create()
+  writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters."))
+  msg = RequestMessage.build("eval").
+                       add("gremlin", "social.V(x)", "bindings", [x: 1], "language", "gremlin-groovy", "aliases", [g: "social"]).create()
+  writer.write(toJson(msg, "Sessionless Eval", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\"."))
+
+  writer.write("\n")
+  writer.write("ResponseMessage\n")
+  writer.write("~~~~~~~~~~~~~~~\n\n")
+  msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
+                        code(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode.AUTHENTICATE).create()
+  writer.write(toJson(msg, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server)."))
+  msg = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
+                        code(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode.SUCCESS).
+                        result(Arrays.asList(graph.vertices().next())).create()
+  writer.write(toJson(msg, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script."))
+
+  writer.write("\n")
+  writer.write("Extended\n")
+  writer.write("~~~~~~~~\n\n")
+  writer.write("""Note that the "extended" types require the addition of the separate `GraphSONXModuleV2d0` module as follows:\n
+[source,java]
+----
+mapper = GraphSONMapper.build().
+                        typeInfo(TypeInfo.PARTIAL_TYPES).
+                        addCustomModule(GraphSONXModuleV2d0.build().create(false)).
+                        version(GraphSONVersion.V2_0).create().createMapper()
+----\n
+""")
+  writer.write(toJson(new java.math.BigDecimal(new java.math.BigInteger("123456789987654321123456789987654321")), "BigDecimal"))
+  writer.write(toJson(new java.math.BigInteger("123456789987654321123456789987654321"), "BigInteger"))
+  writer.write(toJson(new Byte("1"), "Byte"))
+  writer.write(toJson(java.nio.ByteBuffer.wrap([1,2,3,4,5] as byte[]), "ByteBuffer"))
+  writer.write(toJson("x".charAt(0), "Char"))
+  writer.write(toJson(Duration.ofDays(5), "Duration", "The following example is a `Duration` of five days."))
+  writer.write(toJson(java.net.InetAddress.getByName("localhost"), "InetAddress"))
+  writer.write(toJson(Instant.now(), "Instant"))
+  writer.write(toJson(LocalDate.of(2016, 1, 1), "LocalDate"))
+  writer.write(toJson(LocalDateTime.of(2016, 1, 1, 12, 30), "LocalDateTime"))
+  writer.write(toJson(LocalTime.of(12, 30, 45), "LocalTime"))
+  writer.write(toJson(MonthDay.of(1, 1), "MonthDay"))
+  writer.write(toJson(OffsetDateTime.now(), "OffsetDateTime"))
+  writer.write(toJson(OffsetTime.now(), "OffsetTime"))
+  writer.write(toJson(Period.of(1, 6, 15), "Period", "The following example is a `Period` of one year, six months and fifteen days."))
+  writer.write(toJson(new Short("100"), "Short"))
+  writer.write(toJson(Year.of(2016), "Year", "The following example is of the `Year` \"2016\"."))
+  writer.write(toJson(YearMonth.of(2016, 6), "YearMonth", "The following example is a `YearMonth` of \"June 2016\""))
+  writer.write(toJson(ZonedDateTime.now(), "ZonedDateTime"))
+  writer.write(toJson(ZoneOffset.ofHoursMinutesSeconds(3, 6, 9), "ZoneOffset", "The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds."))
+
+}
+*******************************************************************************
+
+
+////
+[[graphson]]
+GraphSON
+========
+
+image:gremlin-graphson.png[width=350,float=left] GraphSON is a JSON-based format that is designed for human readable
+output that is easily supported in any programming language through the wide-array of JSON parsing libraries that
+exist on virtually all platforms. GraphSON is considered both a "graph" format and a generalized object serialization
+format. That characteristic makes it useful as a serialization format for Gremlin Server where arbitrary objects
+of varying types may be returned as results.
+
+When considering GraphSON as a "graph" format, the relevant feature to consider is the `writeGraph` and `readGraph`
+methods on the `GraphSONWriter` and `GraphSONReader` interfaces, respectively. These methods write the entire `Graph`
+instance as output or read an entire `Graph` instance input and they do so in a way external to generalized object
+serialization. In other words, the output of:
+
+[source,java]
+----
+final Graph graph = TinkerFactory.createModern();
+final GraphWriter writer = graph.io(IoCore.graphson()).writer();
+writer.writeGraph("tinkerpop-modern.json");
+----
+
+will be different of:
+
+[source,java]
+----
+final Graph graph = TinkerFactory.createModern();
+final GraphWriter writer = graph.io(IoCore.graphson()).writer();
+final OutputStream os = new FileOutputStream("tinkerpop-modern.json");
+writer.writeObject(os, graph);
+----
+
+Generalized object serialization will be discussed later in this section, so for now the focus will be on the "graph"
+format. Unlike GraphML, GraphSON does not use an edge list format. It uses an adjacency list. In the adjacency list,
+each vertex is essentially a line in the file and the vertex line contains a list of all the edges associated with
+that vertex. The GraphSON 2.0 representation looks like this for the Modern toy graph:
+
+[source,json]
+----
+{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}
+{"id":{"@type":"g:Int32","@value":2},"label":"person","inE":{"knows":[{"id":{"@type":"g:Int32","@value":7},"outV":{"@type":"g:Int32","@value":1},"properties":{"weight":{"@type":"g:Double","@value":0.5}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":2},"value":"vadas"}],"age":[{"id":{"@type":"g:Int64","@value":3},"value":{"@type":"g:Int32","@value":27}}]}}
+{"id":{"@type":"g:Int32","@value":3},"label":"software","inE":{"created":[{"id":{"@type":"g:Int32","@value":9},"outV":{"@type":"g:Int32","@value":1},"properties":{"weight":{"@type":"g:Double","@value":0.4}}},{"id":{"@type":"g:Int32","@value":11},"outV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":0.4}}},{"id":{"@type":"g:Int32","@value":12},"outV":{"@type":"g:Int32","@value":6},"properties":{"weight":{"@type":"g:Double","@value":0.2}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":4},"value":"lop"}],"lang":[{"id":{"@type":"g:Int64","@value":5},"value":"java"}]}}
+{"id":{"@type":"g:Int32","@value":4},"label":"person","inE":{"knows":[{"id":{"@type":"g:Int32","@value":8},"outV":{"@type":"g:Int32","@value":1},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"outE":{"created":[{"id":{"@type":"g:Int32","@value":10},"inV":{"@type":"g:Int32","@value":5},"properties":{"weight":{"@type":"g:Double","@value":1.0}}},{"id":{"@type":"g:Int32","@value":11},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":6},"value":"josh"}],"age":[{"id":{"@type":"g:Int64","@value":7},"value":{"@type":"g:Int32","@value":32}}]}}
+{"id":{"@type":"g:Int32","@value":5},"label":"software","inE":{"created":[{"id":{"@type":"g:Int32","@value":10},"outV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":8},"value":"ripple"}],"lang":[{"id":{"@type":"g:Int64","@value":9},"value":"java"}]}}
+{"id":{"@type":"g:Int32","@value":6},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":12},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.2}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":10},"value":"peter"}],"age":[{"id":{"@type":"g:Int64","@value":11},"value":{"@type":"g:Int32","@value":35}}]}}
+----
+
+At a glance, one can see that this is not a valid JSON document. While that may seem incorrect, there is a reason. The
+"graph" format is designed by default to be splittable, such that distributed systems like Spark can easily divide the
+a GraphSON file for processing. If this data were represented as an "array of vertices" with square brackets at the
+beginning and end of the file, the format would be less conducive to fit that purpose. It is possible to change this
+behavior by building the `GraphSONWriter` with the `wrapAdjacencyList` setting set to `true`, in which case the output
+will be a valid JSON document that looks like this:
+
+[source,json]
+----
+{ "vertices": [
+  {"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}
+  {"id":{"@type":"g:Int32","@value":2},"label":"person","inE":{"knows":[{"id":{"@type":"g:Int32","@value":7},"outV":{"@type":"g:Int32","@value":1},"properties":{"weight":{"@type":"g:Double","@value":0.5}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":2},"value":"vadas"}],"age":[{"id":{"@type":"g:Int64","@value":3},"value":{"@type":"g:Int32","@value":27}}]}}
+  {"id":{"@type":"g:Int32","@value":3},"label":"software","inE":{"created":[{"id":{"@type":"g:Int32","@value":9},"outV":{"@type":"g:Int32","@value":1},"properties":{"weight":{"@type":"g:Double","@value":0.4}}},{"id":{"@type":"g:Int32","@value":11},"outV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":0.4}}},{"id":{"@type":"g:Int32","@value":12},"outV":{"@type":"g:Int32","@value":6},"properties":{"weight":{"@type":"g:Double","@value":0.2}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":4},"value":"lop"}],"lang":[{"id":{"@type":"g:Int64","@value":5},"value":"java"}]}}
+  {"id":{"@type":"g:Int32","@value":4},"label":"person","inE":{"knows":[{"id":{"@type":"g:Int32","@value":8},"outV":{"@type":"g:Int32","@value":1},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"outE":{"created":[{"id":{"@type":"g:Int32","@value":10},"inV":{"@type":"g:Int32","@value":5},"properties":{"weight":{"@type":"g:Double","@value":1.0}}},{"id":{"@type":"g:Int32","@value":11},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":6},"value":"josh"}],"age":[{"id":{"@type":"g:Int64","@value":7},"value":{"@type":"g:Int32","@value":32}}]}}
+  {"id":{"@type":"g:Int32","@value":5},"label":"software","inE":{"created":[{"id":{"@type":"g:Int32","@value":10},"outV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":8},"value":"ripple"}],"lang":[{"id":{"@type":"g:Int64","@value":9},"value":"java"}]}}
+  {"id":{"@type":"g:Int32","@value":6},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":12},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.2}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":10},"value":"peter"}],"age":[{"id":{"@type":"g:Int64","@value":11},"value":{"@type":"g:Int32","@value":35}}]}}
+]}
+----
+
+NOTE: The `writeGraph` method essentially calls `writeVertices` with the directionality of `BOTH`. The `writeVertices`
+method simply calls `writeVertex` which detaches each `Vertex` instance into a directional `StarGraph` which forms
+the basis for the format.
+
+The following sections discuss the GraphSON object serialization format as available in each version of GraphSON. Core
+to understanding these sections is to understand that GraphSON can be produced with and without types being embedded
+in the output. Without embedded types, the type system is restricted to standard JSON types of Object, List, String,
+Number, Boolean and that will lead to "lossyness" in the format (i.e. a float will be interpreted as double).
+
+[[graphson-1d0]]
+Version 1.0
+-----------
+
+Version 1.0 of GraphSON was released with TinkerPop 3.0.0. When types are embedded, GraphSON uses the standard
+link:https://github.com/FasterXML/jackson-databind[Jackson] type embedding approach that writes the full Java class
+name into a "@class" field in the JSON. While this approach isn't especially language agnostic it does at least give
+some hint as to what the expected type is.
+
+This section focuses on non-embedded types and their formats as there was little usage of embedded types in generalized
+object serialization use cases. The format was simply too cumbersome to parse of non-Jackson enabled libraries and the
+use cases for it were limited. <<graphson-2d0,GraphSON Version 2.0>> attempts to improve upon this limitation.
+
+Graph Structure
+~~~~~~~~~~~~~~~
+
+Edge
+^^^^
+
+[source,json]
+----
+{
+  "id" : 13,
+  "label" : "develops",
+  "type" : "edge",
+  "inVLabel" : "software",
+  "outVLabel" : "person",
+  "inV" : 10,
+  "outV" : 1,
+  "properties" : {
+    "since" : 2009
+  }
+}
+----
+
+Path
+^^^^
+
+[source,json]
+----
+{
+  "labels" : [ [ ], [ ], [ ] ],
+  "objects" : [ {
+    "id" : 1,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 0,
+        "value" : "marko"
+      } ],
+      "location" : [ {
+        "id" : 6,
+        "value" : "san diego",
+        "properties" : {
+          "startTime" : 1997,
+          "endTime" : 2001
+        }
+      }, {
+        "id" : 7,
+        "value" : "santa cruz",
+        "properties" : {
+          "startTime" : 2001,
+          "endTime" : 2004
+        }
+      }, {
+        "id" : 8,
+        "value" : "brussels",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 9,
+        "value" : "santa fe",
+        "properties" : {
+          "startTime" : 2005
+        }
+      } ]
+    }
+  }, {
+    "id" : 10,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 4,
+        "value" : "gremlin"
+      } ]
+    }
+  }, {
+    "id" : 11,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 5,
+        "value" : "tinkergraph"
+      } ]
+    }
+  } ]
+}
+----
+
+Property
+^^^^^^^^
+
+[source,json]
+----
+{
+  "key" : "since",
+  "value" : 2009
+}
+----
+
+StarGraph
+^^^^^^^^^
+
+[source,json]
+----
+{
+  "id" : 1,
+  "label" : "person",
+  "outE" : {
+    "uses" : [ {
+      "id" : 16,
+      "inV" : 11,
+      "properties" : {
+        "skill" : 5
+      }
+    }, {
+      "id" : 15,
+      "inV" : 10,
+      "properties" : {
+        "skill" : 4
+      }
+    } ],
+    "develops" : [ {
+      "id" : 13,
+      "inV" : 10,
+      "properties" : {
+        "since" : 2009
+      }
+    }, {
+      "id" : 14,
+      "inV" : 11,
+      "properties" : {
+        "since" : 2010
+      }
+    } ]
+  },
+  "properties" : {
+    "name" : [ {
+      "id" : 0,
+      "value" : "marko"
+    } ],
+    "location" : [ {
+      "id" : 6,
+      "value" : "san diego",
+      "properties" : {
+        "startTime" : 1997,
+        "endTime" : 2001
+      }
+    }, {
+      "id" : 7,
+      "value" : "santa cruz",
+      "properties" : {
+        "startTime" : 2001,
+        "endTime" : 2004
+      }
+    }, {
+      "id" : 8,
+      "value" : "brussels",
+      "properties" : {
+        "startTime" : 2004,
+        "endTime" : 2005
+      }
+    }, {
+      "id" : 9,
+      "value" : "santa fe",
+      "properties" : {
+        "startTime" : 2005
+      }
+    } ]
+  }
+}
+----
+
+TinkerGraph
+^^^^^^^^^^^
+
+`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`.
+
+[source,json]
+----
+{
+  "vertices" : [ {
+    "id" : 1,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 0,
+        "value" : "marko"
+      } ],
+      "location" : [ {
+        "id" : 6,
+        "value" : "san diego",
+        "properties" : {
+          "startTime" : 1997,
+          "endTime" : 2001
+        }
+      }, {
+        "id" : 7,
+        "value" : "santa cruz",
+        "properties" : {
+          "startTime" : 2001,
+          "endTime" : 2004
+        }
+      }, {
+        "id" : 8,
+        "value" : "brussels",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 9,
+        "value" : "santa fe",
+        "properties" : {
+          "startTime" : 2005
+        }
+      } ]
+    }
+  }, {
+    "id" : 7,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 1,
+        "value" : "stephen"
+      } ],
+      "location" : [ {
+        "id" : 10,
+        "value" : "centreville",
+        "properties" : {
+          "startTime" : 1990,
+          "endTime" : 2000
+        }
+      }, {
+        "id" : 11,
+        "value" : "dulles",
+        "properties" : {
+          "startTime" : 2000,
+          "endTime" : 2006
+        }
+      }, {
+        "id" : 12,
+        "value" : "purcellville",
+        "properties" : {
+          "startTime" : 2006
+        }
+      } ]
+    }
+  }, {
+    "id" : 8,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 2,
+        "value" : "matthias"
+      } ],
+      "location" : [ {
+        "id" : 13,
+        "value" : "bremen",
+        "properties" : {
+          "startTime" : 2004,
+          "endTime" : 2007
+        }
+      }, {
+        "id" : 14,
+        "value" : "baltimore",
+        "properties" : {
+          "startTime" : 2007,
+          "endTime" : 2011
+        }
+      }, {
+        "id" : 15,
+        "value" : "oakland",
+        "properties" : {
+          "startTime" : 2011,
+          "endTime" : 2014
+        }
+      }, {
+        "id" : 16,
+        "value" : "seattle",
+        "properties" : {
+          "startTime" : 2014
+        }
+      } ]
+    }
+  }, {
+    "id" : 9,
+    "label" : "person",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 3,
+        "value" : "daniel"
+      } ],
+      "location" : [ {
+        "id" : 17,
+        "value" : "spremberg",
+        "properties" : {
+          "startTime" : 1982,
+          "endTime" : 2005
+        }
+      }, {
+        "id" : 18,
+        "value" : "kaiserslautern",
+        "properties" : {
+          "startTime" : 2005,
+          "endTime" : 2009
+        }
+      }, {
+        "id" : 19,
+        "value" : "aachen",
+        "properties" : {
+          "startTime" : 2009
+        }
+      } ]
+    }
+  }, {
+    "id" : 10,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 4,
+        "value" : "gremlin"
+      } ]
+    }
+  }, {
+    "id" : 11,
+    "label" : "software",
+    "type" : "vertex",
+    "properties" : {
+      "name" : [ {
+        "id" : 5,
+        "value" : "tinkergraph"
+      } ]
+    }
+  } ],
+  "edges" : [ {
+    "id" : 13,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 1,
+    "properties" : {
+      "since" : 2009
+    }
+  }, {
+    "id" : 14,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 1,
+    "properties" : {
+      "since" : 2010
+    }
+  }, {
+    "id" : 15,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 1,
+    "properties" : {
+      "skill" : 4
+    }
+  }, {
+    "id" : 16,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 1,
+    "properties" : {
+      "skill" : 5
+    }
+  }, {
+    "id" : 17,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 7,
+    "properties" : {
+      "since" : 2010
+    }
+  }, {
+    "id" : 18,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 7,
+    "properties" : {
+      "since" : 2011
+    }
+  }, {
+    "id" : 19,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 7,
+    "properties" : {
+      "skill" : 5
+    }
+  }, {
+    "id" : 20,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 7,
+    "properties" : {
+      "skill" : 4
+    }
+  }, {
+    "id" : 21,
+    "label" : "develops",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 8,
+    "properties" : {
+      "since" : 2012
+    }
+  }, {
+    "id" : 22,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 8,
+    "properties" : {
+      "skill" : 3
+    }
+  }, {
+    "id" : 23,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 8,
+    "properties" : {
+      "skill" : 3
+    }
+  }, {
+    "id" : 24,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 10,
+    "outV" : 9,
+    "properties" : {
+      "skill" : 5
+    }
+  }, {
+    "id" : 25,
+    "label" : "uses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : 11,
+    "outV" : 9,
+    "properties" : {
+      "skill" : 3
+    }
+  }, {
+    "id" : 26,
+    "label" : "traverses",
+    "type" : "edge",
+    "inVLabel" : "software",
+    "outVLabel" : "software",
+    "inV" : 11,
+    "outV" : 10
+  } ]
+}
+----
+
+Tree
+^^^^
+
+[source,json]
+----
+{
+  "1" : {
+    "key" : {
+      "id" : 1,
+      "label" : "person",
+      "type" : "vertex",
+      "properties" : {
+        "name" : [ {
+          "id" : 0,
+          "value" : "marko"
+        } ],
+        "location" : [ {
+          "id" : 6,
+          "value" : "san diego",
+          "properties" : {
+            "startTime" : 1997,
+            "endTime" : 2001
+          }
+        }, {
+          "id" : 7,
+          "value" : "santa cruz",
+          "properties" : {
+            "startTime" : 2001,
+            "endTime" : 2004
+          }
+        }, {
+          "id" : 8,
+          "value" : "brussels",
+          "properties" : {
+            "startTime" : 2004,
+            "endTime" : 2005
+          }
+        }, {
+          "id" : 9,
+          "value" : "santa fe",
+          "properties" : {
+            "startTime" : 2005
+          }
+        } ]
+      }
+    },
+    "value" : {
+      "10" : {
+        "key" : {
+          "id" : 10,
+          "label" : "software",
+          "type" : "vertex",
+          "properties" : {
+            "name" : [ {
+              "id" : 4,
+              "value" : "gremlin"
+            } ]
+          }
+        },
+        "value" : {
+          "11" : {
+            "key" : {
+              "id" : 11,
+              "label" : "software",
+              "type" : "vertex",
+              "properties" : {
+                "name" : [ {
+                  "id" : 5,
+                  "value" : "tinkergraph"
+                } ]
+              }
+            },
+            "value" : { }
+          }
+        }
+      }
+    }
+  },
+  "7" : {
+    "key" : {
+      "id" : 7,
+      "label" : "person",
+      "type" : "vertex",
+      "properties" : {
+        "name" : [ {
+          "id" : 1,
+          "value" : "stephen"
+        } ],
+        "location" : [ {
+          "id" : 10,
+          "value" : "centreville",
+          "properties" : {
+            "startTime" : 1990,
+            "endTime" : 2000
+          }
+        }, {
+          "id" : 11,
+          "value" : "dulles",
+          "properties" : {
+            "startTime" : 2000,
+            "endTime" : 2006
+          }
+        }, {
+          "id" : 12,
+          "value" : "purcellville",
+          "properties" : {
+            "startTime" : 2006
+          }
+        } ]
+      }
+    },
+    "value" : {
+      "10" : {
+        "key" : {
+          "id" : 10,
+          "label" : "software",
+          "type" : "vertex",
+          "properties" : {
+            "name" : [ {
+              "id" : 4,
+              "value" : "gremlin"
+            } ]
+          }
+        },
+        "value" : {
+          "11" : {
+            "key" : {
+              "id" : 11,
+              "label" : "software",
+              "type" : "vertex",
+              "properties" : {
+                "name" : [ {
+                  "id" : 5,
+                  "value" : "tinkergraph"
+                } ]
+              }
+            },
+            "value" : { }
+          }
+        }
+      }
+    }
+  },
+  "8" : {
+    "key" : {
+      "id" : 8,
+      "label" : "person",
+      "type" : "vertex",
+      "properties" : {
+        "name" : [ {
+          "id" : 2,
+          "value" : "matthias"
+        } ],
+        "location" : [ {
+          "id" : 13,
+          "value" : "bremen",
+          "properties" : {
+            "startTime" : 2004,
+            "endTime" : 2007
+          }
+        }, {
+          "id" : 14,
+          "value" : "baltimore",
+          "properties" : {
+            "startTime" : 2007,
+            "endTime" : 2011
+          }
+        }, {
+          "id" : 15,
+          "value" : "oakland",
+          "properties" : {
+            "startTime" : 2011,
+            "endTime" : 2014
+          }
+        }, {
+          "id" : 16,
+          "value" : "seattle",
+          "properties" : {
+            "startTime" : 2014
+          }
+        } ]
+      }
+    },
+    "value" : {
+      "10" : {
+        "key" : {
+          "id" : 10,
+          "label" : "software",
+          "type" : "vertex",
+          "properties" : {
+            "name" : [ {
+              "id" : 4,
+              "value" : "gremlin"
+            } ]
+          }
+        },
+        "value" : {
+          "11" : {
+            "key" : {
+              "id" : 11,
+              "label" : "software",
+              "type" : "vertex",
+              "properties" : {
+                "name" : [ {
+                  "id" : 5,
+                  "value" : "tinkergraph"
+                } ]
+              }
+            },
+            "value" : { }
+          }
+        }
+      }
+    }
+  },
+  "9" : {
+    "key" : {
+      "id" : 9,
+      "label" : "person",
+      "type" : "vertex",
+      "properties" : {
+        "name" : [ {
+          "id" : 3,
+          "value" : "daniel"
+        } ],
+        "location" : [ {
+          "id" : 17,
+          "value" : "spremberg",
+          "properties" : {
+            "startTime" : 1982,
+            "endTime" : 2005
+          }
+        }, {
+          "id" : 18,
+          "value" : "kaiserslautern",
+          "properties" : {
+            "startTime" : 2005,
+            "endTime" : 2009
+          }
+        }, {
+          "id" : 19,
+          "value" : "aachen",
+          "properties" : {
+            "startTime" : 2009
+          }
+        } ]
+      }
+    },
+    "value" : {
+      "10" : {
+        "key" : {
+          "id" : 10,
+          "label" : "software",
+          "type" : "vertex",
+          "properties" : {
+            "name" : [ {
+              "id" : 4,
+              "value" : "gremlin"
+            } ]
+          }
+        },
+        "value" : {
+          "11" : {
+            "key" : {
+              "id" : 11,
+              "label" : "software",
+              "type" : "vertex",
+              "properties" : {
+                "name" : [ {
+                  "id" : 5,
+                  "value" : "tinkergraph"
+                } ]
+              }
+            },
+            "value" : { }
+          }
+        }
+      }
+    }
+  }
+}
+----
+
+Vertex
+^^^^^^
+
+[source,json]
+----
+{
+  "id" : 1,
+  "label" : "person",
+  "type" : "vertex",
+  "properties" : {
+    "name" : [ {
+      "id" : 0,
+      "value" : "marko"
+    } ],
+    "location" : [ {
+      "id" : 6,
+      "value" : "san diego",
+      "properties" : {
+        "startTime" : 1997,
+        "endTime" : 2001
+      }
+    }, {
+      "id" : 7,
+      "value" : "santa cruz",
+      "properties" : {
+        "startTime" : 2001,
+        "endTime" : 2004
+      }
+    }, {
+      "id" : 8,
+      "value" : "brussels",
+      "properties" : {
+        "startTime" : 2004,
+        "endTime" : 2005
+      }
+    }, {
+      "id" : 9,
+      "value" : "santa fe",
+      "properties" : {
+        "startTime" : 2005
+      }
+    } ]
+  }
+}
+----
+
+VertexProperty
+^^^^^^^^^^^^^^
+
+[source,json]
+----
+{
+  "id" : 0,
+  "value" : "marko",
+  "label" : "name"
+}
+----
+
+
+RequestMessage
+~~~~~~~~~~~~~~
+
+Authentication Response
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.
+
+[source,json]
+----
+{
+  "requestId" : "e943a111-a9f4-4fbd-bc47-28c5e01de67e",
+  "op" : "authentication",
+  "processor" : "",
+  "args" : {
+    "saslMechanism" : "PLAIN",
+    "sasl" : "AHN0ZXBocGhlbgBwYXNzd29yZA=="
+  }
+}
+----
+
+Session Eval
+^^^^^^^^^^^^
+
+The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.
+
+[source,json]
+----
+{
+  "requestId" : "5d7e3354-cd29-47eb-b14a-d6fcc973e58e",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "session" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
+----
+
+Session Eval
+^^^^^^^^^^^^
+
+The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of "g" to "social".
+
+[source,json]
+----
+{
+  "requestId" : "bb310bd3-f44f-4617-8195-4794e8e5851b",
+  "op" : "eval",
+  "processor" : "session",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "session" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
+----
+
+Session Close
+^^^^^^^^^^^^^
+
+The following `RequestMessage` is an example of a request to close a session.
+
+[source,json]
+----
+{
+  "requestId" : "58d90945-76b1-4109-b6f8-44629752bda0",
+  "op" : "close",
+  "processor" : "session",
+  "args" : {
+    "session" : "41d2e28a-20a4-4ab0-b379-d810dede3786"
+  }
+}
+----
+
+Sessionless Eval
+^^^^^^^^^^^^^^^^
+
+The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.
+
+[source,json]
+----
+{
+  "requestId" : "7239b3a7-0e5a-4b6f-b941-bcbc2b38bf3e",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "g.V(x)",
+    "language" : "gremlin-groovy",
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
+----
+
+Sessionless Eval
+^^^^^^^^^^^^^^^^
+
+The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of "g" to "social".
+
+[source,json]
+----
+{
+  "requestId" : "6e0fea49-2ea4-4cf9-859d-723b4b468efe",
+  "op" : "eval",
+  "processor" : "",
+  "args" : {
+    "gremlin" : "social.V(x)",
+    "language" : "gremlin-groovy",
+    "aliases" : {
+      "g" : "social"
+    },
+    "bindings" : {
+      "x" : 1
+    }
+  }
+}
+----
+
+
+ResponseMessage
+~~~~~~~~~~~~~~~
+
+Authentication Challenge
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).
+
+[source,json]
+----
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 407,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : null,
+    "meta" : { }
+  }
+}
+----
+
+Standard Result
+^^^^^^^^^^^^^^^
+
+The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.
+
+[source,json]
+----
+{
+  "requestId" : "41d2e28a-20a4-4ab0-b379-d810dede3786",
+  "status" : {
+    "message" : "",
+    "code" : 200,
+    "attributes" : { }
+  },
+  "result" : {
+    "data" : [ {
+      "id" : 1,
+      "label" : "person",
+      "type" : "vertex",
+      "properties" : {
+        "name" : [ {
+          "id" : 0,
+          "value" : "marko"
+        } ],
+        "location" : [ {
+          "id" : 6,
+          "value" : "san diego",
+          "properties" : {
+            "startTime" : 1997,
+            "endTime" : 2001
+          }
+        }, {
+          "id" : 7,
+          "value" : "santa cruz",
+          "properties" : {
+            "startTime" : 2001,
+            "endTime" : 2004
+          }
+        }, {
+          "id" : 8,
+          "value" : "brussels",
+          "properties" : {
+            "startTime" : 2004,
+            "endTime" : 2005
+          }
+        }, {
+          "id" : 9,
+          "value" : "santa fe",
+          "properties" : {
+            "startTime" : 2005
+          }
+        } ]
+      }
+    } ],
+    "meta" : { }
+  }
+}
+----
+
+
+Time
+~~~~
+
+Duration
+^^^^^^^^
+
+The following example is a `Duration` of five days.
+
+[source,json]
+----
+"PT120H"
+----
+
+Instant
+^^^^^^^
+
+[source,json]
+----
+"2016-10-04T12:17:19.571Z"
+----
+
+LocalDate
+^^^^^^^^^
+
+[source,json]
+----
+"2016-01-01"
+----
+
+LocalDateTime
+^^^^^^^^^^^^^
+
+[source,json]
+----
+"2016-01-01T12:30"
+----
+
+LocalTime
+^^^^^^^^^
+
+[source,json]
+----
+"12:30:45"
+----
+
+MonthDay
+^^^^^^^^
+
+[source,json]
+----
+"--01-01"
+----
+
+OffsetDateTime
+^^^^^^^^^^^^^^
+
+[source,json]
+----
+"2016-10-04T08:17:19.613-04:00"
+----
+
+OffsetTime
+^^^^^^^^^^
+
+[source,json]
+----
+"08:17:19.620-04:00"
+----
+
+Period
+^^^^^^
+
+The following example is a `Period` of one year, six months and fifteen days.
+
+[source,json]
+----
+"P1Y6M15D"
+----
+
+Year
+^^^^
+
+The following example is of the `Year` "2016".
+
+[source,json]
+----
+"2016"
+----
+
+YearMonth
+^^^^^^^^^
+
+The following example is a `YearMonth` of "June 2016"
+
+[source,json]
+----
+"2016-06"
+----
+
+ZonedDateTime
+^^^^^^^^^^^^^
+
+[source,json]
+----
+"2016-10-04T08:17:19.633-04:00[America/New_York]"
+----
+
+ZoneOffset
+^^^^^^^^^^
+
+The following example is a `ZoneOffset` of three hours, six minutes, and nine seconds.
+
+[source,json]
+----
+"+03:06:09"
+----
+
+[[graphson-2d0]]
+Version 2.0
+-----------
+
+Version 2.0 of GraphSON was first introduced on TinkerPop 3.2.2. It was designed to be less tied to
+link:https://github.com/FasterXML/jackson-databind[Jackson] (a JVM library) and to be less lossy as it pertained to
+types. While the <<graphson-1d0,GraphSON 1.0>> section focused on GraphSON without embedded types, GraphSON 2.0 will
+do the opposite as embedded types is the expected manner in which non-JVM languages will interact with TinkerPop.
+
+With GraphSON 2.0, there are essentially two type formats:
+
+* A non-typed value which is assumed the type implied by JSON. These non-types are limited to `String`, `Boolean`,
+`Map` and `Collection`.
+* All other values are typed by way of a "complex object" that defines a `@typeId` and `@value`. The `@typeId` is
+composed of two parts: a namespace and a type name, in the format "namespace:typename". A namespace allows TinkerPop
+providers and users to categorize custom types that they may implement and avoid collision with existing TinkerPop
+types. By default, TinkerPop types will have the namespace "g" (or "gx" for "extended" types).
+
+Core
+~~~~
+
+Class
+^^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Class",
+  "@value" : "java.io.File"
+}
+----
+
+Date
+^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Date",
+  "@value" : 1475583442552
+}
+----
+
+Double
+^^^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Double",
+  "@value" : 100.0
+}
+----
+
+Float
+^^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Float",
+  "@value" : 100.0
+}
+----
+
+Integer
+^^^^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Int32",
+  "@value" : 100
+}
+----
+
+Long
+^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Int64",
+  "@value" : 100
+}
+----
+
+Timestamp
+^^^^^^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Timestamp",
+  "@value" : 1475583442558
+}
+----
+
+UUID
+^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:UUID",
+  "@value" : "41d2e28a-20a4-4ab0-b379-d810dede3786"
+}
+----
+
+
+Graph Structure
+~~~~~~~~~~~~~~~
+
+Edge
+^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Edge",
+  "@value" : {
+    "id" : {
+      "@type" : "g:Int32",
+      "@value" : 13
+    },
+    "label" : "develops",
+    "inVLabel" : "software",
+    "outVLabel" : "person",
+    "inV" : {
+      "@type" : "g:Int32",
+      "@value" : 10
+    },
+    "outV" : {
+      "@type" : "g:Int32",
+      "@value" : 1
+    },
+    "properties" : {
+      "since" : {
+        "@type" : "g:Property",
+        "@value" : {
+          "key" : "since",
+          "value" : {
+            "@type" : "g:Int32",
+            "@value" : 2009
+          }
+        }
+      }
+    }
+  }
+}
+----
+
+Path
+^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Path",
+  "@value" : {
+    "labels" : [ [ ], [ ], [ ] ],
+    "objects" : [ {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 4
+              },
+              "value" : "gremlin",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 5
+              },
+              "value" : "tinkergraph",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    } ]
+  }
+}
+----
+
+Property
+^^^^^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Property",
+  "@value" : {
+    "key" : "since",
+    "value" : {
+      "@type" : "g:Int32",
+      "@value" : 2009
+    }
+  }
+}
+----
+
+StarGraph
+^^^^^^^^^
+
+[source,json]
+----
+{
+  "id" : {
+    "@type" : "g:Int32",
+    "@value" : 1
+  },
+  "label" : "person",
+  "outE" : {
+    "uses" : [ {
+      "id" : {
+        "@type" : "g:Int32",
+        "@value" : 16
+      },
+      "inV" : {
+        "@type" : "g:Int32",
+        "@value" : 11
+      },
+      "properties" : {
+        "skill" : {
+          "@type" : "g:Int32",
+          "@value" : 5
+        }
+      }
+    }, {
+      "id" : {
+        "@type" : "g:Int32",
+        "@value" : 15
+      },
+      "inV" : {
+        "@type" : "g:Int32",
+        "@value" : 10
+      },
+      "properties" : {
+        "skill" : {
+          "@type" : "g:Int32",
+          "@value" : 4
+        }
+      }
+    } ],
+    "develops" : [ {
+      "id" : {
+        "@type" : "g:Int32",
+        "@value" : 13
+      },
+      "inV" : {
+        "@type" : "g:Int32",
+        "@value" : 10
+      },
+      "properties" : {
+        "since" : {
+          "@type" : "g:Int32",
+          "@value" : 2009
+        }
+      }
+    }, {
+      "id" : {
+        "@type" : "g:Int32",
+        "@value" : 14
+      },
+      "inV" : {
+        "@type" : "g:Int32",
+        "@value" : 11
+      },
+      "properties" : {
+        "since" : {
+          "@type" : "g:Int32",
+          "@value" : 2010
+        }
+      }
+    } ]
+  },
+  "properties" : {
+    "name" : [ {
+      "id" : {
+        "@type" : "g:Int64",
+        "@value" : 0
+      },
+      "value" : "marko"
+    } ],
+    "location" : [ {
+      "id" : {
+        "@type" : "g:Int64",
+        "@value" : 6
+      },
+      "value" : "san diego",
+      "properties" : {
+        "startTime" : {
+          "@type" : "g:Int32",
+          "@value" : 1997
+        },
+        "endTime" : {
+          "@type" : "g:Int32",
+          "@value" : 2001
+        }
+      }
+    }, {
+      "id" : {
+        "@type" : "g:Int64",
+        "@value" : 7
+      },
+      "value" : "santa cruz",
+      "properties" : {
+        "startTime" : {
+          "@type" : "g:Int32",
+          "@value" : 2001
+        },
+        "endTime" : {
+          "@type" : "g:Int32",
+          "@value" : 2004
+        }
+      }
+    }, {
+      "id" : {
+        "@type" : "g:Int64",
+        "@value" : 8
+      },
+      "value" : "brussels",
+      "properties" : {
+        "startTime" : {
+          "@type" : "g:Int32",
+          "@value" : 2004
+        },
+        "endTime" : {
+          "@type" : "g:Int32",
+          "@value" : 2005
+        }
+      }
+    }, {
+      "id" : {
+        "@type" : "g:Int64",
+        "@value" : 9
+      },
+      "value" : "santa fe",
+      "properties" : {
+        "startTime" : {
+          "@type" : "g:Int32",
+          "@value" : 2005
+        }
+      }
+    } ]
+  }
+}
+----
+
+TinkerGraph
+^^^^^^^^^^^
+
+`TinkerGraph` has a custom serializer that is registered as part of the `TinkerIoRegistry`.
+
+[source,json]
+----
+{
+  "@type" : "tinker:graph",
+  "@value" : {
+    "vertices" : [ {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 1
+              },
+              "value" : "stephen",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 10
+              },
+              "value" : "centreville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1990
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 11
+              },
+              "value" : "dulles",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 12
+              },
+              "value" : "purcellville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 2
+              },
+              "value" : "matthias",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 13
+              },
+              "value" : "bremen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2007
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 14
+              },
+              "value" : "baltimore",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2007
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2011
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 15
+              },
+              "value" : "oakland",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2011
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2014
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 16
+              },
+              "value" : "seattle",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2014
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 3
+              },
+              "value" : "daniel",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 17
+              },
+              "value" : "spremberg",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1982
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 18
+              },
+              "value" : "kaiserslautern",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2009
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 19
+              },
+              "value" : "aachen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2009
+                }
+              }
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 4
+              },
+              "value" : "gremlin",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    }, {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "label" : "software",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 5
+              },
+              "value" : "tinkergraph",
+              "label" : "name"
+            }
+          } ]
+        }
+      }
+    } ],
+    "edges" : [ {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 13
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2009
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 14
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2010
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 15
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 4
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 16
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 17
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2010
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 18
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2011
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 19
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 20
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 4
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 21
+        },
+        "label" : "develops",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "since" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "since",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 2012
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 22
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 23
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 24
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 5
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 25
+        },
+        "label" : "uses",
+        "inVLabel" : "software",
+        "outVLabel" : "person",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 9
+        },
+        "properties" : {
+          "skill" : {
+            "@type" : "g:Property",
+            "@value" : {
+              "key" : "skill",
+              "value" : {
+                "@type" : "g:Int32",
+                "@value" : 3
+              }
+            }
+          }
+        }
+      }
+    }, {
+      "@type" : "g:Edge",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 26
+        },
+        "label" : "traverses",
+        "inVLabel" : "software",
+        "outVLabel" : "software",
+        "inV" : {
+          "@type" : "g:Int32",
+          "@value" : 11
+        },
+        "outV" : {
+          "@type" : "g:Int32",
+          "@value" : 10
+        }
+      }
+    } ]
+  }
+}
+----
+
+Tree
+^^^^
+
+[source,json]
+----
+{
+  "@type" : "g:Tree",
+  "@value" : [ {
+    "key" : {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 1
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 0
+              },
+              "value" : "marko",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 6
+              },
+              "value" : "san diego",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1997
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 7
+              },
+              "value" : "santa cruz",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2001
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 8
+              },
+              "value" : "brussels",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2004
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 9
+              },
+              "value" : "santa fe",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2005
+                }
+              }
+            }
+          } ]
+        }
+      }
+    },
+    "value" : {
+      "@type" : "g:Tree",
+      "@value" : [ {
+        "key" : {
+          "@type" : "g:Vertex",
+          "@value" : {
+            "id" : {
+              "@type" : "g:Int32",
+              "@value" : 10
+            },
+            "label" : "software",
+            "properties" : {
+              "name" : [ {
+                "@type" : "g:VertexProperty",
+                "@value" : {
+                  "id" : {
+                    "@type" : "g:Int64",
+                    "@value" : 4
+                  },
+                  "value" : "gremlin",
+                  "label" : "name"
+                }
+              } ]
+            }
+          }
+        },
+        "value" : {
+          "@type" : "g:Tree",
+          "@value" : [ {
+            "key" : {
+              "@type" : "g:Vertex",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int32",
+                  "@value" : 11
+                },
+                "label" : "software",
+                "properties" : {
+                  "name" : [ {
+                    "@type" : "g:VertexProperty",
+                    "@value" : {
+                      "id" : {
+                        "@type" : "g:Int64",
+                        "@value" : 5
+                      },
+                      "value" : "tinkergraph",
+                      "label" : "name"
+                    }
+                  } ]
+                }
+              }
+            },
+            "value" : {
+              "@type" : "g:Tree",
+              "@value" : [ ]
+            }
+          } ]
+        }
+      } ]
+    }
+  }, {
+    "key" : {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 7
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 1
+              },
+              "value" : "stephen",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 10
+              },
+              "value" : "centreville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 1990
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 11
+              },
+              "value" : "dulles",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2000
+                },
+                "endTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          }, {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 12
+              },
+              "value" : "purcellville",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+                  "@value" : 2006
+                }
+              }
+            }
+          } ]
+        }
+      }
+    },
+    "value" : {
+      "@type" : "g:Tree",
+      "@value" : [ {
+        "key" : {
+          "@type" : "g:Vertex",
+          "@value" : {
+            "id" : {
+              "@type" : "g:Int32",
+              "@value" : 10
+            },
+            "label" : "software",
+            "properties" : {
+              "name" : [ {
+                "@type" : "g:VertexProperty",
+                "@value" : {
+                  "id" : {
+                    "@type" : "g:Int64",
+                    "@value" : 4
+                  },
+                  "value" : "gremlin",
+                  "label" : "name"
+                }
+              } ]
+            }
+          }
+        },
+        "value" : {
+          "@type" : "g:Tree",
+          "@value" : [ {
+            "key" : {
+              "@type" : "g:Vertex",
+              "@value" : {
+                "id" : {
+                  "@type" : "g:Int32",
+                  "@value" : 11
+                },
+                "label" : "software",
+                "properties" : {
+                  "name" : [ {
+                    "@type" : "g:VertexProperty",
+                    "@value" : {
+                      "id" : {
+                        "@type" : "g:Int64",
+                        "@value" : 5
+                      },
+                      "value" : "tinkergraph",
+                      "label" : "name"
+                    }
+                  } ]
+                }
+              }
+            },
+            "value" : {
+              "@type" : "g:Tree",
+              "@value" : [ ]
+            }
+          } ]
+        }
+      } ]
+    }
+  }, {
+    "key" : {
+      "@type" : "g:Vertex",
+      "@value" : {
+        "id" : {
+          "@type" : "g:Int32",
+          "@value" : 8
+        },
+        "label" : "person",
+        "properties" : {
+          "name" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 2
+              },
+              "value" : "matthias",
+              "label" : "name"
+            }
+          } ],
+          "location" : [ {
+            "@type" : "g:VertexProperty",
+            "@value" : {
+              "id" : {
+                "@type" : "g:Int64",
+                "@value" : 13
+              },
+              "value" : "bremen",
+              "label" : "location",
+              "properties" : {
+                "startTime" : {
+                  "@type" : "g:Int32",
+            

<TRUNCATED>

[06/20] tinkerpop git commit: added more FilterRankStrategy tests.

Posted by sp...@apache.org.
added more FilterRankStrategy tests.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 68bbae10521350085b60f4dbf8819f06494ff6be
Parents: ff1c384
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Sep 29 15:56:06 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 .../traversal/strategy/optimization/FilterRankingStrategy.java | 2 +-
 .../strategy/optimization/FilterRankingStrategyTest.java       | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68bbae10/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index dead668..06726b1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -92,7 +92,7 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
         while(modified) {
             modified = false;
             for (final Step<?, ?> step : traversal.getSteps()) {
-                if (!step.getLabels().isEmpty()) {
+                if (step instanceof FilterStep && !step.getLabels().isEmpty()) {
                     final Step<?, ?> nextStep = step.getNextStep();
                     if (nextStep instanceof FilterStep && !(nextStep instanceof TraversalParent)) {
                         TraversalHelper.copyLabels(step, nextStep, true);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68bbae10/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
index 52379fd..bd12e34 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
@@ -32,7 +32,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 
-import static org.apache.tinkerpop.gremlin.process.traversal.P.eq;
+import static org.apache.tinkerpop.gremlin.process.traversal.P.neq;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.filter;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
@@ -80,8 +80,10 @@ public class FilterRankingStrategyTest {
 
         return Arrays.asList(new Object[][]{
                 {__.dedup().order(), __.dedup().order(), Collections.emptyList()},
+                {__.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")), __.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")), Collections.emptyList()},
+                {__.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), Collections.emptyList()},
                 {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), Collections.emptyList()},
-                {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a","b"), Collections.emptyList()},
+                {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a", "b"), Collections.emptyList()},
                 {__.order().dedup(), __.dedup().order(), Collections.emptyList()},
                 {__.order().as("a").dedup(), __.order().as("a").dedup(), Collections.emptyList()},
                 {__.identity().order().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())},


[12/20] tinkerpop git commit: fixed a bug in NotStep where child requirements were not being analyzed. Added a test to MatchTest to verify proper functioning. CTR.

Posted by sp...@apache.org.
fixed a bug in NotStep where child requirements were not being analyzed. Added a test to MatchTest to verify proper functioning. CTR.


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

Branch: refs/heads/TINKERPOP-1487
Commit: c7f42d827414ea7dced0549c02bbc37f40666849
Parents: 85ec40b
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Oct 3 10:46:04 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 10:46:04 2016 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../process/traversal/step/filter/NotStep.java  |  7 +++
 .../traversal/step/map/GroovyMatchTest.groovy   | 10 ++++
 .../process/traversal/step/map/MatchTest.java   | 63 ++++++++++++++------
 4 files changed, 62 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c7f42d82/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d0aa8e8..cf89a5c 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.1.5 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Fixed a bug in `NotStep` where child requirements were not being analyzed.
 * Fixed output redirection and potential memory leak in `GremlinGroovyScriptEngine`.
 * Corrected naming of `g_withPath_V_asXaX_out_out_mapXa_name_it_nameX` and `g_withPath_V_asXaX_out_mapXa_nameX` in `MapTest`.
 * Improved session cleanup when a close is triggered by the client.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c7f42d82/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NotStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NotStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NotStep.java
index 56ad497..e0f7038 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NotStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NotStep.java
@@ -21,11 +21,13 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 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.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -65,4 +67,9 @@ public final class NotStep<S> extends FilterStep<S> implements TraversalParent {
     public int hashCode() {
         return super.hashCode() ^ this.notTraversal.hashCode();
     }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c7f42d82/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
index c2f9d43..b3d8ea9 100644
--- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
+++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
@@ -338,5 +338,15 @@ public abstract class GroovyMatchTest {
                     __.as('b').both.as('c')).dedup('a','b').by(label)
             """, g)
         }
+
+        @Override
+        public Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
+            TraversalScriptHelper.compute("""
+                g.V.not(match(
+                            __.as('a').age.as('b'),
+                            __.as('a').name.as('c')).
+                        where('b', eq('c')).select('a')).name
+            """, g)
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c7f42d82/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
index 5d2ed95..46b8e59 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
@@ -43,8 +43,17 @@ import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
 import static org.apache.tinkerpop.gremlin.process.traversal.P.eq;
 import static org.apache.tinkerpop.gremlin.process.traversal.P.neq;
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*;
-import static org.junit.Assert.*;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.and;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.as;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.match;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.not;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.repeat;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.where;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 /**
  * @author Joshua Shinavier (http://fortytwo.net)
@@ -134,6 +143,9 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     // distinct values with by()-modulation
     public abstract Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_both_b__b_both_cX_dedupXa_bX_byXlabelX();
 
+    // test not(match)
+    public abstract Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_valueMap_matchXa_selectXnameX_bX() {
@@ -144,7 +156,7 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
             counter++;
             final Map<String, Object> map = traversal.next();
             assertTrue(Map.class.isAssignableFrom(map.get("a").getClass()));
-            final String name = ((Map<String,List<String>>) map.get("a")).get("name").get(0);
+            final String name = ((Map<String, List<String>>) map.get("a")).get("name").get(0);
             assertEquals(name, ((List<String>) map.get("b")).get(0));
         }
         assertEquals(6, counter);
@@ -156,12 +168,12 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_out_bX();
         printTraversalForm(traversal);
         checkResults(makeMapList(2,
-                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "lop"),
-                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"),
-                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "vadas"),
-                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "ripple"),
-                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop"),
-                        "a", convertToVertex(graph, "peter"), "b", convertToVertex(graph, "lop")),
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"),
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "vadas"),
+                "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "ripple"),
+                "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "peter"), "b", convertToVertex(graph, "lop")),
                 traversal);
     }
 
@@ -266,10 +278,10 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_created_b__b_0created_aX();
         printTraversalForm(traversal);
         checkResults(makeMapList(2,
-                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "lop"),
-                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop"),
-                        "a", convertToVertex(graph, "peter"), "b", convertToVertex(graph, "lop"),
-                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "ripple")),
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "peter"), "b", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "ripple")),
                 traversal);
 
     }
@@ -368,12 +380,12 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
 
     private void assertCommon(Traversal<Vertex, Map<String, Vertex>> traversal) {
         checkResults(makeMapList(4,
-                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"), "c", convertToVertex(graph, "CREAM PUFF WAR"), "d", convertToVertex(graph, "Garcia"),
-                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"), "c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "d", convertToVertex(graph, "Garcia"),
-                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "c", convertToVertex(graph, "CREAM PUFF WAR"), "d", convertToVertex(graph, "Garcia"),
-                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "d", convertToVertex(graph, "Garcia"),
-                    "a", convertToVertex(graph, "Grateful_Dead"), "b", convertToVertex(graph, "CANT COME DOWN"), "c", convertToVertex(graph, "DOWN SO LONG"), "d", convertToVertex(graph, "Garcia"),
-                    "a", convertToVertex(graph, "Grateful_Dead"), "b", convertToVertex(graph, "THE ONLY TIME IS NOW"), "c", convertToVertex(graph, "DOWN SO LONG"), "d", convertToVertex(graph, "Garcia")), traversal);
+                "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"), "c", convertToVertex(graph, "CREAM PUFF WAR"), "d", convertToVertex(graph, "Garcia"),
+                "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"), "c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "d", convertToVertex(graph, "Garcia"),
+                "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "c", convertToVertex(graph, "CREAM PUFF WAR"), "d", convertToVertex(graph, "Garcia"),
+                "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "d", convertToVertex(graph, "Garcia"),
+                "a", convertToVertex(graph, "Grateful_Dead"), "b", convertToVertex(graph, "CANT COME DOWN"), "c", convertToVertex(graph, "DOWN SO LONG"), "d", convertToVertex(graph, "Garcia"),
+                "a", convertToVertex(graph, "Grateful_Dead"), "b", convertToVertex(graph, "THE ONLY TIME IS NOW"), "c", convertToVertex(graph, "DOWN SO LONG"), "d", convertToVertex(graph, "Garcia")), traversal);
     }
 
     @Test
@@ -483,6 +495,14 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         assertEquals(results.size(), counter);
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
+        final Traversal<Vertex, String> traversal = get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name();
+        printTraversalForm(traversal);
+        checkResults(Arrays.asList("marko", "peter", "josh", "vadas", "lop", "ripple"), traversal);
+    }
+
     public static class GreedyMatchTraversals extends Traversals {
         @Before
         public void setupTest() {
@@ -739,5 +759,10 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
                     as("a").both().as("b"),
                     as("b").both().as("c")).dedup("a", "b").by(T.label);
         }
+
+        @Override
+        public Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
+            return g.V().not(match(__.as("a").values("age").as("b"), __.as("a").values("name").as("c")).where("b", eq("c")).select("a")).values("name");
+        }
     }
 }


[11/20] tinkerpop git commit: Added support for or(has(x), has(y)) to be has(x.or(y)) in InlineFilterStrategy. While doing this, I found a bug in ConnectiveP steps where nested equivalents were not being inlined. That bug has been fixed. Added test cases

Posted by sp...@apache.org.
Added support for or(has(x),has(y)) to be has(x.or(y)) in InlineFilterStrategy. While doing this, I found a bug in ConnectiveP steps where nested equivalents were not being inlined. That bug has been fixed. Added test cases to PTest to demonstrate proper inlining and nesting of ConnectivePs. I left two TODOs. One regarding match()-pulls that are labeled (interfering with FilterRankStrategy) and one regarding, has(x).has(y) being turned into has(x.and(y)). The reason why the latter isn't done now as it may greatly mess up providers who just rely on eq() for index lookups and are not smart enough to look into and()/or() predicates.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 8eb0fdded4fd8943a1541fda33e0785ea10751ee
Parents: 233a6ba
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Sep 29 10:39:20 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   3 +-
 .../upgrade/release-3.2.x-incubating.asciidoc   |  18 ++
 .../optimization/InlineFilterStrategy.java      |  45 +++-
 .../gremlin/process/traversal/util/AndP.java    |   8 +-
 .../process/traversal/util/ConnectiveP.java     |   3 +-
 .../gremlin/process/traversal/util/OrP.java     |   9 +-
 .../gremlin/process/traversal/PTest.java        | 245 ++++++++++---------
 .../optimization/InlineFilterStrategyTest.java  |  18 ++
 .../TinkerGraphStepStrategyTest.java            |   3 +-
 9 files changed, 233 insertions(+), 119 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index ade43cd..d204b44 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Fixed a bug in `ConnectiveP` where nested equivalent connectives should be inlined.
 * Fixed a bug in `IncidentToAdjacentStrategy` where `TreeStep` traversals were allowed.
 * Fixed a end-step label bug in `MatchPredicateStrategy`.
 * Fixed a bug in `MatchPredicateStrategy` where inlined traversals did not have strategies applied to it.
@@ -33,7 +34,7 @@ TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Added `TraversalHelper.copyLabels()` for copying (or moving) labels form one step to another.
 * Added `TraversalHelper.applySingleLevelStrategies()` which will apply a subset of strategies but not walk the child tree.
 * Added the concept that hidden labels using during traversal compilation are removed at the end during `StandardVerificationStrategy`. (*breaking*)
-* Added `InlineFilterStrategy` which will determine if a `TraversalFilterStep`, `AndStep`, `MatchStep` children are filters and if so, inline them.
+* Added `InlineFilterStrategy` which will determine if a `TraversalFilterStep`, `AndStep`, `OrStep`, `MatchStep` children are filters and if so, inline them.
 * Removed `IdentityRemovalStrategy` from the default listing as its not worth the clock cycles.
 * Removed the "!" symbol in `NotStep.toString()` as it is confusing and the `NotStep`-name is sufficient.
 * Fixed a bug in `TraversalVertexProgram` (OLAP) around ordering and connectives (i.e. `and()` and `or()`).

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/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 0ba09bd..49790af 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -171,6 +171,15 @@ uses of these exception builders as they will be removed in the future.
 
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-944[TINKERPOP-944]
 
+Hidden Step Labels for Compilation Only
++++++++++++++++++++++++++++++++++++++++
+
+In order for `SubgraphStrategy` to work, it was necessary to have multi-level children communicate with one another
+via hidden step labels. It was decided that hidden step labels are for compilation purposes only and will be removed
+prior to traversal evaluation. This is a valid decision given that hidden labels for graph system providers are
+not allowed to be used by users. Likewise, hidden labels for steps should not be allowed be used by
+users as well.
+
 PropertyMapStep with Selection Traversal
 ++++++++++++++++++++++++++++++++++++++++
 
@@ -181,6 +190,15 @@ and if so, use that in their introspection for respective strategies. This model
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-1456[TINKERPOP-1456],
 link:https://issues.apache.org/jira/browse/TINKERPOP-844[TINKERPOP-844]
 
+ConnectiveP Nesting Inlined
++++++++++++++++++++++++++++
+
+There was a bug in `ConnectiveP` (`AndP`/`OrP`), where `eq(1).and(eq(2).and(eq(3)))` was `OrP(eq(1),AndP(eq(2),eq(3)))`
+instead of unnested/inlined as `OrP(eq(1),eq(2),eq(3))`. Likewise, for `AndP`. If a provider was leveraging `ConnectiveP`
+predicates for their custom steps (e.g. graph- or vertex-centric index lookups), then they should be aware of the inlining
+and can simplify any and/or-tree walking code in their respective `ProviderOptimizationStrategy`.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1470[TINKERPOP-1470]
 
 TinkerPop 3.2.2
 ---------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index 7452b3b..0b7a5cc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -20,6 +20,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization;
 
 import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimization.GraphFilterStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
@@ -29,10 +30,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalSte
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.OrStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TraversalFilterStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 
@@ -89,6 +92,46 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
                     traversal.removeStep(step);
                 }
             }
+            // or(has(x,y),has(x,z)) --> has(x,y.or(z))
+            for (final OrStep<?> step : TraversalHelper.getStepsOfClass(OrStep.class, traversal)) {
+                boolean process = true;
+                String key = null;
+                P predicate = null;
+                final List<String> labels = new ArrayList<>();
+                for (final Traversal.Admin<?, ?> childTraversal : step.getLocalChildren()) {
+                    this.apply(childTraversal); // todo: this may be a bad idea, but I can't seem to find a test case to break it
+                    for (final Step<?, ?> childStep : childTraversal.getSteps()) {
+                        if (childStep instanceof HasStep) {
+                            for (final HasContainer hasContainer : ((HasStep<?>) childStep).getHasContainers()) {
+                                if (null == key)
+                                    key = hasContainer.getKey();
+                                else if (!hasContainer.getKey().equals(key)) {
+                                    process = false;
+                                    break;
+                                }
+                                predicate = null == predicate ?
+                                        hasContainer.getPredicate() :
+                                        predicate.or(hasContainer.getPredicate());
+                            }
+                            labels.addAll(childStep.getLabels());
+                        } else {
+                            process = false;
+                            break;
+                        }
+                    }
+                    if (!process)
+                        break;
+                }
+                if (process) {
+                    changed = true;
+                    final HasStep hasStep = new HasStep<>(traversal, new HasContainer(key, predicate));
+                    TraversalHelper.replaceStep(step, hasStep, traversal);
+                    TraversalHelper.copyLabels(step, hasStep, false);
+                    for (final String label : labels) {
+                        hasStep.addLabel(label);
+                    }
+                }
+            }
             // and(x,y) --> x.y
             for (final AndStep<?> step : TraversalHelper.getStepsOfClass(AndStep.class, traversal)) {
                 boolean process = true;
@@ -139,6 +182,7 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
                                 TraversalHelper.applySingleLevelStrategies(traversal, matchTraversal, InlineFilterStrategy.class);
                                 step.removeGlobalChild(matchTraversal);
                                 step.getPreviousStep().addLabel(startLabel);
+                                // TODO: matchTraversal.getEndStep().addLabel(startLabel); (perhaps insert an identity so filter rank can push has()-left)
                                 if (null != endLabel) matchTraversal.getEndStep().addLabel(endLabel);
                                 TraversalHelper.insertTraversal((Step) step.getPreviousStep(), matchTraversal, traversal);
                             }
@@ -149,7 +193,6 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
                 }
             }
         }
-
     }
 
     private static final String determineStartLabelForHasPullOut(final MatchStep<?, ?> matchStep) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
index 8a7784f..cb001ff 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/AndP.java
@@ -34,6 +34,9 @@ public final class AndP<V> extends ConnectiveP<V> {
 
     public AndP(final List<P<V>> predicates) {
         super(predicates);
+        for (final P<V> p : predicates) {
+            this.and(p);
+        }
         this.biPredicate = new AndBiPredicate(this);
     }
 
@@ -49,7 +52,10 @@ public final class AndP<V> extends ConnectiveP<V> {
     public P<V> and(final Predicate<? super V> predicate) {
         if (!(predicate instanceof P))
             throw new IllegalArgumentException("Only P predicates can be and'd together");
-        this.predicates.add((P<V>) predicate);   // TODO: clone and add?
+        else if (predicate instanceof AndP)
+            this.predicates.addAll(((AndP) predicate).getPredicates());
+        else
+            this.predicates.add((P<V>) predicate);
         return this;
     }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
index 70f008a..855fc06 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
@@ -31,13 +31,12 @@ import java.util.function.Predicate;
  */
 public abstract class ConnectiveP<V> extends P<V> {
 
-    protected List<P<V>> predicates;
+    protected List<P<V>> predicates = new ArrayList<>();
 
     public ConnectiveP(final List<P<V>> predicates) {
         super(null, null);
         if (predicates.size() < 2)
             throw new IllegalArgumentException("The provided " + this.getClass().getSimpleName() + " array must have at least two arguments: " + predicates.size());
-        this.predicates = new ArrayList<>(predicates); // to avoid Arrays.asList() and unmodifiable exceptions
     }
 
     @Deprecated

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
index 8bc4387..f7363b4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/OrP.java
@@ -22,7 +22,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.BiPredicate;
@@ -35,6 +34,9 @@ public final class OrP<V> extends ConnectiveP<V> {
 
     public OrP(final List<P<V>> predicates) {
         super(predicates);
+        for (final P<V> p : predicates) {
+            this.or(p);
+        }
         this.biPredicate = new OrBiPredicate(this);
     }
 
@@ -50,7 +52,10 @@ public final class OrP<V> extends ConnectiveP<V> {
     public P<V> or(final Predicate<? super V> predicate) {
         if (!(predicate instanceof P))
             throw new IllegalArgumentException("Only P predicates can be or'd together");
-        this.predicates.add((P<V>) predicate);   // TODO: clone and add?
+        else if (predicate instanceof OrP)
+            this.predicates.addAll(((OrP) predicate).getPredicates());
+        else
+            this.predicates.add((P<V>) predicate);
         return this;
     }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
index 3810c96..6ec33cc 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
@@ -19,8 +19,11 @@
 package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -29,135 +32,157 @@ import java.util.Arrays;
 import java.util.Random;
 import java.util.function.Predicate;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-@RunWith(Parameterized.class)
+@RunWith(Enclosed.class)
 public class PTest {
 
-    @Parameterized.Parameters(name = "{0}.test({1}) = {2}")
-    public static Iterable<Object[]> data() {
-        return new ArrayList<>(Arrays.asList(new Object[][]{
-                {P.eq(0), 0, true},
-                {P.eq(0), 1, false},
-                {P.neq(0), 0, false},
-                {P.neq(0), 1, true},
-                {P.gt(0), -1, false},
-                {P.gt(0), 0, false},
-                {P.gt(0), 1, true},
-                {P.lt(0), -1, true},
-                {P.lt(0), 0, false},
-                {P.lt(0), 1, false},
-                {P.gte(0), -1, false},
-                {P.gte(0), 0, true},
-                {P.gte(0), 1, true},
-                {P.lte(0), -1, true},
-                {P.lte(0), 0, true},
-                {P.lte(0), 1, false},
-                {P.between(1, 10), 0, false},
-                {P.between(1, 10), 1, true},
-                {P.between(1, 10), 9, true},
-                {P.between(1, 10), 10, false},
-                {P.inside(1, 10), 0, false},
-                {P.inside(1, 10), 1, false},
-                {P.inside(1, 10), 9, true},
-                {P.inside(1, 10), 10, false},
-                {P.outside(1, 10), 0, true},
-                {P.outside(1, 10), 1, false},
-                {P.outside(1, 10), 9, false},
-                {P.outside(1, 10), 10, false},
-                {P.within(1, 2, 3), 0, false},
-                {P.within(1, 2, 3), 1, true},
-                {P.within(1, 2, 3), 10, false},
-                {P.within(Arrays.asList(1, 2, 3)), 0, false},
-                {P.within(Arrays.asList(1, 2, 3)), 1, true},
-                {P.within(Arrays.asList(1, 2, 3)), 10, false},
-                {P.without(1, 2, 3), 0, true},
-                {P.without(1, 2, 3), 1, false},
-                {P.without(1, 2, 3), 10, true},
-                {P.without(Arrays.asList(1, 2, 3)), 0, true},
-                {P.without(Arrays.asList(1, 2, 3)), 1, false},
-                {P.without(Arrays.asList(1, 2, 3)), 10, true},
-                {P.between("m", "n").and(P.neq("marko")), "marko", false},
-                {P.between("m", "n").and(P.neq("marko")), "matthias", true},
-                {P.between("m", "n").or(P.eq("daniel")), "marko", true},
-                {P.between("m", "n").or(P.eq("daniel")), "daniel", true},
-                {P.between("m", "n").or(P.eq("daniel")), "stephen", false},
-        }));
-    }
+    @RunWith(Parameterized.class)
+    public static class ParameterizedTest {
+
+        @Parameterized.Parameters(name = "{0}.test({1}) = {2}")
+        public static Iterable<Object[]> data() {
+            return new ArrayList<>(Arrays.asList(new Object[][]{
+                    {P.eq(0), 0, true},
+                    {P.eq(0), 1, false},
+                    {P.neq(0), 0, false},
+                    {P.neq(0), 1, true},
+                    {P.gt(0), -1, false},
+                    {P.gt(0), 0, false},
+                    {P.gt(0), 1, true},
+                    {P.lt(0), -1, true},
+                    {P.lt(0), 0, false},
+                    {P.lt(0), 1, false},
+                    {P.gte(0), -1, false},
+                    {P.gte(0), 0, true},
+                    {P.gte(0), 1, true},
+                    {P.lte(0), -1, true},
+                    {P.lte(0), 0, true},
+                    {P.lte(0), 1, false},
+                    {P.between(1, 10), 0, false},
+                    {P.between(1, 10), 1, true},
+                    {P.between(1, 10), 9, true},
+                    {P.between(1, 10), 10, false},
+                    {P.inside(1, 10), 0, false},
+                    {P.inside(1, 10), 1, false},
+                    {P.inside(1, 10), 9, true},
+                    {P.inside(1, 10), 10, false},
+                    {P.outside(1, 10), 0, true},
+                    {P.outside(1, 10), 1, false},
+                    {P.outside(1, 10), 9, false},
+                    {P.outside(1, 10), 10, false},
+                    {P.within(1, 2, 3), 0, false},
+                    {P.within(1, 2, 3), 1, true},
+                    {P.within(1, 2, 3), 10, false},
+                    {P.within(Arrays.asList(1, 2, 3)), 0, false},
+                    {P.within(Arrays.asList(1, 2, 3)), 1, true},
+                    {P.within(Arrays.asList(1, 2, 3)), 10, false},
+                    {P.without(1, 2, 3), 0, true},
+                    {P.without(1, 2, 3), 1, false},
+                    {P.without(1, 2, 3), 10, true},
+                    {P.without(Arrays.asList(1, 2, 3)), 0, true},
+                    {P.without(Arrays.asList(1, 2, 3)), 1, false},
+                    {P.without(Arrays.asList(1, 2, 3)), 10, true},
+                    {P.between("m", "n").and(P.neq("marko")), "marko", false},
+                    {P.between("m", "n").and(P.neq("marko")), "matthias", true},
+                    {P.between("m", "n").or(P.eq("daniel")), "marko", true},
+                    {P.between("m", "n").or(P.eq("daniel")), "daniel", true},
+                    {P.between("m", "n").or(P.eq("daniel")), "stephen", false},
+            }));
+        }
 
-    @Parameterized.Parameter(value = 0)
-    public P predicate;
+        @Parameterized.Parameter(value = 0)
+        public P predicate;
 
-    @Parameterized.Parameter(value = 1)
-    public Object value;
+        @Parameterized.Parameter(value = 1)
+        public Object value;
 
-    @Parameterized.Parameter(value = 2)
-    public boolean expected;
+        @Parameterized.Parameter(value = 2)
+        public boolean expected;
 
-    @Test
-    public void shouldTest() {
-        assertEquals(expected, predicate.test(value));
-        assertEquals(!expected, predicate.clone().negate().test(value));
-        assertEquals(!expected, P.not(predicate).test(value));
-    }
-
-    @Before
-    public void init() {
-        final Object pv = predicate.getValue();
-        final Random r = new Random();
-        assertNotNull(predicate.getBiPredicate());
-        predicate.setValue(r.nextDouble());
-        assertNotNull(predicate.getValue());
-        predicate.setValue(pv);
-        assertEquals(pv, predicate.getValue());
-        assertNotNull(predicate.hashCode());
-        assertEquals(predicate, predicate.clone());
-        assertNotEquals(__.identity(), predicate);
-
-        boolean thrown = true;
-        try {
-            predicate.and(new CustomPredicate());
-            thrown = false;
-        } catch (IllegalArgumentException ex) {
-            assertEquals("Only P predicates can be and'd together", ex.getMessage());
-        } finally {
-            assertTrue(thrown);
+        @Test
+        public void shouldTest() {
+            assertEquals(expected, predicate.test(value));
+            assertEquals(!expected, predicate.clone().negate().test(value));
+            assertEquals(!expected, P.not(predicate).test(value));
         }
 
-        thrown = true;
-        try {
-            predicate.or(new CustomPredicate());
-            thrown = false;
-        } catch (IllegalArgumentException ex) {
-            assertEquals("Only P predicates can be or'd together", ex.getMessage());
-        } finally {
-            assertTrue(thrown);
+        @Before
+        public void init() {
+            final Object pv = predicate.getValue();
+            final Random r = new Random();
+            assertNotNull(predicate.getBiPredicate());
+            predicate.setValue(r.nextDouble());
+            assertNotNull(predicate.getValue());
+            predicate.setValue(pv);
+            assertEquals(pv, predicate.getValue());
+            assertNotNull(predicate.hashCode());
+            assertEquals(predicate, predicate.clone());
+            assertNotEquals(__.identity(), predicate);
+
+            boolean thrown = true;
+            try {
+                predicate.and(new CustomPredicate());
+                thrown = false;
+            } catch (IllegalArgumentException ex) {
+                assertEquals("Only P predicates can be and'd together", ex.getMessage());
+            } finally {
+                assertTrue(thrown);
+            }
+
+            thrown = true;
+            try {
+                predicate.or(new CustomPredicate());
+                thrown = false;
+            } catch (IllegalArgumentException ex) {
+                assertEquals("Only P predicates can be or'd together", ex.getMessage());
+            } finally {
+                assertTrue(thrown);
+            }
         }
-    }
 
-    private class CustomPredicate implements Predicate {
+        private class CustomPredicate implements Predicate {
 
-        @Override
-        public boolean test(Object o) {
-            return false;
-        }
+            @Override
+            public boolean test(Object o) {
+                return false;
+            }
 
-        @Override
-        public Predicate and(Predicate other) {
-            return null;
-        }
+            @Override
+            public Predicate and(Predicate other) {
+                return null;
+            }
 
-        @Override
-        public Predicate negate() {
-            return null;
+            @Override
+            public Predicate negate() {
+                return null;
+            }
+
+            @Override
+            public Predicate or(Predicate other) {
+                return null;
+            }
         }
+    }
 
-        @Override
-        public Predicate or(Predicate other) {
-            return null;
+    public static class ConnectiveTest {
+
+        @Test
+        public void shouldComposeCorrectly() {
+            assertEquals(P.eq(1), P.eq(1));
+            assertEquals(P.eq(1).and(P.eq(2)), new AndP<>(Arrays.asList(P.eq(1), P.eq(2))));
+            assertEquals(P.eq(1).and(P.eq(2).and(P.eq(3))), new AndP<>(Arrays.asList(P.eq(1), P.eq(2), P.eq(3))));
+            assertEquals(P.eq(1).and(P.eq(2).and(P.eq(3).and(P.eq(4)))), new AndP<>(Arrays.asList(P.eq(1), P.eq(2), P.eq(3), P.eq(4))));
+            assertEquals(P.eq(1).or(P.eq(2).or(P.eq(3).or(P.eq(4)))), new OrP<>(Arrays.asList(P.eq(1), P.eq(2), P.eq(3), P.eq(4))));
+            assertEquals(P.eq(1).or(P.eq(2).and(P.eq(3).or(P.eq(4)))), new OrP<>(Arrays.asList(P.eq(1), new AndP<>(Arrays.asList(P.eq(2), new OrP<>(Arrays.asList(P.eq(3), P.eq(4))))))));
+            assertEquals(P.eq(1).and(P.eq(2).or(P.eq(3).and(P.eq(4)))), new AndP<>(Arrays.asList(P.eq(1), new OrP<>(Arrays.asList(P.eq(2), new AndP<>(Arrays.asList(P.eq(3), P.eq(4))))))));
+            assertEquals(P.eq(1).and(P.eq(2).and(P.eq(3).or(P.eq(4)))), new AndP<>(Arrays.asList(P.eq(1), P.eq(2), new OrP<>(Arrays.asList(P.eq(3), P.eq(4))))));
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
index aeae593..9530c82 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
@@ -29,6 +29,9 @@ import org.junit.runners.Parameterized;
 
 import java.util.Arrays;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.P.eq;
+import static org.apache.tinkerpop.gremlin.process.traversal.P.gt;
+import static org.apache.tinkerpop.gremlin.process.traversal.P.lt;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.V;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.and;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.as;
@@ -39,6 +42,7 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.limit;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.map;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.match;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.tail;
 import static org.junit.Assert.assertEquals;
@@ -46,6 +50,8 @@ import static org.junit.Assert.assertEquals;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
+
+
 @RunWith(Parameterized.class)
 public class InlineFilterStrategyTest {
 
@@ -74,9 +80,21 @@ public class InlineFilterStrategyTest {
                 {filter(has("age", P.gt(10)).as("a")), has("age", P.gt(10)).as("a")},
                 {filter(and(has("age", P.gt(10)).as("a"), has("name", "marko"))), has("age", P.gt(10)).as("a").has("name", "marko")},
                 //
+                {or(has("name", "marko"), has("age", 32)), or(has("name", "marko"), has("age", 32))},
+                {or(has("name", "marko"), has("name", "bob")), has("name", eq("marko").or(eq("bob")))},
+                {or(has("name", "marko"), has("name")), or(has("name", "marko"), has("name"))},
+                {or(has("age", 10), and(has("age", gt(20)), has("age", lt(100)))), has("age", eq(10).or(gt(20).and(lt(100))))},
+                {or(has("name", "marko"), filter(has("name", "bob"))), has("name", eq("marko").or(eq("bob")))},
+                {or(has("name", "marko"), filter(or(filter(has("name", "bob")), has("name", "stephen")))), has("name", eq("marko").or(eq("bob").or(eq("stephen"))))},
+                {or(has("name", "marko").as("a"), filter(or(filter(has("name", "bob")).as("b"), has("name", "stephen").as("c")))), has("name", eq("marko").or(eq("bob").or(eq("stephen")))).as("a", "b", "c")},
+                //
                 {and(has("age", P.gt(10)), filter(has("age", 22))), has("age", P.gt(10)).has("age", 22)},
+                {and(has("age", P.gt(10)).as("a"), filter(has("age", 22).as("b")).as("c")).as("d"), has("age", P.gt(10)).as("a").has("age", 22).as("b", "c", "d")},
                 {and(has("age", P.gt(10)).as("a"), and(filter(has("age", 22).as("b")).as("c"), has("name", "marko").as("d"))), has("age", P.gt(10)).as("a").has("age", 22).as("b", "c").has("name", "marko").as("d")},
+                {and(has("age", P.gt(10)).as("a"), and(has("name","stephen").as("b"), has("name", "marko").as("c")).as("d")).as("e"), has("age", P.gt(10)).as("a").has("name","stephen").as("b").has("name","marko").as("c","d","e")},
                 {and(has("age", P.gt(10)), and(out("knows"), has("name", "marko"))), has("age", P.gt(10)).and(out("knows"), has("name", "marko"))},
+                {and(has("age", P.gt(20)), or(has("age", lt(10)), has("age", gt(100)))), has("age", gt(20)).has("age", lt(10).or(gt(100)))},
+                {and(has("age", P.gt(20)).as("a"), or(has("age", lt(10)), has("age", gt(100)).as("b"))), has("age", gt(20)).as("a").has("age", lt(10).or(gt(100))).as("b")},
                 //
                 {V().match(as("a").has("age", 10), as("a").filter(has("name")).as("b")), V().as("a").has("age", 10).match(as("a").has("name").as("b"))},
                 {match(as("a").has("age", 10), as("a").filter(has("name")).as("b")), match(as("a").has("age", 10), as("a").has("name").as("b"))},

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8eb0fdde/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
index d2bc0ea..9f97466 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
@@ -48,7 +48,6 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.filter
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.not;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.properties;
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -111,7 +110,7 @@ public class TinkerGraphStepStrategyTest {
                 {__.V().as("a").dedup().has("name", "marko").or(has("age"), has("age", gt(32))).filter(has("name", "bob")).has("lang", "java"),
                         g_V("name", eq("marko"), "name", eq("bob"), "lang", eq("java")).as("a").or(has("age"), has("age", gt(32))).dedup(), Arrays.asList(InlineFilterStrategy.instance(), FilterRankingStrategy.instance())},
                 {__.V().as("a").dedup().has("name", "marko").or(has("age", 10), has("age", gt(32))).filter(has("name", "bob")).has("lang", "java"),
-                        g_V("name", eq("marko"), "name", eq("bob"), "lang", eq("java")).as("a").or(has("age", 10), has("age", gt(32))).dedup(), TraversalStrategies.GlobalCache.getStrategies(TinkerGraph.class).toList()},
+                        g_V("name", eq("marko"), "age", eq(10).or(gt(32)), "name", eq("bob"), "lang", eq("java")).as("a").dedup(), TraversalStrategies.GlobalCache.getStrategies(TinkerGraph.class).toList()},
                 {__.V().has("name", "marko").or(not(has("age")), has("age", gt(32))).has("name", "bob").has("lang", "java"),
                         g_V("name", eq("marko"), "name", eq("bob"), "lang", eq("java")).or(not(filter(properties("age"))), has("age", gt(32))), TraversalStrategies.GlobalCache.getStrategies(TinkerGraph.class).toList()}
         });


[09/20] tinkerpop git commit: CHANGELOG tweak.

Posted by sp...@apache.org.
CHANGELOG tweak.


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

Branch: refs/heads/TINKERPOP-1487
Commit: bc00bb3c4535aec8229b7770f9e8ab60326117ef
Parents: 62197e2
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Oct 3 08:23:38 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

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


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/bc00bb3c/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 60e895b..4dc4dc3 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,7 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* `FilterRankStrategy` now propagates labels "right" non-`Scoping` filters.
+* `FilterRankStrategy` now propagates labels "right" over non-`Scoping` filters.
 * Fixed a bug in `ConnectiveP` where nested equivalent connectives should be inlined.
 * Fixed a bug in `IncidentToAdjacentStrategy` where `TreeStep` traversals were allowed.
 * Fixed a end-step label bug in `MatchPredicateStrategy`.


[02/20] tinkerpop git commit: Merge remote-tracking branch 'origin/TINKERPOP-1467' into TINKERPOP-1467-master

Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-1467' into TINKERPOP-1467-master

Conflicts:
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java


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

Branch: refs/heads/TINKERPOP-1487
Commit: 9d860ca0c880bf7d8c974df4d021266d1868dcf0
Parents: 233a6ba 6d14adb
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Sat Oct 1 05:48:21 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Sat Oct 1 05:48:21 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 17 +++++
 .../tinkerpop/gremlin/driver/Channelizer.java   |  2 +-
 .../apache/tinkerpop/gremlin/driver/Client.java | 42 +++++++++--
 .../tinkerpop/gremlin/driver/Cluster.java       | 24 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 67 +++++++++++++++--
 .../gremlin/driver/ConnectionPool.java          | 21 +++---
 .../tinkerpop/gremlin/driver/Handler.java       | 26 +++++--
 .../tinkerpop/gremlin/driver/ResultQueue.java   |  4 +
 .../driver/handler/WebSocketClientHandler.java  |  4 +-
 .../server/GremlinDriverIntegrateTest.java      | 79 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 255 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/CHANGELOG.asciidoc
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
----------------------------------------------------------------------
diff --cc gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index 7b9262e,3a03141..bd397a1
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
@@@ -350,11 -295,17 +355,17 @@@ public abstract class Client 
      public final static class ClusteredClient extends Client {
  
          private ConcurrentMap<Host, ConnectionPool> hostConnectionPools = new ConcurrentHashMap<>();
+         private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
  
 -        ClusteredClient(final Cluster cluster) {
 -            super(cluster);
 +        ClusteredClient(final Cluster cluster, final Client.Settings settings) {
 +            super(cluster, settings);
          }
  
+         @Override
+         public boolean isClosing() {
+             return closing.get() != null;
+         }
+ 
          /**
           * Submits a Gremlin script to the server and returns a {@link ResultSet} once the write of the request is
           * complete.
@@@ -650,10 -503,12 +670,12 @@@
  
          private ConnectionPool connectionPool;
  
+         private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
+ 
 -        SessionedClient(final Cluster cluster, final String sessionId, final boolean manageTransactions) {
 -            super(cluster);
 -            this.sessionId = sessionId;
 -            this.manageTransactions = manageTransactions;
 +        SessionedClient(final Cluster cluster, final Client.Settings settings) {
 +            super(cluster, settings);
 +            this.sessionId = settings.getSession().get().sessionId;
 +            this.manageTransactions = settings.getSession().get().manageTransactions;
          }
  
          String getSessionId() {
@@@ -697,134 -557,13 +724,139 @@@
           * Close the bound {@link ConnectionPool}.
           */
          @Override
-         public CompletableFuture<Void> closeAsync() {
-             return connectionPool.closeAsync();
+         public synchronized CompletableFuture<Void> closeAsync() {
+             if (closing.get() != null)
+                 return closing.get();
+ 
+             final CompletableFuture<Void> connectionPoolClose = connectionPool.closeAsync();
+             closing.set(connectionPoolClose);
+             return connectionPoolClose;
          }
      }
 +
 +    /**
 +     * Settings given to {@link Cluster#connect(Settings)} that configures how a {@link Client} will behave.
 +     */
 +    public static class Settings {
 +        private final Optional<SessionSettings> session;
 +
 +        private Settings(final Builder builder) {
 +            this.session = builder.session;
 +        }
 +
 +        public static Builder build() {
 +            return new Builder();
 +        }
 +
 +        /**
 +         * Determines if the {@link Client} is to be constructed with a session. If the value is present, then a
 +         * session is expected.
 +         */
 +        public Optional<SessionSettings> getSession() {
 +            return session;
 +        }
 +
 +        public static class Builder {
 +            private Optional<SessionSettings> session = Optional.empty();
 +
 +            private Builder() {}
 +
 +            /**
 +             * Enables a session. By default this will create a random session name and configure transactions to be
 +             * unmanaged. This method will override settings provided by calls to the other overloads of
 +             * {@code useSession}.
 +             */
 +            public Builder useSession(final boolean enabled) {
 +                session = enabled ? Optional.of(SessionSettings.build().create()) : Optional.empty();
 +                return this;
 +            }
 +
 +            /**
 +             * Enables a session. By default this will create a session with the provided name and configure
 +             * transactions to be unmanaged. This method will override settings provided by calls to the other
 +             * overloads of {@code useSession}.
 +             */
 +            public Builder useSession(final String sessionId) {
 +                session = sessionId != null && !sessionId.isEmpty() ?
 +                        Optional.of(SessionSettings.build().sessionId(sessionId).create()) : Optional.empty();
 +                return this;
 +            }
 +
 +            /**
 +             * Enables a session. This method will override settings provided by calls to the other overloads of
 +             * {@code useSession}.
 +             */
 +            public Builder useSession(final SessionSettings settings) {
 +                session = Optional.ofNullable(settings);
 +                return this;
 +            }
 +
 +            public Settings create() {
 +                return new Settings(this);
 +            }
 +
 +        }
 +    }
 +
 +    /**
 +     * Settings for a {@link Client} that involve a session.
 +     */
 +    public static class SessionSettings {
 +        private final boolean manageTransactions;
 +        private final String sessionId;
 +
 +        private SessionSettings(final Builder builder) {
 +            manageTransactions = builder.manageTransactions;
 +            sessionId = builder.sessionId;
 +        }
 +
 +        /**
 +         * If enabled, transactions will be "managed" such that each request will represent a complete transaction.
 +         */
 +        public boolean manageTransactions() {
 +            return manageTransactions;
 +        }
 +
 +        /**
 +         * Provides the identifier of the session.
 +         */
 +        public String getSessionId() {
 +            return sessionId;
 +        }
 +
 +        public static SessionSettings.Builder build() {
 +            return new SessionSettings.Builder();
 +        }
 +
 +        public static class Builder {
 +            private boolean manageTransactions = false;
 +            private String sessionId = UUID.randomUUID().toString();
 +
 +            private Builder() {}
 +
 +            /**
 +             * If enabled, transactions will be "managed" such that each request will represent a complete transaction.
 +             * By default this value is {@code false}.
 +             */
 +            public Builder manageTransactions(final boolean manage) {
 +                manageTransactions = manage;
 +                return this;
 +            }
 +
 +            /**
 +             * Provides the identifier of the session. This value cannot be null or empty. By default it is set to
 +             * a random {@code UUID}.
 +             */
 +            public Builder sessionId(final String sessionId) {
 +                if (null == sessionId || sessionId.isEmpty())
 +                    throw new IllegalArgumentException("sessionId cannot be null or empty");
 +                this.sessionId = sessionId;
 +                return this;
 +            }
 +
 +            public SessionSettings create() {
 +                return new SessionSettings(this);
 +            }
 +        }
 +    }
  }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
----------------------------------------------------------------------
diff --cc gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
index b9a3cee,473991a..567bfb4
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
@@@ -84,7 -84,9 +85,9 @@@ public final class Cluster 
       * submitted or can be directly initialized via {@link Client#init()}.
       */
      public <T extends Client> T connect() {
-         return (T) new Client.ClusteredClient(this, Client.Settings.build().create());
 -        final Client client = new Client.ClusteredClient(this);
++        final Client client = new Client.ClusteredClient(this, Client.Settings.build().create());
+         manager.trackClient(client);
+         return (T) client;
      }
  
      /**
@@@ -121,19 -123,11 +124,21 @@@
       * @param manageTransactions enables auto-transactions when set to true
       */
      public <T extends Client> T connect(final String sessionId, final boolean manageTransactions) {
 -        if (null == sessionId || sessionId.isEmpty())
 -            throw new IllegalArgumentException("sessionId cannot be null or empty");
 -        final Client client = new Client.SessionedClient(this, sessionId, manageTransactions);
 +        final Client.SessionSettings sessionSettings = Client.SessionSettings.build()
 +                .manageTransactions(manageTransactions)
 +                .sessionId(sessionId).create();
 +        final Client.Settings settings = Client.Settings.build().useSession(sessionSettings).create();
 +        return connect(settings);
 +    }
 +
 +    /**
 +     * Creates a new {@link Client} based on the settings provided.
 +     */
 +    public <T extends Client> T connect(final Client.Settings settings) {
-         return settings.getSession().isPresent() ? (T) new Client.SessionedClient(this, settings) :
-                 (T) new Client.ClusteredClient(this, settings);
++        final Client client = settings.getSession().isPresent() ? new Client.SessionedClient(this, settings) :
++                new Client.ClusteredClient(this, settings);
+         manager.trackClient(client);
+         return (T) client;
      }
  
      @Override
@@@ -863,15 -687,11 +868,17 @@@
  
          private final ScheduledExecutorService executor;
  
 +        private final int nioPoolSize;
 +        private final int workerPoolSize;
 +        private final int port;
 +
          private final AtomicReference<CompletableFuture<Void>> closeFuture = new AtomicReference<>();
  
+         private final List<WeakReference<Client>> openedClients = new ArrayList<>();
+ 
          private Manager(final Builder builder) {
 +            validateBuilder(builder);
 +
              this.loadBalancingStrategy = builder.loadBalancingStrategy;
              this.authProps = builder.authProps;
              this.contactPoints = builder.getContactPoints();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
----------------------------------------------------------------------
diff --cc gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
index 02ec0b3,660ad0d..2a68032
--- 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
@@@ -158,15 -150,12 +159,16 @@@ final class Connection 
          return pending;
      }
  
-     public CompletableFuture<Void> closeAsync() {
+     public synchronized CompletableFuture<Void> closeAsync() {
+         if (isClosing()) return closeFuture.get();
+ 
          final CompletableFuture<Void> future = new CompletableFuture<>();
-         if (!closeFuture.compareAndSet(null, future))
-             return closeFuture.get();
+         closeFuture.set(future);
  
 +        // stop any pings being sent at the server for keep-alive
 +        final ScheduledFuture keepAlive = keepAliveFuture.get();
 +        if (keepAlive != null) keepAlive.cancel(true);
 +
          // make sure all requests in the queue are fully processed before killing.  if they are then shutdown
          // can be immediate.  if not this method will signal the readCompleted future defined in the write()
          // operation to check if it can close.  in this way the connection no longer receives writes, but

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
----------------------------------------------------------------------
diff --cc gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 96cde54,bf66b0d..d8aff4a
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@@ -26,9 -25,7 +26,8 @@@ import org.apache.tinkerpop.gremlin.dri
  import org.apache.tinkerpop.gremlin.driver.Cluster;
  import org.apache.tinkerpop.gremlin.driver.Result;
  import org.apache.tinkerpop.gremlin.driver.ResultSet;
- import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
  import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 +import org.apache.tinkerpop.gremlin.driver.handler.WebSocketClientHandler;
  import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
  import org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer;
  import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0;


[04/20] tinkerpop git commit: FilterRankStategy is now smart about pushing labels 'right'. Why is this good -- it ensures that filter-chains are as concatenated as possible without changing path semantics. This is about increasing the number of potential

Posted by sp...@apache.org.
FilterRankStategy is now smart about pushing labels 'right'. Why is this good -- it ensures that filter-chains are as concatenated as possible without changing path semantics. This is about increasing the number of potential has()-steps that providers can grab for index lookups. Also, InlineFilterStep is is able to compress has().has() chains into a single has() and propagate labels accordingly. Added various test cases to validate behavior. The only thing left is HasContainer being able to compress AndP predicates and we will have a really tight compression on filters.


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

Branch: refs/heads/TINKERPOP-1487
Commit: ff1c3844a487cf4db437edfdf7f2251c38da50ab
Parents: 9ef8a9a
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Sep 29 14:42:51 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../optimization/FilterRankingStrategy.java     | 16 ++++++--
 .../optimization/InlineFilterStrategy.java      | 18 ++++++++-
 .../process/traversal/util/TraversalHelper.java | 11 ++++--
 .../decoration/SubgraphStrategyTest.java        | 28 +++++++-------
 .../optimization/FilterRankingStrategyTest.java |  3 ++
 .../optimization/InlineFilterStrategyTest.java  | 39 +++++++++++++-------
 7 files changed, 79 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d204b44..638a80c 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* `FilterRankStrategy` now propagates labels "right" across non-`TraversalParent` filters.
 * Fixed a bug in `ConnectiveP` where nested equivalent connectives should be inlined.
 * Fixed a bug in `IncidentToAdjacentStrategy` where `TreeStep` traversals were allowed.
 * Fixed a end-step label bug in `MatchPredicateStrategy`.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index 2a0a025..dead668 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -43,7 +43,6 @@ import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -89,9 +88,18 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        boolean modified;
-        do {
+        boolean modified = true;
+        while(modified) {
             modified = false;
+            for (final Step<?, ?> step : traversal.getSteps()) {
+                if (!step.getLabels().isEmpty()) {
+                    final Step<?, ?> nextStep = step.getNextStep();
+                    if (nextStep instanceof FilterStep && !(nextStep instanceof TraversalParent)) {
+                        TraversalHelper.copyLabels(step, nextStep, true);
+                        modified = true;
+                    }
+                }
+            }
             final List<Step> steps = traversal.getSteps();
             int prevRank = 0;
             for (int i = steps.size() - 1; i >= 0; i--) {
@@ -105,7 +113,7 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
                 }
                 prevRank = rank;
             }
-        } while (modified);
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index a3ed9a1..820143a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -76,7 +76,10 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
         while (changed) {
             changed = false;
             for (final FilterStep<?> step : TraversalHelper.getStepsOfAssignableClass(FilterStep.class, traversal)) {
-                if (step instanceof TraversalFilterStep && InlineFilterStrategy.processTraversalFilterStep((TraversalFilterStep) step, traversal))
+                if (step instanceof HasStep && InlineFilterStrategy.processHasStep((HasStep) step, traversal))
+                    // has(a,b).has(c) --> has(a,b,c)
+                    changed = true;
+                else if (step instanceof TraversalFilterStep && InlineFilterStrategy.processTraversalFilterStep((TraversalFilterStep) step, traversal))
                     // filter(x.y) --> x.y
                     changed = true;
                 else if (step instanceof OrStep && InlineFilterStrategy.processOrStep((OrStep) step, traversal))
@@ -99,6 +102,19 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
     ////////////////////////////
     ///////////////////////////
 
+    private static final boolean processHasStep(final HasStep<?> step, final Traversal.Admin<?, ?> traversal) {
+        if (step.getPreviousStep() instanceof HasStep) {
+            final HasStep<?> previousStep = (HasStep<?>) step.getPreviousStep();
+            for (final HasContainer hasContainer : step.getHasContainers()) {
+                previousStep.addHasContainer(hasContainer);
+            }
+            TraversalHelper.copyLabels(step, previousStep, false);
+            traversal.removeStep(step);
+            return true;
+        }
+        return false;
+    }
+
     private static final boolean processTraversalFilterStep(final TraversalFilterStep<?> step, final Traversal.Admin<?, ?> traversal) {
         final Traversal.Admin<?, ?> childTraversal = step.getLocalChildren().get(0);
         if (TraversalHelper.hasAllStepsOfClass(childTraversal, FilterStep.class) &&

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index 2192666..be1406d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -50,6 +50,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -572,10 +573,12 @@ public final class TraversalHelper {
     }
 
     public static void copyLabels(final Step<?, ?> fromStep, final Step<?, ?> toStep, final boolean moveLabels) {
-        for (final String label : fromStep.getLabels()) {
-            toStep.addLabel(label);
-            if (moveLabels)
-                fromStep.removeLabel(label);
+        if (!fromStep.getLabels().isEmpty()) {
+            for (final String label : moveLabels ? new LinkedHashSet<>(fromStep.getLabels()) : fromStep.getLabels()) {
+                toStep.addLabel(label);
+                if (moveLabels)
+                    fromStep.removeLabel(label);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
index 7082838..901d3a5 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyTest.java
@@ -69,28 +69,26 @@ public class SubgraphStrategyTest {
         @Parameterized.Parameter(value = 1)
         public Traversal optimized;
 
-
-        void applySubgraphStrategyTest(final Traversal traversal) {
-            final TraversalStrategies strategies = new DefaultTraversalStrategies();
-            strategies.addStrategies(SubgraphStrategy.build().
+        @Test
+        public void doTest() {
+            final TraversalStrategies originalStrategies = new DefaultTraversalStrategies();
+            originalStrategies.addStrategies(SubgraphStrategy.build().
                     vertices(__.and(has("name", "marko"), has("age", 29))).
                     edges(hasLabel("knows")).
                     vertexProperties(__.<VertexProperty, Long>values().count().and(is(P.lt(10)), is(0))).create());
-            strategies.addStrategies(InlineFilterStrategy.instance());
-            strategies.addStrategies(StandardVerificationStrategy.instance());
-            traversal.asAdmin().setStrategies(strategies);
-            traversal.asAdmin().applyStrategies();
-        }
-
-        @Test
-        public void doTest() {
-            applySubgraphStrategyTest(original);
-            assertEquals(optimized, original);
+            originalStrategies.addStrategies(InlineFilterStrategy.instance());
+            originalStrategies.addStrategies(StandardVerificationStrategy.instance());
+            this.original.asAdmin().setStrategies(originalStrategies);
+            this.original.asAdmin().applyStrategies();
+            final TraversalStrategies optimizedStrategies = new DefaultTraversalStrategies();
+            optimizedStrategies.addStrategies(InlineFilterStrategy.instance());
+            this.optimized.asAdmin().setStrategies(optimizedStrategies);
+            this.optimized.asAdmin().applyStrategies();
+            assertEquals(this.optimized, this.original);
         }
 
         @Parameterized.Parameters(name = "{0}")
         public static Iterable<Object[]> generateTestParameters() {
-
             return Arrays.asList(new Traversal[][]{
                     {__.outE(), __.outE().hasLabel("knows").and(
                             inV().has("name", "marko").has("age", 29),

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
index dc0d17a..52379fd 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
@@ -32,6 +32,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.P.eq;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.filter;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
@@ -79,6 +80,8 @@ public class FilterRankingStrategyTest {
 
         return Arrays.asList(new Object[][]{
                 {__.dedup().order(), __.dedup().order(), Collections.emptyList()},
+                {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), Collections.emptyList()},
+                {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a","b"), Collections.emptyList()},
                 {__.order().dedup(), __.dedup().order(), Collections.emptyList()},
                 {__.order().as("a").dedup(), __.order().as("a").dedup(), Collections.emptyList()},
                 {__.identity().order().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())},

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ff1c3844/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
index 9530c82..abf1f00 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategyTest.java
@@ -22,6 +22,10 @@ package org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -40,7 +44,6 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.drop;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.filter;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.limit;
-import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.map;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.match;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
@@ -74,11 +77,13 @@ public class InlineFilterStrategyTest {
     public static Iterable<Object[]> generateTestParameters() {
 
         return Arrays.asList(new Traversal[][]{
+                {has("age", 10).as("a").has("name", "marko").as("b").coin(0.5).as("c"), addHas(__.start(), "age", eq(10), "name", eq("marko")).as("a","b").coin(0.5).as("c")},
+                //
                 {filter(out("knows")), filter(out("knows"))},
-                {filter(has("age", P.gt(10))).as("a"), has("age", P.gt(10)).as("a")},
-                {filter(has("age", P.gt(10)).as("b")).as("a"), has("age", P.gt(10)).as("b", "a")},
-                {filter(has("age", P.gt(10)).as("a")), has("age", P.gt(10)).as("a")},
-                {filter(and(has("age", P.gt(10)).as("a"), has("name", "marko"))), has("age", P.gt(10)).as("a").has("name", "marko")},
+                {filter(has("age", gt(10))).as("a"), has("age", gt(10)).as("a")},
+                {filter(has("age", gt(10)).as("b")).as("a"), has("age", gt(10)).as("b", "a")},
+                {filter(has("age", gt(10)).as("a")), has("age", gt(10)).as("a")},
+                {filter(and(has("age", gt(10)).as("a"), has("name", "marko"))), addHas(__.start(), "age", gt(10), "name", eq("marko")).as("a")},
                 //
                 {or(has("name", "marko"), has("age", 32)), or(has("name", "marko"), has("age", 32))},
                 {or(has("name", "marko"), has("name", "bob")), has("name", eq("marko").or(eq("bob")))},
@@ -88,17 +93,17 @@ public class InlineFilterStrategyTest {
                 {or(has("name", "marko"), filter(or(filter(has("name", "bob")), has("name", "stephen")))), has("name", eq("marko").or(eq("bob").or(eq("stephen"))))},
                 {or(has("name", "marko").as("a"), filter(or(filter(has("name", "bob")).as("b"), has("name", "stephen").as("c")))), has("name", eq("marko").or(eq("bob").or(eq("stephen")))).as("a", "b", "c")},
                 //
-                {and(has("age", P.gt(10)), filter(has("age", 22))), has("age", P.gt(10)).has("age", 22)},
-                {and(has("age", P.gt(10)).as("a"), filter(has("age", 22).as("b")).as("c")).as("d"), has("age", P.gt(10)).as("a").has("age", 22).as("b", "c", "d")},
-                {and(has("age", P.gt(10)).as("a"), and(filter(has("age", 22).as("b")).as("c"), has("name", "marko").as("d"))), has("age", P.gt(10)).as("a").has("age", 22).as("b", "c").has("name", "marko").as("d")},
-                {and(has("age", P.gt(10)).as("a"), and(has("name","stephen").as("b"), has("name", "marko").as("c")).as("d")).as("e"), has("age", P.gt(10)).as("a").has("name","stephen").as("b").has("name","marko").as("c","d","e")},
-                {and(has("age", P.gt(10)), and(out("knows"), has("name", "marko"))), has("age", P.gt(10)).and(out("knows"), has("name", "marko"))},
-                {and(has("age", P.gt(20)), or(has("age", lt(10)), has("age", gt(100)))), has("age", gt(20)).has("age", lt(10).or(gt(100)))},
-                {and(has("age", P.gt(20)).as("a"), or(has("age", lt(10)), has("age", gt(100)).as("b"))), has("age", gt(20)).as("a").has("age", lt(10).or(gt(100))).as("b")},
+                {and(has("age", gt(10)), filter(has("age", 22))), addHas(__.start(), "age", gt(10), "age", eq(22))},
+                {and(has("age", gt(10)).as("a"), filter(has("age", 22).as("b")).as("c")).as("d"), addHas(__.start(), "age", gt(10), "age", eq(22)).as("a", "b", "c", "d")},
+                {and(has("age", gt(10)).as("a"), and(filter(has("age", 22).as("b")).as("c"), has("name", "marko").as("d"))), addHas(__.start(), "age", gt(10), "age", eq(22), "name", eq("marko")).as("a", "b", "c", "d")},
+                {and(has("age", gt(10)).as("a"), and(has("name", "stephen").as("b"), has("name", "marko").as("c")).as("d")).as("e"), addHas(__.start(), "age", gt(10), "name", eq("stephen"), "name", eq("marko")).as("a", "b", "c", "d", "e")},
+                {and(has("age", gt(10)), and(out("knows"), has("name", "marko"))), has("age", gt(10)).and(out("knows"), has("name", "marko"))},
+                {and(has("age", gt(20)), or(has("age", lt(10)), has("age", gt(100)))), addHas(__.start(), "age", gt(20), "age", lt(10).or(gt(100)))},
+                {and(has("age", gt(20)).as("a"), or(has("age", lt(10)), has("age", gt(100)).as("b"))), addHas(__.start(), "age", gt(20), "age", lt(10).or(gt(100))).as("a", "b")},
                 //
                 {V().match(as("a").has("age", 10), as("a").filter(has("name")).as("b")), V().as("a").has("age", 10).match(as("a").has("name").as("b"))},
                 {match(as("a").has("age", 10), as("a").filter(has("name")).as("b")), match(as("a").has("age", 10), as("a").has("name").as("b"))},
-                {map(match(as("a").has("age", 10), as("a").filter(has("name")).as("b"))), map(match(as("a").has("age", 10), as("a").has("name").as("b")))},
+                {__.map(match(as("a").has("age", 10), as("a").filter(has("name")).as("b"))), __.map(match(as("a").has("age", 10), as("a").has("name").as("b")))},
                 {V().match(as("a").has("age", 10)), V().as("a").has("age", 10)},
                 {V().match(as("a").has("age", 10).as("b"), as("a").filter(has("name")).as("b")), V().as("a").has("age", 10).as("b").match(as("a").has("name").as("b"))},
                 //
@@ -108,4 +113,12 @@ public class InlineFilterStrategyTest {
                 {filter(tail(10).as("a")), filter(tail(10).as("a"))},
         });
     }
+
+    private static GraphTraversal.Admin<?, ?> addHas(final GraphTraversal<?, ?> traversal, final Object... hasKeyValues) {
+        final HasStep<?> hasStep = new HasStep<>((Traversal.Admin) traversal);
+        for (int i = 0; i < hasKeyValues.length; i = i + 2) {
+            hasStep.addHasContainer(new HasContainer((String) hasKeyValues[i], (P) hasKeyValues[i + 1]));
+        }
+        return traversal.asAdmin().addStep(hasStep);
+    }
 }


[15/20] tinkerpop git commit: Merge remote-tracking branch 'origin/TINKERPOP-1467-master'

Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-1467-master'

Conflicts:
	CHANGELOG.asciidoc


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

Branch: refs/heads/TINKERPOP-1487
Commit: 5e55379a8d25a5964bb9554206651cebd7a591ce
Parents: 8ab682f 9d860ca
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Oct 4 13:40:52 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue Oct 4 13:40:52 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 17 +++++
 .../tinkerpop/gremlin/driver/Channelizer.java   |  2 +-
 .../apache/tinkerpop/gremlin/driver/Client.java | 42 +++++++++--
 .../tinkerpop/gremlin/driver/Cluster.java       | 24 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 67 +++++++++++++++--
 .../gremlin/driver/ConnectionPool.java          | 21 +++---
 .../tinkerpop/gremlin/driver/Handler.java       | 26 +++++--
 .../tinkerpop/gremlin/driver/ResultQueue.java   |  4 +
 .../driver/handler/WebSocketClientHandler.java  |  4 +-
 .../server/GremlinDriverIntegrateTest.java      | 79 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 255 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5e55379a/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index dc2b03b,86ed392..93308b6
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -429,7 -427,7 +429,8 @@@ image::https://raw.githubusercontent.co
  TinkerPop 3.1.5 (Release Date: NOT OFFICIALLY RELEASED YET)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
+ * Improved handling of `Cluster.close()` and `Client.close()` to prevent the methods from hanging.
 +* Fixed a bug in `NotStep` where child requirements were not being analyzed.
  * Fixed output redirection and potential memory leak in `GremlinGroovyScriptEngine`.
  * Corrected naming of `g_withPath_V_asXaX_out_out_mapXa_name_it_nameX` and `g_withPath_V_asXaX_out_mapXa_nameX` in `MapTest`.
  * Improved session cleanup when a close is triggered by the client.


[18/20] tinkerpop git commit: Add IO Reference docs

Posted by sp...@apache.org.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/src/dev/io/gryo.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/io/gryo.asciidoc b/docs/src/dev/io/gryo.asciidoc
new file mode 100644
index 0000000..61afdb0
--- /dev/null
+++ b/docs/src/dev/io/gryo.asciidoc
@@ -0,0 +1,63 @@
+////
+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.
+////
+[[gryo]]
+Gryo
+====
+
+image:gremlin-kryo.png[width=400,float=left] Gryo uses the popular link:https://github.com/EsotericSoftware/kryo[Kryo]
+library to handle binary serialization for the JVM. There currently aren't any Kryo implementations in other languages
+so the binding of this format to the JVM is a bit of a limitation, but if building a system on the JVM the use of
+Gryo over other serialization format should yield smaller data sizes than other formats like GraphSON or GraphML,
+improved serialization speed, as well as better support for the various Java data types that might not be supported
+otherwise.
+
+Gryo is useful both as a "graph" serialization format and as a generalized serialization format that can read or
+write any object. This characteristic makes it ideal for use in Gremlin Server, which is designed to return arbitrary
+results of varying types.
+
+It is unlikely that Gryo users will try to consume or produce Gryo without using TinkerPop and Kryo classes to help do
+it. Attempting to read or write a byte stream of Gryo without those tools would be challenging, so the depths of
+what the Gryo format looks like in a byte-by-byte perspective will not be discussed here. It is enough to know that
+TinkerPop has Kryo-based serializers for certain classes that it supports and that the bytes written or read must be
+Kryo compliant.
+
+While there is only one version of Gryo at the moment, 1.0, the format has generally expanded as new releases of
+TinkerPop have been produced. "Expansion" has generally meant that new types have come to be supported over time. The
+addition of new types means that while Gryo has remained at 1.0, older releases that produced Gryo files will not
+be compatible with newer TinkerPop releases if the newer types are utilized. On the flip side, newer release of
+TinkerPop are fully backward compatible with Gryo produced on older versions of TinkerPop.
+
+The full list of Gryo 1.0 types can be found in the `GryoMapper` source code. Looking at the source code for a specific
+release tag would show what types were compatible for a specific release. For example, the type listing for 3.2.2
+can be found link:https://github.com/apache/tinkerpop/blob/3.2.2/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapper.java#L249[here].
+
+One of the key aspects of Gryo is that, by default, it requires that all types expected to be used to be registered
+with the `GryoMapper`. There are two ways to do that:
+
+* On the `GryoMapper.Builder`, use the `addCustom` methods. These methods allow registration of single classes with
+an optional custom serializer.
+* Add a custom `IoRegistry` implementation with the `addRegistry` method on `GryoMapper.Builder`. The `IoRegistry`
+contains registrations that will be supplied to the `GryoMapper`. There is additional documentation on how this works
+in the link:http://tinkerpop.apache.org/docs/current/dev/provider/#io-implementations[provider documentation].
+
+When using `addCustom` or `addRegistry`, it is important to remember that the order in which those methods are called
+is important. The registrations get numeric "registration ids" and their order must match if the the Gryo is expected
+to be compatible. Calls to `addCustom` will be applied first, prior to calls to `addRegistry` (which internally call
+`addCustom`).
+
+It is possible to disable registration by setting `registrationRequired` on the `GryoMapper.Builder` to `false`, but
+Gryo is less efficient with this feature is turned off.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/src/dev/io/index.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/io/index.asciidoc b/docs/src/dev/io/index.asciidoc
new file mode 100644
index 0000000..9eaf02a
--- /dev/null
+++ b/docs/src/dev/io/index.asciidoc
@@ -0,0 +1,37 @@
+////
+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.
+////
+image::apache-tinkerpop-logo.png[width=500,link="http://tinkerpop.apache.org"]
+
+*x.y.z*
+
+:toc-position: left
+
+IO Reference
+============
+
+image:gremlin-io2.png[width=300]
+
+IO features, capabilities and use cases are initially discussed in the TinkerPop
+link:http://tinkerpop.apache.org/docs/x.y.z/reference/#_gremlin_i_o[Reference Documentation]. This document focuses
+more on the details of the implementations for both production and consumption of the various formats. It contains
+samples of the various formats and development details that provide deeper insight for their usage.
+
+include::graphml.asciidoc[]
+
+include::graphson.asciidoc[]
+
+include::gryo.asciidoc[]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/src/dev/provider/index.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/provider/index.asciidoc b/docs/src/dev/provider/index.asciidoc
index bb41241..af1be4f 100644
--- a/docs/src/dev/provider/index.asciidoc
+++ b/docs/src/dev/provider/index.asciidoc
@@ -785,6 +785,9 @@ Gremlin Server will send:
 |599 |SERVER SERIALIZATION ERROR |The server was not capable of serializing an object that was returned from the script supplied on the request. Either transform the object into something Gremlin Server can process within the script or install mapper serialization classes to Gremlin Server.
 |=========================================================
 
+NOTE: Please refer to the link:http://tinkerpop.apache.org/docs/current/dev/io[IO Reference Documentation] for more
+examples of `RequestMessage` and `ResponseMessage` instances.
+
 OpProcessors Arguments
 ~~~~~~~~~~~~~~~~~~~~~~
 
@@ -827,6 +830,7 @@ evaluated and is committed when the script completes (or rolled back if an error
 |=========================================================
 |Key |Type |Description
 |sasl |byte[] | *Required* The response to the server authentication challenge.  This value is dependent on the SASL authentication mechanism required by the server.
+|saslMechanism |String | The SASL mechanism: `PLAIN` or `GSSAPI`. Note that it is up to the server implementation to use or disregard this setting (default implementation in Gremlin Server ignores it).
 |=========================================================
 
 '`eval` operation arguments'

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/src/index.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/index.asciidoc b/docs/src/index.asciidoc
index 51d2105..09ffc2f 100644
--- a/docs/src/index.asciidoc
+++ b/docs/src/index.asciidoc
@@ -88,4 +88,6 @@ Developer
 Provides information on ways to contribute to TinkerPop as well as details on building the project and other specific information for contributors.
 |image:tinkerpop-enabled.png[width=200] |link:http://tinkerpop.apache.org/docs/x.y.z/dev/provider/[Providers] +
 Documentation for providers who implement the TinkerPop interfaces, develop plugins or drivers, or provide other third-party libraries for TinkerPop.
+|image:gremlin-io2.png[width=200] |link:http://tinkerpop.apache.org/docs/x.y.z/dev/io/[IO Reference] +
+Reference Documentation for providers and users of the various IO formats that TinkerPop has: GraphML, GraphSON and Gryo.
 |=========================================================
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/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 49790af..05d8a5d 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -152,6 +152,15 @@ there is no need to do that manually.
 
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-790[TINKERPOP-790]
 
+IO Reference Documentation
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+There is new reference documentation for the various IO formats. The documentation provides more details and samples
+that should be helpful to users and providers who intend to work directly with the TinkerPop supported serialization
+formats: GraphML, GraphSON and Gryo.
+
+See: link:http://tinkerpop.apache.org/docs/3.2.3/dev/io/[IO Reference Documentation]
+
 Upgrading for Providers
 ~~~~~~~~~~~~~~~~~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/static/images/gremlin-io2.png
----------------------------------------------------------------------
diff --git a/docs/static/images/gremlin-io2.png b/docs/static/images/gremlin-io2.png
new file mode 100755
index 0000000..99b8a30
Binary files /dev/null and b/docs/static/images/gremlin-io2.png differ

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index 787867f..5fb84f1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -101,7 +101,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     put(Property.class, "Property");
                     put(Path.class, "Path");
                     put(VertexProperty.class, "VertexProperty");
-                    put(Metrics.class, "metrics");
+                    put(Metrics.class, "Metrics");
                     put(TraversalMetrics.class, "TraversalMetrics");
                     put(Traverser.class, "Traverser");
                     put(Tree.class, "Tree");

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 632ed60..2e67eda 100644
--- a/pom.xml
+++ b/pom.xml
@@ -856,6 +856,31 @@ limitations under the License.
                                 </configuration>
                             </execution>
                             <execution>
+                                <id>io-book</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>process-asciidoc</goal>
+                                </goals>
+                                <configuration>
+                                    <sourceDirectory>${asciidoc.input.dir}/dev/io</sourceDirectory>
+                                    <sourceDocumentName>index.asciidoc</sourceDocumentName>
+                                    <outputDirectory>${htmlsingle.output.dir}/dev/io</outputDirectory>
+                                    <backend>html5</backend>
+                                    <doctype>book</doctype>
+                                    <attributes>
+                                        <imagesdir>../../images</imagesdir>
+                                        <encoding>UTF-8</encoding>
+                                        <toc>true</toc>
+                                        <toclevels>3</toclevels>
+                                        <toc-position>left</toc-position>
+                                        <stylesdir>${asciidoctor.style.dir}</stylesdir>
+                                        <stylesheet>tinkerpop.css</stylesheet>
+                                        <source-highlighter>coderay</source-highlighter>
+                                        <basedir>${project.basedir}</basedir>
+                                    </attributes>
+                                </configuration>
+                            </execution>
+                            <execution>
                                 <id>provider-book</id>
                                 <phase>generate-resources</phase>
                                 <goals>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
index da9edb5..0681ff1 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerIoRegistryV2d0.java
@@ -130,7 +130,7 @@ public final class TinkerIoRegistryV2d0 extends AbstractIoRegistry {
 
         @Override
         public String getTypeNamespace() {
-            return "gremlin";
+            return "tinker";
         }
     }
 


[13/20] tinkerpop git commit: merged NotStep fix and tests from tp31. CTR.

Posted by sp...@apache.org.
merged NotStep fix and tests from tp31. CTR.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 8ab682fef3e3da12904cb0d825abf4cc1ba8235a
Parents: bc00bb3 c7f42d8
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Oct 3 10:55:41 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 10:55:41 2016 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                 |  1 +
 .../process/traversal/step/filter/NotStep.java     |  7 +++++++
 .../traversal/step/map/GroovyMatchTest.groovy      | 10 ++++++++++
 .../process/traversal/step/map/MatchTest.java      | 17 +++++++++++++++++
 4 files changed, 35 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ab682fe/CHANGELOG.asciidoc
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ab682fe/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NotStep.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ab682fe/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
----------------------------------------------------------------------
diff --cc gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
index b35b763,b3d8ea9..f953e91
--- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
+++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
@@@ -336,27 -336,17 +336,37 @@@ public abstract class GroovyMatchTest 
               g.V.match(
                      __.as('a').both.as('b'),
                      __.as('b').both.as('c')).dedup('a','b').by(label)
 -            """, g)
 +            """)
 +        }
 +
 +        @Override
 +        public Traversal<Vertex, Long> get_g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count() {
 +            new ScriptTraversal<>(g, "gremlin-groovy", """
 +             g.V.hasLabel('song').match(
 +                    __.as('a').values('name').as('b'),
 +                    __.as('a').values('performances').as('c')
 +            ).select('b', 'c').count();
 +            """)
 +        }
 +
 +        @Override
 +        public Traversal<Vertex, Long> get_g_V_matchXa_knows_count_bX_selectXbX() {
 +            new ScriptTraversal<>(g, "gremlin-groovy", "g.V.match(__.as('a').out('knows').count.as('b')).select('b')")
 +        }
 +
 +        @Override
 +        public Traversal<Vertex, String> get_g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX() {
 +            new ScriptTraversal<>(g, "gremlin-groovy", "g.V.match(__.as('a').out('knows').as('b'), __.as('b').out('created').as('c'), __.as('a').out('created').as('c')).dedup('a', 'b', 'c').select('a').by('name')")
          }
+ 
+         @Override
+         public Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
 -            TraversalScriptHelper.compute("""
++            new ScriptTraversal<>(g, "gremlin-groovy", """
+                 g.V.not(match(
+                             __.as('a').age.as('b'),
+                             __.as('a').name.as('c')).
+                         where('b', eq('c')).select('a')).name
+             """, g)
+         }
      }
  }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ab682fe/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
----------------------------------------------------------------------
diff --cc gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
index 508968a,46b8e59..ce60734
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
@@@ -146,16 -143,11 +147,20 @@@ public abstract class MatchTest extend
      // distinct values with by()-modulation
      public abstract Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_both_b__b_both_cX_dedupXa_bX_byXlabelX();
  
 +    public abstract Traversal<Vertex, Long> get_g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count();
 +
 +    // reducing barrier on lazy standard shouldn't yield an empty barrier
 +    public abstract Traversal<Vertex, Long> get_g_V_matchXa_knows_count_bX_selectXbX();
 +
 +    // verifying keep labels and dedup labels interactions
 +    public abstract Traversal<Vertex, String> get_g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX();
 +
+     // test not(match)
+     public abstract Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name();
+ 
      @Test
      @LoadGraphWith(MODERN)
++
      public void g_V_valueMap_matchXa_selectXnameX_bX() {
          final Traversal<Vertex, Map<String, Object>> traversal = get_g_V_valueMap_matchXa_selectXnameX_bX();
          printTraversalForm(traversal);
@@@ -519,33 -496,13 +524,40 @@@
      }
  
      @Test
 +    @LoadGraphWith(GRATEFUL)
 +    public void g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count() {
 +        final Traversal<Vertex, Long> traversal = get_g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count();
 +        printTraversalForm(traversal);
 +        assertEquals(584, traversal.next().longValue());
 +        assertFalse(traversal.hasNext());
 +    }
 +
 +    @Test
 +    @LoadGraphWith(MODERN)
 +    public void g_V_matchXa_knows_count_bX_selectXbX() {
 +        final Traversal<Vertex, Long> traversal = get_g_V_matchXa_knows_count_bX_selectXbX();
 +        printTraversalForm(traversal);
 +        checkResults(Arrays.asList(0L, 0L, 0L, 0L, 0L, 2L), traversal);
 +        assertFalse(traversal.hasNext());
 +    }
 +
 +    @Test
 +    @LoadGraphWith(MODERN)
 +    public void g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX() {
 +        final Traversal<Vertex, String> traversal = get_g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX();
 +        printTraversalForm(traversal);
 +        assertEquals("marko", traversal.next());
 +        assertFalse(traversal.hasNext());
 +    }
 +
 +
+     @LoadGraphWith(MODERN)
+     public void g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
+         final Traversal<Vertex, String> traversal = get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name();
+         printTraversalForm(traversal);
+         checkResults(Arrays.asList("marko", "peter", "josh", "vadas", "lop", "ripple"), traversal);
+     }
+ 
      public static class GreedyMatchTraversals extends Traversals {
          @Before
          public void setupTest() {
@@@ -804,24 -761,8 +816,29 @@@
          }
  
          @Override
 +        public Traversal<Vertex, Long> get_g_V_hasLabelXsongsX_matchXa_name_b__a_performances_cX_selectXb_cX_count() {
 +            return g.V().hasLabel("song").match(
 +                    __.as("a").values("name").as("b"),
 +                    __.as("a").values("performances").as("c")
 +            ).select("b", "c").count();
 +        }
 +
 +        @Override
 +        public Traversal<Vertex, Long> get_g_V_matchXa_knows_count_bX_selectXbX() {
 +            return g.V().match(as("a").out("knows").count().as("b")).select("b");
 +        }
 +
 +        @Override
 +        public Traversal<Vertex, String> get_g_V_matchXa_knows_b__b_created_c__a_created_cX_dedupXa_b_cX_selectXaX_byXnameX() {
 +            return g.V().match(
 +                    as("a").out("knows").as("b"),
 +                    as("b").out("created").as("c"),
 +                    as("a").out("created").as("c")).dedup("a", "b", "c").<String>select("a").by("name");
 +        }
++
++        @Override
+         public Traversal<Vertex, String> get_g_V_notXmatchXa_age_b__a_name_cX_whereXb_eqXcXX_selectXaXX_name() {
+             return g.V().not(match(__.as("a").values("age").as("b"), __.as("a").values("name").as("c")).where("b", eq("c")).select("a")).values("name");
+         }
      }
  }


[07/20] tinkerpop git commit: made the recommended changes from @dkuppitz.

Posted by sp...@apache.org.
made the recommended changes from @dkuppitz.


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

Branch: refs/heads/TINKERPOP-1487
Commit: e3991eae76e1a3eca64c9b20582c025a92447daf
Parents: b8a92a3
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Oct 3 08:09:19 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 .../optimization/InlineFilterStrategy.java      | 29 ++++++++------------
 1 file changed, 12 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3991eae/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index 820143a..8072ca0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -42,6 +42,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -75,24 +76,18 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
         boolean changed = true; // recursively walk child traversals trying to inline them into the current traversal line.
         while (changed) {
             changed = false;
-            for (final FilterStep<?> step : TraversalHelper.getStepsOfAssignableClass(FilterStep.class, traversal)) {
-                if (step instanceof HasStep && InlineFilterStrategy.processHasStep((HasStep) step, traversal))
-                    // has(a,b).has(c) --> has(a,b,c)
-                    changed = true;
-                else if (step instanceof TraversalFilterStep && InlineFilterStrategy.processTraversalFilterStep((TraversalFilterStep) step, traversal))
-                    // filter(x.y) --> x.y
-                    changed = true;
-                else if (step instanceof OrStep && InlineFilterStrategy.processOrStep((OrStep) step, traversal))
-                    // or(has(x,y),has(x,z)) --> has(x,y.or(z))
-                    changed = true;
-                else if (step instanceof AndStep && InlineFilterStrategy.processAndStep((AndStep) step, traversal))
-                    // and(x,y) --> x.y
-                    changed = true;
+            final Iterator<FilterStep> filterStepIterator = TraversalHelper.getStepsOfAssignableClass(FilterStep.class, traversal).iterator();
+            while (!changed && filterStepIterator.hasNext()) {
+                final FilterStep<?> step = filterStepIterator.next();
+                changed = step instanceof HasStep && InlineFilterStrategy.processHasStep((HasStep) step, traversal) ||
+                        step instanceof TraversalFilterStep && InlineFilterStrategy.processTraversalFilterStep((TraversalFilterStep) step, traversal) ||
+                        step instanceof OrStep && InlineFilterStrategy.processOrStep((OrStep) step, traversal) ||
+                        step instanceof AndStep && InlineFilterStrategy.processAndStep((AndStep) step, traversal);
             }
-            // match(as('a').has(key,value),...) --> as('a').has(key,value).match(...)
-            if (traversal.getParent() instanceof EmptyStep) {
-                for (final MatchStep<?, ?> step : TraversalHelper.getStepsOfClass(MatchStep.class, traversal)) {
-                    if (InlineFilterStrategy.processMatchStep(step, traversal))
+            if (!changed && traversal.getParent() instanceof EmptyStep) {
+                final Iterator<MatchStep> matchStepIterator = TraversalHelper.getStepsOfClass(MatchStep.class, traversal).iterator();
+                while (!changed && matchStepIterator.hasNext()) {
+                    if (InlineFilterStrategy.processMatchStep(matchStepIterator.next(), traversal))
                         changed = true;
                 }
             }


[08/20] tinkerpop git commit: FilterRankStrategy is getting nasty solid at optimizing filters and itself, as a strategy, is now super efficient -- gutting code here and there as I realize that this is just a that.

Posted by sp...@apache.org.
FilterRankStrategy is getting nasty solid at optimizing filters and itself, as a strategy, is now super efficient -- gutting code here and there as I realize that this is just a that.


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

Branch: refs/heads/TINKERPOP-1487
Commit: b8a92a30df8ce67a437c8484d950437d3a34cbca
Parents: 56de652
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Fri Sep 30 13:42:33 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 .../optimization/FilterRankingStrategy.java     | 43 ++++++++------------
 .../process/traversal/util/TraversalHelper.java | 10 -----
 .../optimization/FilterRankingStrategyTest.java | 11 ++++-
 .../PathRetractionStrategyTest.java             |  3 +-
 4 files changed, 26 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b8a92a30/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index 2065ea1..2f8061b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -42,7 +42,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversal
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -91,29 +90,24 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
         boolean modified = true;
         while (modified) {
             modified = false;
-            final Set<String> currentLabels = new HashSet<>();
-            for (final Step<?, ?> step : traversal.getSteps()) {
-                if (!step.getLabels().isEmpty()) {
-                    currentLabels.addAll(step.getLabels());
-                    final Step<?, ?> nextStep = step.getNextStep();
-                    if (validFilterStep(nextStep) && !usesLabels(nextStep, currentLabels)) {
-                        TraversalHelper.copyLabels(step, nextStep, true);
-                        modified = true;
-                    }
-                }
-            }
             final List<Step> steps = traversal.getSteps();
-            int prevRank = 0;
-            for (int i = steps.size() - 1; i >= 0; i--) {
-                final Step curr = steps.get(i);
-                final int rank = usesLabels(curr, TraversalHelper.getLabelsUpTo(curr)) ? 0 : getStepRank(curr);
-                if (prevRank > 0 && rank > prevRank) {
-                    final Step next = curr.getNextStep();
-                    traversal.removeStep(next);
-                    traversal.addStep(i, next);
-                    modified = true;
+            for (int i = 0; i < steps.size() - 1; i++) {
+                final Step<?, ?> step = steps.get(i);
+                final Step<?, ?> nextStep = step.getNextStep();
+                if (!usesLabels(nextStep, step.getLabels())) {
+                    final int nextRank = getStepRank(nextStep);
+                    if (nextRank != 0) {
+                        if (!step.getLabels().isEmpty()) {
+                            TraversalHelper.copyLabels(step, nextStep, true);
+                            modified = true;
+                        }
+                        if (getStepRank(step) > nextRank) {
+                            traversal.removeStep(nextStep);
+                            traversal.addStep(i, nextStep);
+                            modified = true;
+                        }
+                    }
                 }
-                prevRank = rank;
             }
         }
     }
@@ -152,11 +146,6 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
             return 0;
     }
 
-
-    private static boolean validFilterStep(final Step<?, ?> step) {
-        return ((step instanceof FilterStep && !(step instanceof LambdaHolder)) || step instanceof OrderGlobalStep);
-    }
-
     private static boolean usesLabels(final Step<?, ?> step, final Set<String> labels) {
         if (step instanceof LambdaHolder)
             return true;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b8a92a30/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index 1fb9fab..87d3479 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -592,16 +592,6 @@ public final class TraversalHelper {
         }
     }
 
-    public static Set<String> getLabelsUpTo(final Step<?, ?> stopStep) {
-        final Set<String> labels = new HashSet<>();
-        Step<?, ?> step = stopStep.getPreviousStep();
-        while (!(step instanceof EmptyStep)) {
-            labels.addAll(step.getLabels());
-            step = step.getPreviousStep();
-        }
-        return labels;
-    }
-
     public static boolean hasAllStepsOfClass(final Traversal.Admin<?, ?> traversal, final Class<?>... classesToCheck) {
         for (final Step step : traversal.getSteps()) {
             boolean foundInstance = false;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b8a92a30/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
index 99e0cab..ff72f8c 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
@@ -21,7 +21,6 @@ package org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -34,6 +33,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.function.Predicate;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.P.eq;
 import static org.apache.tinkerpop.gremlin.process.traversal.P.neq;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.filter;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has;
@@ -86,11 +86,18 @@ public class FilterRankingStrategyTest {
                 {__.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), Collections.emptyList()},
                 {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("a"), Collections.emptyList()},
                 {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("b", "a"), Collections.emptyList()},
+                {__.where("b", eq("c")).as("a").dedup("a").has("name", "marko"), __.has("name", "marko").where("b", eq("c")).as("a").dedup("a"), Collections.emptyList()},
+                {__.where("b", eq("c")).has("name", "bob").as("a").dedup("a").has("name", "marko"), __.has("name", "bob").has("name", "marko").where("b", eq("c")).as("a").dedup("a"), Collections.emptyList()},
+                {__.has("name","marko").as("a").out().has("name","bob").dedup().as("b").where(__.as("a").out().as("b")),__.has("name","marko").as("a").out().has("name","bob").dedup().as("b").where(__.as("a").out().as("b")),Collections.emptyList()},
+                {__.has("name","marko").as("a").out().has("name","bob").as("b").dedup().where(__.as("a").out().as("b")),__.has("name","marko").as("a").out().has("name","bob").dedup().as("b").where(__.as("a").out().as("b")),Collections.emptyList()},
+                {__.has("name","marko").as("a").out().has("name","bob").dedup().as("c").where(__.as("a").out().as("b")),__.has("name","marko").as("a").out().has("name","bob").where(__.as("a").out().as("b")).dedup().as("c"),Collections.emptyList()},
                 {__.order().dedup(), __.dedup().order(), Collections.emptyList()},
                 {__.order().filter(testP).dedup(), __.order().filter(testP).dedup(), Collections.emptyList()},
                 {__.order().as("a").dedup(), __.dedup().order().as("a"), Collections.emptyList()},
                 {__.order().as("a").dedup("a"), __.order().as("a").dedup("a"), Collections.emptyList()},
-                // {__.order().as("a").dedup("a").has("name","marko"), __.has("name","marko").order().as("a").dedup("a"), Collections.emptyList()},
+                {__.order().as("a").dedup("a").has("name", "marko"), __.has("name", "marko").as("a").dedup("a").order(), Collections.emptyList()},
+                {__.order().as("a").dedup("a").has("name", "marko").out(), __.has("name", "marko").as("a").dedup("a").order().out(), Collections.emptyList()},
+                {__.order().as("a").dedup("a").has("name", "marko").where("a", eq("b")).out(), __.has("name", "marko").as("a").where("a", eq("b")).dedup("a").order().out(), Collections.emptyList()},
                 {__.identity().order().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())},
                 {__.order().identity().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())},
                 {__.order().out().dedup(), __.order().out().dedup(), Collections.emptyList()},

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b8a92a30/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
index 0063289..e95c729 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathRetractionStrategyTest.java
@@ -60,8 +60,7 @@ public class PathRetractionStrategyTest {
             new DefaultTraversalStrategies().addStrategies(PathRetractionStrategy.instance()),
             new DefaultTraversalStrategies().addStrategies(PathRetractionStrategy.instance(), PathProcessorStrategy.instance()),
             new DefaultTraversalStrategies().addStrategies(PathRetractionStrategy.instance(), PathProcessorStrategy.instance(), MatchPredicateStrategy.instance()),
-            new DefaultTraversalStrategies().addStrategies(PathRetractionStrategy.instance(), PathProcessorStrategy.instance(), MatchPredicateStrategy.instance(), RepeatUnrollStrategy.instance()),
-            TraversalStrategies.GlobalCache.getStrategies(Graph.class));
+            new DefaultTraversalStrategies().addStrategies(PathRetractionStrategy.instance(), PathProcessorStrategy.instance(), MatchPredicateStrategy.instance(), RepeatUnrollStrategy.instance()));
 
     @Parameterized.Parameter(value = 0)
     public Traversal.Admin traversal;


[10/20] tinkerpop git commit: minor change to CHANGELOG.

Posted by sp...@apache.org.
minor change to CHANGELOG.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 62197e25369bfcfd9b7036c6cc379182e5a6b073
Parents: e3991ea
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Oct 3 08:14:58 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

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


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/62197e25/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 638a80c..60e895b 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,7 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* `FilterRankStrategy` now propagates labels "right" across non-`TraversalParent` filters.
+* `FilterRankStrategy` now propagates labels "right" non-`Scoping` filters.
 * Fixed a bug in `ConnectiveP` where nested equivalent connectives should be inlined.
 * Fixed a bug in `IncidentToAdjacentStrategy` where `TreeStep` traversals were allowed.
 * Fixed a end-step label bug in `MatchPredicateStrategy`.


[14/20] tinkerpop git commit: Merge remote-tracking branch 'origin/TINKERPOP-1467' into tp31

Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-1467' into tp31

Conflicts:
	CHANGELOG.asciidoc


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

Branch: refs/heads/TINKERPOP-1487
Commit: 9ba68068f711913df221477256c7c62e7a1df835
Parents: c7f42d8 6d14adb
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Oct 4 13:39:36 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue Oct 4 13:39:36 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 17 +++++
 .../tinkerpop/gremlin/driver/Channelizer.java   |  6 +-
 .../apache/tinkerpop/gremlin/driver/Client.java | 42 +++++++++--
 .../tinkerpop/gremlin/driver/Cluster.java       | 22 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 68 +++++++++++++++--
 .../gremlin/driver/ConnectionPool.java          | 21 +++---
 .../tinkerpop/gremlin/driver/Handler.java       | 27 +++++--
 .../tinkerpop/gremlin/driver/ResultQueue.java   |  4 +
 .../driver/handler/WebSocketClientHandler.java  |  4 +-
 .../server/GremlinDriverIntegrateTest.java      | 79 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 255 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9ba68068/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index cf89a5c,9f45477..1917aae
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -26,7 -26,7 +26,8 @@@ image::https://raw.githubusercontent.co
  TinkerPop 3.1.5 (Release Date: NOT OFFICIALLY RELEASED YET)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
+ * Improved handling of `Cluster.close()` and `Client.close()` to prevent the methods from hanging.
 +* Fixed a bug in `NotStep` where child requirements were not being analyzed.
  * Fixed output redirection and potential memory leak in `GremlinGroovyScriptEngine`.
  * Corrected naming of `g_withPath_V_asXaX_out_out_mapXa_name_it_nameX` and `g_withPath_V_asXaX_out_mapXa_nameX` in `MapTest`.
  * Improved session cleanup when a close is triggered by the client.


[17/20] tinkerpop git commit: Merge branch 'tp31'

Posted by sp...@apache.org.
Merge branch 'tp31'


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

Branch: refs/heads/TINKERPOP-1487
Commit: d23b971d02b00a4aad64882fb772e993e261c348
Parents: 5e55379 ffe0b1f
Author: Daniel Kuppitz <da...@hotmail.com>
Authored: Tue Oct 4 19:50:45 2016 +0200
Committer: Daniel Kuppitz <da...@hotmail.com>
Committed: Tue Oct 4 19:50:45 2016 +0200

----------------------------------------------------------------------
 bin/publish-docs.sh | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/d23b971d/bin/publish-docs.sh
----------------------------------------------------------------------


[16/20] tinkerpop git commit: CTR: Handle new directories properly in `publish-docs.sh`.

Posted by sp...@apache.org.
CTR: Handle new directories properly in `publish-docs.sh`.


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

Branch: refs/heads/TINKERPOP-1487
Commit: ffe0b1f55af41e649961374e14b251d795286bed
Parents: 9ba6806
Author: Daniel Kuppitz <da...@hotmail.com>
Authored: Tue Oct 4 19:49:41 2016 +0200
Committer: Daniel Kuppitz <da...@hotmail.com>
Committed: Tue Oct 4 19:49:41 2016 +0200

----------------------------------------------------------------------
 bin/publish-docs.sh | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ffe0b1f5/bin/publish-docs.sh
----------------------------------------------------------------------
diff --git a/bin/publish-docs.sh b/bin/publish-docs.sh
index 49ed9bd..739deb5 100755
--- a/bin/publish-docs.sh
+++ b/bin/publish-docs.sh
@@ -53,15 +53,23 @@ diff -rq -I 'Generated by javadoc' -I '^<meta name="date"' javadocs/${VERSION}/
 # copy new / modified files
 for file in $(cat ../publish-docs.docs | awk '/^[AU]/ {print $2}' | grep -v '.graffle$')
 do
-  cp "../docs/htmlsingle/${file}" "docs/${VERSION}/${file}"
+  if [ -d "../docs/htmlsingle/${file}" ]; then
+    mkdir -p "docs/${VERSION}/${file}" && cp -r "../docs/htmlsingle/${file}"/* "$_"
+  else
+    mkdir -p "docs/${VERSION}/`dirname ${file}`" && cp "../docs/htmlsingle/${file}" "$_"
+  fi
 done
 for file in $(cat ../publish-docs.javadocs | awk '/^[AU]/ {print $2}')
 do
-  cp "../site/apidocs/${file}" "javadocs/${VERSION}/${file}"
+  if [ -d "../site/apidocs/${file}" ]; then
+    mkdir -p "javadocs/${VERSION}/${file}" && cp -r "../site/apidocs/${file}"/* "$_"
+  else
+    mkdir -p "javadocs/${VERSION}/`dirname ${file}`" && cp "../site/apidocs/${file}" "$_"
+  fi
 done
 
-pushd "docs/${VERSION}/"; cat ../../../publish-docs.docs | awk '/^A/ {print $2}' | grep -v '.graffle$' | xargs --no-run-if-empty svn add; popd
-pushd "javadocs/${VERSION}/"; cat ../../../publish-docs.javadocs | awk '/^A/ {print $2}' | xargs --no-run-if-empty svn add; popd
+pushd "docs/${VERSION}/"; cat ../../../publish-docs.docs | awk '/^A/ {print $2}' | grep -v '.graffle$' | xargs --no-run-if-empty svn add --parents; popd
+pushd "javadocs/${VERSION}/"; cat ../../../publish-docs.javadocs | awk '/^A/ {print $2}' | xargs --no-run-if-empty svn add --parents; popd
 
 # delete old files
 pushd "docs/${VERSION}/"; cat ../../../publish-docs.docs | awk '/^D/ {print $2}' | xargs --no-run-if-empty svn delete; popd


[05/20] tinkerpop git commit: cleaned up InlineFilterStrategy. Processing methods for step-types introduced. This is not only cleaner, but will allow users/providers to turn on/off InlineFiltering for different step types.

Posted by sp...@apache.org.
cleaned up InlineFilterStrategy. Processing methods for step-types introduced. This is not only cleaner, but will allow users/providers to turn on/off InlineFiltering for different step types.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 9ef8a9a6ce7fded4a98480de792d62ab0e62abab
Parents: 8eb0fdd
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Sep 29 13:36:20 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 .../optimization/InlineFilterStrategy.java      | 240 ++++++++++---------
 1 file changed, 125 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9ef8a9a6/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index 0b7a5cc..a3ed9a1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -75,137 +75,147 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
         boolean changed = true; // recursively walk child traversals trying to inline them into the current traversal line.
         while (changed) {
             changed = false;
-            // filter(x.y) --> x.y
-            for (final TraversalFilterStep<?> step : TraversalHelper.getStepsOfClass(TraversalFilterStep.class, traversal)) {
-                final Traversal.Admin<?, ?> childTraversal = step.getLocalChildren().get(0);
-                if (TraversalHelper.hasAllStepsOfClass(childTraversal, FilterStep.class) &&
-                        !TraversalHelper.hasStepOfClass(childTraversal,
-                                DropStep.class,
-                                RangeGlobalStep.class,
-                                DedupGlobalStep.class,
-                                LambdaHolder.class)) {
+            for (final FilterStep<?> step : TraversalHelper.getStepsOfAssignableClass(FilterStep.class, traversal)) {
+                if (step instanceof TraversalFilterStep && InlineFilterStrategy.processTraversalFilterStep((TraversalFilterStep) step, traversal))
+                    // filter(x.y) --> x.y
                     changed = true;
-                    TraversalHelper.applySingleLevelStrategies(traversal, childTraversal, InlineFilterStrategy.class);
-                    final Step<?, ?> finalStep = childTraversal.getEndStep();
-                    TraversalHelper.insertTraversal((Step) step, childTraversal, traversal);
-                    TraversalHelper.copyLabels(step, finalStep, false);
-                    traversal.removeStep(step);
+                else if (step instanceof OrStep && InlineFilterStrategy.processOrStep((OrStep) step, traversal))
+                    // or(has(x,y),has(x,z)) --> has(x,y.or(z))
+                    changed = true;
+                else if (step instanceof AndStep && InlineFilterStrategy.processAndStep((AndStep) step, traversal))
+                    // and(x,y) --> x.y
+                    changed = true;
+            }
+            // match(as('a').has(key,value),...) --> as('a').has(key,value).match(...)
+            if (traversal.getParent() instanceof EmptyStep) {
+                for (final MatchStep<?, ?> step : TraversalHelper.getStepsOfClass(MatchStep.class, traversal)) {
+                    if (InlineFilterStrategy.processMatchStep(step, traversal))
+                        changed = true;
                 }
             }
-            // or(has(x,y),has(x,z)) --> has(x,y.or(z))
-            for (final OrStep<?> step : TraversalHelper.getStepsOfClass(OrStep.class, traversal)) {
-                boolean process = true;
-                String key = null;
-                P predicate = null;
-                final List<String> labels = new ArrayList<>();
-                for (final Traversal.Admin<?, ?> childTraversal : step.getLocalChildren()) {
-                    this.apply(childTraversal); // todo: this may be a bad idea, but I can't seem to find a test case to break it
-                    for (final Step<?, ?> childStep : childTraversal.getSteps()) {
-                        if (childStep instanceof HasStep) {
-                            for (final HasContainer hasContainer : ((HasStep<?>) childStep).getHasContainers()) {
-                                if (null == key)
-                                    key = hasContainer.getKey();
-                                else if (!hasContainer.getKey().equals(key)) {
-                                    process = false;
-                                    break;
-                                }
-                                predicate = null == predicate ?
-                                        hasContainer.getPredicate() :
-                                        predicate.or(hasContainer.getPredicate());
-                            }
-                            labels.addAll(childStep.getLabels());
-                        } else {
+        }
+    }
+
+    ////////////////////////////
+    ///////////////////////////
+
+    private static final boolean processTraversalFilterStep(final TraversalFilterStep<?> step, final Traversal.Admin<?, ?> traversal) {
+        final Traversal.Admin<?, ?> childTraversal = step.getLocalChildren().get(0);
+        if (TraversalHelper.hasAllStepsOfClass(childTraversal, FilterStep.class) &&
+                !TraversalHelper.hasStepOfClass(childTraversal,
+                        DropStep.class,
+                        RangeGlobalStep.class,
+                        DedupGlobalStep.class,
+                        LambdaHolder.class)) {
+            TraversalHelper.applySingleLevelStrategies(traversal, childTraversal, InlineFilterStrategy.class);
+            final Step<?, ?> finalStep = childTraversal.getEndStep();
+            TraversalHelper.insertTraversal((Step) step, childTraversal, traversal);
+            TraversalHelper.copyLabels(step, finalStep, false);
+            traversal.removeStep(step);
+            return true;
+        }
+        return false;
+    }
+
+    private static final boolean processOrStep(final OrStep<?> step, final Traversal.Admin<?, ?> traversal) {
+        boolean process = true;
+        String key = null;
+        P predicate = null;
+        final List<String> labels = new ArrayList<>();
+        for (final Traversal.Admin<?, ?> childTraversal : step.getLocalChildren()) {
+            InlineFilterStrategy.instance().apply(childTraversal); // todo: this may be a bad idea, but I can't seem to find a test case to break it
+            for (final Step<?, ?> childStep : childTraversal.getSteps()) {
+                if (childStep instanceof HasStep) {
+                    for (final HasContainer hasContainer : ((HasStep<?>) childStep).getHasContainers()) {
+                        if (null == key)
+                            key = hasContainer.getKey();
+                        else if (!hasContainer.getKey().equals(key)) {
                             process = false;
                             break;
                         }
+                        predicate = null == predicate ?
+                                hasContainer.getPredicate() :
+                                predicate.or(hasContainer.getPredicate());
                     }
-                    if (!process)
-                        break;
-                }
-                if (process) {
-                    changed = true;
-                    final HasStep hasStep = new HasStep<>(traversal, new HasContainer(key, predicate));
-                    TraversalHelper.replaceStep(step, hasStep, traversal);
-                    TraversalHelper.copyLabels(step, hasStep, false);
-                    for (final String label : labels) {
-                        hasStep.addLabel(label);
-                    }
+                    labels.addAll(childStep.getLabels());
+                } else {
+                    process = false;
+                    break;
                 }
             }
-            // and(x,y) --> x.y
-            for (final AndStep<?> step : TraversalHelper.getStepsOfClass(AndStep.class, traversal)) {
-                boolean process = true;
-                for (final Traversal.Admin<?, ?> childTraversal : step.getLocalChildren()) {
-                    if (!TraversalHelper.hasAllStepsOfClass(childTraversal, FilterStep.class) ||
-                            TraversalHelper.hasStepOfClass(childTraversal,
-                                    DropStep.class,
-                                    RangeGlobalStep.class,
-                                    DedupGlobalStep.class,
-                                    LambdaHolder.class)) {
-                        process = false;
-                        break;
-                    }
-                }
-                if (process) {
-                    changed = true;
-                    final List<Traversal.Admin<?, ?>> childTraversals = (List) step.getLocalChildren();
-                    Step<?, ?> finalStep = null;
-                    for (int i = childTraversals.size() - 1; i >= 0; i--) {
-                        final Traversal.Admin<?, ?> childTraversal = childTraversals.get(i);
-                        TraversalHelper.applySingleLevelStrategies(traversal, childTraversal, InlineFilterStrategy.class);
-                        if (null == finalStep)
-                            finalStep = childTraversal.getEndStep();
-                        TraversalHelper.insertTraversal((Step) step, childTraversals.get(i), traversal);
+            if (!process)
+                break;
+        }
+        if (process) {
+            final HasStep hasStep = new HasStep<>(traversal, new HasContainer(key, predicate));
+            TraversalHelper.replaceStep(step, hasStep, traversal);
+            TraversalHelper.copyLabels(step, hasStep, false);
+            for (final String label : labels) {
+                hasStep.addLabel(label);
+            }
+            return true;
+        }
+        return false;
+    }
 
-                    }
-                    if (null != finalStep) TraversalHelper.copyLabels(step, finalStep, false);
-                    traversal.removeStep(step);
-                }
+    private static final boolean processAndStep(final AndStep<?> step, final Traversal.Admin<?, ?> traversal) {
+        boolean process = true;
+        for (final Traversal.Admin<?, ?> childTraversal : step.getLocalChildren()) {
+            if (!TraversalHelper.hasAllStepsOfClass(childTraversal, FilterStep.class) ||
+                    TraversalHelper.hasStepOfClass(childTraversal,
+                            DropStep.class,
+                            RangeGlobalStep.class,
+                            DedupGlobalStep.class,
+                            LambdaHolder.class)) {
+                process = false;
+                break;
             }
-            // match(as('a').has(key,value),...) --> as('a').has(key,value).match(...)
-            if (traversal.getParent() instanceof EmptyStep) {
-                for (final MatchStep<?, ?> step : TraversalHelper.getStepsOfClass(MatchStep.class, traversal)) {
-                    final String startLabel = determineStartLabelForHasPullOut(step);
-                    if (null != startLabel) {
-                        for (final Traversal.Admin<?, ?> matchTraversal : new ArrayList<>(step.getGlobalChildren())) {
-                            if (!(step.getPreviousStep() instanceof EmptyStep) &&
-                                    TraversalHelper.hasAllStepsOfClass(matchTraversal,
-                                            HasStep.class,
-                                            MatchStep.MatchStartStep.class,
-                                            MatchStep.MatchEndStep.class) &&
-                                    matchTraversal.getStartStep() instanceof MatchStep.MatchStartStep &&
-                                    startLabel.equals(((MatchStep.MatchStartStep) matchTraversal.getStartStep()).getSelectKey().orElse(null))) {
-                                changed = true;
-                                final String endLabel = ((MatchStep.MatchEndStep) matchTraversal.getEndStep()).getMatchKey().orElse(null); // why would this exist? but just in case
-                                matchTraversal.removeStep(0);                                       // remove MatchStartStep
-                                matchTraversal.removeStep(matchTraversal.getSteps().size() - 1);    // remove MatchEndStep
-                                TraversalHelper.applySingleLevelStrategies(traversal, matchTraversal, InlineFilterStrategy.class);
-                                step.removeGlobalChild(matchTraversal);
-                                step.getPreviousStep().addLabel(startLabel);
-                                // TODO: matchTraversal.getEndStep().addLabel(startLabel); (perhaps insert an identity so filter rank can push has()-left)
-                                if (null != endLabel) matchTraversal.getEndStep().addLabel(endLabel);
-                                TraversalHelper.insertTraversal((Step) step.getPreviousStep(), matchTraversal, traversal);
-                            }
-                        }
-                        if (step.getGlobalChildren().isEmpty())
-                            traversal.removeStep(step);
-                    }
-                }
+        }
+        if (process) {
+            final List<Traversal.Admin<?, ?>> childTraversals = (List) step.getLocalChildren();
+            Step<?, ?> finalStep = null;
+            for (int i = childTraversals.size() - 1; i >= 0; i--) {
+                final Traversal.Admin<?, ?> childTraversal = childTraversals.get(i);
+                TraversalHelper.applySingleLevelStrategies(traversal, childTraversal, InlineFilterStrategy.class);
+                if (null == finalStep)
+                    finalStep = childTraversal.getEndStep();
+                TraversalHelper.insertTraversal((Step) step, childTraversals.get(i), traversal);
+
             }
+            if (null != finalStep) TraversalHelper.copyLabels(step, finalStep, false);
+            traversal.removeStep(step);
+            return true;
         }
+        return false;
     }
 
-    private static final String determineStartLabelForHasPullOut(final MatchStep<?, ?> matchStep) {
-        final String startLabel = MatchStep.Helper.computeStartLabel(matchStep.getGlobalChildren());
-        Step<?, ?> previousStep = matchStep.getPreviousStep();
-        if (previousStep.getLabels().contains(startLabel))
-            return startLabel;
-        while (!(previousStep instanceof EmptyStep)) {
-            if (!previousStep.getLabels().isEmpty())
-                return null;
-            previousStep = previousStep.getPreviousStep();
+    private static final boolean processMatchStep(final MatchStep<?, ?> step, final Traversal.Admin<?, ?> traversal) {
+        if (step.getPreviousStep() instanceof EmptyStep)
+            return false;
+        boolean changed = false;
+        final String startLabel = MatchStep.Helper.computeStartLabel(step.getGlobalChildren());
+        for (final Traversal.Admin<?, ?> matchTraversal : new ArrayList<>(step.getGlobalChildren())) {
+            if (TraversalHelper.hasAllStepsOfClass(matchTraversal,
+                    HasStep.class,
+                    MatchStep.MatchStartStep.class,
+                    MatchStep.MatchEndStep.class) &&
+                    matchTraversal.getStartStep() instanceof MatchStep.MatchStartStep &&
+                    startLabel.equals(((MatchStep.MatchStartStep) matchTraversal.getStartStep()).getSelectKey().orElse(null))) {
+                changed = true;
+                final String endLabel = ((MatchStep.MatchEndStep) matchTraversal.getEndStep()).getMatchKey().orElse(null); // why would this exist? but just in case
+                matchTraversal.removeStep(0);                                       // remove MatchStartStep
+                matchTraversal.removeStep(matchTraversal.getSteps().size() - 1);    // remove MatchEndStep
+                TraversalHelper.applySingleLevelStrategies(traversal, matchTraversal, InlineFilterStrategy.class);
+                step.removeGlobalChild(matchTraversal);
+                step.getPreviousStep().addLabel(startLabel);
+                // TODO: matchTraversal.getEndStep().addLabel(startLabel); (perhaps insert an identity so filter rank can push has()-left)
+                if (null != endLabel) matchTraversal.getEndStep().addLabel(endLabel);
+                TraversalHelper.insertTraversal((Step) step.getPreviousStep(), matchTraversal, traversal);
+            }
         }
-        return startLabel;
+        if (step.getGlobalChildren().isEmpty())
+            traversal.removeStep(step);
+        return changed;
     }
 
     @Override


[03/20] tinkerpop git commit: FilterRankStrategy now is smart about Scoping steps and thus, can rank labeled steps. order().as('a').dedup() is dedup().order().as('a'), but order().as('a').dedup('a') is order().as('a').dedup('a'). Lots of test cases in Fi

Posted by sp...@apache.org.
FilterRankStrategy now is smart about Scoping steps and thus, can rank labeled steps. order().as('a').dedup() is dedup().order().as('a'), but order().as('a').dedup('a') is order().as('a').dedup('a'). Lots of test cases in FilterRankStrategyTest updated with more efficient reordering.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 56de6529f2c5c59b83ff34d0190788a0ccfaf17c
Parents: 68bbae1
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Fri Sep 30 10:36:23 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Oct 3 08:24:17 2016 -0600

----------------------------------------------------------------------
 .../optimization/FilterRankingStrategy.java     | 86 ++++++++------------
 .../process/traversal/util/TraversalHelper.java | 20 +++++
 .../optimization/FilterRankingStrategyTest.java | 15 ++--
 .../TinkerGraphStepStrategyTest.java            | 10 +--
 4 files changed, 68 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56de6529/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index 06726b1..2065ea1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.step.LambdaHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ClassFilterStep;
@@ -39,17 +40,16 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversal
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.Collections;
-import java.util.Iterator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 /**
- * FilterRankingStrategy reorders filter- and order-steps according to their rank. Labeled steps or lambda holders or
- * steps that contain child traversals, that have labeled steps or lambda holders, will not be reordered.
+ * FilterRankingStrategy reorders filter- and order-steps according to their rank. It will also do its best to push
+ * step labels as far "right" as possible in order to keep traversers as small and bulkable as possible prior to the
+ * absolute need for path-labeling.
  * <p/>
  * <table>
  * <thead>
@@ -89,12 +89,14 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
         boolean modified = true;
-        while(modified) {
+        while (modified) {
             modified = false;
+            final Set<String> currentLabels = new HashSet<>();
             for (final Step<?, ?> step : traversal.getSteps()) {
-                if (step instanceof FilterStep && !step.getLabels().isEmpty()) {
+                if (!step.getLabels().isEmpty()) {
+                    currentLabels.addAll(step.getLabels());
                     final Step<?, ?> nextStep = step.getNextStep();
-                    if (nextStep instanceof FilterStep && !(nextStep instanceof TraversalParent)) {
+                    if (validFilterStep(nextStep) && !usesLabels(nextStep, currentLabels)) {
                         TraversalHelper.copyLabels(step, nextStep, true);
                         modified = true;
                     }
@@ -104,7 +106,7 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
             int prevRank = 0;
             for (int i = steps.size() - 1; i >= 0; i--) {
                 final Step curr = steps.get(i);
-                final int rank = rank(curr);
+                final int rank = usesLabels(curr, TraversalHelper.getLabelsUpTo(curr)) ? 0 : getStepRank(curr);
                 if (prevRank > 0 && rank > prevRank) {
                     final Step next = curr.getNextStep();
                     traversal.removeStep(next);
@@ -116,15 +118,6 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
         }
     }
 
-    @Override
-    public Set<Class<? extends OptimizationStrategy>> applyPrior() {
-        return PRIORS;
-    }
-
-    public static FilterRankingStrategy instance() {
-        return INSTANCE;
-    }
-
     /**
      * Ranks the given step. Steps with lower ranks can be moved in front of steps with higher ranks. 0 means that
      * the step has no rank and thus is not exchangeable with its neighbors.
@@ -159,47 +152,34 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
             return 0;
     }
 
-    /**
-     * If the given step has no child traversal that holds a lambda, then the actual rank determined by
-     * {@link #getStepRank(Step)} is returned, otherwise 0.
-     *
-     * @param step the step to get a ranking for
-     * @return The rank of the given step.
-     */
-    private static int rank(final Step step) {
-        if (isNotOptimizableStep(step)) {
-            return 0;
-        }
-        final int rank = getStepRank(step);
-        if (rank > 0 && step instanceof TraversalParent) {
-            final TraversalParent tp = (TraversalParent) step;
-            final Iterator<Traversal.Admin<Object, Object>> childTraversalIterator = IteratorUtils.concat(
-                    tp.getLocalChildren().iterator(), tp.getGlobalChildren().iterator());
-            while (childTraversalIterator.hasNext()) {
-                if (TraversalHelper.anyStepRecursively(FilterRankingStrategy::isNotOptimizableStep, childTraversalIterator.next())) {
-                    return 0;
-                }
-            }
-        }
-        return rank;
+
+    private static boolean validFilterStep(final Step<?, ?> step) {
+        return ((step instanceof FilterStep && !(step instanceof LambdaHolder)) || step instanceof OrderGlobalStep);
     }
 
-    /**
-     * Returns true if the step is not optimizable, otherwise false. A step is not optimizable if it (or any of its
-     * child traversals) is a lambda holder or has a label.
-     *
-     * @param step the step to check for optimizability
-     * @return true if the given step is optimizable, otherwise false.
-     */
-    private static boolean isNotOptimizableStep(final Step<?, ?> step) {
+    private static boolean usesLabels(final Step<?, ?> step, final Set<String> labels) {
         if (step instanceof LambdaHolder)
             return true;
-        else {
-            for (final String label : step.getLabels()) {
-                if (!Graph.Hidden.isHidden(label))
+        if (step instanceof Scoping) {
+            final Set<String> scopes = ((Scoping) step).getScopeKeys();
+            for (final String label : labels) {
+                if (scopes.contains(label))
                     return true;
             }
-            return false;
         }
+        if (step instanceof TraversalParent) {
+            if (TraversalHelper.anyStepRecursively(s -> usesLabels(s, labels), (TraversalParent) step))
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public Set<Class<? extends OptimizationStrategy>> applyPrior() {
+        return PRIORS;
+    }
+
+    public static FilterRankingStrategy instance() {
+        return INSTANCE;
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56de6529/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index be1406d..1fb9fab 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -425,6 +425,16 @@ public final class TraversalHelper {
         return false;
     }
 
+    public static boolean anyStepRecursively(final Predicate<Step> predicate, final TraversalParent step) {
+        for (final Traversal.Admin<?, ?> localChild : step.getLocalChildren()) {
+            if (anyStepRecursively(predicate, localChild)) return true;
+        }
+        for (final Traversal.Admin<?, ?> globalChild : step.getGlobalChildren()) {
+            if (anyStepRecursively(predicate, globalChild)) return true;
+        }
+        return false;
+    }
+
     public static <S> void addToCollection(final Collection<S> collection, final S s, final long bulk) {
         if (collection instanceof BulkSet) {
             ((BulkSet<S>) collection).add(s, bulk);
@@ -582,6 +592,16 @@ public final class TraversalHelper {
         }
     }
 
+    public static Set<String> getLabelsUpTo(final Step<?, ?> stopStep) {
+        final Set<String> labels = new HashSet<>();
+        Step<?, ?> step = stopStep.getPreviousStep();
+        while (!(step instanceof EmptyStep)) {
+            labels.addAll(step.getLabels());
+            step = step.getPreviousStep();
+        }
+        return labels;
+    }
+
     public static boolean hasAllStepsOfClass(final Traversal.Admin<?, ?> traversal, final Class<?>... classesToCheck) {
         for (final Step step : traversal.getSteps()) {
             boolean foundInstance = false;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56de6529/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
index bd12e34..99e0cab 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategyTest.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -31,6 +32,7 @@ import org.junit.runners.Parameterized;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.function.Predicate;
 
 import static org.apache.tinkerpop.gremlin.process.traversal.P.neq;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.filter;
@@ -77,15 +79,18 @@ public class FilterRankingStrategyTest {
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> generateTestParameters() {
-
+        final Predicate testP = t -> true;
         return Arrays.asList(new Object[][]{
                 {__.dedup().order(), __.dedup().order(), Collections.emptyList()},
-                {__.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")), __.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")), Collections.emptyList()},
+                {__.has("name", "marko").as("a").out().as("b").has("age", 32).where("a", neq("b")).as("c").out(), __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")).as("c").out(), Collections.emptyList()},
                 {__.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), __.has("name", "marko").as("a").out().has("age", 32).as("b").where("a", neq("b")), Collections.emptyList()},
-                {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), Collections.emptyList()},
-                {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a", "b"), Collections.emptyList()},
+                {__.has("name", "marko").has("age", 32).dedup().has("name", "bob").as("a"), __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("a"), Collections.emptyList()},
+                {__.has("name", "marko").dedup().as("a").has("age", 32).has("name", "bob").as("b"), __.has("name", "marko").has("age", 32).has("name", "bob").dedup().as("b", "a"), Collections.emptyList()},
                 {__.order().dedup(), __.dedup().order(), Collections.emptyList()},
-                {__.order().as("a").dedup(), __.order().as("a").dedup(), Collections.emptyList()},
+                {__.order().filter(testP).dedup(), __.order().filter(testP).dedup(), Collections.emptyList()},
+                {__.order().as("a").dedup(), __.dedup().order().as("a"), Collections.emptyList()},
+                {__.order().as("a").dedup("a"), __.order().as("a").dedup("a"), Collections.emptyList()},
+                // {__.order().as("a").dedup("a").has("name","marko"), __.has("name","marko").order().as("a").dedup("a"), Collections.emptyList()},
                 {__.identity().order().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())},
                 {__.order().identity().dedup(), __.dedup().order(), Collections.singletonList(IdentityRemovalStrategy.instance())},
                 {__.order().out().dedup(), __.order().out().dedup(), Collections.emptyList()},

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/56de6529/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
index 9f97466..35f936c 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerGraphStepStrategyTest.java
@@ -100,17 +100,17 @@ public class TinkerGraphStepStrategyTest {
                 {__.V().has("name", "marko").as("a").or(has("age"), has("age", gt(32))).has("lang", "java"),
                         g_V("name", eq("marko")).as("a").or(has("age"), has("age", gt(32))).has("lang", "java"), Collections.emptyList()},
                 {__.V().has("name", "marko").as("a").or(has("age"), has("age", gt(32))).has("lang", "java"),
-                        g_V("name", eq("marko"), "lang", eq("java")).as("a").or(has("age"), has("age", gt(32))), Collections.singletonList(FilterRankingStrategy.instance())},
+                        g_V("name", eq("marko"), "lang", eq("java")).or(has("age"), has("age", gt(32))).as("a"), Collections.singletonList(FilterRankingStrategy.instance())},
                 {__.V().dedup().has("name", "marko").or(has("age"), has("age", gt(32))).has("lang", "java"),
                         g_V("name", eq("marko"), "lang", eq("java")).or(has("age"), has("age", gt(32))).dedup(), Collections.singletonList(FilterRankingStrategy.instance())},
                 {__.V().as("a").dedup().has("name", "marko").or(has("age"), has("age", gt(32))).has("lang", "java"),
-                        g_V("name", eq("marko"), "lang", eq("java")).as("a").or(has("age"), has("age", gt(32))).dedup(), Collections.singletonList(FilterRankingStrategy.instance())},
+                        g_V("name", eq("marko"), "lang", eq("java")).or(has("age"), has("age", gt(32))).dedup().as("a"), Collections.singletonList(FilterRankingStrategy.instance())},
                 {__.V().as("a").has("name", "marko").as("b").or(has("age"), has("age", gt(32))).has("lang", "java"),
-                        g_V("name", eq("marko"), "lang", eq("java")).as("a", "b").or(has("age"), has("age", gt(32))), Collections.singletonList(FilterRankingStrategy.instance())},
+                        g_V("name", eq("marko"), "lang", eq("java")).or(has("age"), has("age", gt(32))).as("b", "a"), Collections.singletonList(FilterRankingStrategy.instance())},
                 {__.V().as("a").dedup().has("name", "marko").or(has("age"), has("age", gt(32))).filter(has("name", "bob")).has("lang", "java"),
-                        g_V("name", eq("marko"), "name", eq("bob"), "lang", eq("java")).as("a").or(has("age"), has("age", gt(32))).dedup(), Arrays.asList(InlineFilterStrategy.instance(), FilterRankingStrategy.instance())},
+                        g_V("name", eq("marko"), "name", eq("bob"), "lang", eq("java")).or(has("age"), has("age", gt(32))).dedup().as("a"), Arrays.asList(InlineFilterStrategy.instance(), FilterRankingStrategy.instance())},
                 {__.V().as("a").dedup().has("name", "marko").or(has("age", 10), has("age", gt(32))).filter(has("name", "bob")).has("lang", "java"),
-                        g_V("name", eq("marko"), "age", eq(10).or(gt(32)), "name", eq("bob"), "lang", eq("java")).as("a").dedup(), TraversalStrategies.GlobalCache.getStrategies(TinkerGraph.class).toList()},
+                        g_V("name", eq("marko"), "age", eq(10).or(gt(32)), "name", eq("bob"), "lang", eq("java")).dedup().as("a"), TraversalStrategies.GlobalCache.getStrategies(TinkerGraph.class).toList()},
                 {__.V().has("name", "marko").or(not(has("age")), has("age", gt(32))).has("name", "bob").has("lang", "java"),
                         g_V("name", eq("marko"), "name", eq("bob"), "lang", eq("java")).or(not(filter(properties("age"))), has("age", gt(32))), TraversalStrategies.GlobalCache.getStrategies(TinkerGraph.class).toList()}
         });


[20/20] tinkerpop git commit: Add IO Reference docs

Posted by sp...@apache.org.
Add IO Reference docs

IO Reference docs provide more details and samples for GraphML, Gryo and GraphSON.


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

Branch: refs/heads/TINKERPOP-1487
Commit: 6f481b0bab4a15b6db3dec716c15aab0136e7698
Parents: d23b971
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Tue Oct 4 12:19:39 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue Oct 4 14:29:24 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |    1 +
 docs/src/dev/io/graphml.asciidoc                |  119 +
 docs/src/dev/io/graphson.asciidoc               | 4586 ++++++++++++++++++
 docs/src/dev/io/gryo.asciidoc                   |   63 +
 docs/src/dev/io/index.asciidoc                  |   37 +
 docs/src/dev/provider/index.asciidoc            |    4 +
 docs/src/index.asciidoc                         |    2 +
 .../upgrade/release-3.2.x-incubating.asciidoc   |    9 +
 docs/static/images/gremlin-io2.png              |  Bin 0 -> 185756 bytes
 .../structure/io/graphson/GraphSONModule.java   |    2 +-
 pom.xml                                         |   25 +
 .../structure/TinkerIoRegistryV2d0.java         |    2 +-
 12 files changed, 4848 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 93308b6..8db7833 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -47,6 +47,7 @@ TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 * `SubgraphStrategy` now supports vertex property filtering.
 * Fixed a bug in Gremlin-Python `P` where predicates reversed the order of the predicates.
 * Added tests to `DedupTest` for the `dedup(Scope, String...)` overload.
+* Added more detailed reference documentation for IO formats.
 * Fixed a bug in serialization of `Lambda` instances in GraphSON, which prevented their use in remote traversals.
 * Fixed a naming bug in Gremlin-Python where `P._and` and `P._or` should be `P.and_` and `P.or_`. (*breaking*)
 * `where()` predicate-based steps now support `by()`-modulation.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6f481b0b/docs/src/dev/io/graphml.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/io/graphml.asciidoc b/docs/src/dev/io/graphml.asciidoc
new file mode 100644
index 0000000..89eb0da
--- /dev/null
+++ b/docs/src/dev/io/graphml.asciidoc
@@ -0,0 +1,119 @@
+////
+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.
+////
+[[graphml]]
+GraphML
+=======
+
+image:gremlin-graphml.png[width=350,float=left] The link:http://graphml.graphdrawing.org/[GraphML] file format is a
+common XML-based representation of a graph. It uses an edge list format where vertices and their properties are listed
+and edges and their properties are listed by referencing the in and out vertices for each edge. GraphML does support a
+number of features which are not implemented by TinkerPop (e.g. extending GraphML with custom types) and there are
+features of TinkerPop that are not supported by GraphML (e.g. meta-properties), but GraphML does represent the most
+universal way to consume or produce a graph for integration with other systems as GraphML tends to have fairly wide
+support.
+
+In TinkerPop, GraphML is also not extended for purpose of serializing just any type (i.e. serialize just a `Vertex` to
+XML). It is only supported for a `Graph` instance.
+
+The following example is a representation of the Modern toy graph in GraphML:
+
+[source,xml]
+----
+<?xml version="1.0" encoding="UTF-8"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.1/graphml.xsd">
+  <key id="labelV" for="node" attr.name="labelV" attr.type="string" />
+  <key id="name" for="node" attr.name="name" attr.type="string" />
+  <key id="lang" for="node" attr.name="lang" attr.type="string" />
+  <key id="age" for="node" attr.name="age" attr.type="int" />
+  <key id="labelE" for="edge" attr.name="labelE" attr.type="string" />
+  <key id="weight" for="edge" attr.name="weight" attr.type="double" />
+  <graph id="G" edgedefault="directed">
+    <node id="1">
+      <data key="labelV">person</data>
+      <data key="name">marko</data>
+      <data key="age">29</data>
+    </node>
+    <node id="2">
+      <data key="labelV">person</data>
+      <data key="name">vadas</data>
+      <data key="age">27</data>
+    </node>
+    <node id="3">
+      <data key="labelV">software</data>
+      <data key="name">lop</data>
+      <data key="lang">java</data>
+    </node>
+    <node id="4">
+      <data key="labelV">person</data>
+      <data key="name">josh</data>
+      <data key="age">32</data>
+    </node>
+    <node id="5">
+      <data key="labelV">software</data>
+      <data key="name">ripple</data>
+      <data key="lang">java</data>
+    </node>
+    <node id="6">
+      <data key="labelV">person</data>
+      <data key="name">peter</data>
+      <data key="age">35</data>
+    </node>
+    <edge id="7" source="1" target="2">
+      <data key="labelE">knows</data>
+      <data key="weight">0.5</data>
+    </edge>
+    <edge id="8" source="1" target="4">
+      <data key="labelE">knows</data>
+      <data key="weight">1.0</data>
+    </edge>
+    <edge id="9" source="1" target="3">
+      <data key="labelE">created</data>
+      <data key="weight">0.4</data>
+    </edge>
+    <edge id="10" source="4" target="5">
+      <data key="labelE">created</data>
+      <data key="weight">1.0</data>
+    </edge>
+    <edge id="11" source="4" target="3">
+      <data key="labelE">created</data>
+      <data key="weight">0.4</data>
+    </edge>
+    <edge id="12" source="6" target="3">
+      <data key="labelE">created</data>
+      <data key="weight">0.2</data>
+    </edge>
+  </graph>
+</graphml>
+----
+
+Consider the following points when reading a GraphML file to TinkerPop that was generated outside of TinkerPop:
+
+* Supports the following values in `attr.type`:
+** `string`
+** `float`
+** `double`
+** `int`
+** `long`
+** `boolean`
+* Does not currently support the `<default>` tag in the schema definitions.
+* The GraphML will be read as a directed graph regardless of the value supplied `edgedefault` setting in the `<graph>`
+tag as that is the nature of the type of graph that TinkerPop supports.
+* The vertex and edge `id` values will always be treated as a `String` if the `Graph` instance consuming the data
+supports user-supplied identifiers (i.e. TinkerGraph).
+* By default the labels for vertex and edges are referred to as "labelV" and "labelE" respectively. It is possible to
+change these defaults on the `Builder` for the `GraphReader`. If no label is supplied, the reader will default to
+"vertex" and "edge" respectively as is the general expectation in TinkerPop when those values are omitted.
\ No newline at end of file