8000 Fix compilation. Add clear implementation. · dotnet/SqlClient@daa1413 · GitHub
[go: up one dir, main page]

Skip to content

Commit daa1413

Browse files
committed
Fix compilation. Add clear implementation.
1 parent 938afde commit daa1413

File tree

2 files changed

+81
-71
lines changed

2 files changed

+81
-71
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AsyncFlagFunc.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/BetterSyncPool.cs

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,27 @@ internal override bool IsRunning
6363

6464
internal override void Clear()
6565
{
66-
//TODO
66+
Interlocked.Increment(ref _clearCounter);
67+
68+
if (Interlocked.CompareExchange(ref _isClearing, 1, 0) == 1)
69+
return;
70+
71+
try
72+
{
73+
var count = _idleCount;
74+
while (count > 0 && _idleConnectorReader.TryRead(out var connector))
75+
{
76+
if (CheckIdleConnector(connector))
77+
{
78+
CloseConnector(connector);
79+
count--;
80+
}
81+
}
82+
}
83+
finally
84+
{
85+
_isClearing = 0;
86+
}
6787
}
6888

6989
internal override bool TryGetConnection(DbConnection owningObject, TaskCompletionSource<DbConnectionInternal> taskCompletionSource, DbConnectionOptions userOptions, out DbConnectionInternal? connection)
@@ -113,8 +133,7 @@ internal override void PutObjectFromTransactedPool(DbConnectionInternal obj)
113133

114134
internal override void Startup()
115135
{
116-
// NOTE: this occupies a thread for the whole duration of the warmup process.
117-
ThreadPool.QueueUserWorkItem(async (_) => { await WarmUp(); });
136+
_ = WarmUp();
118137
}
119138

120139
internal override void Shutdown()
@@ -134,7 +153,6 @@ internal override void TransactionEnded(Transaction transaction, DbConnectionInt
134153
#endregion
135154

136155
#region Implementation
137-
138156
private readonly DbConnectionPoolIdentity _identity;
139157

140158
private readonly DbConnectionFactory _connectionFactory;
@@ -180,7 +198,13 @@ internal override void TransactionEnded(Transaction transaction, DbConnectionInt
180198
private Task _warmupTask;
181199
private readonly SemaphoreSlim _warmupLock;
182200

183-
private PoolPruningParameters _pruningParameters;
201+
internal int _minIdleCount;
202+
internal PeriodicTimer PruningTimer { get; init; }
203+
internal PeriodicTimer MinIdleCountTimer { get; init; }
204+
internal ValueTask PruningTimerListener { get; init; }
205+
internal Task PruningTask { get; set; }
206+
internal ValueTask UpdateMinIdleCountTask { get; init; }
207+
internal SemaphoreSlim PruningLock { get; init; }
184208
#endregion
185209

186210
// Counts the total number of open connectors tracked by the pool.
@@ -189,6 +213,13 @@ internal override void TransactionEnded(Transaction transaction, DbConnectionInt
189213
// Counts the number of connectors currently sitting idle in the pool.
190214
private volatile int _idleCount;
191215

216+
/// <summary>
217+
/// Incremented every time this pool is cleared. Allows us to identify connections which were
218+
/// created before the clear.
219+
/// </summary>
220+
private volatile int _clearCounter;
221+
private volatile int _isClearing;
222+
192223
/// <summary>
193224
/// Initializes a new PoolingDataSource.
194225
/// </summary>
@@ -200,6 +231,8 @@ internal BetterSyncPool(
200231
DbConnectionPoolProviderInfo connectionPoolProviderInfo,
201232
RateLimiterBase connectionRateLimiter)
202233
{
234+
State = Initializing;
235+
203236
_connectionRateLimiter = connectionRateLimiter;
204237
_connectionFactory = connectionFactory;
205238
_connectionPoolGroup = connectionPoolGroup;
@@ -227,19 +260,20 @@ internal BetterSyncPool(
227260
_warmupTask = Task.CompletedTask;
228261
_warmupLock = new SemaphoreSlim(1);
229262

263+
var pruningTimer = new PeriodicTimer(DefaultPruningPeriod);
230264

231-
_pruningParameters = new PoolPruningParameters
232-
{
233-
_minIdleCount = int.MaxValue,
234-
235-
// TODO: base this on a user provided param?
236-
PruningTimer = new PeriodicTimer(DefaultPruningPeriod),
237-
MinIdleCountTimer = new PeriodicTimer(MinIdleCountPeriod),
238-
PruningLock = new SemaphoreSlim(1),
239-
PruningTimerListener = InitiatePruningTimerListener(),
240-
PruningTask = Task.CompletedTask,
241-
UpdateMinIdleCountTask = UpdateMinIdleCount(),
242-
};
265+
_minIdleCount = int.MaxValue;
266+
267+
// TODO: make these private readonly if possible
268+
// TODO: base pruning timer on a user provided param?
269+
PruningTimer = pruningTimer;
270+
MinIdleCountTimer = new PeriodicTimer(MinIdleCountPeriod);
271+
PruningLock = new SemaphoreSlim(1);
272+
PruningTimerListener = InitiatePruningTimerListener();
273+
PruningTask = Task.CompletedTask;
274+
UpdateMinIdleCountTask = UpdateMinIdleCount();
275+
276+
State = Running;
243277
}
244278

245279
#region properties
@@ -443,6 +477,7 @@ private void CloseConnector(DbConnectionInternal connector)
443477
//TODO: log error
444478
}
445479

480+
// TODO: check clear counter so that we don't clear new connections
446481

447482
int i;
448483
for (i = 0; i < MaxPoolSize; i++)
@@ -523,10 +558,10 @@ internal readonly struct OpenInternalConnectionState
523558
// It's better to block this thread and keep throughput high than to queue all of our opens onto a single worker thread.
524559
// Add an async path when this support is added to DbConnectionInternal.
525560
DbConnectionInternal? newConnection = state.Pool.ConnectionFactory.CreatePooledConnection(
526-
state.Pool,
527-
state.OwningConnection,
528-
state.Pool._connectionPoolGroup.ConnectionOptions,
529-
state.Pool._connectionPoolGroup.PoolKey,
561+
state.Pool,
562+
state.OwningConnection,
563+
state.Pool._connectionPoolGroup.ConnectionOptions,
564+
state.Pool._connectionPoolGroup.PoolKey,
530565
state.UserOptions);
531566

532567
if (newConnection == null)
@@ -599,7 +634,7 @@ internal async ValueTask InitiatePruningTimerListener()
599634
{
600635
_shutdownCT.ThrowIfCancellationRequested();
601636

602-
while (await _pruningParameters.PruningTimer.WaitForNextTickAsync(_shutdownCT))
637+
while (await PruningTimer.WaitForNextTickAsync(_shutdownCT))
603638
{
604639
await await PruneIdleConnections();
605640
}
@@ -613,35 +648,35 @@ internal async ValueTask InitiatePruningTimerListener()
613648
/// <returns>A ValueTask containing a Task that represents the pruning operation.</returns>
614649
internal async ValueTask<Task> PruneIdleConnections()
615650
{
616-
if (!_pruningParameters.PruningTask.IsCompleted)
651+
if (!PruningTask.IsCompleted)
617652
{
618-
return _pruningParameters.PruningTask;
653+
return PruningTask;
619654
}
620655

621-
await _pruningParameters.PruningLock.WaitAsync();
656+
await PruningLock.WaitAsync();
622657

623658
try
624659
{
625-
if (_pruningParameters.PruningTask.IsCompleted)
660+
if (PruningTask.IsCompleted && State is Running)
626661
{
627-
_pruningParameters.PruningTask = _PruneIdleConnections();
662+
PruningTask = _PruneIdleConnections();
628663
}
629664
}
630665
finally
631666
{
632-
_pruningParameters.PruningLock.Release();
667+
PruningLock.Release();
633668
}
634669

635-
return _pruningParameters.PruningTask;
670+
return PruningTask;
636671

637672
async Task _PruneIdleConnections()
638673
{
639674
try
640675
{
641-
int numConnectionsToPrune = _pruningParameters._minIdleCount;
676+
int numConnectionsToPrune = _minIdleCount;
642677

643678
// Reset _minIdleCount for the next pruning period
644-
_pruningParameters._minIdleCount = int.MaxValue;
679+
_minIdleCount = int.MaxValue;
645680

646681
// If we don't stop on null, we might cycle a bit?
647682
// we might read out all of the nulls we just wrote into the channel
@@ -686,22 +721,26 @@ internal async ValueTask UpdateMinIdleCount()
686721
{
687722
_shutdownCT.ThrowIfCancellationRequested();
688723

689-
while (await _pruningParameters.MinIdleCountTimer.WaitForNextTickAsync(_shutdownCT))
724+
while (await MinIdleCountTimer.WaitForNextTickAsync(_shutdownCT))
690725
{
726+
if (State is not Running)
727+
{
728+
continue;
729+
}
691730
try
692731
{
693732
int currentMinIdle;
694733
int currentIdle;
695734
do
696735
{
697-
currentMinIdle = _pruningParameters._minIdleCount;
736+
currentMinIdle = _minIdleCount;
698737
currentIdle = _idleCount;
699738
if (currentIdle >= currentMinIdle)
700739
{
701740
break;
702741
}
703742
}
704-
while (Interlocked.CompareExchange(ref _pruningParameters._minIdleCount, currentIdle, currentMinIdle) != currentMinIdle);
743+
while (Interlocked.CompareExchange(ref _minIdleCount, currentIdle, currentMinIdle) != currentMinIdle);
705744
}
706745
catch
707746
{
@@ -736,7 +775,7 @@ internal async ValueTask<Task> WarmUp()
736775
{
737776
// The task may have been started by another thread while we were
738777
// waiting on the semaphore
739-
if (_warmupTask.IsCompleted)
778+
if (_warmupTask.IsCompleted && State is Running)
740779
{
741780
_warmupTask = _WarmUp(_shutdownCT);
742781
}
@@ -790,12 +829,14 @@ internal async ValueTask ShutdownAsync()
790829
{
791830
SqlClientEventSource.Log.TryPoolerTraceEvent("<prov.DbConnectionPool.Shutdown|RES|INFO|CPOOL> {0}", ObjectID);
792831

832+
State = ShuttingDown;
833+
793834
// Cancel background tasks
794835
_shutdownCTS.Cancel();
795836
await Task.WhenAll(
796-
_pruningParameters.PruningTimerListener.AsTask(),
797-
_pruningParameters.PruningTask,
798-
_pruningParameters.UpdateMinIdleCountTask.AsTask(),
837+
PruningTimerListener.AsTask(),
838+
PruningTask,
839+
UpdateMinIdleCountTask.AsTask(),
799840
_warmupTask);
800841

801842
// Clean pool state
@@ -804,24 +845,13 @@ await Task.WhenAll(
804845
// Handle disposable resources
805846
_shutdownCTS.Dispose();
806847
_warmupLock.Dispose();
807-
_pruningParameters.PruningTimer.Dispose();
808-
_pruningParameters.MinIdleCountTimer.Dispose();
848+
PruningTimer.Dispose();
849+
MinIdleCountTimer.Dispose();
809850
_connectionRateLimiter?.Dispose();
810851
}
811852

812853
// TODO: override clear method
813854
#endregion
814-
815-
internal struct PoolPruningParameters
816-
{
817-
internal int _minIdleCount;
818-
internal readonly PeriodicTimer PruningTimer { get; init; }
819-
internal readonly PeriodicTimer MinIdleCountTimer { get; init; }
820-
internal readonly ValueTask PruningTimerListener { get; init; }
821-
internal Task PruningTask { get; set; }
822-
internal readonly ValueTask UpdateMinIdleCountTask { get; init; }
823-
internal readonly SemaphoreSlim PruningLock { get; init; }
824-
}
825855
}
826856
}
827857
#endif

0 commit comments

Comments
 (0)
0