Skip to content

Commit 6969fd9

Browse files
NinoFlorisYohDeadfall
authored andcommitted
Pool contention enhancements and bug fixes
Fixes #2513
1 parent f04aa56 commit 6969fd9

File tree

6 files changed

+240
-328
lines changed

6 files changed

+240
-328
lines changed

src/Npgsql/ConnectorPool.cs

Lines changed: 217 additions & 284 deletions
Large diffs are not rendered by default.

src/Npgsql/NpgsqlConnection.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,10 @@ internal void Close(bool wasBroken)
608608

609609
Connector.CloseOngoingOperations();
610610

611+
// The connector has closed us during CloseOngoingOperations due to an underlying failure.
612+
if (Connector == null)
613+
return;
614+
611615
if (Settings.Pooling)
612616
{
613617
if (EnlistedTransaction == null)

src/Npgsql/NpgsqlConnector.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ int ReceiveTimeout
194194
/// </summary>
195195
internal DateTime ReleaseTimestamp { get; set; } = DateTime.MaxValue;
196196

197+
/// <summary>
198+
/// If pooled, the pool index on which this connector will be returned to the pool.
199+
/// </summary>
200+
internal int PoolIndex { get; set; } = int.MaxValue;
201+
197202
internal int ClearCounter { get; set; }
198203

199204
static readonly NpgsqlLogger Log = NpgsqlLogManager.CreateLogger(nameof(NpgsqlConnector));

src/Npgsql/NpgsqlEventSource.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ static int GetBusyConnections()
9898
var pool = kv.Pool;
9999
if (pool == null)
100100
return sum;
101-
sum += pool.State.Busy;
101+
var (_, _, busy) = pool.State;
102+
sum += busy;
102103
}
103104
return sum;
104105
}

test/Npgsql.Tests/PoolManagerTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void ClearAll()
4747

4848
NpgsqlConnection.ClearAllPools();
4949
Assert.That(pool.State.Idle, Is.Zero);
50-
Assert.That(pool.State.Total, Is.Zero);
50+
Assert.That(pool.State.Open, Is.Zero);
5151
}
5252

5353
[Test]
@@ -62,10 +62,10 @@ public void ClearAllWithBusy()
6262
NpgsqlConnection.ClearAllPools();
6363
Assert.That(PoolManager.TryGetValue(ConnectionString, out pool), Is.True);
6464
Assert.That(pool!.State.Idle, Is.Zero);
65-
Assert.That(pool.State.Total, Is.EqualTo(1));
65+
Assert.That(pool.State.Open, Is.EqualTo(1));
6666
}
6767
Assert.That(pool.State.Idle, Is.Zero);
68-
Assert.That(pool.State.Total, Is.Zero);
68+
Assert.That(pool.State.Open, Is.Zero);
6969
}
7070

7171
[SetUp]

test/Npgsql.Tests/PoolTests.cs

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class PoolTests : TestBase
1414
[Test]
1515
public void MinPoolSizeEqualsMaxPoolSize()
1616
{
17-
using (var conn = new NpgsqlConnection(new NpgsqlConnectionStringBuilder(ConnectionString)
17+
using (var conn = new NpgsqlConnection(new NpgsqlConnectionStringBuilder(ConnectionString)
1818
{
1919
MinPoolSize = 30,
2020
MaxPoolSize = 30
@@ -59,7 +59,7 @@ public void ReuseConnectorBeforeCreatingNew()
5959
[Test, Timeout(10000)]
6060
public void GetConnectorFromExhaustedPool()
6161
{
62-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
62+
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
6363
{
6464
MaxPoolSize = 1,
6565
Timeout = 0
@@ -101,7 +101,7 @@ public async Task GetConnectorFromExhaustedPoolAsync()
101101
[Test]
102102
public void TimeoutGettingConnectorFromExhaustedPool()
103103
{
104-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
104+
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
105105
{
106106
MaxPoolSize = 1,
107107
Timeout = 2
@@ -141,42 +141,11 @@ public async Task TimeoutGettingConnectorFromExhaustedPoolAsync()
141141
conn3.Open();
142142
}
143143

144-
[Test]
145-
public void OverflowExceptionWhenTooManyWaiting()
146-
{
147-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
148-
{
149-
ApplicationName = nameof(OverflowExceptionWhenTooManyWaiting),
150-
MaxPoolSize = 1,
151-
}.ToString();
152-
153-
using (var conn = new NpgsqlConnection(connString))
154-
{
155-
conn.Open();
156-
Assert.True(PoolManager.TryGetValue(connString, out var pool));
157-
var state = pool!.State;
158-
159-
try
160-
{
161-
var newState = state;
162-
newState.Waiting = int.MaxValue;
163-
pool!.State = newState;
164-
var conn2 = new NpgsqlConnection(connString);
165-
Assert.Catch<OverflowException>(() => conn2.Open());
166-
}
167-
finally
168-
{
169-
// Restore state for the closes work correctly.
170-
pool!.State = state;
171-
}
172-
}
173-
}
174-
175144
//[Test, Timeout(10000)]
176145
//[Explicit("Timing-based")]
177146
public async Task CancelOpenAsync()
178147
{
179-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
148+
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
180149
{
181150
ApplicationName = nameof(CancelOpenAsync),
182151
MaxPoolSize = 1,
@@ -338,7 +307,7 @@ public void ClearWithBusy()
338307
[Test]
339308
public void ClearWithNoPool()
340309
{
341-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
310+
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
342311
{
343312
ApplicationName = nameof(ClearWithNoPool)
344313
}.ToString();
@@ -349,7 +318,7 @@ public void ClearWithNoPool()
349318
[Test, Description("https://github.com/npgsql/npgsql/commit/45e33ecef21f75f51a625c7b919a50da3ed8e920#r28239653")]
350319
public void PhysicalOpenFailure()
351320
{
352-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
321+
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
353322
{
354323
ApplicationName = nameof(PhysicalOpenFailure),
355324
Port = 44444,
@@ -373,7 +342,7 @@ public void PhysicalOpenFailure()
373342
//[TestCase(10, 20, 30, false)]
374343
public void ExercisePool(int maxPoolSize, int numTasks, int seconds, bool async)
375344
{
376-
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
345+
var connString = new NpgsqlConnectionStringBuilder(ConnectionString)
377346
{
378347
ApplicationName = nameof(ExercisePool),
379348
MaxPoolSize = maxPoolSize
@@ -409,8 +378,8 @@ void AssertPoolState(ConnectorPool? pool, int idle, int busy, int waiting=0)
409378

410379
var state = pool.State;
411380
Assert.That(state.Idle, Is.EqualTo(idle), $"Idle should be {idle} but is {state.Idle}");
412-
Assert.That(state.Busy, Is.EqualTo(busy), $"Busy should be {busy} but is {state.Busy}");
413-
Assert.That(state.Waiting, Is.EqualTo(waiting), $"Waiting should be {waiting} but is {state.Waiting}");
381+
var stateBusy = state.Open - state.Idle;
382+
Assert.That(stateBusy, Is.EqualTo(busy), $"Busy should be {busy} but is {stateBusy}");
414383
}
415384
}
416385
}

0 commit comments

Comments
 (0)