PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/0.5.1.0/CassandraSharp/Cluster.cs

http://cassandra-sharp.googlecode.com/
C# | 223 lines | 187 code | 32 blank | 4 comment | 35 complexity | b947642ec5cd36b39d9e5ec09e4ed297 MD5 | raw file
Possible License(s): Apache-2.0
  1. namespace CassandraSharp
  2. {
  3. using System;
  4. using System.IO;
  5. using System.Net.Sockets;
  6. using Apache.Cassandra;
  7. using CassandraSharp.Commands;
  8. using CassandraSharp.EndpointStrategy;
  9. using CassandraSharp.Pool;
  10. using CassandraSharp.Transport;
  11. using CassandraSharp.Utils;
  12. using log4net;
  13. using Thrift.Protocol;
  14. using Thrift.Transport;
  15. internal class Cluster : ICluster
  16. {
  17. private readonly IEndpointStrategy _endpointsManager;
  18. private readonly ILog _logger = LogManager.GetLogger(typeof(Cluster));
  19. private readonly IPool<IConnection> _pool;
  20. private readonly ITransportFactory _transportFactory;
  21. public Cluster(IBehaviorConfig behaviorConfig, IPool<IConnection> pool, ITransportFactory transportFactory, IEndpointStrategy endpointsManager)
  22. {
  23. BehaviorConfig = behaviorConfig;
  24. _pool = pool;
  25. _endpointsManager = endpointsManager;
  26. _transportFactory = transportFactory;
  27. }
  28. public IBehaviorConfig BehaviorConfig { get; private set; }
  29. public void Dispose()
  30. {
  31. _pool.SafeDispose();
  32. }
  33. public TResult ExecuteCommand<TResult>(IBehaviorConfig behaviorConfig, Func<Cassandra.Client, TResult> func)
  34. {
  35. if (null == behaviorConfig)
  36. {
  37. behaviorConfig = BehaviorConfig;
  38. }
  39. int tryCount = 1;
  40. while (true)
  41. {
  42. IConnection connection = null;
  43. try
  44. {
  45. connection = AcquireConnection();
  46. OpenConnection(connection, behaviorConfig);
  47. TResult res = func(connection.CassandraClient);
  48. ReleaseConnection(connection, false);
  49. return res;
  50. }
  51. catch (Exception ex)
  52. {
  53. bool connectionDead;
  54. bool retry;
  55. DecipherException(ex, behaviorConfig, out connectionDead, out retry);
  56. string errMsg = string.Format("Exception during command processing: connectionDead={0} retry={1}", connectionDead, retry);
  57. _logger.Error(errMsg, ex);
  58. ReleaseConnection(connection, connectionDead);
  59. if (!retry || tryCount >= behaviorConfig.MaxRetries)
  60. {
  61. _logger.Fatal("Max retry count reached");
  62. throw;
  63. }
  64. }
  65. ++tryCount;
  66. }
  67. }
  68. private static void OpenConnection(IConnection connection, IBehaviorConfig behaviorConfig)
  69. {
  70. TTransport transport = connection.CassandraClient.InputProtocol.Transport;
  71. if (!transport.IsOpen)
  72. {
  73. transport.Open();
  74. }
  75. bool userChanged = connection.User != behaviorConfig.User;
  76. if (userChanged && null != behaviorConfig.User && null != behaviorConfig.Password)
  77. {
  78. SystemManagement.Login(connection.CassandraClient, behaviorConfig.User, behaviorConfig.Password);
  79. }
  80. bool keyspaceChanged = connection.KeySpace != behaviorConfig.KeySpace;
  81. if (keyspaceChanged && null != behaviorConfig.KeySpace)
  82. {
  83. SystemManagement.SetKeySpace(connection.CassandraClient, behaviorConfig.KeySpace);
  84. connection.KeySpace = behaviorConfig.KeySpace;
  85. }
  86. }
  87. private static void DecipherException(Exception ex, IBehaviorConfig behaviorConfig, out bool connectionDead, out bool retry)
  88. {
  89. // connection dead exception handling
  90. if (ex is TTransportException)
  91. {
  92. connectionDead = true;
  93. retry = true;
  94. }
  95. else if (ex is IOException)
  96. {
  97. connectionDead = true;
  98. retry = true;
  99. }
  100. else if (ex is SocketException)
  101. {
  102. connectionDead = true;
  103. retry = true;
  104. }
  105. // functional exception handling
  106. else if (ex is TimedOutException)
  107. {
  108. connectionDead = false;
  109. retry = behaviorConfig.RetryOnTimeout;
  110. }
  111. else if (ex is UnavailableException)
  112. {
  113. connectionDead = false;
  114. retry = behaviorConfig.RetryOnUnavailable;
  115. }
  116. else if (ex is NotFoundException)
  117. {
  118. connectionDead = false;
  119. retry = behaviorConfig.RetryOnNotFound;
  120. }
  121. // other exceptions ==> connection is not dead / do not retry
  122. else
  123. {
  124. connectionDead = false;
  125. retry = false;
  126. }
  127. }
  128. private IConnection AcquireConnection()
  129. {
  130. IConnection connection;
  131. if (_pool.Acquire(out connection))
  132. {
  133. return connection;
  134. }
  135. TTransport transport = null;
  136. try
  137. {
  138. Endpoint endpoint = _endpointsManager.Pick();
  139. if (null == endpoint)
  140. {
  141. throw new ArgumentException("Can't find any valid endpoint");
  142. }
  143. transport = _transportFactory.Create(endpoint.Address);
  144. TProtocol protocol = new TBinaryProtocol(transport);
  145. Cassandra.Client client = new Cassandra.Client(protocol);
  146. connection = new Connection(client, endpoint);
  147. return connection;
  148. }
  149. catch
  150. {
  151. if (null != transport)
  152. {
  153. transport.Close();
  154. }
  155. throw;
  156. }
  157. }
  158. private void ReleaseConnection(IConnection connection, bool hasFailed)
  159. {
  160. // protect against exception during acquire connection
  161. if (null != connection)
  162. {
  163. if (hasFailed)
  164. {
  165. _endpointsManager.Ban(connection.Endpoint);
  166. connection.SafeDispose();
  167. }
  168. else
  169. {
  170. _pool.Release(connection);
  171. }
  172. }
  173. }
  174. private class Connection : IConnection
  175. {
  176. public Connection(Cassandra.Client client, Endpoint endpoint)
  177. {
  178. Endpoint = endpoint;
  179. CassandraClient = client;
  180. }
  181. public void Dispose()
  182. {
  183. CassandraClient.InputProtocol.Transport.Close();
  184. }
  185. public string KeySpace { get; set; }
  186. public string User { get; set; }
  187. public Endpoint Endpoint { get; private set; }
  188. public Cassandra.Client CassandraClient { get; private set; }
  189. }
  190. }
  191. }