29
29
// Copyright (c) 2007-2024 Broadcom. All Rights Reserved.
30
30
//---------------------------------------------------------------------------
31
31
32
+ using System ;
32
33
using System . Buffers . Binary ;
33
34
using System . Collections . Concurrent ;
34
35
using System . Collections . Generic ;
@@ -52,6 +53,70 @@ internal partial class Channel : IChannel, IRecoverable
52
53
private readonly SemaphoreSlim _confirmSemaphore = new ( 1 , 1 ) ;
53
54
private readonly ConcurrentDictionary < ulong , TaskCompletionSource < bool > > _confirmsTaskCompletionSources = new ( ) ;
54
55
56
+ private class PublisherConfirmationInfo
57
+ {
58
+ private ulong _publishSequenceNumber ;
59
+ private TaskCompletionSource < bool > ? _publisherConfirmationTcs ;
60
+
61
+ internal PublisherConfirmationInfo ( )
62
+ {
63
+ _publishSequenceNumber = 0 ;
64
+ _publisherConfirmationTcs = null ;
65
+ }
66
+
67
+ internal PublisherConfirmationInfo ( ulong publishSequenceNumber , TaskCompletionSource < bool > ? publisherConfirmationTcs )
68
+ {
69
+ _publishSequenceNumber = publishSequenceNumber ;
70
+ _publisherConfirmationTcs = publisherConfirmationTcs ;
71
+ }
72
+
73
+ internal ulong PublishSequenceNumber => _publishSequenceNumber ;
74
+
75
+ internal TaskCompletionSource < bool > ? PublisherConfirmationTcs => _publisherConfirmationTcs ;
76
+
77
+ internal async Task MaybeWaitForConfirmationAsync ( CancellationToken cancellationToken )
78
+ {
79
+ if ( _publisherConfirmationTcs is not null )
80
+ {
81
+ await _publisherConfirmationTcs . Task . WaitAsync ( cancellationToken )
82
+ . ConfigureAwait ( false ) ;
83
+ }
84
+ }
85
+
86
+ internal bool MaybeHandleException ( Exception ex )
87
+ {
88
+ bool exceptionWasHandled = false ;
89
+
90
+ if ( _publisherConfirmationTcs is not null )
91
+ {
92
+ _publisherConfirmationTcs . SetException ( ex ) ;
93
+ exceptionWasHandled = true ;
94
+ }
95
+
96
+ return exceptionWasHandled ;
97
+ }
98
+ }
99
+
100
+ public async ValueTask < ulong > GetNextPublishSequenceNumberAsync ( CancellationToken cancellationToken = default )
101
+ {
102
+ if ( _publisherConfirmationsEnabled )
103
+ {
104
+ await _confirmSemaphore . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
105
+ try
106
+ {
107
+ return _nextPublishSeqNo ;
108
+ }
109
+ finally
110
+ {
111
+ _confirmSemaphore . Release ( ) ;
112
+ }
113
+ }
114
+ else
115
+ {
116
+ return _nextPublishSeqNo ;
117
+ }
118
+ }
119
+
55
120
private void ConfigurePublisherConfirmations ( bool publisherConfirmationsEnabled , bool publisherConfirmationTrackingEnabled )
56
121
{
57
122
_publisherConfirmationsEnabled = publisherConfirmationsEnabled ;
@@ -98,10 +163,17 @@ await ModelSendAsync(in method, k.CancellationToken)
98
163
}
99
164
}
100
165
166
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
167
+ private bool ShouldHandleAckOrNack ( ulong deliveryTag )
168
+ {
169
+ return _publisherConfirmationsEnabled && _publisherConfirmationTrackingEnabled &&
170
+ deliveryTag > 0 && ! _confirmsTaskCompletionSources . IsEmpty ;
171
+ }
172
+
101
173
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
102
174
private void HandleAck ( ulong deliveryTag , bool multiple )
103
175
{
104
- if ( _publisherConfirmationsEnabled && _publisherConfirmationTrackingEnabled && deliveryTag > 0 && ! _confirmsTaskCompletionSources . IsEmpty )
176
+ if ( ShouldHandleAckOrNack ( deliveryTag ) )
105
177
{
106
178
if ( multiple )
107
179
{
@@ -127,7 +199,7 @@ private void HandleAck(ulong deliveryTag, bool multiple)
127
199
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
128
200
private void HandleNack ( ulong deliveryTag , bool multiple , bool isReturn )
129
201
{
130
- if ( _publisherConfirmationsEnabled && _publisherConfirmationTrackingEnabled && deliveryTag > 0 && ! _confirmsTaskCompletionSources . IsEmpty )
202
+ if ( ShouldHandleAckOrNack ( deliveryTag ) )
131
203
{
132
204
if ( multiple )
133
205
{
@@ -192,5 +264,67 @@ await _confirmSemaphore.WaitAsync(reason.CancellationToken)
192
264
}
193
265
}
194
266
}
267
+
268
+ private async Task < PublisherConfirmationInfo ? > MaybeStartPublisherConfirmationTracking ( CancellationToken cancellationToken )
269
+ {
270
+ if ( _publisherConfirmationsEnabled )
271
+ {
272
+ await _confirmSemaphore . WaitAsync ( cancellationToken )
273
+ . ConfigureAwait ( false ) ;
274
+
275
+ ulong publishSequenceNumber = _nextPublishSeqNo ;
276
+
277
+ TaskCompletionSource < bool > ? publisherConfirmationTcs = null ;
278
+ if ( _publisherConfirmationTrackingEnabled )
279
+ {
280
+ publisherConfirmationTcs = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
281
+ _confirmsTaskCompletionSources [ publishSequenceNumber ] = publisherConfirmationTcs ;
282
+ }
283
+
284
+ _nextPublishSeqNo ++ ;
285
+
286
+ return new PublisherConfirmationInfo ( publishSequenceNumber , publisherConfirmationTcs ) ;
287
+ }
288
+ else
289
+ {
290
+ return null ;
291
+ }
292
+ }
293
+
294
+ private bool MaybeHandleExceptionWithEnabledPublisherConfirmations ( PublisherConfirmationInfo ? publisherConfirmationInfo ,
295
+ Exception ex )
296
+ {
297
+ bool exceptionWasHandled = false ;
298
+
299
+ if ( _publisherConfirmationsEnabled &&
300
+ publisherConfirmationInfo is not null )
301
+ {
302
+ _nextPublishSeqNo -- ;
303
+
304
+ if ( _publisherConfirmationTrackingEnabled )
305
+ {
306
+ _confirmsTaskCompletionSources . TryRemove ( publisherConfirmationInfo . PublishSequenceNumber , out _ ) ;
307
+ }
308
+
309
+ exceptionWasHandled = publisherConfirmationInfo . MaybeHandleException ( ex ) ;
310
+ }
311
+
312
+ return exceptionWasHandled ;
313
+ }
314
+
315
+ private async Task MaybeEndPublisherConfirmationTracking ( PublisherConfirmationInfo ? publisherConfirmationInfo ,
316
+ CancellationToken cancellationToken )
317
+ {
318
+ if ( _publisherConfirmationsEnabled )
319
+ {
320
+ _confirmSemaphore . Release ( ) ;
321
+
322
+ if ( publisherConfirmationInfo is not null )
323
+ {
324
+ await publisherConfirmationInfo . MaybeWaitForConfirmationAsync ( cancellationToken )
325
+ . ConfigureAwait ( false ) ;
326
+ }
327
+ }
328
+ }
195
329
}
196
330
}
0 commit comments