Skip to content

Commit 88588c9

Browse files
CSHARP-3038: Use a single instance of DnsClient.LookupClient per process.
1 parent 7d8033a commit 88588c9

File tree

6 files changed

+84
-85
lines changed

6 files changed

+84
-85
lines changed

src/MongoDB.Driver.Core/Core/Clusters/DnsMonitorFactory.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,17 @@ namespace MongoDB.Driver.Core.Clusters
2121
{
2222
internal class DnsMonitorFactory : IDnsMonitorFactory
2323
{
24-
private readonly IDnsResolver _dnsResolver;
2524
private readonly IEventSubscriber _eventSubscriber;
2625

27-
public DnsMonitorFactory(
28-
IEventSubscriber eventSubscriber,
29-
IDnsResolver dnsResolver = null)
26+
public DnsMonitorFactory(IEventSubscriber eventSubscriber)
3027
{
3128
_eventSubscriber = Ensure.IsNotNull(eventSubscriber, nameof(eventSubscriber));
32-
_dnsResolver = dnsResolver ?? new DnsClientWrapper();
3329
}
3430

3531
public IDnsMonitor CreateDnsMonitor(IDnsMonitoringCluster cluster, string lookupDomainName, CancellationToken cancellationToken)
3632
{
37-
return new DnsMonitor(cluster, _dnsResolver, lookupDomainName, _eventSubscriber, cancellationToken);
33+
var dnsResolver = DnsClientWrapper.Instance;
34+
return new DnsMonitor(cluster, dnsResolver, lookupDomainName, _eventSubscriber, cancellationToken);
3835
}
3936
}
4037
}

src/MongoDB.Driver.Core/Core/Configuration/ConnectionString.cs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using System.Text.RegularExpressions;
2222
using System.Threading;
2323
using System.Threading.Tasks;
24-
using DnsClient;
2524
using MongoDB.Bson;
2625
using MongoDB.Bson.IO;
2726
using MongoDB.Driver.Core.Clusters;
@@ -62,6 +61,7 @@ public sealed class ConnectionString
6261
private readonly NameValueCollection _unknownOptions;
6362
private readonly Dictionary<string, string> _authMechanismProperties;
6463
private readonly CompressorsOptions _compressorsOptions;
64+
private readonly IDnsResolver _dnsResolver;
6565

6666
// these are all readonly, but since they are not assigned
6767
// from the ctor, they cannot be marked as such.
@@ -110,14 +110,19 @@ public sealed class ConnectionString
110110
/// Initializes a new instance of the <see cref="ConnectionString" /> class.
111111
/// </summary>
112112
/// <param name="connectionString">The connection string.</param>
113-
public ConnectionString(string connectionString)
113+
public ConnectionString(string connectionString) : this(connectionString, DnsClientWrapper.Instance)
114+
{
115+
}
116+
117+
internal ConnectionString(string connectionString, IDnsResolver dnsResolver)
114118
{
115119
_originalConnectionString = Ensure.IsNotNull(connectionString, nameof(connectionString));
116120

117121
_allOptions = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
118122
_unknownOptions = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
119123
_authMechanismProperties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
120124
_compressorsOptions = new CompressorsOptions();
125+
_dnsResolver = Ensure.IsNotNull(dnsResolver, nameof(dnsResolver));
121126
Parse();
122127

123128
_isResolved = _scheme != ConnectionStringScheme.MongoDBPlusSrv;
@@ -511,19 +516,21 @@ public string GetOption(string name)
511516
/// Resolves a connection string. If the connection string indicates more information is available
512517
/// in the DNS system, it will acquire that information as well.
513518
/// </summary>
519+
/// <param name="cancellationToken">The cancellation token.</param>
514520
/// <returns>A resolved ConnectionString.</returns>
515-
public ConnectionString Resolve()
521+
public ConnectionString Resolve(CancellationToken cancellationToken = default(CancellationToken))
516522
{
517-
return Resolve(resolveHosts: true);
523+
return Resolve(resolveHosts: true, cancellationToken);
518524
}
519525

520526
/// <summary>
521527
/// Resolves a connection string. If the connection string indicates more information is available
522528
/// in the DNS system, it will acquire that information as well.
523529
/// </summary>
524530
/// <param name="resolveHosts">Whether to resolve hosts.</param>
531+
/// <param name="cancellationToken">The cancellation token.</param>
525532
/// <returns>A resolved ConnectionString.</returns>
526-
public ConnectionString Resolve(bool resolveHosts)
533+
public ConnectionString Resolve(bool resolveHosts, CancellationToken cancellationToken = default(CancellationToken))
527534
{
528535
if (_isResolved)
529536
{
@@ -532,15 +539,13 @@ public ConnectionString Resolve(bool resolveHosts)
532539

533540
var host = GetHostNameForDns();
534541

535-
var client = new LookupClient();
536-
537542
ConnectionStringScheme resolvedScheme;
538543
List<string> hosts;
539544
if (resolveHosts)
540545
{
541546
resolvedScheme = ConnectionStringScheme.MongoDB;
542-
var srvResponse = client.Query(srvPrefix + host, QueryType.SRV, QueryClass.IN);
543-
hosts = GetHostsFromResponse(srvResponse);
547+
var srvRecords = _dnsResolver.ResolveSrvRecords(srvPrefix + host, cancellationToken);
548+
hosts = GetHostsFromSrvRecords(srvRecords);
544549
ValidateResolvedHosts(host, hosts);
545550
}
546551
else
@@ -549,8 +554,8 @@ public ConnectionString Resolve(bool resolveHosts)
549554
hosts = new List<string> { host };
550555
}
551556

552-
var txtResponse = client.Query(host, QueryType.TXT, QueryClass.IN);
553-
var options = GetOptionsFromResponse(txtResponse);
557+
var txtRecords = _dnsResolver.ResolveTxtRecords(host, cancellationToken);
558+
var options = GetOptionsFromTxtRecords(txtRecords);
554559

555560
var resolvedOptions = GetResolvedOptions(options);
556561

@@ -584,15 +589,13 @@ public ConnectionString Resolve(bool resolveHosts)
584589

585590
var host = GetHostNameForDns();
586591

587-
var client = new LookupClient();
588-
589592
ConnectionStringScheme resolvedScheme;
590593
List<string> hosts;
591594
if (resolveHosts)
592595
{
593596
resolvedScheme = ConnectionStringScheme.MongoDB;
594-
var srvResponse = await client.QueryAsync(srvPrefix + host, QueryType.SRV, QueryClass.IN).ConfigureAwait(false);
595-
hosts = GetHostsFromResponse(srvResponse);
597+
var srvRecords = await _dnsResolver.ResolveSrvRecordsAsync(srvPrefix + host, cancellationToken).ConfigureAwait(false);
598+
hosts = GetHostsFromSrvRecords(srvRecords);
596599
ValidateResolvedHosts(host, hosts);
597600
}
598601
else
@@ -601,8 +604,8 @@ public ConnectionString Resolve(bool resolveHosts)
601604
hosts = new List<string> { host };
602605
}
603606

604-
var txtResponse = await client.QueryAsync(host, QueryType.TXT, QueryClass.IN).ConfigureAwait(false);
605-
var options = GetOptionsFromResponse(txtResponse);
607+
var txtRecords = await _dnsResolver.ResolveTxtRecordsAsync(host, cancellationToken).ConfigureAwait(false);
608+
var options = GetOptionsFromTxtRecords(txtRecords);
606609

607610
var resolvedOptions = GetResolvedOptions(options);
608611

@@ -1196,33 +1199,30 @@ private bool EnsureTlsInsecureIsValid(bool value)
11961199
return value;
11971200
}
11981201

1199-
private List<string> GetHostsFromResponse(IDnsQueryResponse response)
1202+
private List<string> GetHostsFromSrvRecords(IEnumerable<SrvRecord> srvRecords)
12001203
{
12011204
var hosts = new List<string>();
1202-
foreach (var srvRecord in response.Answers.SrvRecords())
1205+
foreach (var srvRecord in srvRecords)
12031206
{
1204-
var h = srvRecord.Target.ToString();
1207+
var h = srvRecord.EndPoint.Host;
12051208
if (h.EndsWith(".", StringComparison.Ordinal))
12061209
{
12071210
h = h.Substring(0, h.Length - 1);
12081211
}
1209-
hosts.Add(h + ":" + srvRecord.Port);
1212+
hosts.Add(h + ":" + srvRecord.EndPoint.Port);
12101213
}
12111214

12121215
return hosts;
12131216
}
12141217

1215-
private List<string> GetOptionsFromResponse(IDnsQueryResponse response)
1218+
private List<string> GetOptionsFromTxtRecords(List<TxtRecord> txtRecords)
12161219
{
1217-
var txtRecords = response.Answers
1218-
.TxtRecords().ToList();
1219-
12201220
if (txtRecords.Count > 1)
12211221
{
12221222
throw new MongoConfigurationException("Only 1 TXT record is allowed when using the SRV protocol.");
12231223
}
12241224

1225-
return txtRecords.Select(tr => tr.Text.Aggregate("", (acc, s) => acc + Uri.UnescapeDataString(s))).ToList();
1225+
return txtRecords.Select(tr => tr.Strings.Aggregate("", (acc, s) => acc + Uri.UnescapeDataString(s))).ToList();
12261226
}
12271227

12281228
private NameValueCollection GetResolvedOptions(List<string> options)

src/MongoDB.Driver.Core/Core/Misc/DnsClientWrapper.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,20 @@ namespace MongoDB.Driver.Core.Misc
2525
{
2626
internal class DnsClientWrapper : IDnsResolver
2727
{
28+
#region static
29+
private static IDnsResolver __instance = new DnsClientWrapper();
30+
public static IDnsResolver Instance => __instance;
31+
#endregion
32+
2833
// private fields
2934
private readonly LookupClient _lookupClient;
3035

3136
// constructors
32-
public DnsClientWrapper()
37+
private DnsClientWrapper()
3338
{
3439
_lookupClient = new LookupClient();
3540
}
3641

37-
// public properties
38-
public LookupClient LookupClient => _lookupClient;
39-
4042
// public methods
4143
public List<SrvRecord> ResolveSrvRecords(string service, CancellationToken cancellationToken)
4244
{

src/MongoDB.Driver/MongoUrl.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -660,19 +660,21 @@ public WriteConcern GetWriteConcern(bool enabledDefault)
660660
/// Resolves a connection string. If the connection string indicates more information is available
661661
/// in the DNS system, it will acquire that information as well.
662662
/// </summary>
663+
/// <param name="cancellationToken">The cancellation token.</param>
663664
/// <returns>A resolved MongoURL.</returns>
664-
public MongoUrl Resolve()
665+
public MongoUrl Resolve(CancellationToken cancellationToken = default(CancellationToken))
665666
{
666-
return Resolve(resolveHosts: true);
667+
return Resolve(resolveHosts: true, cancellationToken);
667668
}
668669

669670
/// <summary>
670671
/// Resolves a connection string. If the connection string indicates more information is available
671672
/// in the DNS system, it will acquire that information as well.
672673
/// </summary>
673674
/// <param name="resolveHosts">Whether to resolve hosts.</param>
675+
/// <param name="cancellationToken">The cancellation token.</param>
674676
/// <returns>A resolved MongoURL.</returns>
675-
public MongoUrl Resolve(bool resolveHosts)
677+
public MongoUrl Resolve(bool resolveHosts, CancellationToken cancellationToken = default(CancellationToken))
676678
{
677679
if (_isResolved)
678680
{
@@ -681,7 +683,7 @@ public MongoUrl Resolve(bool resolveHosts)
681683

682684
var connectionString = new ConnectionString(_originalUrl);
683685

684-
var resolved = connectionString.Resolve(resolveHosts);
686+
var resolved = connectionString.Resolve(resolveHosts, cancellationToken);
685687

686688
return new MongoUrl(resolved.ToString(), isResolved: true);
687689
}

0 commit comments

Comments
 (0)