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

Add | Adding disposable stack temp ref struct and use #1818

Merged
merged 2 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs">
<Link>Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs">
<Link>Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\EnclaveDelegate.cs">
<Link>Microsoft\Data\SqlClient\EnclaveDelegate.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4399,6 +4399,7 @@ private void AssertReaderState(bool requireData, bool permitAsync, int? columnIn
public override Task<bool> NextResultAsync(CancellationToken cancellationToken)
{
using (TryEventScope.Create("SqlDataReader.NextResultAsync | API | Object Id {0}", ObjectID))
using (var registrationHolder = new DisposableTemporaryOnStack<CancellationTokenRegistration>())
{
TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();

Expand All @@ -4408,15 +4409,14 @@ public override Task<bool> NextResultAsync(CancellationToken cancellationToken)
return source.Task;
}

CancellationTokenRegistration registration = default;
if (cancellationToken.CanBeCanceled)
{
if (cancellationToken.IsCancellationRequested)
{
source.SetCanceled();
return source.Task;
}
registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command);
registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command));
}

Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
Expand All @@ -4434,7 +4434,7 @@ public override Task<bool> NextResultAsync(CancellationToken cancellationToken)
return source.Task;
}

return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registration));
return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registrationHolder.Take()));
}
}

Expand Down Expand Up @@ -4729,17 +4729,17 @@ out bytesRead
public override Task<bool> ReadAsync(CancellationToken cancellationToken)
{
using (TryEventScope.Create("SqlDataReader.ReadAsync | API | Object Id {0}", ObjectID))
using (var registrationHolder = new DisposableTemporaryOnStack<CancellationTokenRegistration>())
{
if (IsClosed)
{
return Task.FromException<bool>(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed()));
}

// Register first to catch any already expired tokens to be able to trigger cancellation event.
CancellationTokenRegistration registration = default;
if (cancellationToken.CanBeCanceled)
{
registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command);
registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command));
}

// If user's token is canceled, return a canceled task
Expand Down Expand Up @@ -4852,7 +4852,7 @@ public override Task<bool> ReadAsync(CancellationToken cancellationToken)

Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ReadAsyncCallContext was not properly disposed");

context.Set(this, source, registration);
context.Set(this, source, registrationHolder.Take());
context._hasMoreData = more;
context._hasReadRowToken = rowTokenRead;

Expand Down Expand Up @@ -4990,49 +4990,51 @@ override public Task<bool> IsDBNullAsync(int i, CancellationToken cancellationTo
return Task.FromException<bool>(ex);
}

// Setup and check for pending task
TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
if (original != null)
using (var registrationHolder = new DisposableTemporaryOnStack<CancellationTokenRegistration>())
{
source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
return source.Task;
}
// Setup and check for pending task
TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
if (original != null)
{
source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
return source.Task;
}

// Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
if (_cancelAsyncOnCloseToken.IsCancellationRequested)
{
source.SetCanceled();
_currentTask = null;
return source.Task;
}
// Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
if (_cancelAsyncOnCloseToken.IsCancellationRequested)
{
source.SetCanceled();
_currentTask = null;
return source.Task;
}

// Setup cancellations
CancellationTokenRegistration registration = default;
if (cancellationToken.CanBeCanceled)
{
registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command);
}
// Setup cancellations
if (cancellationToken.CanBeCanceled)
{
registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command));
}

IsDBNullAsyncCallContext context = null;
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
{
context = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderIsDBNullContext, null);
}
if (context is null)
{
context = new IsDBNullAsyncCallContext();
}
IsDBNullAsyncCallContext context = null;
if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection)
{
context = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderIsDBNullContext, null);
}
if (context is null)
{
context = new IsDBNullAsyncCallContext();
}

Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ISDBNullAsync context not properly disposed");
Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ISDBNullAsync context not properly disposed");

context.Set(this, source, registration);
context._columnIndex = i;
context.Set(this, source, registrationHolder.Take());
context._columnIndex = i;

// Setup async
PrepareAsyncInvocation(useSnapshot: true);
// Setup async
PrepareAsyncInvocation(useSnapshot: true);

return InvokeAsyncCall(context);
return InvokeAsyncCall(context);
}
}
}

Expand Down Expand Up @@ -5137,37 +5139,39 @@ override public Task<T> GetFieldValueAsync<T>(int i, CancellationToken cancellat
return Task.FromException<T>(ex);
}

// Setup and check for pending task
TaskCompletionSource<T> source = new TaskCompletionSource<T>();
Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
if (original != null)
using (var registrationHolder = new DisposableTemporaryOnStack<CancellationTokenRegistration>())
{
source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
return source.Task;
}
// Setup and check for pending task
TaskCompletionSource<T> source = new TaskCompletionSource<T>();
Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null);
if (original != null)
{
source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending()));
return source.Task;
}

// Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
if (_cancelAsyncOnCloseToken.IsCancellationRequested)
{
source.SetCanceled();
_currentTask = null;
return source.Task;
}
// Check if cancellation due to close is requested (this needs to be done after setting _currentTask)
if (_cancelAsyncOnCloseToken.IsCancellationRequested)
{
source.SetCanceled();
_currentTask = null;
return source.Task;
}

// Setup cancellations
CancellationTokenRegistration registration = default;
if (cancellationToken.CanBeCanceled)
{
registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command);
}
// Setup cancellations
if (cancellationToken.CanBeCanceled)
{
registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command));
}

// Setup async
PrepareAsyncInvocation(useSnapshot: true);
// Setup async
PrepareAsyncInvocation(useSnapshot: true);

GetFieldValueAsyncCallContext<T> context = new GetFieldValueAsyncCallContext<T>(this, source, registration);
context._columnIndex = i;
GetFieldValueAsyncCallContext<T> context = new GetFieldValueAsyncCallContext<T>(this, source, registrationHolder.Take());
context._columnIndex = i;

return InvokeAsyncCall(context);
return InvokeAsyncCall(context);
}
}

private static Task<T> GetFieldValueAsyncExecute<T>(Task task, object state)
Expand Down Expand Up @@ -5382,6 +5386,9 @@ protected override void Clear()
internal override Func<Task, object, Task<T>> Execute => s_execute;
}




Wraith2 marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Starts the process of executing an async call using an SqlDataReaderAsyncCallContext derived context object.
/// After this call the context lifetime is handled by BeginAsyncCall ContinueAsyncCall and CompleteAsyncCall AsyncCall methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs">
<Link>Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs">
<Link>Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\EnclaveDelegate.cs">
<Link>Microsoft\Data\SqlClient\EnclaveDelegate.cs</Link>
</Compile>
Expand Down
Loading