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-902611 move control over creation of session to session pool #783

Merged
merged 12 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 Snowflake.Data.Tests/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Copyright (c) 2012-2017 Snowflake Computing Inc. All rights reserved.
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>

<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="test_%property{framework}.log" />
Expand All @@ -29,7 +29,7 @@ Copyright (c) 2012-2017 Snowflake Computing Inc. All rights reserved.
<root>
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
</root>
</root>
<root>
<level value="WARN" />
<appender-ref ref="ConsoleAppender" />
Expand All @@ -39,12 +39,12 @@ Copyright (c) 2012-2017 Snowflake Computing Inc. All rights reserved.
<!-- used in SFDbFactoryIT.cs to test registering DbProviderFactoryClass -->
<system.data>
<DbProviderFactories>
<add name="Snowflake" invariant="Snowflake.Data"
type="Snowflake.Data.Client.SnowflakeDbFactory, Snowflake.Data, Culture=neutral, PublicKeyToken=null"
<add name="Snowflake" invariant="Snowflake.Data"
type="Snowflake.Data.Client.SnowflakeDbFactory, Snowflake.Data, Culture=neutral, PublicKeyToken=null"
description="Snowflake Provider" />
</DbProviderFactories>
</system.data>

<!--
=========== Enable Network debug log ===============
<system.diagnostics>
Expand Down
3 changes: 0 additions & 3 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public void TestBasicConnection()
{
using (IDbConnection conn = new SnowflakeDbConnection())
{
SnowflakeDbConnectionPool.SetPooling(false);
conn.ConnectionString = ConnectionString;
conn.Open();
Assert.AreEqual(ConnectionState.Open, conn.State);
Expand Down Expand Up @@ -137,7 +136,6 @@ public void TestIncorrectUserOrPasswordBasicConnection()
[TestCase(false)]
public void TestConnectionIsNotMarkedAsOpenWhenWasNotCorrectlyOpenedBefore(bool explicitClose)
{
SnowflakeDbConnectionPool.SetPooling(true);
for (int i = 0; i < 2; ++i)
{
s_logger.Debug($"Running try #{i}");
Expand Down Expand Up @@ -1891,7 +1889,6 @@ public void TestCloseAsyncFailure()
{
using (var conn = new MockSnowflakeDbConnection(new MockCloseSessionException()))
{
SnowflakeDbConnectionPool.SetPooling(false);
conn.ConnectionString = ConnectionString;
Assert.AreEqual(conn.State, ConnectionState.Closed);
Task task = null;
Expand Down
17 changes: 8 additions & 9 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionPoolT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,24 @@ public void Reset()
SnowflakeDbConnectionPool.SetPooling(_pooling);
}
}

[TestFixture, NonParallelizable]
class SFConnectionPoolT : SFBaseTest
{
private static SFLogger logger = SFLoggerFactory.GetLogger<SFConnectionPoolT>();
private static readonly PoolConfig previousPoolConfig = new PoolConfig();

private static readonly PoolConfig s_previousPoolConfig = new PoolConfig();

[SetUp]
public void BeforeTest()
{
previousPoolConfig.Reset();
s_previousPoolConfig.Reset();
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.ClearAllPools();
}

[TearDown]
public void AfterTest()
{
previousPoolConfig.Reset();
s_previousPoolConfig.Reset();
}

[OneTimeTearDown]
Expand Down Expand Up @@ -435,20 +434,20 @@ public void TestConnectionPoolTurnOff()
class SFConnectionPoolITAsync : SFBaseTestAsync
{
private static SFLogger logger = SFLoggerFactory.GetLogger<SFConnectionPoolITAsync>();
private static readonly PoolConfig previousPoolConfig = new PoolConfig();
private static readonly PoolConfig s_previousPoolConfigRestorer = new PoolConfig();

[SetUp]
public void BeforeTest()
{
previousPoolConfig.Reset();
s_previousPoolConfigRestorer.Reset();
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.ClearAllPools();
}

[TearDown]
public void AfterTest()
{
previousPoolConfig.Reset();
s_previousPoolConfigRestorer.Reset();
}

[OneTimeTearDown]
Expand Down
3 changes: 0 additions & 3 deletions Snowflake.Data.Tests/IntegrationTests/SFDbCommandIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,6 @@ public void TestSimpleLargeResultSet()
}


/*
* Disabled to make sure that configuration changes does not cause problems with appveyor
*/
[Test, NonParallelizable]
public void TestUseV1ResultParser()
{
Expand Down
2 changes: 1 addition & 1 deletion Snowflake.Data.Tests/Mock/MockRetryUntilRestTimeout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
string sid = "")
{
// Override the http timeout and set to 1ms to force all http request to timeout and retry
message.Properties[BaseRestRequest.HTTP_REQUEST_TIMEOUT_KEY] = TimeSpan.FromMilliseconds(1);
message.Properties[BaseRestRequest.HTTP_REQUEST_TIMEOUT_KEY] = TimeSpan.FromTicks(0);
return await (base.SendAsync(message, restTimeout, externalCancellationToken).ConfigureAwait(false));
}
}
Expand Down
5 changes: 5 additions & 0 deletions Snowflake.Data.Tests/Mock/MockSnowflakeDbConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,10 @@ private void OnSessionEstablished()
{
_connectionState = ConnectionState.Open;
}

protected override bool CanReuseSession(TransactionRollbackStatus transactionRollbackStatus)
{
return false;
}
}
}
75 changes: 27 additions & 48 deletions Snowflake.Data/Client/SnowflakeDbConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class SnowflakeDbConnection : DbConnection
// Will fix that in a separated PR though as it's a different issue
private static Boolean _isArrayBindStageCreated;

private enum TransactionRollbackStatus
protected enum TransactionRollbackStatus
{
Undefined, // used to indicate ignored transaction status when pool disabled
Success,
Expand Down Expand Up @@ -232,7 +232,7 @@ public Task CloseAsync(CancellationToken cancellationToken)
return taskCompletionSource.Task;
}

private bool CanReuseSession(TransactionRollbackStatus transactionRollbackStatus)
protected virtual bool CanReuseSession(TransactionRollbackStatus transactionRollbackStatus)
{
return SnowflakeDbConnectionPool.GetPooling() &&
transactionRollbackStatus == TransactionRollbackStatus.Success;
Expand All @@ -246,39 +246,30 @@ public override void Open()
logger.Debug($"Open with a connection already opened: {_connectionState}");
return;
}
SfSession = SnowflakeDbConnectionPool.GetSession(this.ConnectionString);
if (SfSession != null)
try
{
OnSessionConnecting();
SfSession = SnowflakeDbConnectionPool.GetSession(ConnectionString, Password);
if (SfSession == null)
throw new SnowflakeDbException(SFError.INTERNAL_ERROR, "Could not open session");
logger.Debug($"Connection open with pooled session: {SfSession.sessionId}");
OnSessionEstablished();
}
else
catch (Exception e)
{
SetSession();
try
// Otherwise when Dispose() is called, the close request would timeout.
_connectionState = ConnectionState.Closed;
logger.Error("Unable to connect: ", e);
if (e is SnowflakeDbException)
{
SfSession.Open();
}
catch (Exception e)
{
// Otherwise when Dispose() is called, the close request would timeout.
_connectionState = ConnectionState.Closed;
logger.Error("Unable to connect", e);
if (!(e.GetType() == typeof(SnowflakeDbException)))
{
throw
new SnowflakeDbException(
e,
SnowflakeDbException.CONNECTION_FAILURE_SSTATE,
SFError.INTERNAL_ERROR,
"Unable to connect. " + e.Message);
}
else
{
throw;
}
throw;
}
throw new SnowflakeDbException(
e,
SnowflakeDbException.CONNECTION_FAILURE_SSTATE,
SFError.INTERNAL_ERROR,
"Unable to connect. " + e.Message);
}
OnSessionEstablished();
}

public override Task OpenAsync(CancellationToken cancellationToken)
Expand All @@ -289,19 +280,11 @@ public override Task OpenAsync(CancellationToken cancellationToken)
logger.Debug($"Open with a connection already opened: {_connectionState}");
return Task.CompletedTask;
}
SfSession = SnowflakeDbConnectionPool.GetSession(this.ConnectionString);
if (SfSession != null)
{
logger.Debug($"Connection open with pooled session: {SfSession.sessionId}");
OnSessionEstablished();
return Task.CompletedTask;
}

registerConnectionCancellationCallback(cancellationToken);
SetSession();

return SfSession.OpenAsync(cancellationToken).ContinueWith(
previousTask =>
OnSessionConnecting();
return SnowflakeDbConnectionPool
.GetSessionAsync(ConnectionString, Password, cancellationToken)
.ContinueWith(previousTask =>
{
if (previousTask.IsFaulted)
{
Expand All @@ -322,8 +305,9 @@ public override Task OpenAsync(CancellationToken cancellationToken)
}
else
{
logger.Debug("All good");
// Only continue if the session was opened successfully
SfSession = previousTask.Result;
logger.Debug($"Connection open with pooled session: {SfSession.sessionId}");
OnSessionEstablished();
}
},
Expand All @@ -345,19 +329,14 @@ public void SetArrayBindStageCreated()
_isArrayBindStageCreated = true;
}

/// <summary>
/// Create a new SFsession with the connection string settings.
/// </summary>
/// <exception cref="SnowflakeDbException">If the connection string can't be processed</exception>
private void SetSession()
private void OnSessionConnecting()
{
SfSession = new SFSession(ConnectionString, Password);
_connectionTimeout = (int)SfSession.connectionTimeout.TotalSeconds;
_connectionState = ConnectionState.Connecting;
}

private void OnSessionEstablished()
{
_connectionTimeout = (int)SfSession.connectionTimeout.TotalSeconds;
_connectionState = ConnectionState.Open;
}

Expand Down
16 changes: 12 additions & 4 deletions Snowflake.Data/Client/SnowflakeDbConnectionPool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Snowflake.Data.Core;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
using Snowflake.Data.Core;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Log;

Expand All @@ -8,12 +11,17 @@ public class SnowflakeDbConnectionPool
{
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<SnowflakeDbConnectionPool>();

internal static SFSession GetSession(string connStr)
internal static SFSession GetSession(string connStr, SecureString password)
{
s_logger.Debug("SnowflakeDbConnectionPool::GetSession");
return SessionPoolSingleton.Instance.GetSession(connStr);
return SessionPoolSingleton.Instance.GetSession(connStr, password);
}


internal static Task<SFSession> GetSessionAsync(string connStr, SecureString password, CancellationToken cancellationToken)
{
return SessionPoolSingleton.Instance.GetSessionAsync(connStr, password, cancellationToken);
}

internal static bool AddSession(SFSession session)
{
s_logger.Debug("SnowflakeDbConnectionPool::AddSession");
Expand Down
5 changes: 4 additions & 1 deletion Snowflake.Data/Core/HttpUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,10 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
if (!httpTimeout.Equals(Timeout.InfiniteTimeSpan))
{
childCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
childCts.CancelAfter(httpTimeout);
if (httpTimeout.Ticks == 0)
childCts.Cancel();
else
childCts.CancelAfter(httpTimeout);
}
response = await base.SendAsync(requestMessage, childCts == null ?
cancellationToken : childCts.Token).ConfigureAwait(false);
Expand Down
2 changes: 1 addition & 1 deletion Snowflake.Data/Core/Session/SFSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ internal void Open()

internal async Task OpenAsync(CancellationToken cancellationToken)
{
logger.Debug("Open Session");
logger.Debug("Open Session Async");

if (authenticator == null)
{
Expand Down
Loading