Skip to content

Commit 77491d1

Browse files
CSHARP-3669: Support loadBalanced URI option (v2). (#557)
CSHARP-3669: Support loadBalanced URI option.
1 parent dd1d9ae commit 77491d1

File tree

19 files changed

+496
-43
lines changed

19 files changed

+496
-43
lines changed

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@
1313
* limitations under the License.
1414
*/
1515

16-
using System;
17-
using System.Collections.Generic;
18-
using System.Linq;
19-
using System.Text;
20-
using System.Threading.Tasks;
21-
2216
namespace MongoDB.Driver.Core.Clusters
2317
{
2418
/// <summary>
@@ -44,6 +38,11 @@ public enum ClusterType
4438
/// <summary>
4539
/// The cluster is a sharded cluster.
4640
/// </summary>
47-
Sharded
41+
Sharded,
42+
43+
/// <summary>
44+
/// The cluster is in a load balanced mode.
45+
/// </summary>
46+
LoadBalanced
4847
}
4948
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class ClusterSettings
4242
private readonly bool? _directConnection;
4343
private readonly IReadOnlyList<EndPoint> _endPoints;
4444
private readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> _kmsProviders;
45+
private readonly bool _loadBalanced;
4546
private readonly TimeSpan _localThreshold;
4647
private readonly int _maxServerSelectionWaitQueueSize;
4748
private readonly string _replicaSetName;
@@ -61,6 +62,7 @@ public class ClusterSettings
6162
/// <param name="directConnection">The directConnection.</param>
6263
/// <param name="endPoints">The end points.</param>
6364
/// <param name="kmsProviders">The kms providers.</param>
65+
/// <param name="loadBalanced">The load balanced.</param>
6466
/// <param name="localThreshold">The local threshold.</param>
6567
/// <param name="maxServerSelectionWaitQueueSize">Maximum size of the server selection wait queue.</param>
6668
/// <param name="replicaSetName">Name of the replica set.</param>
@@ -78,6 +80,7 @@ public ClusterSettings(
7880
Optional<bool?> directConnection = default,
7981
Optional<IEnumerable<EndPoint>> endPoints = default(Optional<IEnumerable<EndPoint>>),
8082
Optional<IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>>> kmsProviders = default(Optional<IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>>>),
83+
Optional<bool> loadBalanced = default,
8184
Optional<TimeSpan> localThreshold = default,
8285
Optional<int> maxServerSelectionWaitQueueSize = default(Optional<int>),
8386
Optional<string> replicaSetName = default(Optional<string>),
@@ -95,6 +98,7 @@ public ClusterSettings(
9598
_directConnection = directConnection.WithDefault(null);
9699
_endPoints = Ensure.IsNotNull(endPoints.WithDefault(__defaultEndPoints), "endPoints").ToList();
97100
_kmsProviders = kmsProviders.WithDefault(null);
101+
_loadBalanced = loadBalanced.WithDefault(false);
98102
_localThreshold = Ensure.IsGreaterThanOrEqualToZero(localThreshold.WithDefault(TimeSpan.FromMilliseconds(15)), "localThreshold");
99103
_maxServerSelectionWaitQueueSize = Ensure.IsGreaterThanOrEqualToZero(maxServerSelectionWaitQueueSize.WithDefault(500), "maxServerSelectionWaitQueueSize");
100104
_replicaSetName = replicaSetName.WithDefault(null);
@@ -176,6 +180,14 @@ public IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> KmsProvi
176180
get { return _kmsProviders; }
177181
}
178182

183+
/// <summary>
184+
/// Gets whether to use load balanced.
185+
/// </summary>
186+
public bool LoadBalanced
187+
{
188+
get { return _loadBalanced; }
189+
}
190+
179191
/// <summary>
180192
/// Gets the local threshold.
181193
/// </summary>
@@ -284,6 +296,7 @@ public IServerSelector PostServerSelector
284296
/// <param name="directConnection">The directConnection.</param>
285297
/// <param name="endPoints">The end points.</param>
286298
/// <param name="kmsProviders">The kms providers.</param>
299+
/// <param name="loadBalanced">The load balanced.</param>
287300
/// <param name="localThreshold">The local threshold.</param>
288301
/// <param name="maxServerSelectionWaitQueueSize">Maximum size of the server selection wait queue.</param>
289302
/// <param name="replicaSetName">Name of the replica set.</param>
@@ -302,6 +315,7 @@ public ClusterSettings With(
302315
Optional<bool?> directConnection = default,
303316
Optional<IEnumerable<EndPoint>> endPoints = default(Optional<IEnumerable<EndPoint>>),
304317
Optional<IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>>> kmsProviders = default(Optional<IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>>>),
318+
Optional<bool> loadBalanced = default,
305319
Optional<TimeSpan> localThreshold = default(Optional<TimeSpan>),
306320
Optional<int> maxServerSelectionWaitQueueSize = default(Optional<int>),
307321
Optional<string> replicaSetName = default(Optional<string>),
@@ -318,6 +332,7 @@ public ClusterSettings With(
318332
directConnection: directConnection.WithDefault(_directConnection),
319333
endPoints: Optional.Enumerable(endPoints.WithDefault(_endPoints)),
320334
kmsProviders: Optional.Create(kmsProviders.WithDefault(_kmsProviders)),
335+
loadBalanced: Optional.Create(loadBalanced.WithDefault(_loadBalanced)),
321336
localThreshold: localThreshold.WithDefault(_localThreshold),
322337
maxServerSelectionWaitQueueSize: maxServerSelectionWaitQueueSize.WithDefault(_maxServerSelectionWaitQueueSize),
323338
replicaSetName: replicaSetName.WithDefault(_replicaSetName),
@@ -332,6 +347,11 @@ public ClusterSettings With(
332347
// internal methods
333348
internal ClusterType GetInitialClusterType()
334349
{
350+
if (_loadBalanced)
351+
{
352+
return ClusterType.LoadBalanced;
353+
}
354+
335355
#pragma warning disable CS0618 // Type or member is obsolete
336356
if (_connectionModeSwitch == ConnectionModeSwitch.UseDirectConnection)
337357
#pragma warning restore CS0618 // Type or member is obsolete

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public sealed class ConnectionString
8282
private bool? _ipv6;
8383
private bool _isResolved;
8484
private bool? _journal;
85+
private bool _loadBalanced;
8586
private TimeSpan? _localThreshold;
8687
private TimeSpan? _maxIdleTime;
8788
private TimeSpan? _maxLifeTime;
@@ -319,6 +320,11 @@ public bool? Journal
319320
get { return _journal; }
320321
}
321322

323+
/// <summary>
324+
/// Gets a value indicating whether load balanced mode is used.
325+
/// </summary>
326+
public bool LoadBalanced => _loadBalanced;
327+
322328
/// <summary>
323329
/// Gets the local threshold.
324330
/// </summary>
@@ -884,6 +890,24 @@ private void Parse()
884890
throw new MongoConfigurationException("Direct connect cannot be used with multiple host names.");
885891
}
886892

893+
if (_loadBalanced)
894+
{
895+
if (_hosts.Count > 1)
896+
{
897+
throw new MongoConfigurationException("Load balanced mode cannot be used with multiple host names.");
898+
}
899+
900+
if (_replicaSet != null)
901+
{
902+
throw new MongoConfigurationException("ReplicaSetName cannot be used with load balanced mode.");
903+
}
904+
905+
if (IsDirectConnection())
906+
{
907+
throw new MongoConfigurationException("Load balanced mode cannot be used with direct connection.");
908+
}
909+
}
910+
887911
bool IsDirectConnection() =>
888912
_directConnection.GetValueOrDefault() ||
889913
#pragma warning disable CS0618 // Type or member is obsolete
@@ -957,6 +981,9 @@ private void ParseOption(string name, string value)
957981
case "journal":
958982
_journal = ParseBoolean(name, value);
959983
break;
984+
case "loadbalanced":
985+
_loadBalanced = ParseBoolean(name, value);
986+
break;
960987
case "maxidletime":
961988
case "maxidletimems":
962989
_maxIdleTime = ParseTimeSpan(name, value);
@@ -1361,10 +1388,10 @@ internal static bool HasValidParentDomain(string original, DnsEndPoint resolvedE
13611388

13621389
private void ValidateResolvedOptions(IEnumerable<string> optionNames)
13631390
{
1364-
if (optionNames.Any(x => !string.Equals(x, "authSource", StringComparison.OrdinalIgnoreCase)
1365-
&& !string.Equals(x, "replicaSet", StringComparison.OrdinalIgnoreCase)))
1391+
var allowedOptionsInTxtRecords = new[] { "authSource", "replicaSet", "loadBalanced" };
1392+
if (optionNames.Any(o => !allowedOptionsInTxtRecords.Contains(o, StringComparer.OrdinalIgnoreCase)))
13661393
{
1367-
throw new MongoConfigurationException($"Only 'authSource' and 'replicaSet' are allowed in a TXT record.");
1394+
throw new MongoConfigurationException($"Only {string.Join(", ", allowedOptionsInTxtRecords)} are allowed in a TXT record.");
13681395
}
13691396
}
13701397

src/MongoDB.Driver.Legacy/MongoServerSettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,7 @@ internal ClusterKey ToClusterKey()
12021202
_heartbeatTimeout,
12031203
_ipv6,
12041204
kmsProviders: null, // not supported for legacy
1205+
loadBalanced: false, // not supported for legacy, so turn it off
12051206
_localThreshold,
12061207
_maxConnectionIdleTime,
12071208
_maxConnectionLifeTime,

src/MongoDB.Driver/ClusterKey.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ internal class ClusterKey
4343
private readonly TimeSpan _heartbeatTimeout;
4444
private readonly bool _ipv6;
4545
private readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> _kmsProviders;
46+
private readonly bool _loadBalanced;
4647
private readonly TimeSpan _localThreshold;
4748
private readonly TimeSpan _maxConnectionIdleTime;
4849
private readonly TimeSpan _maxConnectionLifeTime;
@@ -80,6 +81,7 @@ public ClusterKey(
8081
TimeSpan heartbeatTimeout,
8182
bool ipv6,
8283
IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> kmsProviders,
84+
bool loadBalanced,
8385
TimeSpan localThreshold,
8486
TimeSpan maxConnectionIdleTime,
8587
TimeSpan maxConnectionLifeTime,
@@ -115,6 +117,7 @@ public ClusterKey(
115117
_heartbeatTimeout = heartbeatTimeout;
116118
_ipv6 = ipv6;
117119
_kmsProviders = kmsProviders;
120+
_loadBalanced = loadBalanced;
118121
_localThreshold = localThreshold;
119122
_maxConnectionIdleTime = maxConnectionIdleTime;
120123
_maxConnectionLifeTime = maxConnectionLifeTime;
@@ -176,6 +179,7 @@ public bool? DirectConnection
176179
public TimeSpan HeartbeatTimeout { get { return _heartbeatTimeout; } }
177180
public bool IPv6 { get { return _ipv6; } }
178181
public IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> KmsProviders { get { return _kmsProviders; } }
182+
public bool LoadBalanced => _loadBalanced;
179183
public TimeSpan LocalThreshold { get { return _localThreshold; } }
180184
public TimeSpan MaxConnectionIdleTime { get { return _maxConnectionIdleTime; } }
181185
public TimeSpan MaxConnectionLifeTime { get { return _maxConnectionLifeTime; } }
@@ -228,6 +232,7 @@ public override bool Equals(object obj)
228232
_heartbeatTimeout == rhs._heartbeatTimeout &&
229233
_ipv6 == rhs._ipv6 &&
230234
KmsProvidersHelper.Equals(_kmsProviders, rhs.KmsProviders) &&
235+
_loadBalanced == rhs._loadBalanced &&
231236
_localThreshold == rhs._localThreshold &&
232237
_maxConnectionIdleTime == rhs._maxConnectionIdleTime &&
233238
_maxConnectionLifeTime == rhs._maxConnectionLifeTime &&

src/MongoDB.Driver/ClusterRegistry.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey cl
9191
directConnection: directConnection,
9292
endPoints: Optional.Enumerable(endPoints),
9393
kmsProviders: Optional.Create(clusterKey.KmsProviders),
94+
loadBalanced: clusterKey.LoadBalanced,
9495
localThreshold: clusterKey.LocalThreshold,
9596
replicaSetName: clusterKey.ReplicaSetName,
9697
maxServerSelectionWaitQueueSize: clusterKey.WaitQueueSize,

src/MongoDB.Driver/MongoClientSettings.cs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class MongoClientSettings : IEquatable<MongoClientSettings>, IInheritable
4949
private TimeSpan _heartbeatInterval;
5050
private TimeSpan _heartbeatTimeout;
5151
private bool _ipv6;
52+
private bool _loadBalanced;
5253
private TimeSpan _localThreshold;
5354
private TimeSpan _maxConnectionIdleTime;
5455
private TimeSpan _maxConnectionLifeTime;
@@ -104,6 +105,7 @@ public MongoClientSettings()
104105
_heartbeatInterval = ServerSettings.DefaultHeartbeatInterval;
105106
_heartbeatTimeout = ServerSettings.DefaultHeartbeatTimeout;
106107
_ipv6 = false;
108+
_loadBalanced = false;
107109
_localThreshold = MongoDefaults.LocalThreshold;
108110
_maxConnectionIdleTime = MongoDefaults.MaxConnectionIdleTime;
109111
_maxConnectionLifeTime = MongoDefaults.MaxConnectionLifeTime;
@@ -400,6 +402,19 @@ public bool IPv6
400402
}
401403
}
402404

405+
/// <summary>
406+
/// Gets or sets whether load balanced mode is used.
407+
/// </summary>
408+
public bool LoadBalanced
409+
{
410+
get { return _loadBalanced; }
411+
set
412+
{
413+
if (_isFrozen) { throw new InvalidOperationException("MongoClientSettings is frozen."); }
414+
_loadBalanced = value;
415+
}
416+
}
417+
403418
/// <summary>
404419
/// Gets or sets the local threshold.
405420
/// </summary>
@@ -869,6 +884,8 @@ public static MongoClientSettings FromUrl(MongoUrl url)
869884
clientSettings.HeartbeatInterval = url.HeartbeatInterval;
870885
clientSettings.HeartbeatTimeout = url.HeartbeatTimeout;
871886
clientSettings.IPv6 = url.IPv6;
887+
clientSettings.LoadBalanced = url.LoadBalanced;
888+
clientSettings.LocalThreshold = url.LocalThreshold;
872889
clientSettings.MaxConnectionIdleTime = url.MaxConnectionIdleTime;
873890
clientSettings.MaxConnectionLifeTime = url.MaxConnectionLifeTime;
874891
clientSettings.MaxConnectionPoolSize = ConnectionStringConversions.GetEffectiveMaxConnections(url.MaxConnectionPoolSize);
@@ -879,7 +896,6 @@ public static MongoClientSettings FromUrl(MongoUrl url)
879896
clientSettings.ReplicaSetName = url.ReplicaSetName;
880897
clientSettings.RetryReads = url.RetryReads.GetValueOrDefault(true);
881898
clientSettings.RetryWrites = url.RetryWrites.GetValueOrDefault(true);
882-
clientSettings.LocalThreshold = url.LocalThreshold;
883899
clientSettings.Scheme = url.Scheme;
884900
clientSettings.Servers = new List<MongoServerAddress>(url.Servers);
885901
clientSettings.ServerSelectionTimeout = url.ServerSelectionTimeout;
@@ -921,6 +937,8 @@ public MongoClientSettings Clone()
921937
clone._heartbeatInterval = _heartbeatInterval;
922938
clone._heartbeatTimeout = _heartbeatTimeout;
923939
clone._ipv6 = _ipv6;
940+
clone._loadBalanced = _loadBalanced;
941+
clone._localThreshold = _localThreshold;
924942
clone._maxConnectionIdleTime = _maxConnectionIdleTime;
925943
clone._maxConnectionLifeTime = _maxConnectionLifeTime;
926944
clone._maxConnectionPoolSize = _maxConnectionPoolSize;
@@ -931,7 +949,6 @@ public MongoClientSettings Clone()
931949
clone._replicaSetName = _replicaSetName;
932950
clone._retryReads = _retryReads;
933951
clone._retryWrites = _retryWrites;
934-
clone._localThreshold = _localThreshold;
935952
clone._scheme = _scheme;
936953
clone._sdamLogFilename = _sdamLogFilename;
937954
clone._serverApi = _serverApi;
@@ -985,6 +1002,8 @@ public override bool Equals(object obj)
9851002
_heartbeatInterval == rhs._heartbeatInterval &&
9861003
_heartbeatTimeout == rhs._heartbeatTimeout &&
9871004
_ipv6 == rhs._ipv6 &&
1005+
_loadBalanced == rhs._loadBalanced &&
1006+
_localThreshold == rhs._localThreshold &&
9881007
_maxConnectionIdleTime == rhs._maxConnectionIdleTime &&
9891008
_maxConnectionLifeTime == rhs._maxConnectionLifeTime &&
9901009
_maxConnectionPoolSize == rhs._maxConnectionPoolSize &&
@@ -995,7 +1014,6 @@ public override bool Equals(object obj)
9951014
_replicaSetName == rhs._replicaSetName &&
9961015
_retryReads == rhs._retryReads &&
9971016
_retryWrites == rhs._retryWrites &&
998-
_localThreshold == rhs._localThreshold &&
9991017
_scheme == rhs._scheme &&
10001018
_sdamLogFilename == rhs._sdamLogFilename &&
10011019
_serverApi == rhs._serverApi &&
@@ -1067,6 +1085,8 @@ public override int GetHashCode()
10671085
.Hash(_heartbeatInterval)
10681086
.Hash(_heartbeatTimeout)
10691087
.Hash(_ipv6)
1088+
.Hash(_loadBalanced)
1089+
.Hash(_localThreshold)
10701090
.Hash(_maxConnectionIdleTime)
10711091
.Hash(_maxConnectionLifeTime)
10721092
.Hash(_maxConnectionPoolSize)
@@ -1077,7 +1097,6 @@ public override int GetHashCode()
10771097
.Hash(_replicaSetName)
10781098
.Hash(_retryReads)
10791099
.Hash(_retryWrites)
1080-
.Hash(_localThreshold)
10811100
.Hash(_scheme)
10821101
.Hash(_sdamLogFilename)
10831102
.Hash(_serverApi)
@@ -1131,6 +1150,11 @@ public override string ToString()
11311150
sb.AppendFormat("HeartbeatInterval={0};", _heartbeatInterval);
11321151
sb.AppendFormat("HeartbeatTimeout={0};", _heartbeatTimeout);
11331152
sb.AppendFormat("IPv6={0};", _ipv6);
1153+
if (_loadBalanced)
1154+
{
1155+
sb.AppendFormat("LoadBalanced={0};", _loadBalanced);
1156+
}
1157+
sb.AppendFormat("LocalThreshold={0};", _localThreshold);
11341158
sb.AppendFormat("MaxConnectionIdleTime={0};", _maxConnectionIdleTime);
11351159
sb.AppendFormat("MaxConnectionLifeTime={0};", _maxConnectionLifeTime);
11361160
sb.AppendFormat("MaxConnectionPoolSize={0};", _maxConnectionPoolSize);
@@ -1144,7 +1168,6 @@ public override string ToString()
11441168
sb.AppendFormat("ReplicaSetName={0};", _replicaSetName);
11451169
sb.AppendFormat("RetryReads={0}", _retryReads);
11461170
sb.AppendFormat("RetryWrites={0}", _retryWrites);
1147-
sb.AppendFormat("LocalThreshold={0};", _localThreshold);
11481171
if (_scheme != ConnectionStringScheme.MongoDB)
11491172
{
11501173
sb.AppendFormat("Scheme={0};", _scheme);
@@ -1193,6 +1216,7 @@ internal ClusterKey ToClusterKey()
11931216
_heartbeatTimeout,
11941217
_ipv6,
11951218
_autoEncryptionOptions?.KmsProviders,
1219+
_loadBalanced,
11961220
_localThreshold,
11971221
_maxConnectionIdleTime,
11981222
_maxConnectionLifeTime,
@@ -1236,6 +1260,24 @@ private void ThrowIfSettingsAreInvalid()
12361260
}
12371261
}
12381262

1263+
if (_loadBalanced)
1264+
{
1265+
if (_servers.Count > 1)
1266+
{
1267+
throw new InvalidOperationException("Load balanced mode cannot be used with multiple host names.");
1268+
}
1269+
1270+
if (_replicaSetName != null)
1271+
{
1272+
throw new InvalidOperationException("ReplicaSetName cannot be used with load balanced mode.");
1273+
}
1274+
1275+
if (IsDirectConnection())
1276+
{
1277+
throw new InvalidOperationException("Load balanced mode cannot be used with direct connection.");
1278+
}
1279+
}
1280+
12391281
bool IsDirectConnection()
12401282
{
12411283
if (_connectionModeSwitch == ConnectionModeSwitch.UseDirectConnection)

0 commit comments

Comments
 (0)