ClusterRegistry.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* Copyright 2010-2016 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System.Collections.Generic;
  16. using System.Linq;
  17. using System.Net;
  18. using System.Net.Security;
  19. using System.Net.Sockets;
  20. using System.Security.Cryptography.X509Certificates;
  21. using MongoDB.Driver.Core.Authentication;
  22. using MongoDB.Driver.Core.Clusters;
  23. using MongoDB.Driver.Core.Clusters.ServerSelectors;
  24. using MongoDB.Driver.Core.Configuration;
  25. using MongoDB.Driver.Core.ConnectionPools;
  26. using MongoDB.Driver.Core.Connections;
  27. using MongoDB.Driver.Core.Events;
  28. using MongoDB.Driver.Core.Events.Diagnostics;
  29. using MongoDB.Driver.Core.Misc;
  30. using MongoDB.Driver.Core.Servers;
  31. namespace MongoDB.Driver
  32. {
  33. /// <summary>
  34. /// Represents a registry of already created clusters.
  35. /// </summary>
  36. public class ClusterRegistry
  37. {
  38. #region static
  39. // static fields
  40. private static readonly ClusterRegistry __instance = new ClusterRegistry();
  41. // static properties
  42. /// <summary>
  43. /// Gets the default cluster registry.
  44. /// </summary>
  45. /// <value>
  46. /// The default cluster registry.
  47. /// </value>
  48. public static ClusterRegistry Instance
  49. {
  50. get { return __instance; }
  51. }
  52. #endregion
  53. // fields
  54. private readonly object _lock = new object();
  55. private readonly Dictionary<ClusterKey, ICluster> _registry = new Dictionary<ClusterKey, ICluster>();
  56. // methods
  57. private ICluster CreateCluster(ClusterKey clusterKey)
  58. {
  59. var builder = new ClusterBuilder()
  60. .ConfigureCluster(settings => ConfigureCluster(settings, clusterKey))
  61. .ConfigureServer(settings => ConfigureServer(settings, clusterKey))
  62. .ConfigureConnectionPool(settings => ConfigureConnectionPool(settings, clusterKey))
  63. .ConfigureConnection(settings => ConfigureConnection(settings, clusterKey))
  64. .ConfigureTcp(settings => ConfigureTcp(settings, clusterKey));
  65. if (clusterKey.UseSsl)
  66. {
  67. builder.ConfigureSsl(settings => ConfigureSsl(settings, clusterKey));
  68. }
  69. if (clusterKey.ClusterConfigurator != null)
  70. {
  71. clusterKey.ClusterConfigurator(builder);
  72. }
  73. var cluster = builder.BuildCluster();
  74. cluster.Initialize();
  75. return cluster;
  76. }
  77. private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey clusterKey)
  78. {
  79. var endPoints = clusterKey.Servers.Select(s => EndPointHelper.Parse(s.ToString()));
  80. return settings.With(
  81. connectionMode: clusterKey.ConnectionMode.ToCore(),
  82. endPoints: Optional.Enumerable(endPoints),
  83. replicaSetName: clusterKey.ReplicaSetName,
  84. maxServerSelectionWaitQueueSize: clusterKey.WaitQueueSize,
  85. serverSelectionTimeout: clusterKey.ServerSelectionTimeout,
  86. postServerSelector: new LatencyLimitingServerSelector(clusterKey.LocalThreshold));
  87. }
  88. private ConnectionPoolSettings ConfigureConnectionPool(ConnectionPoolSettings settings, ClusterKey clusterKey)
  89. {
  90. return settings.With(
  91. // maintenanceInterval: TODO: should this be configurable?
  92. maxConnections: clusterKey.MaxConnectionPoolSize,
  93. minConnections: clusterKey.MinConnectionPoolSize,
  94. waitQueueSize: clusterKey.WaitQueueSize,
  95. waitQueueTimeout: clusterKey.WaitQueueTimeout);
  96. }
  97. private ConnectionSettings ConfigureConnection(ConnectionSettings settings, ClusterKey clusterKey)
  98. {
  99. var authenticators = clusterKey.Credentials.Select(c => c.ToAuthenticator());
  100. return settings.With(
  101. authenticators: Optional.Enumerable(authenticators),
  102. maxIdleTime: clusterKey.MaxConnectionIdleTime,
  103. maxLifeTime: clusterKey.MaxConnectionLifeTime,
  104. applicationName: clusterKey.ApplicationName);
  105. }
  106. private ServerSettings ConfigureServer(ServerSettings settings, ClusterKey clusterKey)
  107. {
  108. return settings.With(
  109. heartbeatInterval: clusterKey.HeartbeatInterval,
  110. heartbeatTimeout: clusterKey.HeartbeatTimeout);
  111. }
  112. private SslStreamSettings ConfigureSsl(SslStreamSettings settings, ClusterKey clusterKey)
  113. {
  114. if (clusterKey.UseSsl)
  115. {
  116. var sslSettings = clusterKey.SslSettings ?? new SslSettings();
  117. var validationCallback = sslSettings.ServerCertificateValidationCallback;
  118. if (validationCallback == null && !clusterKey.VerifySslCertificate)
  119. {
  120. validationCallback = AcceptAnySslCertificate;
  121. }
  122. return settings.With(
  123. clientCertificates: Optional.Enumerable(sslSettings.ClientCertificates ?? Enumerable.Empty<X509Certificate>()),
  124. checkCertificateRevocation: sslSettings.CheckCertificateRevocation,
  125. clientCertificateSelectionCallback: sslSettings.ClientCertificateSelectionCallback,
  126. enabledProtocols: sslSettings.EnabledSslProtocols,
  127. serverCertificateValidationCallback: validationCallback);
  128. }
  129. return settings;
  130. }
  131. private TcpStreamSettings ConfigureTcp(TcpStreamSettings settings, ClusterKey clusterKey)
  132. {
  133. if (clusterKey.IPv6)
  134. {
  135. settings = settings.With(addressFamily: AddressFamily.InterNetworkV6);
  136. }
  137. return settings.With(
  138. connectTimeout: clusterKey.ConnectTimeout,
  139. readTimeout: clusterKey.SocketTimeout,
  140. receiveBufferSize: clusterKey.ReceiveBufferSize,
  141. sendBufferSize: clusterKey.SendBufferSize,
  142. writeTimeout: clusterKey.SocketTimeout);
  143. }
  144. internal ICluster GetOrCreateCluster(ClusterKey clusterKey)
  145. {
  146. lock (_lock)
  147. {
  148. ICluster cluster;
  149. if (!_registry.TryGetValue(clusterKey, out cluster))
  150. {
  151. cluster = CreateCluster(clusterKey);
  152. _registry.Add(clusterKey, cluster);
  153. }
  154. return cluster;
  155. }
  156. }
  157. private static bool AcceptAnySslCertificate(
  158. object sender,
  159. X509Certificate certificate,
  160. X509Chain chain,
  161. SslPolicyErrors sslPolicyErrors
  162. )
  163. {
  164. return true;
  165. }
  166. /// <summary>
  167. /// Unregisters and disposes the cluster.
  168. /// </summary>
  169. /// <param name="cluster">The cluster.</param>
  170. public void UnregisterAndDisposeCluster(ICluster cluster)
  171. {
  172. Ensure.IsNotNull(cluster, nameof(cluster));
  173. lock (_lock)
  174. {
  175. ClusterKey clusterKey = null;
  176. foreach (var keyValuePair in _registry)
  177. {
  178. if (object.ReferenceEquals(keyValuePair.Value, cluster))
  179. {
  180. clusterKey = keyValuePair.Key;
  181. break;
  182. }
  183. }
  184. if (clusterKey != null)
  185. {
  186. _registry.Remove(clusterKey);
  187. }
  188. }
  189. cluster.Dispose();
  190. }
  191. }
  192. }