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/09/28 18:48:39 UTC

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

Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1467-master [created] 6c84a71f5


Merge remote-tracking branch 'origin/TINKERPOP-1467' into TINKERPOP-1467-master

Conflicts:
	CHANGELOG.asciidoc
	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
	gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 6c84a71f5b50ba9e8a96b8ec766f26f1c8132b72
Parents: 7a4a836 934054f
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Sep 28 14:05:27 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Sep 28 14:05:27 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       | 22 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 56 +++++++++++++--
 .../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      | 74 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 241 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6c84a71f/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index 47d4bbf,66706d9..fba659b
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -421,7 -26,7 +421,8 @@@ image::https://raw.githubusercontent.co
  TinkerPop 3.1.5 (Release Date: NOT OFFICIALLY RELEASED YET)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
 +* Fixed output redirection and potential memory leak in `GremlinGroovyScriptEngine`.
+ * Improved handling of `Cluster.close()` and `Client.close()` to prevent the methods from hanging.
  * 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.
  * Removed the `appveyor.yml` file as the AppVeyor build is no longer enabled by Apache Infrastructure.

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

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6c84a71f/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/6c84a71f/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 f79e719,473991a..f426a3c
--- 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,21 -123,13 +124,23 @@@
       * @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);
++        final Client client = connect(settings);
+         manager.trackClient(client);
+         return (T) client;
      }
  
 +    /**
 +     * 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);
 +    }
 +
      @Override
      public String toString() {
          return manager.toString();
@@@ -862,12 -687,10 +867,14 @@@
  
          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) {
              this.loadBalancingStrategy = builder.loadBalancingStrategy;
              this.authProps = builder.authProps;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6c84a71f/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 1ef9b98,766db2e..8576de5
--- 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
@@@ -153,15 -150,12 +154,16 @@@ final class Connection 
          return pending;
      }
  
-     public CompletableFuture<Void> closeAsync() {
+     public synchronized CompletableFuture<Void> closeAsync() {
+         if (isClosed()) 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/6c84a71f/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
----------------------------------------------------------------------

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

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

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

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6c84a71f/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,8f24de2..5c0e903
--- 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;