Skip to content

Commit

Permalink
SNOW-902611
Browse files Browse the repository at this point in the history
- removed singleton pattern from SessionPool; introduced new interface for ConnectionManager; split tests of ConnectionPool and some cleanup in the classes
SNOW-902608
- new Connection Pool Manager version implementation
- unit tests for new pool; introduction of SessionFactory for unit testing of new pool manager and session pooling
- integration tests for two versions of Connection Pool
- ClearAllPools removes entire SessionPools collection in new pool
- Fixes to flaky tests of connection pool
  • Loading branch information
sfc-gh-mhofman committed Nov 9, 2023
1 parent 22d32dd commit c401f2c
Show file tree
Hide file tree
Showing 16 changed files with 817 additions and 83 deletions.
12 changes: 12 additions & 0 deletions CodingConventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ public class ExampleClass
}
```

#### Property

Use PascalCase, eg. `SomeProperty`.

```csharp
public ExampleProperty
{
get;
set;
}
```

### Local variables

Use camelCase, eg. `someVariable`.
Expand Down
173 changes: 134 additions & 39 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionPoolIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,43 @@
* Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
*/

using Snowflake.Data.Tests.Util;
using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Snowflake.Data.Core;
using Snowflake.Data.Client;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Log;
using NUnit.Framework;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
{
[TestFixture, NonParallelizable]
[TestFixture(ConnectionPoolType.SingleConnectionCache)]
[TestFixture(ConnectionPoolType.MultipleConnectionPool)]
[NonParallelizable]
class SFConnectionPoolIT : SFBaseTest
{
private readonly ConnectionPoolType _connectionPoolTypeUnderTest;
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<ConnectionPoolManager>();
private static PoolConfig s_previousPoolConfig;

[OneTimeSetUp]
public static void BeforeAllTests()
public SFConnectionPoolIT(ConnectionPoolType connectionPoolTypeUnderTest)
{
_connectionPoolTypeUnderTest = connectionPoolTypeUnderTest;
s_previousPoolConfig = new PoolConfig();
}

[SetUp]
public new void BeforeTest()
{
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.SetConnectionPoolVersion(_connectionPoolTypeUnderTest);
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetPooling(true);
s_logger.Debug($"---------------- BeforeTest ---------------------");
s_logger.Debug($"Testing Pool Type: {SnowflakeDbConnectionPool.GetConnectionPoolVersion()}");
}

[TearDown]
Expand Down Expand Up @@ -74,6 +82,7 @@ static void ConcurrentPoolingHelper(string connectionString, bool closeConnectio
const int PoolTimeout = 3;

// reset to default settings in case it changed by other test cases
Assert.AreEqual(true, SnowflakeDbConnectionPool.GetPool(connectionString).GetPooling()); // to instantiate pool
SnowflakeDbConnectionPool.SetMaxPoolSize(10);
SnowflakeDbConnectionPool.SetTimeout(PoolTimeout);

Expand All @@ -86,8 +95,6 @@ static void ConcurrentPoolingHelper(string connectionString, bool closeConnectio
});
}
Task.WaitAll(threads);
// set pooling timeout back to default to avoid impact on other test cases
SnowflakeDbConnectionPool.SetTimeout(3600);
}

// thead to execute query with new connection in a loop
Expand Down Expand Up @@ -140,7 +147,7 @@ public void TestBasicConnectionPool()
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
}

[Test]
Expand All @@ -150,47 +157,49 @@ public void TestConnectionPool()
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);
conn1.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString;
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());

conn2.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestConnectionPoolIsFull()
{
var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString + " retryCount=1";
conn2.ConnectionString = ConnectionString;
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);

var conn3 = new SnowflakeDbConnection();
conn3.ConnectionString = ConnectionString + " retryCount=2";
conn3.ConnectionString = ConnectionString;
conn3.Open();
Assert.AreEqual(ConnectionState.Open, conn3.State);
SnowflakeDbConnectionPool.ClearAllPools();
pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
SnowflakeDbConnectionPool.SetMaxPoolSize(2);

conn1.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, pool.GetCurrentPoolSize());
conn2.Close();
Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(2, pool.GetCurrentPoolSize());
conn3.Close();
Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(2, pool.GetCurrentPoolSize());

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Expand Down Expand Up @@ -223,13 +232,14 @@ public void TestConnectionPoolExpirationWorks()
// The pooling timeout should apply to all connections being pooled,
// not just the connections created after the new setting,
// so expected result should be 0
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
SnowflakeDbConnectionPool.SetPooling(false);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
}

[Test]
public void TestConnectionPoolClean()
{
TestOnlyForOldPool();

SnowflakeDbConnectionPool.SetMaxPoolSize(2);
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
Expand Down Expand Up @@ -257,12 +267,49 @@ public void TestConnectionPoolClean()
Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Assert.AreEqual(ConnectionState.Closed, conn3.State);
}

[Test]
public void TestNewConnectionPoolClean()
{
TestOnlyForNewPool();

SnowflakeDbConnectionPool.SetMaxPoolSize(2);
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString + " retryCount=1";
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);

var conn3 = new SnowflakeDbConnection();
conn3.ConnectionString = ConnectionString + " retryCount=2";
conn3.Open();
Assert.AreEqual(ConnectionState.Open, conn3.State);

conn1.Close();
conn2.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(conn2.ConnectionString).GetCurrentPoolSize());
SnowflakeDbConnectionPool.ClearAllPools();
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn2.ConnectionString).GetCurrentPoolSize());
conn3.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(conn3.ConnectionString).GetCurrentPoolSize());

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Assert.AreEqual(ConnectionState.Closed, conn3.State);
}

[Test]
public void TestConnectionPoolFull()
{
TestOnlyForOldPool();

SnowflakeDbConnectionPool.SetMaxPoolSize(2);

var conn1 = new SnowflakeDbConnection();
Expand Down Expand Up @@ -300,6 +347,50 @@ public void TestConnectionPoolFull()
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestNewConnectionPoolFull()
{
TestOnlyForNewPool();

var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
pool.SetMaxPoolSize(2);

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString;
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);

Assert.AreEqual(0, pool.GetCurrentPoolSize());
conn1.Close();
conn2.Close();
Assert.AreEqual(2, pool.GetCurrentPoolSize());

var conn3 = new SnowflakeDbConnection();
conn3.ConnectionString = ConnectionString;
conn3.Open();
Assert.AreEqual(ConnectionState.Open, conn3.State);

var conn4 = new SnowflakeDbConnection();
conn4.ConnectionString = ConnectionString;
conn4.Open();
Assert.AreEqual(ConnectionState.Open, conn4.State);

conn3.Close();
Assert.AreEqual(1, pool.GetCurrentPoolSize()); // TODO: when SNOW-937189 complete should be 2
conn4.Close();
Assert.AreEqual(2, pool.GetCurrentPoolSize());

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Assert.AreEqual(ConnectionState.Closed, conn3.State);
Assert.AreEqual(ConnectionState.Closed, conn4.State);
}

[Test]
public void TestConnectionPoolMultiThreading()
{
Expand Down Expand Up @@ -335,6 +426,7 @@ void ThreadProcess2(string connstr)
SFBaseResultSet resultSet = statement.Execute(0, "select 1", null, false);
Assert.AreEqual(true, resultSet.Next());
Assert.AreEqual("1", resultSet.GetString(0));
conn1.Close();
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(0);
SnowflakeDbConnectionPool.SetPooling(false);
Expand All @@ -343,7 +435,8 @@ void ThreadProcess2(string connstr)
[Test]
public void TestConnectionPoolDisable()
{
SnowflakeDbConnectionPool.SetPooling(false);
var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
pool.SetPooling(false);

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
Expand All @@ -352,27 +445,21 @@ public void TestConnectionPoolDisable()
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, pool.GetCurrentPoolSize());
}

[Test]
public void TestConnectionPoolWithDispose()
{
SnowflakeDbConnectionPool.SetMaxPoolSize(1);

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = "";
try
{
conn1.Open();
}
catch (SnowflakeDbException ex)
{
conn1.Close();
}
conn1.ConnectionString = "bad connection string";
Assert.Throws<SnowflakeDbException>(() => conn1.Open());
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
}

[Test]
Expand All @@ -381,7 +468,6 @@ public void TestConnectionPoolTurnOff()
SnowflakeDbConnectionPool.SetPooling(false);
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.SetMaxPoolSize(1);
SnowflakeDbConnectionPool.ClearAllPools();

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
Expand All @@ -390,10 +476,19 @@ public void TestConnectionPoolTurnOff()
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());

SnowflakeDbConnectionPool.SetPooling(false);
//Put a breakpoint at SFSession close function, after connection pool is off, it will send close session request.
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
}

private void TestOnlyForOldPool()
{
if (_connectionPoolTypeUnderTest != ConnectionPoolType.SingleConnectionCache)
Assert.Ignore($"Test case relates only to {ConnectionPoolType.SingleConnectionCache} pool type");
}

private void TestOnlyForNewPool()
{
if (_connectionPoolTypeUnderTest != ConnectionPoolType.MultipleConnectionPool)
Assert.Ignore($"Test case relates only to {ConnectionPoolType.MultipleConnectionPool} pool type");
}
}
}
Loading

0 comments on commit c401f2c

Please sign in to comment.