[ 
https://issues.apache.org/jira/browse/TINKERPOP-1774?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16598780#comment-16598780
 ] 

ASF GitHub Bot commented on TINKERPOP-1774:
-------------------------------------------

Github user FlorianHockmann commented on a diff in the pull request:

    https://github.com/apache/tinkerpop/pull/903#discussion_r214373377
  
    --- Diff: gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPool.cs ---
    @@ -33,91 +34,135 @@ internal class ConnectionPool : IDisposable
         {
             private readonly ConnectionFactory _connectionFactory;
             private readonly ConcurrentBag<Connection> _connections = new 
ConcurrentBag<Connection>();
    -        private readonly object _connectionsLock = new object();
    +        private readonly AsyncAutoResetEvent _newConnectionAvailable = new 
AsyncAutoResetEvent();
    +        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) ??
    +                         await 
WaitForConnectionAsync().ConfigureAwait(false);
    +            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().ConfigureAwait(false);
             }
     
             private async Task<Connection> CreateNewConnectionAsync()
             {
    -            NrConnections++;
                 var newConnection = _connectionFactory.CreateConnection();
                 await newConnection.ConnectAsync().ConfigureAwait(false);
                 return newConnection;
             }
     
    -        private void AddConnectionIfOpen(Connection connection)
    +        private async Task<Connection> WaitForConnectionAsync()
             {
    -            if (!connection.IsOpen)
    +            var start = DateTimeOffset.Now;
    +            var remaining = _waitForConnectionTimeout;
    +            do
    --- End diff --
    
    The problem is that another thread can call `TryGetConnectionFromPool` 
without waiting for a signal on `_newConnectionAvailable` as that's the first 
thing happening in `GetAvailableConnectionAsync`.
    So, even if we get a signal that a new connection is available, we still 
can't be sure that we are actually getting this connection. Therefore, the 
thread can wait again for another signal until it actually reaches its timeout. 
(The Java driver does it the same way.)


> Gremlin .NET: Support min and max sizes in Connection pool
> ----------------------------------------------------------
>
>                 Key: TINKERPOP-1774
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-1774
>             Project: TinkerPop
>          Issue Type: Improvement
>          Components: dotnet
>    Affects Versions: 3.2.7
>            Reporter: Jorge Bay
>            Assignee: Florian Hockmann
>            Priority: Minor
>
> Similar to the java connection pool, we should limit the maximum amount of 
> connections and start with a minimum number.
> It would also a good opportunity to remove the synchronous acquisitions of 
> {{lock}} in the pool implementation.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to