66
77namespace Ydb . Sdk . Ado . Session ;
88
9- internal sealed class PoolingSessionSource : ISessionSource < PoolingSessionBase >
9+ internal sealed class PoolingSessionSource < T > : ISessionSource where T : PoolingSessionBase < T >
1010{
11- private readonly ConcurrentStack < PoolingSessionBase > _idleSessions = new ( ) ;
12- private readonly ConcurrentQueue < TaskCompletionSource < PoolingSessionBase ? > > _waiters = new ( ) ;
13-
14- private readonly IPoolingSessionFactory _sessionFactory ;
11+ private readonly ConcurrentStack < T > _idleSessions = new ( ) ;
12+ private readonly ConcurrentQueue < TaskCompletionSource < T ? > > _waiters = new ( ) ;
1513
14+ private readonly IPoolingSessionFactory < T > _sessionFactory ;
1615 private readonly int _minSessionSize ;
1716 private readonly int _maxSessionSize ;
18-
19- private readonly PoolingSessionBase ? [ ] _sessions ;
20-
17+ private readonly T ? [ ] _sessions ;
2118 private readonly int _createSessionTimeout ;
2219 private readonly TimeSpan _sessionIdleTimeout ;
2320 private readonly Timer _cleanerTimer ;
2421
2522 private volatile int _numSessions ;
2623
2724 public PoolingSessionSource (
28- IPoolingSessionFactory sessionFactory ,
25+ IPoolingSessionFactory < T > sessionFactory ,
2926 YdbConnectionStringBuilder settings
3027 )
3128 {
@@ -39,19 +36,19 @@ YdbConnectionStringBuilder settings
3936 $ "Connection can't have 'Max Session Pool' { _maxSessionSize } under 'Min Session Pool' { _minSessionSize } ") ;
4037 }
4138
42- _sessions = new PoolingSessionBase ? [ _maxSessionSize ] ;
39+ _sessions = new T ? [ _maxSessionSize ] ;
4340 _createSessionTimeout = settings . CreateSessionTimeout ;
4441 _sessionIdleTimeout = TimeSpan . FromSeconds ( settings . SessionIdleTimeout ) ;
4542 _cleanerTimer = new Timer ( CleanIdleSessions , this , _sessionIdleTimeout , _sessionIdleTimeout ) ;
4643 }
4744
48- public ValueTask < PoolingSessionBase > OpenSession ( CancellationToken cancellationToken = default ) =>
45+ public ValueTask < ISession > OpenSession ( CancellationToken cancellationToken = default ) =>
4946 TryGetIdleSession ( out var session )
50- ? new ValueTask < PoolingSessionBase > ( session )
47+ ? new ValueTask < ISession > ( session )
5148 : RentAsync ( cancellationToken ) ;
5249
5350 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
54- private bool TryGetIdleSession ( [ NotNullWhen ( true ) ] out PoolingSessionBase ? session )
51+ private bool TryGetIdleSession ( [ NotNullWhen ( true ) ] out T ? session )
5552 {
5653 while ( _idleSessions . TryPop ( out session ) )
5754 {
@@ -65,7 +62,7 @@ private bool TryGetIdleSession([NotNullWhen(true)] out PoolingSessionBase? sessi
6562 }
6663
6764 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
68- private bool CheckIdleSession ( [ NotNullWhen ( true ) ] PoolingSessionBase ? session )
65+ private bool CheckIdleSession ( [ NotNullWhen ( true ) ] T ? session )
6966 {
7067 if ( session == null || session . State == PoolingSessionState . Clean )
7168 {
@@ -82,7 +79,7 @@ private bool CheckIdleSession([NotNullWhen(true)] PoolingSessionBase? session)
8279 return session . CompareAndSet ( PoolingSessionState . In , PoolingSessionState . Out ) ;
8380 }
8481
85- private async ValueTask < PoolingSessionBase > RentAsync ( CancellationToken cancellationToken )
82+ private async ValueTask < ISession > RentAsync ( CancellationToken cancellationToken )
8683 {
8784 using var ctsGetSession = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
8885 if ( _createSessionTimeout > 0 )
@@ -96,8 +93,7 @@ private async ValueTask<PoolingSessionBase> RentAsync(CancellationToken cancella
9693
9794 while ( true )
9895 {
99- var waiterTcs =
100- new TaskCompletionSource < PoolingSessionBase ? > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
96+ var waiterTcs = new TaskCompletionSource < T ? > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
10197 _waiters . Enqueue ( waiterTcs ) ;
10298 await using var _ = finalToken . Register ( ( ) => waiterTcs . TrySetCanceled ( ) , useSynchronizationContext : false ) ;
10399 session = await waiterTcs . Task . ConfigureAwait ( false ) ;
@@ -111,9 +107,8 @@ private async ValueTask<PoolingSessionBase> RentAsync(CancellationToken cancella
111107 }
112108 }
113109
114- private async ValueTask < PoolingSessionBase ? > OpenNewSession ( CancellationToken cancellationToken )
110+ private async ValueTask < T ? > OpenNewSession ( CancellationToken cancellationToken )
115111 {
116- // As long as we're under max capacity, attempt to increase the session count and open a new session.
117112 for ( var numSessions = _numSessions ; numSessions < _maxSessionSize ; numSessions = _numSessions )
118113 {
119114 if ( Interlocked . CompareExchange ( ref _numSessions , numSessions + 1 , numSessions ) != numSessions )
@@ -135,12 +130,8 @@ private async ValueTask<PoolingSessionBase> RentAsync(CancellationToken cancella
135130 }
136131 catch
137132 {
138- // RPC open failed, decrement the open and busy counter back down.
139133 Interlocked . Decrement ( ref _numSessions ) ;
140134
141- // In case there's a waiting attempt on the waiters queue, we write a null to the idle connector channel
142- // to wake it up, so it will try opening (and probably throw immediately)
143- // Statement order is important since we have synchronous completions on the channel.
144135 WakeUpWaiter ( ) ;
145136
146137 throw ;
@@ -156,7 +147,7 @@ private void WakeUpWaiter()
156147 waiter . TrySetResult ( null ) ; // wake up waiter!
157148 }
158149
159- public void Return ( PoolingSessionBase session )
150+ public void Return ( T session )
160151 {
161152 if ( session . IsBroken )
162153 {
@@ -181,7 +172,7 @@ public void Return(PoolingSessionBase session)
181172 WakeUpWaiter ( ) ;
182173 }
183174
184- private void CloseSession ( PoolingSessionBase session )
175+ private void CloseSession ( T session )
185176 {
186177 var i = 0 ;
187178 for ( ; i < _maxSessionSize ; i ++ )
@@ -202,7 +193,7 @@ private void CloseSession(PoolingSessionBase session)
202193
203194 private static void CleanIdleSessions ( object ? state )
204195 {
205- var pool = ( PoolingSessionSource ) state ! ;
196+ var pool = ( PoolingSessionSource < T > ) state ! ;
206197 var now = DateTime . Now ;
207198
208199 for ( var i = 0 ; i < pool . _maxSessionSize ; i ++ )
@@ -222,9 +213,9 @@ private static void CleanIdleSessions(object? state)
222213 }
223214}
224215
225- internal interface IPoolingSessionFactory
216+ internal interface IPoolingSessionFactory < T > where T : PoolingSessionBase < T >
226217{
227- PoolingSessionBase NewSession ( PoolingSessionSource source ) ;
218+ T NewSession ( PoolingSessionSource < T > source ) ;
228219}
229220
230221internal enum PoolingSessionState
@@ -234,13 +225,13 @@ internal enum PoolingSessionState
234225 Clean
235226}
236227
237- internal abstract class PoolingSessionBase : ISession
228+ internal abstract class PoolingSessionBase < T > : ISession where T : PoolingSessionBase < T >
238229{
239- private readonly PoolingSessionSource _source ;
230+ private readonly PoolingSessionSource < T > _source ;
240231
241232 private int _state = ( int ) PoolingSessionState . In ;
242233
243- protected PoolingSessionBase ( PoolingSessionSource source )
234+ protected PoolingSessionBase ( PoolingSessionSource < T > source )
244235 {
245236 _source = source ;
246237 }
@@ -272,5 +263,5 @@ public abstract ValueTask<IServerStream<ExecuteQueryResponsePart>> ExecuteQuery(
272263
273264 public abstract void OnNotSuccessStatusCode ( StatusCode code ) ;
274265
275- public void Close ( ) => _source . Return ( this ) ;
266+ public void Close ( ) => _source . Return ( ( T ) this ) ;
276267}
0 commit comments