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.

213 lines
6.1 KiB

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