Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1774 9761de177 -> 6ee8033ae (forced update)


Add ConnectionPool min and max sizes TINKERPOP-1774

The Gremlin.Net ConnectionPool now has min and max sizes. The pool will
be initialized with the configured minimum number of connections on
creation. It will also no longer create an unlimited number of
connections. Instead, a TimeoutException will be thrown when the max
limit is reached and no connection became available within a
configurable time.


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

Branch: refs/heads/TINKERPOP-1774
Commit: 6ee8033ae171df5ff0781f2026bf5d178091017c
Parents: 7d21ee0
Author: Florian Hockmann <f...@florian-hockmann.de>
Authored: Mon Jul 30 21:45:26 2018 +0200
Committer: Florian Hockmann <f...@florian-hockmann.de>
Committed: Tue Jul 31 18:47:19 2018 +0200

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   1 +
 docs/src/upgrade/release-3.4.x.asciidoc         |  11 ++
 .../src/Gremlin.Net/Driver/Connection.cs        |  16 +--
 .../src/Gremlin.Net/Driver/ConnectionPool.cs    | 129 +++++++++++++------
 .../Driver/ConnectionPoolSettings.cs            |  55 ++++++++
 .../src/Gremlin.Net/Driver/GremlinClient.cs     |   7 +-
 .../Driver/GremlinClientExtensions.cs           |  12 +-
 .../Driver/Remote/DriverRemoteConnection.cs     |   4 +-
 .../Gremlin.Net/Driver/WebSocketConnection.cs   |  16 +--
 .../Process/Traversal/GraphTraversal.cs         |   9 --
 .../Driver/ConnectionPoolTests.cs               |  70 ++++++++--
 .../RemoteConnectionFactory.cs                  |   4 +-
 12 files changed, 241 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 3054085..930fab5 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 This release also includes changes from <<release-3-3-3, 3.3.3>>.
 
+* Added min and max connection pool sizes for Gremlin.Net which are 
configurable through optional ConnectionPoolSettings.
 * Bumped to Netty 4.1.25.
 * Bumped to Spark 2.3.1.
 * Moved `Parameterizing` interface to the 
`org.apache.tinkerpop.gremlin.process.traversal.step` package with other marker 
interfaces of its type.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/docs/src/upgrade/release-3.4.x.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.4.x.asciidoc 
b/docs/src/upgrade/release-3.4.x.asciidoc
index 2d699dc..5aec7d9 100644
--- a/docs/src/upgrade/release-3.4.x.asciidoc
+++ b/docs/src/upgrade/release-3.4.x.asciidoc
@@ -150,6 +150,17 @@ when dealing with that event. To make this easier, the 
event now raises with a `
 
 link:https://issues.apache.org/jira/browse/TINKERPOP-1831[TINKERPOP-1831]
 
+==== Gremlin.Net: Configurable Max and Min ConnectionPool Sizes
+
+Gremlin.Net's `ConnectionPool` now has a minimum and a maximum size. These 
sizes are configurable through added
+`ConnectionPoolSettings`. The minimum size determines how many connections are 
initially created. The maximum size
+is an upper limit of connections that can be created. When this limit is 
reached and another connection is needed,
+then the connection pool waits for a connection to become available again. The 
time to be waited is limited by the
+newly introduced option `ConnectionPoolSettings.WaitForConnectionTimeout`. A 
`TimeoutException` is thrown when
+no connection becomes available until this timeout is reached.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1774[TINKERPOP-1774]
+
 ==== Deprecation Removal
 
 The following deprecated classes, methods or fields have been removed in this 
version:

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
index 279c708..2452e3e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
@@ -59,23 +59,23 @@ namespace Gremlin.Net.Driver
             return await ReceiveAsync<T>().ConfigureAwait(false);
         }
 
-        public async Task ConnectAsync()
+        public Task ConnectAsync()
         {
-            await 
_webSocketConnection.ConnectAsync(_uri).ConfigureAwait(false);
+            return _webSocketConnection.ConnectAsync(_uri);
         }
 
-        public async Task CloseAsync()
+        public Task CloseAsync()
         {
-            await _webSocketConnection.CloseAsync().ConfigureAwait(false);
+            return _webSocketConnection.CloseAsync();
         }
 
         public bool IsOpen => _webSocketConnection.IsOpen;
 
-        private async Task SendAsync(RequestMessage message)
+        private Task SendAsync(RequestMessage message)
         {
             var graphsonMsg = _graphSONWriter.WriteObject(message);
             var serializedMsg = 
_messageSerializer.SerializeMessage(graphsonMsg);
-            await 
_webSocketConnection.SendMessageAsync(serializedMsg).ConfigureAwait(false);
+            return _webSocketConnection.SendMessageAsync(serializedMsg);
         }
 
         private async Task<IReadOnlyCollection<T>> ReceiveAsync<T>()
@@ -121,7 +121,7 @@ namespace Gremlin.Net.Driver
             return result;
         }
 
-        private async Task AuthenticateAsync()
+        private Task AuthenticateAsync()
         {
             if (string.IsNullOrEmpty(_username) || 
string.IsNullOrEmpty(_password))
                 throw new InvalidOperationException(
@@ -130,7 +130,7 @@ namespace Gremlin.Net.Driver
             var message = 
RequestMessage.Build(Tokens.OpsAuthentication).Processor(Tokens.ProcessorTraversal)
                 .AddArgument(Tokens.ArgsSasl, SaslArgument()).Create();
 
-            await SendAsync(message).ConfigureAwait(false);
+            return SendAsync(message);
         }
 
         private string SaslArgument()

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPool.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPool.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPool.cs
index d9e53f4..b72695e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPool.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPool.cs
@@ -23,7 +23,8 @@
 
 using System;
 using System.Collections.Concurrent;
-using System.Linq;
+using System.Collections.Generic;
+using System.Threading;
 using System.Threading.Tasks;
 using Gremlin.Net.Process;
 
@@ -33,91 +34,134 @@ namespace Gremlin.Net.Driver
     {
         private readonly ConnectionFactory _connectionFactory;
         private readonly ConcurrentBag<Connection> _connections = new 
ConcurrentBag<Connection>();
-        private readonly object _connectionsLock = new object();
+        private readonly AutoResetEvent _newConnectionAvailable = new 
AutoResetEvent(false);
+        private readonly int _minPoolSize;
+        private readonly int _maxPoolSize;
+        private readonly TimeSpan _waitForConnectionTimeout;
+        private int _nrConnections;
 
-        public ConnectionPool(ConnectionFactory connectionFactory)
+        public ConnectionPool(ConnectionFactory connectionFactory, 
ConnectionPoolSettings settings)
         {
             _connectionFactory = connectionFactory;
+            _minPoolSize = settings.MinSize;
+            _maxPoolSize = settings.MaxSize;
+            _waitForConnectionTimeout = settings.WaitForConnectionTimeout;
+            PopulatePoolAsync().WaitUnwrap();
         }
 
-        public int NrConnections { get; private set; }
+        public int NrConnections => Interlocked.CompareExchange(ref 
_nrConnections, 0, 0);
+
+        private async Task PopulatePoolAsync()
+        {
+            var connectionCreationTasks = new 
List<Task<Connection>>(_minPoolSize);
+            for (var i = 0; i < _minPoolSize; i++)
+            {
+                connectionCreationTasks.Add(CreateNewConnectionAsync());
+            }
+
+            var createdConnections = await 
Task.WhenAll(connectionCreationTasks).ConfigureAwait(false);
+            foreach (var c in createdConnections)
+            {
+                _connections.Add(c);
+            }
+
+            Interlocked.CompareExchange(ref _nrConnections, _minPoolSize, 0);
+        }
 
         public async Task<IConnection> GetAvailableConnectionAsync()
         {
-            if (!TryGetConnectionFromPool(out var connection))
-                connection = await 
CreateNewConnectionAsync().ConfigureAwait(false);
+            if (TryGetConnectionFromPool(out var connection))
+                return ProxiedConnection(connection);
+            connection = await 
AddConnectionIfUnderMaximumAsync().ConfigureAwait(false) ?? WaitForConnection();
+            return ProxiedConnection(connection);
+        }
 
-            return new ProxyConnection(connection, AddConnectionIfOpen);
+        private IConnection ProxiedConnection(Connection connection)
+        {
+            return new ProxyConnection(connection, ReturnConnectionIfOpen);
         }
 
-        private bool TryGetConnectionFromPool(out Connection connection)
+        private void ReturnConnectionIfOpen(Connection connection)
+        {
+            if (!connection.IsOpen)
+            {
+                ConsiderUnavailable();
+                DefinitelyDestroyConnection(connection);
+                return;
+            }
+
+            _connections.Add(connection);
+            _newConnectionAvailable.Set();
+        }
+
+        private async Task<Connection> AddConnectionIfUnderMaximumAsync()
         {
             while (true)
             {
-                connection = null;
-                lock (_connectionsLock)
-                {
-                    if (_connections.IsEmpty) return false;
-                    _connections.TryTake(out connection);
-                }
+                var nrOpened = Interlocked.CompareExchange(ref _nrConnections, 
0, 0);
+                if (nrOpened >= _maxPoolSize) return null;
 
-                if (connection.IsOpen) return true;
-                connection.Dispose();
+                if (Interlocked.CompareExchange(ref _nrConnections, nrOpened + 
1, nrOpened) == nrOpened)
+                    break;
             }
+
+            return await CreateNewConnectionAsync();
         }
 
         private async Task<Connection> CreateNewConnectionAsync()
         {
-            NrConnections++;
             var newConnection = _connectionFactory.CreateConnection();
             await newConnection.ConnectAsync().ConfigureAwait(false);
             return newConnection;
         }
 
-        private void AddConnectionIfOpen(Connection connection)
+        private Connection WaitForConnection()
         {
-            if (!connection.IsOpen)
+            var start = DateTimeOffset.Now;
+            var remaining = _waitForConnectionTimeout;
+            do
             {
-                ConsiderUnavailable();
-                connection.Dispose();
-                return;
-            }
-            AddConnection(connection);
+                if (_newConnectionAvailable.WaitOne(remaining))
+                {
+                    if (TryGetConnectionFromPool(out var connection))
+                        return connection;
+                }
+                remaining = _waitForConnectionTimeout - (DateTimeOffset.Now - 
start);
+            } while (remaining > TimeSpan.Zero);
+
+            ConsiderUnavailable();
+            throw new TimeoutException("Timed out while waiting for an 
available connection.");
         }
 
-        private void AddConnection(Connection connection)
+        private bool TryGetConnectionFromPool(out Connection connection)
         {
-            lock (_connectionsLock)
+            while (true)
             {
-                _connections.Add(connection);
+                _connections.TryTake(out connection);
+                if (connection == null) return false; // _connections is empty
+                if (connection.IsOpen) return true;
+                DefinitelyDestroyConnection(connection);
             }
         }
 
         private void ConsiderUnavailable()
         {
-            CloseAndRemoveAllConnections();
-        }
-
-        private void CloseAndRemoveAllConnections()
-        {
-            lock (_connectionsLock)
-            {
-                TeardownAsync().WaitUnwrap();
-                RemoveAllConnections();
-            }
+            CloseAndRemoveAllConnectionsAsync().WaitUnwrap();
         }
 
-        private void RemoveAllConnections()
+        private async Task CloseAndRemoveAllConnectionsAsync()
         {
             while (_connections.TryTake(out var connection))
             {
-                connection.Dispose();
+                await connection.CloseAsync().ConfigureAwait(false);
+                DefinitelyDestroyConnection(connection);
             }
         }
 
-        private async Task TeardownAsync()
+        private void DefinitelyDestroyConnection(Connection connection)
         {
-            await Task.WhenAll(_connections.Select(c => 
c.CloseAsync())).ConfigureAwait(false);
+            connection.Dispose();
+            Interlocked.Decrement(ref _nrConnections);
         }
 
         #region IDisposable Support
@@ -135,10 +179,11 @@ namespace Gremlin.Net.Driver
             if (!_disposed)
             {
                 if (disposing)
-                    CloseAndRemoveAllConnections();
+                    CloseAndRemoveAllConnectionsAsync().WaitUnwrap();
                 _disposed = true;
             }
         }
+
         #endregion
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs
new file mode 100644
index 0000000..b156137
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs
@@ -0,0 +1,55 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+
+namespace Gremlin.Net.Driver
+{
+    /// <summary>
+    ///     Holds settings for the <see cref="ConnectionPool"/>.
+    /// </summary>
+    public class ConnectionPoolSettings
+    {
+        private const int DefaultMinPoolSize = 8;
+        private const int DefaultMaxPoolSize = 128;
+        private static readonly TimeSpan DefaultWaitForConnectionTimeout = 
TimeSpan.FromSeconds(3);
+
+        /// <summary>
+        ///     Gets or sets the minimum size of a connection pool.
+        /// </summary>
+        /// <remarks>The default value is 8.</remarks>
+        public int MinSize { get; set; } = DefaultMinPoolSize;
+
+        /// <summary>
+        ///     Gets or sets the maximum size of a connection pool.
+        /// </summary>
+        /// <remarks>The default value is 128.</remarks>
+        public int MaxSize { get; set; } = DefaultMaxPoolSize;
+
+        /// <summary>
+        ///     Gets or sets the timespan to wait for a new connection before 
timing out.
+        /// </summary>
+        /// <remarks>The default value is 3 seconds.</remarks>
+        public TimeSpan WaitForConnectionTimeout { get; set; } = 
DefaultWaitForConnectionTimeout;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
index 2b47cbc..41f08d1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
@@ -53,13 +53,16 @@ namespace Gremlin.Net.Driver
         /// <param name="graphSONReader">A <see cref="GraphSONReader" /> 
instance to read received GraphSON data.</param>
         /// <param name="graphSONWriter">a <see cref="GraphSONWriter" /> 
instance to write GraphSON data.</param>
         /// <param name="mimeType">The GraphSON version mime type, defaults to 
latest supported by the server.</param>
+        /// <param name="connectionPoolSettings">The <see 
cref="ConnectionPoolSettings"/> for the connection pool.</param>
         public GremlinClient(GremlinServer gremlinServer, GraphSONReader 
graphSONReader = null,
-                             GraphSONWriter graphSONWriter = null, string 
mimeType = null)
+            GraphSONWriter graphSONWriter = null, string mimeType = null,
+            ConnectionPoolSettings connectionPoolSettings = null)
         {
             var reader = graphSONReader ?? new GraphSON3Reader();
             var writer = graphSONWriter ?? new GraphSON3Writer();
             var connectionFactory = new ConnectionFactory(gremlinServer, 
reader, writer, mimeType ?? DefaultMimeType);
-            _connectionPool = new ConnectionPool(connectionFactory);
+            _connectionPool =
+                new ConnectionPool(connectionFactory, connectionPoolSettings 
?? new ConnectionPoolSettings());
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs
index 4aad73e..1365b2f 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClientExtensions.cs
@@ -92,10 +92,10 @@ namespace Gremlin.Net.Driver
         ///     Thrown when a response is received from Gremlin Server that 
indicates
         ///     that an error occurred.
         /// </exception>
-        public static async Task SubmitAsync(this IGremlinClient 
gremlinClient, string requestScript,
+        public static Task SubmitAsync(this IGremlinClient gremlinClient, 
string requestScript,
             Dictionary<string, object> bindings = null)
         {
-            await gremlinClient.SubmitAsync<object>(requestScript, 
bindings).ConfigureAwait(false);
+            return gremlinClient.SubmitAsync<object>(requestScript, bindings);
         }
 
         /// <summary>
@@ -109,9 +109,9 @@ namespace Gremlin.Net.Driver
         ///     Thrown when a response is received from Gremlin Server that 
indicates
         ///     that an error occurred.
         /// </exception>
-        public static async Task SubmitAsync(this IGremlinClient 
gremlinClient, RequestMessage requestMessage)
+        public static Task SubmitAsync(this IGremlinClient gremlinClient, 
RequestMessage requestMessage)
         {
-            await 
gremlinClient.SubmitAsync<object>(requestMessage).ConfigureAwait(false);
+            return gremlinClient.SubmitAsync<object>(requestMessage);
         }
 
         /// <summary>
@@ -126,7 +126,7 @@ namespace Gremlin.Net.Driver
         ///     Thrown when a response is received from Gremlin Server that 
indicates
         ///     that an error occurred.
         /// </exception>
-        public static async Task<IReadOnlyCollection<T>> SubmitAsync<T>(this 
IGremlinClient gremlinClient,
+        public static Task<IReadOnlyCollection<T>> SubmitAsync<T>(this 
IGremlinClient gremlinClient,
             string requestScript,
             Dictionary<string, object> bindings = null)
         {
@@ -134,7 +134,7 @@ namespace Gremlin.Net.Driver
             if (bindings != null)
                 msgBuilder.AddArgument(Tokens.ArgsBindings, bindings);
             var msg = msgBuilder.Create();
-            return await 
gremlinClient.SubmitAsync<T>(msg).ConfigureAwait(false);
+            return gremlinClient.SubmitAsync<T>(msg);
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
----------------------------------------------------------------------
diff --git 
a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
index 8cbd43d..2c3fc28 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
@@ -71,7 +71,7 @@ namespace Gremlin.Net.Driver.Remote
             return new DriverRemoteTraversal<S, E>(_client, requestId, 
resultSet);
         }
 
-        private async Task<IEnumerable<Traverser>> SubmitBytecodeAsync(Guid 
requestid, Bytecode bytecode)
+        private Task<IReadOnlyCollection<Traverser>> SubmitBytecodeAsync(Guid 
requestid, Bytecode bytecode)
         {
             var requestMsg =
                 RequestMessage.Build(Tokens.OpsBytecode)
@@ -80,7 +80,7 @@ namespace Gremlin.Net.Driver.Remote
                     .AddArgument(Tokens.ArgsGremlin, bytecode)
                     .AddArgument(Tokens.ArgsAliases, new Dictionary<string, 
string> {{"g", _traversalSource}})
                     .Create();
-            return await 
_client.SubmitAsync<Traverser>(requestMsg).ConfigureAwait(false);
+            return _client.SubmitAsync<Traverser>(requestMsg);
         }
 
         /// <inheritdoc />

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Driver/WebSocketConnection.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/WebSocketConnection.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/WebSocketConnection.cs
index 9672606..1196359 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/WebSocketConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/WebSocketConnection.cs
@@ -35,24 +35,20 @@ namespace Gremlin.Net.Driver
         private const WebSocketMessageType MessageType = 
WebSocketMessageType.Binary;
         private ClientWebSocket _client;
 
-        public async Task ConnectAsync(Uri uri)
+        public Task ConnectAsync(Uri uri)
         {
             _client = new ClientWebSocket();
-            await _client.ConnectAsync(uri, 
CancellationToken.None).ConfigureAwait(false);
+            return _client.ConnectAsync(uri, CancellationToken.None);
         }
 
-        public async Task CloseAsync()
+        public Task CloseAsync()
         {
-            await
-                _client.CloseAsync(WebSocketCloseStatus.NormalClosure, 
string.Empty, CancellationToken.None)
-                    .ConfigureAwait(false);
+            return _client.CloseAsync(WebSocketCloseStatus.NormalClosure, 
string.Empty, CancellationToken.None);
         }
 
-        public async Task SendMessageAsync(byte[] message)
+        public Task SendMessageAsync(byte[] message)
         {
-            await
-                _client.SendAsync(new ArraySegment<byte>(message), 
MessageType, true, CancellationToken.None)
-                    .ConfigureAwait(false);
+            return _client.SendAsync(new ArraySegment<byte>(message), 
MessageType, true, CancellationToken.None);
         }
 
         public async Task<byte[]> ReceiveMessageAsync()

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs 
b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index 990bc14..4979067 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -1703,14 +1703,5 @@ namespace Gremlin.Net.Process.Traversal
             return Wrap<S, E>(this);
         }
 
-        /// <summary>
-        ///     Adds the with step to this <see cref="GraphTraversal{SType, 
EType}" />.
-        /// </summary>
-        public GraphTraversal<S, E> With (string key, object value)
-        {
-            Bytecode.AddStep("with", key, value);
-            return Wrap<S, E>(this);
-        }
-
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ConnectionPoolTests.cs
----------------------------------------------------------------------
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ConnectionPoolTests.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ConnectionPoolTests.cs
index 21a2627..5515221 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ConnectionPoolTests.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ConnectionPoolTests.cs
@@ -49,8 +49,8 @@ namespace Gremlin.Net.IntegrationTest.Driver
         [Fact]
         public async Task ShouldReuseConnectionForSequentialRequests()
         {
-            var gremlinServer = new GremlinServer(TestHost, TestPort);
-            using (var gremlinClient = new GremlinClient(gremlinServer))
+            const int minConnectionPoolSize = 1;
+            using (var gremlinClient = 
CreateGremlinClient(minConnectionPoolSize))
             {
                 await gremlinClient.SubmitAsync("");
                 await gremlinClient.SubmitAsync("");
@@ -60,31 +60,75 @@ namespace Gremlin.Net.IntegrationTest.Driver
             }
         }
 
-        [Fact]
-        public void ShouldOnlyCreateConnectionWhenNecessary()
+        [Theory]
+        [InlineData(0)]
+        [InlineData(1)]
+        [InlineData(8)]
+        public void ShouldStartWithConfiguredNrMinConnections(int 
minConnectionPoolSize)
         {
-            var gremlinServer = new GremlinServer(TestHost, TestPort);
-            using (var gremlinClient = new GremlinClient(gremlinServer))
+            using (var gremlinClient = 
CreateGremlinClient(minConnectionPoolSize))
             {
                 var nrConnections = gremlinClient.NrConnections;
-                Assert.Equal(0, nrConnections);
+                Assert.Equal(minConnectionPoolSize, nrConnections);
             }
         }
 
         [Fact]
         public async Task ShouldExecuteParallelRequestsOnDifferentConnections()
         {
-            var gremlinServer = new GremlinServer(TestHost, TestPort);
-            using (var gremlinClient = new GremlinClient(gremlinServer))
+            const int nrParallelRequests = 5;
+            using (var gremlinClient = CreateGremlinClient(nrParallelRequests))
             {
-                var sleepTime = 50;
-                var nrParallelRequests = 5;
+                const int sleepTime = 50;
 
                 await 
ExecuteMultipleLongRunningRequestsInParallel(gremlinClient, nrParallelRequests, 
sleepTime);
 
-                var nrConnections = gremlinClient.NrConnections;
-                Assert.Equal(nrParallelRequests, nrConnections);
+                Assert.Equal(nrParallelRequests, gremlinClient.NrConnections);
+            }
+        }
+
+        [Theory]
+        [InlineData(1)]
+        [InlineData(2)]
+        [InlineData(4)]
+        public async Task 
ShouldNotCreateMoreThanConfiguredNrMaxConnections(int maxConnectionPoolSize)
+        {
+            using (var gremlinClient = 
CreateGremlinClient(maxConnectionPoolSize: maxConnectionPoolSize))
+            {
+                const int sleepTime = 100;
+
+                await 
ExecuteMultipleLongRunningRequestsInParallel(gremlinClient, 
maxConnectionPoolSize + 1, sleepTime);
+
+                Assert.Equal(maxConnectionPoolSize, 
gremlinClient.NrConnections);
             }
         }
+
+        [Fact]
+        public async Task 
ShouldThrowTimeoutExceptionWhenNoConnectionIsAvailable()
+        {
+            const int nrParallelRequests = 3;
+            const int waitForConnectionTimeoutInMs = 5;
+            using (var gremlinClient = 
CreateGremlinClient(maxConnectionPoolSize: nrParallelRequests - 1,
+                waitForConnectionTimeoutInMs: waitForConnectionTimeoutInMs))
+            {
+                const int sleepTime = 100;
+
+                await Assert.ThrowsAsync<TimeoutException>(() =>
+                    
ExecuteMultipleLongRunningRequestsInParallel(gremlinClient, nrParallelRequests, 
sleepTime));
+            }
+        }
+
+        private static GremlinClient CreateGremlinClient(int 
minConnectionPoolSize = 0, int maxConnectionPoolSize = 8,
+            int waitForConnectionTimeoutInMs = 5000)
+        {
+            var gremlinServer = new GremlinServer(TestHost, TestPort);
+            return new GremlinClient(gremlinServer,
+                connectionPoolSettings: new ConnectionPoolSettings
+                {
+                    MinSize = minConnectionPoolSize,
+                    MaxSize = maxConnectionPoolSize,
+                    WaitForConnectionTimeout = 
TimeSpan.FromMilliseconds(waitForConnectionTimeoutInMs)
+                });
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6ee8033a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
----------------------------------------------------------------------
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
index 39b7fea..088db59 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
@@ -44,7 +44,9 @@ namespace 
Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
 
         public IRemoteConnection CreateRemoteConnection(string traversalSource)
         {
-            var c = new DriverRemoteConnectionImpl(new GremlinClient(new 
GremlinServer(TestHost, TestPort)),
+            var c = new DriverRemoteConnectionImpl(
+                new GremlinClient(new GremlinServer(TestHost, TestPort),
+                    connectionPoolSettings: new ConnectionPoolSettings 
{MinSize = 1}),
                 traversalSource);
             _connections.Add(c);
             return c;

Reply via email to