Skip to content

Commit

Permalink
SNOW-902610 Min pool size
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-knozderko committed Mar 21, 2024
1 parent db8130a commit 3ad6b97
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Snowflake.Data.Client;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
{
[TestFixture]
[NonParallelizable]
public class ConnectionMultiplePoolsAsyncIT: SFBaseTestAsync
{
private readonly PoolConfig _previousPoolConfig = new PoolConfig();

[SetUp]
public new void BeforeTest()
{
SnowflakeDbConnectionPool.SetConnectionPoolVersion(ConnectionPoolType.MultipleConnectionPool);
SnowflakeDbConnectionPool.ClearAllPools();
}

[TearDown]
public new void AfterTest()
{
_previousPoolConfig.Reset();
}

[Test]
public async Task TestMinPoolSizeAsync()
{
// arrange
var connection = new SnowflakeDbConnection();
connection.ConnectionString = ConnectionString + "application=TestMinPoolSizeAsync;minPoolSize=3";

// act
await connection.OpenAsync().ConfigureAwait(false);
Thread.Sleep(3000);

// assert
var pool = SnowflakeDbConnectionPool.GetPool(connection.ConnectionString);
Assert.AreEqual(3, pool.GetCurrentPoolSize());

// cleanup
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);
}
}
}
57 changes: 39 additions & 18 deletions Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsIT.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Snowflake.Data.Client;
Expand Down Expand Up @@ -51,37 +52,38 @@ public void TestBasicConnectionPool()
[Test]
public void TestReuseSessionInConnectionPool() // old name: TestConnectionPool
{
var conn1 = new SnowflakeDbConnection(ConnectionString);
var connectionString = ConnectionString + "minPoolSize=1";
var conn1 = new SnowflakeDbConnection(connectionString);
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);
conn1.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(connectionString).GetCurrentPoolSize());

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

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

[Test]
public void TestReuseSessionInConnectionPoolReachingMaxConnections() // old name: TestConnectionPoolFull
{
var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
pool.SetMaxPoolSize(2);
var connectionString = ConnectionString + "maxPoolSize=2;minPoolSize=1";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);

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

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

Expand All @@ -91,12 +93,12 @@ public void TestReuseSessionInConnectionPoolReachingMaxConnections() // old name
Assert.AreEqual(2, pool.GetCurrentPoolSize());

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

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

Expand All @@ -115,7 +117,7 @@ public void TestReuseSessionInConnectionPoolReachingMaxConnections() // old name
public void TestWaitForTheIdleConnectionWhenExceedingMaxConnectionsLimit()
{
// arrange
var connectionString = ConnectionString + "application=TestWaitForMaxSize1;waitingForIdleSessionTimeout=1s;maxPoolSize=2";
var connectionString = ConnectionString + "application=TestWaitForMaxSize1;waitingForIdleSessionTimeout=1s;maxPoolSize=2;minPoolSize=1";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
Assert.AreEqual(0, pool.GetCurrentPoolSize(), "expecting pool to be empty");
var conn1 = OpenedConnection(connectionString);
Expand All @@ -141,7 +143,7 @@ public void TestWaitForTheIdleConnectionWhenExceedingMaxConnectionsLimit()
public void TestWaitForTheIdleConnectionWhenExceedingMaxConnectionsLimitAsync()
{
// arrange
var connectionString = ConnectionString + "application=TestWaitForMaxSize2;waitingForIdleSessionTimeout=1s;maxPoolSize=2";
var connectionString = ConnectionString + "application=TestWaitForMaxSize2;waitingForIdleSessionTimeout=1s;maxPoolSize=2;minPoolSize=1";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
Assert.AreEqual(0, pool.GetCurrentPoolSize(), "expecting pool to be empty");
var conn1 = OpenedConnection(connectionString);
Expand Down Expand Up @@ -224,10 +226,10 @@ public void TestWaitInAQueueForAnIdleSession()
public void TestBusyAndIdleConnectionsCountedInPoolSize()
{
// arrange
var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
pool.SetMaxPoolSize(2);
var connectionString = ConnectionString + "maxPoolSize=2;minPoolSize=1";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
var connection = new SnowflakeDbConnection();
connection.ConnectionString = ConnectionString;
connection.ConnectionString = connectionString;

// act
connection.Open();
Expand Down Expand Up @@ -279,7 +281,7 @@ public void TestConnectionPoolDisable()
[Test]
public void TestNewConnectionPoolClean()
{
var connectionString = ConnectionString + "maxPoolSize=2;";
var connectionString = ConnectionString + "maxPoolSize=2;minPoolSize=1;";
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = connectionString;
conn1.Open();
Expand Down Expand Up @@ -313,7 +315,7 @@ public void TestNewConnectionPoolClean()
[Test]
public void TestConnectionPoolExpirationWorks()
{
var connectionString = ConnectionString + "expirationTimeout=0;maxPoolSize=2";
var connectionString = ConnectionString + "expirationTimeout=0;maxPoolSize=2;minPoolSize=1";
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = connectionString;
conn1.Open();
Expand All @@ -333,6 +335,25 @@ public void TestConnectionPoolExpirationWorks()
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(connectionString).GetCurrentPoolSize());
}

[Test]
public void TestMinPoolSize()
{
// arrange
var connection = new SnowflakeDbConnection();
connection.ConnectionString = ConnectionString + "application=TestMinPoolSize;minPoolSize=3";

// act
connection.Open();
Thread.Sleep(3000);

// assert
var pool = SnowflakeDbConnectionPool.GetPool(connection.ConnectionString);
Assert.AreEqual(3, pool.GetCurrentPoolSize());

// cleanup
connection.Close();
}

private SnowflakeDbConnection OpenedConnection(string connectionString)
{
var connection = new SnowflakeDbConnection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public void TestConnectionPoolWithDispose()
conn1.ConnectionString = "bad connection string";
Assert.Throws<SnowflakeDbException>(() => conn1.Open());
conn1.Close();
Thread.Sleep(3000); // minPoolSize = 2 causes that another thread has been started. We sleep to make that thread finish.

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
Expand Down
4 changes: 2 additions & 2 deletions Snowflake.Data.Tests/UnitTests/ConnectionPoolManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ namespace Snowflake.Data.Tests.UnitTests
class ConnectionPoolManagerTest
{
private readonly ConnectionPoolManager _connectionPoolManager = new ConnectionPoolManager();
private const string ConnectionString1 = "database=D1;warehouse=W1;account=A1;user=U1;password=P1;role=R1;";
private const string ConnectionString2 = "database=D2;warehouse=W2;account=A2;user=U2;password=P2;role=R2;";
private const string ConnectionString1 = "database=D1;warehouse=W1;account=A1;user=U1;password=P1;role=R1;minPoolSize=1;";
private const string ConnectionString2 = "database=D2;warehouse=W2;account=A2;user=U2;password=P2;role=R2;minPoolSize=1;";
private readonly SecureString _password = new SecureString();
private static PoolConfig s_poolConfig;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Linq;
using NUnit.Framework;
using Snowflake.Data.Core;
using Snowflake.Data.Core.Session;

namespace Snowflake.Data.Tests.UnitTests.Session
{
[TestFixture]
public class SessionOrCreationTokensTest
{
private SFSession _session = new SFSession("account=test;user=test;password=test", null);

[Test]
public void TestNoBackgroundSessionsToCreateWhenInitialisedWithSession()
{
// arrange
var sessionOrTokens = new SessionOrCreationTokens(_session);

// act
var backgroundCreationTokens = sessionOrTokens.BackgroundSessionCreationTokens();

Assert.AreEqual(0, backgroundCreationTokens.Count);
}

[Test]
public void TestReturnFirstCreationToken()
{
// arrange
var sessionCreationTokenCounter = new SessionCreationTokenCounter(TimeSpan.FromSeconds(10));
var tokens = Enumerable.Range(1, 3)
.Select(_ => sessionCreationTokenCounter.NewToken())
.ToList();
var sessionOrTokens = new SessionOrCreationTokens(tokens);

// act
var token = sessionOrTokens.SessionCreationToken();

// assert
Assert.AreSame(tokens[0], token);
}

[Test]
public void TestReturnCreationTokensFromTheSecondOneForBackgroundExecution()
{
// arrange
var sessionCreationTokenCounter = new SessionCreationTokenCounter(TimeSpan.FromSeconds(10));
var tokens = Enumerable.Range(1, 3)
.Select(_ => sessionCreationTokenCounter.NewToken())
.ToList();
var sessionOrTokens = new SessionOrCreationTokens(tokens);

// act
var backgroundTokens = sessionOrTokens.BackgroundSessionCreationTokens();

// assert
Assert.AreEqual(2, backgroundTokens.Count);
Assert.AreSame(tokens[1], backgroundTokens[0]);
Assert.AreSame(tokens[2], backgroundTokens[1]);
}
}
}
22 changes: 0 additions & 22 deletions Snowflake.Data/Core/Session/SessionOrCreationToken.cs

This file was deleted.

41 changes: 41 additions & 0 deletions Snowflake.Data/Core/Session/SessionOrCreationTokens.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Snowflake.Data.Core.Session
{
internal class SessionOrCreationTokens
{
private static readonly List<SessionCreationToken> s_emptySessionCreationTokenList = new List<SessionCreationToken>();

public SFSession Session { get; }
public List<SessionCreationToken> SessionCreationTokens { get; }

public SessionOrCreationTokens(SFSession session)
{
Session = session ?? throw new Exception("Internal error: missing session");
SessionCreationTokens = s_emptySessionCreationTokenList;
}

public SessionOrCreationTokens(List<SessionCreationToken> sessionCreationTokens)
{
Session = null;
if (sessionCreationTokens == null || sessionCreationTokens.Count == 0)
{
throw new Exception("Internal error: missing session creation token");

Check warning on line 25 in Snowflake.Data/Core/Session/SessionOrCreationTokens.cs

View check run for this annotation

Codecov / codecov/patch

Snowflake.Data/Core/Session/SessionOrCreationTokens.cs#L24-L25

Added lines #L24 - L25 were not covered by tests
}
SessionCreationTokens = sessionCreationTokens;
}

public List<SessionCreationToken> BackgroundSessionCreationTokens()
{
if (Session == null)
{
return SessionCreationTokens.Skip(1).ToList();
}
return SessionCreationTokens;
}

public SessionCreationToken SessionCreationToken() => SessionCreationTokens.First();
}
}
Loading

0 comments on commit 3ad6b97

Please sign in to comment.