PageRenderTime 758ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/netflix/astyanax/thrift/ThriftSyncConnectionFactoryImpl.java

http://github.com/Netflix/astyanax
Java | 292 lines | 238 code | 30 blank | 24 comment | 20 complexity | 44bbe63e62da1246212605cc53ec6527 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright 2011 Netflix
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. ******************************************************************************/
  16. package com.netflix.astyanax.thrift;
  17. import com.google.common.collect.Maps;
  18. import com.google.common.util.concurrent.ThreadFactoryBuilder;
  19. import com.netflix.astyanax.AuthenticationCredentials;
  20. import com.netflix.astyanax.CassandraOperationTracer;
  21. import com.netflix.astyanax.CassandraOperationType;
  22. import com.netflix.astyanax.KeyspaceTracerFactory;
  23. import com.netflix.astyanax.connectionpool.Connection;
  24. import com.netflix.astyanax.connectionpool.ConnectionFactory;
  25. import com.netflix.astyanax.connectionpool.ConnectionPoolConfiguration;
  26. import com.netflix.astyanax.connectionpool.ConnectionPoolMonitor;
  27. import com.netflix.astyanax.connectionpool.Host;
  28. import com.netflix.astyanax.connectionpool.HostConnectionPool;
  29. import com.netflix.astyanax.connectionpool.Operation;
  30. import com.netflix.astyanax.connectionpool.OperationResult;
  31. import com.netflix.astyanax.connectionpool.RateLimiter;
  32. import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
  33. import com.netflix.astyanax.connectionpool.exceptions.IsTimeoutException;
  34. import com.netflix.astyanax.connectionpool.exceptions.ThrottledException;
  35. import com.netflix.astyanax.connectionpool.impl.OperationResultImpl;
  36. import com.netflix.astyanax.connectionpool.impl.SimpleRateLimiterImpl;
  37. import org.apache.cassandra.thrift.AuthenticationException;
  38. import org.apache.cassandra.thrift.AuthenticationRequest;
  39. import org.apache.cassandra.thrift.AuthorizationException;
  40. import org.apache.cassandra.thrift.Cassandra;
  41. import org.apache.cassandra.thrift.TBinaryProtocol;
  42. import org.apache.thrift.TException;
  43. import org.apache.thrift.transport.TFramedTransport;
  44. import org.apache.thrift.transport.TSocket;
  45. import org.apache.thrift.transport.TTransportException;
  46. import java.util.Map;
  47. import java.util.concurrent.ExecutorService;
  48. import java.util.concurrent.Executors;
  49. import java.util.concurrent.atomic.AtomicBoolean;
  50. import java.util.concurrent.atomic.AtomicLong;
  51. public class ThriftSyncConnectionFactoryImpl implements ConnectionFactory<Cassandra.Client> {
  52. private static final String NAME_FORMAT = "ThriftConnection<%s-%d>";
  53. private final AtomicLong idCounter = new AtomicLong(0);
  54. private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setDaemon(true)
  55. .build());
  56. private final RateLimiter limiter;
  57. private final ConnectionPoolConfiguration cpConfig;
  58. private final KeyspaceTracerFactory tracerFactory;
  59. private final ConnectionPoolMonitor monitor;
  60. public ThriftSyncConnectionFactoryImpl(ConnectionPoolConfiguration cpConfig, KeyspaceTracerFactory tracerFactory,
  61. ConnectionPoolMonitor monitor) {
  62. this.cpConfig = cpConfig;
  63. this.limiter = new SimpleRateLimiterImpl(cpConfig);
  64. this.tracerFactory = tracerFactory;
  65. this.monitor = monitor;
  66. }
  67. @Override
  68. public Connection<Cassandra.Client> createConnection(final HostConnectionPool<Cassandra.Client> pool)
  69. throws ThrottledException {
  70. if (limiter.check() == false) {
  71. throw new ThrottledException("Too many connection attempts");
  72. }
  73. return new Connection<Cassandra.Client>() {
  74. private final long id = idCounter.incrementAndGet();
  75. private Cassandra.Client cassandraClient;
  76. private TFramedTransport transport;
  77. private TSocket socket;
  78. private int timeout = 0;
  79. private AtomicLong operationCounter = new AtomicLong();
  80. private AtomicBoolean closed = new AtomicBoolean(false);
  81. private volatile ConnectionException lastException = null;
  82. private volatile String keyspaceName;
  83. @Override
  84. public <R> OperationResult<R> execute(Operation<Cassandra.Client, R> op) throws ConnectionException {
  85. long startTime = System.nanoTime();
  86. long latency = 0;
  87. setTimeout(cpConfig.getSocketTimeout()); // In case the
  88. // configuration
  89. // changed
  90. operationCounter.incrementAndGet();
  91. // Set a new keyspace, if it changed
  92. lastException = null;
  93. if (op.getKeyspace() != null && (keyspaceName == null || !op.getKeyspace().equals(keyspaceName))) {
  94. CassandraOperationTracer tracer = tracerFactory.newTracer(CassandraOperationType.SET_KEYSPACE)
  95. .start();
  96. try {
  97. cassandraClient.set_keyspace(op.getKeyspace());
  98. keyspaceName = op.getKeyspace();
  99. long now = System.nanoTime();
  100. latency = now - startTime;
  101. pool.addLatencySample(latency, now);
  102. tracer.success();
  103. }
  104. catch (Exception e) {
  105. long now = System.nanoTime();
  106. latency = now - startTime;
  107. lastException = ThriftConverter.ToConnectionPoolException(e).setLatency(latency);
  108. if (e instanceof IsTimeoutException)
  109. pool.addLatencySample(latency, now);
  110. tracer.failure(lastException);
  111. throw lastException;
  112. }
  113. startTime = System.nanoTime(); // We don't want to include
  114. // the set_keyspace in our
  115. // latency calculation
  116. }
  117. // Execute the operation
  118. try {
  119. R result = op.execute(cassandraClient);
  120. long now = System.nanoTime();
  121. latency = now - startTime;
  122. pool.addLatencySample(latency, now);
  123. return new OperationResultImpl<R>(getHost(), result, latency);
  124. }
  125. catch (Exception e) {
  126. long now = System.nanoTime();
  127. latency = now - startTime;
  128. lastException = ThriftConverter.ToConnectionPoolException(e).setLatency(latency);
  129. if (e instanceof IsTimeoutException)
  130. pool.addLatencySample(latency, now);
  131. throw lastException;
  132. }
  133. }
  134. @Override
  135. public void open() throws ConnectionException {
  136. if (cassandraClient != null) {
  137. throw new IllegalStateException("Open called on already open connection");
  138. }
  139. long startTime = System.currentTimeMillis();
  140. try {
  141. socket = new TSocket(getHost().getIpAddress(), getHost().getPort(), cpConfig.getConnectTimeout());
  142. socket.getSocket().setTcpNoDelay(true);
  143. socket.getSocket().setKeepAlive(true);
  144. socket.getSocket().setSoLinger(false, 0);
  145. setTimeout(cpConfig.getSocketTimeout());
  146. transport = new TFramedTransport(socket);
  147. transport.open();
  148. cassandraClient = new Cassandra.Client(new TBinaryProtocol(transport));
  149. monitor.incConnectionCreated(getHost());
  150. AuthenticationCredentials credentials = cpConfig.getAuthenticationCredentials();
  151. if (credentials != null) {
  152. Map<String, String> thriftCredentials = Maps.newHashMapWithExpectedSize(2);
  153. thriftCredentials.put("username", credentials.getUsername());
  154. thriftCredentials.put("password", credentials.getPassword());
  155. cassandraClient.login(new AuthenticationRequest(thriftCredentials));
  156. }
  157. }
  158. catch (Exception e) {
  159. closeClient();
  160. ConnectionException ce = ThriftConverter.ToConnectionPoolException(e).setHost(getHost())
  161. .setLatency(System.currentTimeMillis() - startTime);
  162. monitor.incConnectionCreateFailed(getHost(), ce);
  163. throw ce;
  164. }
  165. }
  166. @Override
  167. public void openAsync(final AsyncOpenCallback<Cassandra.Client> callback) {
  168. final Connection<Cassandra.Client> This = this;
  169. executor.submit(new Runnable() {
  170. @Override
  171. public void run() {
  172. try {
  173. open();
  174. callback.success(This);
  175. }
  176. catch (Exception e) {
  177. callback.failure(This, ThriftConverter.ToConnectionPoolException(e));
  178. }
  179. }
  180. });
  181. }
  182. @Override
  183. public void close() {
  184. if (closed.compareAndSet(false, true)) {
  185. monitor.incConnectionClosed(getHost(), lastException);
  186. executor.submit(new Runnable() {
  187. @Override
  188. public void run() {
  189. try {
  190. closeClient();
  191. }
  192. catch (Exception e) {
  193. }
  194. }
  195. });
  196. }
  197. }
  198. private void closeClient() {
  199. if (transport != null) {
  200. try {
  201. transport.flush();
  202. }
  203. catch (TTransportException e) {
  204. }
  205. finally {
  206. try {
  207. transport.close();
  208. }
  209. catch (Exception e) {
  210. }
  211. finally {
  212. transport = null;
  213. }
  214. }
  215. }
  216. if (socket != null) {
  217. try {
  218. socket.close();
  219. }
  220. catch (Exception e) {
  221. }
  222. finally {
  223. socket = null;
  224. }
  225. }
  226. }
  227. @Override
  228. public HostConnectionPool<Cassandra.Client> getHostConnectionPool() {
  229. return pool;
  230. }
  231. @Override
  232. public ConnectionException getLastException() {
  233. return lastException;
  234. }
  235. @Override
  236. public String toString() {
  237. return String.format(NAME_FORMAT, getHost().getHostName(), id);
  238. }
  239. /**
  240. * Compares the toString of these clients
  241. */
  242. @Override
  243. public boolean equals(Object obj) {
  244. return toString().equals(obj.toString());
  245. }
  246. @Override
  247. public long getOperationCount() {
  248. return operationCounter.get();
  249. }
  250. @Override
  251. public Host getHost() {
  252. return pool.getHost();
  253. }
  254. public void setTimeout(int timeout) {
  255. if (this.timeout != timeout) {
  256. socket.setTimeout(timeout);
  257. this.timeout = timeout;
  258. }
  259. }
  260. };
  261. }
  262. }