55using System ;
66using System . Diagnostics ;
77using System . Threading ;
8+ using System . Threading . Channels ;
89using System . Threading . Tasks ;
910using Microsoft . Data . ProviderBase ;
1011
@@ -45,15 +46,17 @@ namespace Microsoft.Data.SqlClient.ConnectionPool
4546 internal sealed class ConnectionPoolSlots
4647 {
4748
48- private sealed class Reservation : IDisposable
49+ private sealed class Reservation < T > : IDisposable
4950 {
50- private readonly ConnectionPoolSlots _slots ;
51+ private Action < T > cleanupCallback ;
52+ private T state ;
5153 private bool _retain = false ;
5254 private bool _disposed = false ;
5355
54- internal Reservation ( ConnectionPoolSlots slots )
56+ internal Reservation ( T state , Action < T > cleanupCallback )
5557 {
56- _slots = slots ;
58+ this . state = state ;
59+ this . cleanupCallback = cleanupCallback ;
5760 }
5861
5962 public void Dispose ( )
@@ -65,19 +68,20 @@ public void Dispose()
6568
6669 if ( ! _retain )
6770 {
68- _slots . ReleaseReservation ( ) ;
69- _disposed = true ;
71+ cleanupCallback ( state ) ;
7072 }
73+
74+ _disposed = true ;
7175 }
7276
7377 internal void Keep ( )
7478 {
7579 _retain = true ;
7680 }
77-
7881 }
7982
80- internal delegate void CleanupCallback ( DbConnectionInternal ? connection ) ;
83+ internal delegate T CreateCallback < T , S > ( S state ) ;
84+ internal delegate void CleanupCallback < T > ( DbConnectionInternal ? connection , T state ) ;
8185
8286 private readonly DbConnectionInternal ? [ ] _connections ;
8387 private readonly uint _capacity ;
@@ -104,11 +108,17 @@ internal ConnectionPoolSlots(uint fixedCapacity)
104108 /// </summary>
105109 /// <param name="createCallback">The connection to add to the collection.</param>
106110 /// <param name="cleanupCallback">Callback to clean up resources if an exception occurs.</param>
111+ /// <param name="createState">State made available to the create callback.</param>
112+ /// <param name="cleanupState">State made available to the cleanup callback.</param>
107113 /// <exception cref="InvalidOperationException">
108114 /// Thrown when unable to find an empty slot.
109115 /// This can occur if a reservation is not taken before adding a connection.
110116 /// </exception>
111- internal DbConnectionInternal ? Add ( Func < DbConnectionInternal ? > createCallback , CleanupCallback cleanupCallback )
117+ internal DbConnectionInternal ? Add < T , S > (
118+ CreateCallback < DbConnectionInternal ? , T > createCallback ,
119+ CleanupCallback < S > cleanupCallback ,
120+ T createState ,
121+ S cleanupState )
112122 {
113123 DbConnectionInternal ? connection = null ;
114124 try
@@ -119,7 +129,7 @@ internal ConnectionPoolSlots(uint fixedCapacity)
119129 return null ;
120130 }
121131
122- connection = createCallback ( ) ;
132+ connection = createCallback ( createState ) ;
123133
124134 if ( connection is null )
125135 {
@@ -139,7 +149,7 @@ internal ConnectionPoolSlots(uint fixedCapacity)
139149 }
140150 catch ( Exception e )
141151 {
142- cleanupCallback ( connection ) ;
152+ cleanupCallback ( connection , cleanupState ) ;
143153 throw new Exception ( "Failed to create or add connection" , e ) ;
144154 }
145155 }
@@ -177,7 +187,7 @@ internal bool TryRemove(DbConnectionInternal connection)
177187 /// Attempts to reserve a spot in the collection.
178188 /// </summary>
179189 /// <returns>True if a reservation was successfully obtained.</returns>
180- private Reservation ? TryReserve ( )
190+ private Reservation < ConnectionPoolSlots > ? TryReserve ( )
181191 {
182192 for ( var expected = _reservations ; expected < _capacity ; expected = _reservations )
183193 {
@@ -191,7 +201,7 @@ internal bool TryRemove(DbConnectionInternal connection)
191201 continue ;
192202 }
193203
194- return new Reservation ( this ) ;
204+ return new Reservation < ConnectionPoolSlots > ( this , ( slots ) => slots . ReleaseReservation ( ) ) ;
195205 }
196206 return null ;
197207 }
0 commit comments