Skip to content

Commit ab7df53

Browse files
authored
Made ICancellable support IAsyncDisposable and CancelAsync (#3704)
Closes #3702
1 parent e4ba5d7 commit ab7df53

6 files changed

Lines changed: 80 additions & 14 deletions

File tree

src/Npgsql/ICancelable.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
using System;
2+
using System.Threading.Tasks;
23

34
namespace Npgsql
45
{
5-
interface ICancelable : IDisposable
6+
interface ICancelable : IDisposable, IAsyncDisposable
67
{
78
void Cancel();
9+
10+
Task CancelAsync();
811
}
912
}

src/Npgsql/Internal/NpgsqlConnector.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,7 +1753,10 @@ copyOperation is NpgsqlCopyTextWriter ||
17531753
{
17541754
try
17551755
{
1756-
copyOperation.Cancel();
1756+
if (async)
1757+
await copyOperation.CancelAsync();
1758+
else
1759+
copyOperation.Cancel();
17571760
}
17581761
catch (Exception e)
17591762
{
@@ -1763,7 +1766,10 @@ copyOperation is NpgsqlCopyTextWriter ||
17631766

17641767
try
17651768
{
1766-
copyOperation.Dispose();
1769+
if (async)
1770+
await copyOperation.DisposeAsync();
1771+
else
1772+
copyOperation.Dispose();
17671773
}
17681774
catch (Exception e)
17691775
{

src/Npgsql/NpgsqlBinaryExporter.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Npgsql
1717
/// Provides an API for a binary COPY TO operation, a high-performance data export mechanism from
1818
/// a PostgreSQL table. Initiated by <see cref="NpgsqlConnection.BeginBinaryExport(string)"/>
1919
/// </summary>
20-
public sealed class NpgsqlBinaryExporter : ICancelable, IAsyncDisposable
20+
public sealed class NpgsqlBinaryExporter : ICancelable
2121
{
2222
#region Fields and Properties
2323

@@ -381,6 +381,15 @@ void CheckDisposed()
381381
/// </summary>
382382
public void Cancel() => _connector.PerformUserCancellation();
383383

384+
/// <summary>
385+
/// Async cancels an ongoing export.
386+
/// </summary>
387+
public Task CancelAsync()
388+
{
389+
Cancel();
390+
return Task.CompletedTask;
391+
}
392+
384393
/// <summary>
385394
/// Completes that binary export and sets the connection back to idle state
386395
/// </summary>

src/Npgsql/NpgsqlBinaryImporter.cs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Npgsql
1717
/// <remarks>
1818
/// See https://www.postgresql.org/docs/current/static/sql-copy.html.
1919
/// </remarks>
20-
public sealed class NpgsqlBinaryImporter : ICancelable, IAsyncDisposable
20+
public sealed class NpgsqlBinaryImporter : ICancelable
2121
{
2222
#region Fields and Properties
2323

@@ -480,15 +480,28 @@ async ValueTask<ulong> Complete(bool async, CancellationToken cancellationToken
480480

481481
void ICancelable.Cancel() => Close();
482482

483+
async Task ICancelable.CancelAsync() => await CloseAsync();
484+
483485
/// <summary>
484-
/// Cancels that binary import and sets the connection back to idle state
486+
/// <para>
487+
/// Terminates the ongoing binary import and puts the connection back into the idle state, where regular commands can be executed.
488+
/// </para>
489+
/// <para>
490+
/// Note that if <see cref="Complete()" /> hasn't been invoked before calling this, the import will be cancelled and all changes will
491+
/// be reverted.
492+
/// </para>
485493
/// </summary>
486494
public void Dispose() => Close();
487495

488496
/// <summary>
489-
/// Async cancels that binary import and sets the connection back to idle state
497+
/// <para>
498+
/// Async terminates the ongoing binary import and puts the connection back into the idle state, where regular commands can be executed.
499+
/// </para>
500+
/// <para>
501+
/// Note that if <see cref="CompleteAsync" /> hasn't been invoked before calling this, the import will be cancelled and all changes will
502+
/// be reverted.
503+
/// </para>
490504
/// </summary>
491-
/// <returns></returns>
492505
public ValueTask DisposeAsync()
493506
{
494507
using (NoSynchronizationContextScope.Enter())
@@ -518,15 +531,25 @@ async Task Cancel(bool async, CancellationToken cancellationToken = default)
518531
}
519532

520533
/// <summary>
521-
/// Completes the import process and signals to the database to write everything.
534+
/// <para>
535+
/// Terminates the ongoing binary import and puts the connection back into the idle state, where regular commands can be executed.
536+
/// </para>
537+
/// <para>
538+
/// Note that if <see cref="Complete()" /> hasn't been invoked before calling this, the import will be cancelled and all changes will
539+
/// be reverted.
540+
/// </para>
522541
/// </summary>
523542
public void Close() => CloseAsync(false).GetAwaiter().GetResult();
524543

525544
/// <summary>
526-
/// Async completes the import process and signals to the database to write everything.
545+
/// <para>
546+
/// Async terminates the ongoing binary import and puts the connection back into the idle state, where regular commands can be executed.
547+
/// </para>
548+
/// <para>
549+
/// Note that if <see cref="CompleteAsync" /> hasn't been invoked before calling this, the import will be cancelled and all changes will
550+
/// be reverted.
551+
/// </para>
527552
/// </summary>
528-
/// <returns></returns>
529-
/// <exception cref="Exception"></exception>
530553
public ValueTask CloseAsync(CancellationToken cancellationToken = default)
531554
{
532555
if (cancellationToken.IsCancellationRequested)

src/Npgsql/NpgsqlRawCopyStream.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,14 @@ async Task Cancel(bool async)
392392

393393
protected override void Dispose(bool disposing) => DisposeAsync(disposing, false).GetAwaiter().GetResult();
394394

395+
#if NETSTANDARD2_0
396+
public ValueTask DisposeAsync()
397+
#else
398+
public override ValueTask DisposeAsync()
399+
#endif
400+
=> DisposeAsync(disposing: true, async: true);
401+
402+
395403
async ValueTask DisposeAsync(bool disposing, bool async)
396404
{
397405
if (_isDisposed || !disposing) { return; }
@@ -526,6 +534,14 @@ public Task CancelAsync()
526534
using (NoSynchronizationContextScope.Enter())
527535
return ((NpgsqlRawCopyStream)BaseStream).CancelAsync();
528536
}
537+
538+
#if NETSTANDARD2_0
539+
public ValueTask DisposeAsync()
540+
{
541+
Dispose();
542+
return default;
543+
}
544+
#endif
529545
}
530546

531547
/// <summary>
@@ -543,18 +559,24 @@ internal NpgsqlCopyTextReader(NpgsqlConnector connector, NpgsqlRawCopyStream und
543559
}
544560

545561
/// <summary>
546-
/// Cancels and terminates an ongoing import.
562+
/// Cancels and terminates an ongoing export.
547563
/// </summary>
548564
public void Cancel()
549565
=> ((NpgsqlRawCopyStream)BaseStream).Cancel();
550566

551567
/// <summary>
552-
/// Cancels and terminates an ongoing import. Any data already written will be discarded.
568+
/// Asynchronously cancels and terminates an ongoing export.
553569
/// </summary>
554570
public Task CancelAsync()
555571
{
556572
using (NoSynchronizationContextScope.Enter())
557573
return ((NpgsqlRawCopyStream)BaseStream).CancelAsync();
558574
}
575+
576+
public ValueTask DisposeAsync()
577+
{
578+
Dispose();
579+
return default;
580+
}
559581
}
560582
}

src/Npgsql/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#nullable enable
22
*REMOVED*abstract Npgsql.NpgsqlDatabaseInfo.GetTypes() -> System.Collections.Generic.IEnumerable<Npgsql.PostgresTypes.PostgresType!>!
33
abstract NpgsqlTypes.NpgsqlTsQuery.Equals(NpgsqlTypes.NpgsqlTsQuery? other) -> bool
4+
Npgsql.NpgsqlBinaryExporter.CancelAsync() -> System.Threading.Tasks.Task!
45
Npgsql.NpgsqlConnection.BeginBinaryExportAsync(string! copyToCommand, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Npgsql.NpgsqlBinaryExporter!>!
56
Npgsql.NpgsqlConnection.BeginBinaryImportAsync(string! copyFromCommand, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Npgsql.NpgsqlBinaryImporter!>!
67
Npgsql.NpgsqlConnection.BeginRawBinaryCopyAsync(string! copyCommand, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Npgsql.NpgsqlRawCopyStream!>!
@@ -31,9 +32,11 @@ Npgsql.NpgsqlConnectionStringBuilder.TargetSessionAttributes.set -> void
3132
*REMOVED*Npgsql.NpgsqlDatabaseInfo.NpgsqlDatabaseInfo(string! host, int port, string! databaseName, System.Version! version) -> void
3233
*REMOVED*Npgsql.NpgsqlDatabaseInfo.Port.get -> int
3334
*REMOVED*Npgsql.NpgsqlDatabaseInfo.Version.get -> System.Version!
35+
Npgsql.NpgsqlCopyTextReader.DisposeAsync() -> System.Threading.Tasks.ValueTask
3436
Npgsql.PhysicalOpenAsyncCallback
3537
Npgsql.PhysicalOpenCallback
3638
NpgsqlTypes.NpgsqlTsQuery.Write(System.Text.StringBuilder! stringBuilder) -> void
39+
override Npgsql.NpgsqlRawCopyStream.DisposeAsync() -> System.Threading.Tasks.ValueTask
3740
override NpgsqlTypes.NpgsqlTsQuery.Equals(object? obj) -> bool
3841
override NpgsqlTypes.NpgsqlTsQuery.GetHashCode() -> int
3942
*REMOVED*static Npgsql.NpgsqlDatabaseInfo.ParseServerVersion(string! value) -> System.Version!

0 commit comments

Comments
 (0)