Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit ace2b3d

Browse files
committed
Fix CancellationTokenRegistration usage
The code was only disposing/unregistering cancellation token registrations if an exception happened, but not if everything completed successfully. This leaks registrations into the cancellation token for as long as the token is alive. The code was also allocating a new delegate for CancelIgnoreFailure on every registration. This can be avoided by passing 'this' through as the object state to the registration, letting the compiler cache the delegate for the lambda.
1 parent a2418fb commit ace2b3d

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

src/System.Data.Common/src/System/Data/Common/DbCommand.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public virtual Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToke
157157
CancellationTokenRegistration registration = new CancellationTokenRegistration();
158158
if (cancellationToken.CanBeCanceled)
159159
{
160-
registration = cancellationToken.Register(CancelIgnoreFailure);
160+
registration = cancellationToken.Register(s => ((DbCommand)s).CancelIgnoreFailure(), this);
161161
}
162162

163163
try
@@ -166,9 +166,12 @@ public virtual Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToke
166166
}
167167
catch (Exception e)
168168
{
169-
registration.Dispose();
170169
return Task.FromException<int>(e);
171170
}
171+
finally
172+
{
173+
registration.Dispose();
174+
}
172175
}
173176
}
174177

@@ -203,7 +206,7 @@ protected virtual Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior be
203206
CancellationTokenRegistration registration = new CancellationTokenRegistration();
204207
if (cancellationToken.CanBeCanceled)
205208
{
206-
registration = cancellationToken.Register(CancelIgnoreFailure);
209+
registration = cancellationToken.Register(s => ((DbCommand)s).CancelIgnoreFailure(), this);
207210
}
208211

209212
try
@@ -212,9 +215,12 @@ protected virtual Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior be
212215
}
213216
catch (Exception e)
214217
{
215-
registration.Dispose();
216218
return Task.FromException<DbDataReader>(e);
217219
}
220+
finally
221+
{
222+
registration.Dispose();
223+
}
218224
}
219225
}
220226

@@ -234,7 +240,7 @@ public virtual Task<object> ExecuteScalarAsync(CancellationToken cancellationTok
234240
CancellationTokenRegistration registration = new CancellationTokenRegistration();
235241
if (cancellationToken.CanBeCanceled)
236242
{
237-
registration = cancellationToken.Register(CancelIgnoreFailure);
243+
registration = cancellationToken.Register(s => ((DbCommand)s).CancelIgnoreFailure(), this);
238244
}
239245

240246
try
@@ -243,9 +249,12 @@ public virtual Task<object> ExecuteScalarAsync(CancellationToken cancellationTok
243249
}
244250
catch (Exception e)
245251
{
246-
registration.Dispose();
247252
return Task.FromException<object>(e);
248253
}
254+
finally
255+
{
256+
registration.Dispose();
257+
}
249258
}
250259
}
251260

0 commit comments

Comments
 (0)