Unverified Commit 748f1fa7 authored by Marc Gravell's avatar Marc Gravell Committed by GitHub

fix error with DNS resolution breaking endpoint iterator (#1393)

* re-implement GetEnumerator in EndPointCollection to be a bit more forgiving to concurrent changes during iteration

* poke release notes
parent 3f0c2b81
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
- fix: `ScriptEvaluateAsync` keyspace isolation (#1377 via gliljas) - fix: `ScriptEvaluateAsync` keyspace isolation (#1377 via gliljas)
- fix: F# compatibility enhancements (#1386) - fix: F# compatibility enhancements (#1386)
- fix: improved `ScriptResult` null support (#1392) - fix: improved `ScriptResult` null support (#1392)
- fix: error with DNS resolution breaking endpoint iterator (#1393)
- tests: better docker support for tests (#1389 via ejsmith; #1391) - tests: better docker support for tests (#1389 via ejsmith; #1391)
- tests: general test improvements (#1183, #1385, #1384) - tests: general test improvements (#1183, #1385, #1384)
......
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Net; using System.Net;
...@@ -8,7 +9,7 @@ namespace StackExchange.Redis ...@@ -8,7 +9,7 @@ namespace StackExchange.Redis
/// <summary> /// <summary>
/// A list of endpoints /// A list of endpoints
/// </summary> /// </summary>
public sealed class EndPointCollection : Collection<EndPoint> public sealed class EndPointCollection : Collection<EndPoint>, IEnumerable, IEnumerable<EndPoint>
{ {
/// <summary> /// <summary>
/// Create a new EndPointCollection /// Create a new EndPointCollection
...@@ -109,5 +110,21 @@ internal void SetDefaultPorts(int defaultPort) ...@@ -109,5 +110,21 @@ internal void SetDefaultPorts(int defaultPort)
} }
} }
} }
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator<EndPoint> IEnumerable<EndPoint>.GetEnumerator() => GetEnumerator();
/// <inheritdoc/>
public new IEnumerator<EndPoint> GetEnumerator()
{
// this does *not* need to handle all threading scenarios; but we do
// want it to at least allow overwrites of existing endpoints without
// breaking the enumerator; in particular, this avoids a problem where
// ResolveEndPointsAsync swaps the addresses on us
for (int i = 0; i < Count; i++)
{
yield return this[i];
}
}
} }
} }
...@@ -385,5 +385,23 @@ public async Task TestAutomaticHeartbeat() ...@@ -385,5 +385,23 @@ public async Task TestAutomaticHeartbeat()
} }
} }
} }
[Fact]
public void EndpointIteratorIsReliableOverChanges()
{
var eps = new EndPointCollection
{
{ IPAddress.Loopback, 7999 },
{ IPAddress.Loopback, 8000 },
};
using var iter = eps.GetEnumerator();
Assert.True(iter.MoveNext());
Assert.Equal(7999, ((IPEndPoint)iter.Current).Port);
eps[1] = new IPEndPoint(IPAddress.Loopback, 8001); // boom
Assert.True(iter.MoveNext());
Assert.Equal(8001, ((IPEndPoint)iter.Current).Port);
Assert.False(iter.MoveNext());
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment