Skip to content

Commit 440bc19

Browse files
authored
Merge pull request #164 from DataAction/163-pooling-remove-connection
Don't double-call `RemoveConnection` in fill-to-min and try-replace pool behaviours
2 parents f2b07d3 + 33602b9 commit 440bc19

File tree

2 files changed

+97
-4
lines changed

2 files changed

+97
-4
lines changed

src/AdoNetCore.AseClient/Internal/ConnectionPool.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ private async Task TryFillPoolToMinSize()
212212
catch(Exception ex)
213213
{
214214
Logger.Instance?.WriteLine($"{nameof(TryFillPoolToMinSize)} exception: {ex}");
215-
RemoveConnection();
216215
}
217216
}
218217
Logger.Instance?.WriteLine($"{nameof(TryFillPoolToMinSize)} end");
@@ -231,7 +230,6 @@ private async Task TryReplaceConnection()
231230
catch (Exception ex)
232231
{
233232
Logger.Instance?.WriteLine($"{nameof(TryReplaceConnection)} exception: {ex}");
234-
RemoveConnection();
235233
}
236234
}
237235
}

test/AdoNetCore.AseClient.Tests/Unit/ConnectionPoolTests.cs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,68 @@ public void WhenMinPoolSizeIsSet_NewPoolFillsToMin()
4444
Task.Delay(1000).Wait();
4545

4646
Assert.AreEqual(10, pool.PoolSize);
47+
Assert.AreEqual(10, pool.Available);
48+
}
49+
50+
[Test]
51+
public void WhenMinPoolSizeIsSet_ButThereIsChanceOfFailure_PoolSizeMatchesAvailableCount()
52+
{
53+
var parameters = new TestConnectionParameters
54+
{
55+
MinPoolSize = 10
56+
};
57+
var pool = new ConnectionPool(parameters, new SequenceSuccessImmediateConnectionFactory(true, false));
58+
59+
Task.Delay(1000).Wait();
60+
61+
Assert.AreEqual(10, pool.PoolSize);
62+
Assert.AreEqual(10, pool.Available);
63+
}
64+
65+
[Test]
66+
public void RemoveAndReplace_ReplacesToMin()
67+
{
68+
var parameters = new TestConnectionParameters
69+
{
70+
MinPoolSize = 10
71+
};
72+
var pool = new ConnectionPool(parameters, new ImmediateConnectionFactory());
73+
74+
Task.Delay(1000).Wait();
75+
76+
Assert.AreEqual(10, pool.PoolSize);
77+
Assert.AreEqual(10, pool.Available);
78+
79+
var c = pool.Reserve(null);
80+
c.IsDoomed = true;
81+
pool.Release(c);
82+
Task.Delay(1000).Wait();
83+
84+
Assert.AreEqual(10, pool.PoolSize);
85+
Assert.AreEqual(10, pool.Available);
86+
}
87+
88+
[Test]
89+
public void RemoveAndReplace_ButThereIsReplacementFailure_DoesNotReplace()
90+
{
91+
var parameters = new TestConnectionParameters
92+
{
93+
MinPoolSize = 2
94+
};
95+
var pool = new ConnectionPool(parameters, new SequenceSuccessImmediateConnectionFactory(true, true, false));
96+
97+
Task.Delay(1000).Wait();
98+
99+
Assert.AreEqual(2, pool.PoolSize);
100+
Assert.AreEqual(2, pool.Available);
101+
102+
var c = pool.Reserve(null);
103+
c.IsDoomed = true;
104+
pool.Release(c);
105+
Task.Delay(1000).Wait();
106+
107+
Assert.AreEqual(1, pool.PoolSize);
108+
Assert.AreEqual(1, pool.Available);
47109
}
48110

49111
[Test]
@@ -57,11 +119,12 @@ public void WhenChangeDatabaseThrows_PoolDoesNotLeak()
57119

58120
var pool = new ConnectionPool(parameters, new ImmediateConnectionFactory(changeDatabaseThrows: true));
59121

60-
for (int i=0; i<5; i++)
122+
for (int i = 0; i < 5; i++)
61123
{
62124
Assert.Throws<AseException>(() => pool.Reserve(null));
63125
}
64126
Assert.AreEqual(0, pool.PoolSize);
127+
Assert.AreEqual(0, pool.Available);
65128
}
66129

67130
[Test]
@@ -78,7 +141,10 @@ public void NewOpenCall_TimesOut_ShouldThrow()
78141
Assert.Throws<AseException>(() => pool.Reserve(null));
79142

80143
Assert.AreEqual(1, pool.PoolSize);
144+
Assert.AreEqual(0, pool.Available);
81145
pool.Release(c1);
146+
Assert.AreEqual(1, pool.PoolSize);
147+
Assert.AreEqual(1, pool.Available);
82148
}
83149

84150
/// <summary>
@@ -127,7 +193,7 @@ public void PoolSpam_Waves(short size, int waves)
127193
ExceptionDispatchInfo.Capture(ae.InnerException ?? ae).Throw();
128194
throw;
129195
}
130-
196+
131197
connections = reserveTask.Result;
132198
}
133199

@@ -185,6 +251,35 @@ public async Task<IInternalConnection> GetNewConnection(CancellationToken token,
185251
}
186252
}
187253

254+
private class SequenceSuccessImmediateConnectionFactory : IInternalConnectionFactory
255+
{
256+
private int _idxNext;
257+
private readonly bool[] _sequence;
258+
259+
public SequenceSuccessImmediateConnectionFactory(params bool[] sequence)
260+
{
261+
_idxNext = 0;
262+
_sequence = sequence ?? new[] { true, false };
263+
}
264+
265+
private bool IsSuccessful()
266+
{
267+
var next = _sequence[_idxNext];
268+
_idxNext = (_idxNext + 1) % _sequence.Length;
269+
return next;
270+
}
271+
272+
public async Task<IInternalConnection> GetNewConnection(CancellationToken token, IInfoMessageEventNotifier eventNotifier)
273+
{
274+
if (IsSuccessful())
275+
{
276+
return await Task.FromResult<IInternalConnection>(new DoNothingInternalConnection());
277+
}
278+
279+
throw new Exception();
280+
}
281+
}
282+
188283
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
189284
[SuppressMessage("ReSharper", "UnusedMember.Local")]
190285
private class DoNothingInternalConnection : IInternalConnection

0 commit comments

Comments
 (0)