Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-860872 connection pool #955

Merged
merged 29 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
af36804
pool/SNOW-902608 #2/4 new pool version v2 (#794)
sfc-gh-mhofman Nov 9, 2023
bf7a13e
pool/SNOW-937189 split pool tests (#815)
sfc-gh-knozderko Nov 20, 2023
56f0b81
Pool/SNOW-937189 busy sessions in pool (3/4) (#818)
sfc-gh-knozderko Nov 28, 2023
85204fc
SNOW-937190 Wait for idle sessions available (#840)
sfc-gh-knozderko Jan 29, 2024
052d895
SNOW-902632 connection string driven pool config (#873)
sfc-gh-knozderko Mar 25, 2024
0983d94
Pool/snow-902610 min pool size (#880)
sfc-gh-knozderko Apr 3, 2024
b842cbd
Fix flaky test TestWaitUntilResourceAvailable (#907)
sfc-gh-knozderko Apr 8, 2024
7db9d54
Pool/SNOW-937183 Prevent evicted connections from returning to the po…
sfc-gh-knozderko Apr 12, 2024
5a3c451
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko Apr 18, 2024
43d8fd4
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko Apr 23, 2024
4f2a167
SNOW-1344341 make new pool as a default one (#931)
sfc-gh-knozderko Apr 26, 2024
5de53f9
SNOW-986233 Log pool status (#936)
sfc-gh-knozderko May 7, 2024
ef2041a
Pool/SNOW-937188 changed session behavior (#937)
sfc-gh-mhofman May 13, 2024
9ac574e
SNOW-1406763 Test for password with special characters (#944)
sfc-gh-knozderko May 13, 2024
a9ade08
SNOW-1373257 Make secure password be a part of pool key (#942)
sfc-gh-knozderko May 14, 2024
97cceaf
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko May 14, 2024
fe51400
SNOW-1373131 disable connection pooling for external browser authenti…
sfc-gh-dstempniak May 14, 2024
ace8f90
Pool/SNOW-1417631 Disable pooling for jwt token authentication wit ke…
sfc-gh-knozderko May 15, 2024
b2b0ddc
Pool/SNOW-1337069 pool docs (#938)
sfc-gh-mhofman May 17, 2024
967528d
Fix pool flaky test (#950)
sfc-gh-knozderko May 17, 2024
00db393
Improve documentation (#951)
sfc-gh-knozderko May 17, 2024
45b428f
SNOW-968914 Log closing sessions (#952)
sfc-gh-knozderko May 20, 2024
b6e598f
SNOW-968914 Break waiting on pool destroy (#953)
sfc-gh-knozderko May 21, 2024
921b9df
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko May 23, 2024
815f708
SNOW-1337069 connection pool doc fix (#958)
sfc-gh-knozderko May 29, 2024
a4349d7
SNOW-1452613 Update secret detector (#961)
sfc-gh-knozderko Jun 6, 2024
4c8d516
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko Jun 7, 2024
f7ba608
Merge branch 'master' into pool/SNOW-860872-connection-pool
sfc-gh-knozderko Jun 12, 2024
53f74be
Fix review notes
sfc-gh-knozderko Jun 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: DotNet Build and Test
# Triggers the workflow on push or pull request events but only for the master branch
on:
push:
branches: [ master ]
branches: [ master, pool/SNOW-860872-connection-pool ]
sfc-gh-knozderko marked this conversation as resolved.
Show resolved Hide resolved
pull_request:
branches: [ master ]
branches: [ master, pool/SNOW-860872-connection-pool ]
workflow_dispatch:
inputs:
logLevel:
Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:
run: |
cd Snowflake.Data.Tests
dotnet restore
dotnet build -f ${{ matrix.dotnet }}
dotnet build -f ${{ matrix.dotnet }} '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:
- name: Build Driver
run: |
dotnet restore
dotnet build
dotnet build '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down Expand Up @@ -178,7 +178,7 @@ jobs:
- name: Build Driver
run: |
dotnet restore
dotnet build
dotnet build '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
repos:
- repo: [email protected]:snowflakedb/casec_precommit.git
rev: v1.20
rev: v1.35.4
hooks:
- id: secret-scanner
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
936 changes: 29 additions & 907 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using Snowflake.Data.Client;
using Snowflake.Data.Core;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Log;
using Snowflake.Data.Tests.Mock;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
{
[TestFixture]
[NonParallelizable]
public class ConnectionMultiplePoolsAsyncIT: SFBaseTestAsync
{
private readonly PoolConfig _previousPoolConfig = new PoolConfig();
private readonly SFLogger logger = SFLoggerFactory.GetLogger<SFConnectionIT>();

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

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

[Test]
public async Task TestAddToPoolOnOpenAsync()
{
// arrange
var connection = new SnowflakeDbConnection(ConnectionString + "minPoolSize=1");

// act
await connection.OpenAsync().ConfigureAwait(false);

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

// cleanup
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);
}

[Test]
public async Task TestFailForInvalidConnectionAsync()
{
// arrange
var invalidConnectionString = ";connection_timeout=123";
var connection = new SnowflakeDbConnection(invalidConnectionString);

// act
try
{
await connection.OpenAsync().ConfigureAwait(false);
Assert.Fail("OpenAsync should fail for invalid connection string");
}
catch {}
var thrown = Assert.Throws<SnowflakeDbException>(() => SnowflakeDbConnectionPool.GetPool(connection.ConnectionString));

// assert
Assert.That(thrown.Message, Does.Contain("Required property ACCOUNT is not provided"));
}

[Test]
public void TestConnectionPoolWithInvalidOpenAsync()
{
// make the connection string unique so it won't pick up connection
// pooled by other test cases.
string connStr = ConnectionString + "minPoolSize=0;maxPoolSize=10;application=conn_pool_test_invalid_openasync2";
using (var connection = new SnowflakeDbConnection())
{
connection.ConnectionString = connStr;
// call openAsync but do not wait and destroy it direct
// so the session is initialized with empty token
connection.OpenAsync();
}

// use the same connection string to make a new connection
// to ensure the invalid connection made previously is not pooled
using (var connection1 = new SnowflakeDbConnection())
{
connection1.ConnectionString = connStr;
// this will not open a new session but get the invalid connection from pool
connection1.Open();
// Now run query with connection1
var command = connection1.CreateCommand();
command.CommandText = "select 1, 2, 3";

try
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
// Process each column as appropriate
reader.GetFieldValue<object>(i);
}
}
}
}
catch (SnowflakeDbException)
{
// fail the test case if anything wrong.
Assert.Fail();
}
}
}

[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);
}

[Test]
public async Task TestPreventConnectionFromReturningToPool()
{
// arrange
var connectionString = ConnectionString + "minPoolSize=0";
var connection = new SnowflakeDbConnection(connectionString);
await connection.OpenAsync().ConfigureAwait(false);
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
Assert.AreEqual(1, pool.GetCurrentPoolSize());

// act
connection.PreventPooling();
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);

// assert
Assert.AreEqual(0, pool.GetCurrentPoolSize());
}

[Test]
public async Task TestReleaseConnectionWhenRollbackFailsAsync()
{
// arrange
var connectionString = ConnectionString + "minPoolSize=0";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
var commandThrowingExceptionOnlyForRollback = MockHelper.CommandThrowingExceptionOnlyForRollback();
var mockDbProviderFactory = new Mock<DbProviderFactory>();
mockDbProviderFactory.Setup(p => p.CreateCommand()).Returns(commandThrowingExceptionOnlyForRollback.Object);
Assert.AreEqual(0, pool.GetCurrentPoolSize());
var connection = new TestSnowflakeDbConnection(mockDbProviderFactory.Object);
connection.ConnectionString = connectionString;
await connection.OpenAsync().ConfigureAwait(false);
connection.BeginTransaction(); // not using async version because it is not available on .net framework
Assert.AreEqual(true, connection.HasActiveExplicitTransaction());

// act
await connection.CloseAsync(CancellationToken.None).ConfigureAwait(false);

// assert
Assert.AreEqual(0, pool.GetCurrentPoolSize(), "Should not return connection to the pool");
}

[Test(Description = "test connection pooling with concurrent connection using async calls")]
public void TestConcurrentConnectionPoolingAsync()
{
// add test case name in connection string to make in unique for each test case
// set short expiration timeout to cover the case that connection expired
string connStr = ConnectionString + ";application=TestConcurrentConnectionPoolingAsync2;ExpirationTimeout=3";
ConnectionSinglePoolCacheAsyncIT.ConcurrentPoolingAsyncHelper(connStr, true, 7, 100, 2);
}

[Test(Description = "test connection pooling with concurrent connection and using async calls no close call for connection. Connection is closed when Dispose() is called by framework.")]
public void TestConcurrentConnectionPoolingDisposeAsync()
{
// add test case name in connection string to make in unique for each test case
// set short expiration timeout to cover the case that connection expired
string connStr = ConnectionString + ";application=TestConcurrentConnectionPoolingDisposeAsync2;ExpirationTimeout=3";
ConnectionSinglePoolCacheAsyncIT.ConcurrentPoolingAsyncHelper(connStr, false, 7, 100, 2);
}
}
}
Loading
Loading