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.

211 lines
6.7 KiB

4 years ago
  1. #if MYSQL_6_10
  2. // Copyright ?2004, 2016, 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 System;
  24. using System.Collections.Generic;
  25. using System.Diagnostics;
  26. using System.Linq;
  27. using System.Threading;
  28. namespace Externals.MySql.Data.MySqlClient
  29. {
  30. /// <summary>
  31. /// Summary description for MySqlPoolManager.
  32. /// </summary>
  33. internal class MySqlPoolManager
  34. {
  35. private static readonly Dictionary<string, MySqlPool> Pools = new Dictionary<string, MySqlPool>();
  36. private static readonly List<MySqlPool> ClearingPools = new List<MySqlPool>();
  37. // Timeout in seconds, after which an unused (idle) connection
  38. // should be closed.
  39. internal static int maxConnectionIdleTime = 180;
  40. #if !NETSTANDARD1_3
  41. static MySqlPoolManager()
  42. {
  43. AppDomain.CurrentDomain.ProcessExit += EnsureClearingPools;
  44. AppDomain.CurrentDomain.DomainUnload += EnsureClearingPools;
  45. }
  46. private static void EnsureClearingPools(object sender, EventArgs e)
  47. {
  48. ClearAllPools();
  49. }
  50. #endif
  51. // we add a small amount to the due time to let the cleanup detect
  52. //expired connections in the first cleanup.
  53. private static Timer timer = new Timer(CleanIdleConnections,
  54. null, (maxConnectionIdleTime * 1000) + 8000, maxConnectionIdleTime * 1000);
  55. private static string GetKey(MySqlConnectionStringBuilder settings)
  56. {
  57. string key = "";
  58. lock (settings)
  59. {
  60. key = settings.ConnectionString;
  61. }
  62. if (!settings.IntegratedSecurity || settings.ConnectionReset) return key;
  63. try
  64. {
  65. // Append SID to the connection string to generate a key
  66. // With Integrated security different Windows users with the same
  67. // connection string may be mapped to different MySQL accounts.
  68. System.Security.Principal.WindowsIdentity id =
  69. System.Security.Principal.WindowsIdentity.GetCurrent();
  70. key += ";" + id.User;
  71. }
  72. catch (System.Security.SecurityException ex)
  73. {
  74. // Documentation for WindowsIdentity.GetCurrent() states
  75. // SecurityException can be thrown. In this case the
  76. // connection can only be pooled if reset is done.
  77. throw new MySqlException(Resources.NoWindowsIdentity, ex);
  78. }
  79. return key;
  80. }
  81. public static MySqlPool GetPool(MySqlConnectionStringBuilder settings)
  82. {
  83. string text = GetKey(settings);
  84. lock (Pools)
  85. {
  86. MySqlPool pool;
  87. Pools.TryGetValue(text, out pool);
  88. if (pool == null)
  89. {
  90. pool = new MySqlPool(settings);
  91. Pools.Add(text, pool);
  92. }
  93. else
  94. pool.Settings = settings;
  95. return pool;
  96. }
  97. }
  98. public static void RemoveConnection(Driver driver)
  99. {
  100. Debug.Assert(driver != null);
  101. MySqlPool pool = driver.Pool;
  102. pool?.RemoveConnection(driver);
  103. }
  104. public static void ReleaseConnection(Driver driver)
  105. {
  106. Debug.Assert(driver != null);
  107. MySqlPool pool = driver.Pool;
  108. pool?.ReleaseConnection(driver);
  109. }
  110. public static void ClearPool(MySqlConnectionStringBuilder settings)
  111. {
  112. Debug.Assert(settings != null);
  113. string text;
  114. try
  115. {
  116. text = GetKey(settings);
  117. }
  118. catch (MySqlException)
  119. {
  120. // Cannot retrieve windows identity for IntegratedSecurity=true
  121. // This can be ignored.
  122. return;
  123. }
  124. ClearPoolByText(text);
  125. }
  126. private static void ClearPoolByText(string key)
  127. {
  128. lock (Pools)
  129. {
  130. // if pools doesn't have it, then this pool must already have been cleared
  131. if (!Pools.ContainsKey(key)) return;
  132. // add the pool to our list of pools being cleared
  133. MySqlPool pool = (Pools[key] as MySqlPool);
  134. ClearingPools.Add(pool);
  135. // now tell the pool to clear itself
  136. pool.Clear();
  137. // and then remove the pool from the active pools list
  138. Pools.Remove(key);
  139. }
  140. }
  141. public static void ClearAllPools()
  142. {
  143. lock (Pools)
  144. {
  145. // Create separate keys list.
  146. List<string> keys = new List<string>(Pools.Count);
  147. keys.AddRange(Pools.Keys);
  148. // Remove all pools by key.
  149. foreach (string key in keys)
  150. ClearPoolByText(key);
  151. }
  152. }
  153. public static void RemoveClearedPool(MySqlPool pool)
  154. {
  155. Debug.Assert(ClearingPools.Contains(pool));
  156. ClearingPools.Remove(pool);
  157. }
  158. /// <summary>
  159. /// Remove drivers that have been idle for too long.
  160. /// </summary>
  161. public static void CleanIdleConnections(object obj)
  162. {
  163. List<Driver> oldDrivers = new List<Driver>();
  164. lock (Pools)
  165. {
  166. foreach (MySqlPool pool in Pools.Keys.Select(key => Pools[key]))
  167. {
  168. oldDrivers.AddRange(pool.RemoveOldIdleConnections());
  169. }
  170. }
  171. foreach (Driver driver in oldDrivers)
  172. {
  173. driver.Close();
  174. }
  175. }
  176. }
  177. }
  178. #endif