You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
7.1 KiB

4 years ago
  1. #if MYSQL_6_9
  2. // Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using Externals.MySql.Data.MySqlClient.Properties;
  24. using System;
  25. using System.Collections.Generic;
  26. using System.ComponentModel;
  27. using System.Text;
  28. using Externals.MySql.Data.MySqlClient;
  29. namespace Externals.MySql.Data.MySqlClient.Replication
  30. {
  31. /// <summary>
  32. /// Manager for Replication and Load Balancing features
  33. /// </summary>
  34. internal static class ReplicationManager
  35. {
  36. private static List<ReplicationServerGroup> groups = new List<ReplicationServerGroup>();
  37. private static Object thisLock = new Object();
  38. //private static Dictionary<string, ReplicationServerSelector> selectors = new Dictionary<string, ReplicationServerSelector>();
  39. static ReplicationManager()
  40. {
  41. Groups = groups;
  42. // load up our selectors
  43. if (MySqlConfiguration.Settings == null) return;
  44. foreach (var group in MySqlConfiguration.Settings.Replication.ServerGroups)
  45. {
  46. ReplicationServerGroup g = AddGroup(group.Name, group.GroupType, group.RetryTime);
  47. foreach (var server in group.Servers)
  48. g.AddServer(server.Name, server.IsMaster, server.ConnectionString);
  49. }
  50. }
  51. /// <summary>
  52. /// Returns Replication Server Group List
  53. /// </summary>
  54. internal static IList<ReplicationServerGroup> Groups { get; private set; }
  55. /// <summary>
  56. /// Adds a Default Server Group to the list
  57. /// </summary>
  58. /// <param name="name">Group name</param>
  59. /// <param name="retryTime">Time between reconnections for failed servers</param>
  60. /// <returns>Replication Server Group added</returns>
  61. internal static ReplicationServerGroup AddGroup(string name, int retryTime)
  62. {
  63. return AddGroup( name, null, retryTime);
  64. }
  65. /// <summary>
  66. /// Adds a Server Group to the list
  67. /// </summary>
  68. /// <param name="name">Group name</param>
  69. /// <param name="groupType">ServerGroup type reference</param>
  70. /// <param name="retryTime">Time between reconnections for failed servers</param>
  71. /// <returns>Server Group added</returns>
  72. internal static ReplicationServerGroup AddGroup(string name, string groupType, int retryTime)
  73. {
  74. if (string.IsNullOrEmpty(groupType))
  75. groupType = "Externals.MySql.Data.MySqlClient.Replication.ReplicationRoundRobinServerGroup";
  76. Type t = Type.GetType(groupType);
  77. ReplicationServerGroup g = (ReplicationServerGroup)Activator.CreateInstance(t, name, retryTime) as ReplicationServerGroup;
  78. groups.Add(g);
  79. return g;
  80. }
  81. /// <summary>
  82. /// Gets the next server from a replication group
  83. /// </summary>
  84. /// <param name="groupName">Group name</param>
  85. /// <param name="isMaster">True if the server to return must be a master</param>
  86. /// <returns>Replication Server defined by the Load Balancing plugin</returns>
  87. internal static ReplicationServer GetServer(string groupName, bool isMaster)
  88. {
  89. ReplicationServerGroup group = GetGroup(groupName);
  90. return group.GetServer(isMaster);
  91. }
  92. /// <summary>
  93. /// Gets a Server Group by name
  94. /// </summary>
  95. /// <param name="groupName">Group name</param>
  96. /// <returns>Server Group if found, otherwise throws an MySqlException</returns>
  97. internal static ReplicationServerGroup GetGroup(string groupName)
  98. {
  99. ReplicationServerGroup group = null;
  100. foreach (ReplicationServerGroup g in groups)
  101. {
  102. if (String.Compare(g.Name, groupName, StringComparison.OrdinalIgnoreCase) != 0) continue;
  103. group = g;
  104. break;
  105. }
  106. if (group == null)
  107. throw new MySqlException(String.Format(Resources.ReplicationGroupNotFound, groupName));
  108. return group;
  109. }
  110. /// <summary>
  111. /// Validates if the replication group name exists
  112. /// </summary>
  113. /// <param name="groupName">Group name to validate</param>
  114. /// <returns>True if replication group name is found, otherwise false</returns>
  115. internal static bool IsReplicationGroup(string groupName)
  116. {
  117. foreach (ReplicationServerGroup g in groups)
  118. if (String.Compare(g.Name, groupName, StringComparison.OrdinalIgnoreCase) == 0) return true;
  119. return false;
  120. }
  121. /// <summary>
  122. /// Assigns a new server driver to the connection object
  123. /// </summary>
  124. /// <param name="groupName">Group name</param>
  125. /// <param name="master">True if the server connection to assign must be a master</param>
  126. /// <param name="connection">MySqlConnection object where the new driver will be assigned</param>
  127. internal static void GetNewConnection(string groupName, bool master, MySqlConnection connection)
  128. {
  129. do
  130. {
  131. lock (thisLock)
  132. {
  133. if (!IsReplicationGroup(groupName)) return;
  134. ReplicationServerGroup group = GetGroup(groupName);
  135. ReplicationServer server = group.GetServer(master, connection.Settings);
  136. if (server == null)
  137. throw new MySqlException(Properties.Resources.Replication_NoAvailableServer);
  138. try
  139. {
  140. bool isNewServer = false;
  141. if (connection.driver == null || !connection.driver.IsOpen)
  142. {
  143. isNewServer = true;
  144. }
  145. else
  146. {
  147. MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder(server.ConnectionString);
  148. if (!msb.Equals(connection.driver.Settings))
  149. {
  150. isNewServer = true;
  151. }
  152. }
  153. if (isNewServer)
  154. {
  155. Driver driver = Driver.Create(new MySqlConnectionStringBuilder(server.ConnectionString));
  156. connection.driver = driver;
  157. }
  158. return;
  159. }
  160. catch (MySqlException ex)
  161. {
  162. connection.driver = null;
  163. server.IsAvailable = false;
  164. MySqlTrace.LogError(ex.Number, ex.ToString());
  165. if (ex.Number == 1042)
  166. {
  167. // retry to open a failed connection and update its status
  168. group.HandleFailover(server, ex);
  169. }
  170. else
  171. throw;
  172. }
  173. }
  174. } while (true);
  175. }
  176. }
  177. }
  178. #endif