PageRenderTime 91ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/org/elasticsearch/action/support/single/custom/TransportSingleCustomOperationAction.java

https://bitbucket.org/dkartaschew/elasticsearch
Java | 370 lines | 287 code | 51 blank | 32 comment | 33 complexity | 53b2685d60c8c1bab8d9010d0a6cb89d MD5 | raw file
  1. /*
  2. * Licensed to Elastic Search and Shay Banon under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. Elastic Search licenses this
  6. * file to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.elasticsearch.action.support.single.custom;
  20. import org.elasticsearch.ElasticSearchException;
  21. import org.elasticsearch.action.ActionListener;
  22. import org.elasticsearch.action.ActionResponse;
  23. import org.elasticsearch.action.NoShardAvailableActionException;
  24. import org.elasticsearch.action.support.TransportAction;
  25. import org.elasticsearch.cluster.ClusterService;
  26. import org.elasticsearch.cluster.ClusterState;
  27. import org.elasticsearch.cluster.block.ClusterBlockException;
  28. import org.elasticsearch.cluster.node.DiscoveryNode;
  29. import org.elasticsearch.cluster.node.DiscoveryNodes;
  30. import org.elasticsearch.cluster.routing.ShardRouting;
  31. import org.elasticsearch.cluster.routing.ShardsIterator;
  32. import org.elasticsearch.common.io.stream.StreamInput;
  33. import org.elasticsearch.common.io.stream.StreamOutput;
  34. import org.elasticsearch.common.settings.Settings;
  35. import org.elasticsearch.threadpool.ThreadPool;
  36. import org.elasticsearch.transport.*;
  37. import java.io.IOException;
  38. /**
  39. *
  40. */
  41. public abstract class TransportSingleCustomOperationAction<Request extends SingleCustomOperationRequest, Response extends ActionResponse> extends TransportAction<Request, Response> {
  42. protected final ClusterService clusterService;
  43. protected final TransportService transportService;
  44. final String transportAction;
  45. final String transportShardAction;
  46. final String executor;
  47. protected TransportSingleCustomOperationAction(Settings settings, ThreadPool threadPool, ClusterService clusterService, TransportService transportService) {
  48. super(settings, threadPool);
  49. this.clusterService = clusterService;
  50. this.transportService = transportService;
  51. this.transportAction = transportAction();
  52. this.transportShardAction = transportAction() + "/s";
  53. this.executor = executor();
  54. transportService.registerHandler(transportAction, new TransportHandler());
  55. transportService.registerHandler(transportShardAction, new ShardTransportHandler());
  56. }
  57. @Override
  58. protected void doExecute(Request request, ActionListener<Response> listener) {
  59. new AsyncSingleAction(request, listener).start();
  60. }
  61. protected abstract String transportAction();
  62. protected abstract String executor();
  63. /**
  64. * Can return null to execute on this local node.
  65. */
  66. protected abstract ShardsIterator shards(ClusterState state, Request request);
  67. protected abstract Response shardOperation(Request request, int shardId) throws ElasticSearchException;
  68. protected abstract Request newRequest();
  69. protected abstract Response newResponse();
  70. protected abstract ClusterBlockException checkGlobalBlock(ClusterState state, Request request);
  71. protected abstract ClusterBlockException checkRequestBlock(ClusterState state, Request request);
  72. private class AsyncSingleAction {
  73. private final ActionListener<Response> listener;
  74. private final ShardsIterator shardsIt;
  75. private final Request request;
  76. private final DiscoveryNodes nodes;
  77. private AsyncSingleAction(Request request, ActionListener<Response> listener) {
  78. this.request = request;
  79. this.listener = listener;
  80. ClusterState clusterState = clusterService.state();
  81. nodes = clusterState.nodes();
  82. ClusterBlockException blockException = checkGlobalBlock(clusterState, request);
  83. if (blockException != null) {
  84. throw blockException;
  85. }
  86. blockException = checkRequestBlock(clusterState, request);
  87. if (blockException != null) {
  88. throw blockException;
  89. }
  90. this.shardsIt = shards(clusterState, request);
  91. }
  92. public void start() {
  93. performFirst();
  94. }
  95. private void onFailure(ShardRouting shardRouting, Throwable e) {
  96. if (logger.isTraceEnabled() && e != null) {
  97. logger.trace(shardRouting.shortSummary() + ": Failed to execute [" + request + "]", e);
  98. }
  99. perform(e);
  100. }
  101. /**
  102. * First get should try and use a shard that exists on a local node for better performance
  103. */
  104. private void performFirst() {
  105. if (shardsIt == null) {
  106. // just execute it on the local node
  107. if (request.operationThreaded()) {
  108. request.beforeLocalFork();
  109. threadPool.executor(executor()).execute(new Runnable() {
  110. @Override
  111. public void run() {
  112. try {
  113. Response response = shardOperation(request, -1);
  114. listener.onResponse(response);
  115. } catch (Throwable e) {
  116. onFailure(null, e);
  117. }
  118. }
  119. });
  120. return;
  121. } else {
  122. try {
  123. final Response response = shardOperation(request, -1);
  124. listener.onResponse(response);
  125. return;
  126. } catch (Throwable e) {
  127. onFailure(null, e);
  128. }
  129. }
  130. return;
  131. }
  132. if (request.preferLocalShard()) {
  133. boolean foundLocal = false;
  134. ShardRouting shardX;
  135. while ((shardX = shardsIt.nextOrNull()) != null) {
  136. final ShardRouting shard = shardX;
  137. if (shard.currentNodeId().equals(nodes.localNodeId())) {
  138. foundLocal = true;
  139. if (request.operationThreaded()) {
  140. request.beforeLocalFork();
  141. threadPool.executor(executor()).execute(new Runnable() {
  142. @Override
  143. public void run() {
  144. try {
  145. Response response = shardOperation(request, shard.id());
  146. listener.onResponse(response);
  147. } catch (Throwable e) {
  148. shardsIt.reset();
  149. onFailure(shard, e);
  150. }
  151. }
  152. });
  153. return;
  154. } else {
  155. try {
  156. final Response response = shardOperation(request, shard.id());
  157. listener.onResponse(response);
  158. return;
  159. } catch (Throwable e) {
  160. shardsIt.reset();
  161. onFailure(shard, e);
  162. }
  163. }
  164. }
  165. }
  166. if (!foundLocal) {
  167. // no local node get, go remote
  168. shardsIt.reset();
  169. perform(null);
  170. }
  171. } else {
  172. perform(null);
  173. }
  174. }
  175. private void perform(final Throwable lastException) {
  176. final ShardRouting shard = shardsIt == null ? null : shardsIt.nextOrNull();
  177. if (shard == null) {
  178. Throwable failure = lastException;
  179. if (failure == null) {
  180. failure = new NoShardAvailableActionException(null, "No shard available for [" + request + "]");
  181. } else {
  182. if (logger.isDebugEnabled()) {
  183. logger.debug("failed to execute [" + request + "]", failure);
  184. }
  185. }
  186. listener.onFailure(failure);
  187. } else {
  188. if (shard.currentNodeId().equals(nodes.localNodeId())) {
  189. // we don't prefer local shard, so try and do it here
  190. if (!request.preferLocalShard()) {
  191. if (request.operationThreaded()) {
  192. request.beforeLocalFork();
  193. threadPool.executor(executor).execute(new Runnable() {
  194. @Override
  195. public void run() {
  196. try {
  197. Response response = shardOperation(request, shard.id());
  198. listener.onResponse(response);
  199. } catch (Throwable e) {
  200. onFailure(shard, e);
  201. }
  202. }
  203. });
  204. } else {
  205. try {
  206. final Response response = shardOperation(request, shard.id());
  207. listener.onResponse(response);
  208. } catch (Throwable e) {
  209. onFailure(shard, e);
  210. }
  211. }
  212. } else {
  213. perform(lastException);
  214. }
  215. } else {
  216. DiscoveryNode node = nodes.get(shard.currentNodeId());
  217. transportService.sendRequest(node, transportShardAction, new ShardSingleOperationRequest(request, shard.id()), new BaseTransportResponseHandler<Response>() {
  218. @Override
  219. public Response newInstance() {
  220. return newResponse();
  221. }
  222. @Override
  223. public String executor() {
  224. return ThreadPool.Names.SAME;
  225. }
  226. @Override
  227. public void handleResponse(final Response response) {
  228. listener.onResponse(response);
  229. }
  230. @Override
  231. public void handleException(TransportException exp) {
  232. onFailure(shard, exp);
  233. }
  234. });
  235. }
  236. }
  237. }
  238. }
  239. private class TransportHandler extends BaseTransportRequestHandler<Request> {
  240. @Override
  241. public Request newInstance() {
  242. return newRequest();
  243. }
  244. @Override
  245. public void messageReceived(Request request, final TransportChannel channel) throws Exception {
  246. // no need to have a threaded listener since we just send back a response
  247. request.listenerThreaded(false);
  248. // if we have a local operation, execute it on a thread since we don't spawn
  249. request.operationThreaded(true);
  250. execute(request, new ActionListener<Response>() {
  251. @Override
  252. public void onResponse(Response result) {
  253. try {
  254. channel.sendResponse(result);
  255. } catch (Throwable e) {
  256. onFailure(e);
  257. }
  258. }
  259. @Override
  260. public void onFailure(Throwable e) {
  261. try {
  262. channel.sendResponse(e);
  263. } catch (Exception e1) {
  264. logger.warn("Failed to send response for get", e1);
  265. }
  266. }
  267. });
  268. }
  269. @Override
  270. public String executor() {
  271. return ThreadPool.Names.SAME;
  272. }
  273. }
  274. private class ShardTransportHandler extends BaseTransportRequestHandler<ShardSingleOperationRequest> {
  275. @Override
  276. public ShardSingleOperationRequest newInstance() {
  277. return new ShardSingleOperationRequest();
  278. }
  279. @Override
  280. public String executor() {
  281. return executor;
  282. }
  283. @Override
  284. public void messageReceived(final ShardSingleOperationRequest request, final TransportChannel channel) throws Exception {
  285. Response response = shardOperation(request.request(), request.shardId());
  286. channel.sendResponse(response);
  287. }
  288. }
  289. protected class ShardSingleOperationRequest extends TransportRequest {
  290. private Request request;
  291. private int shardId;
  292. ShardSingleOperationRequest() {
  293. }
  294. public ShardSingleOperationRequest(Request request, int shardId) {
  295. super(request);
  296. this.request = request;
  297. this.shardId = shardId;
  298. }
  299. public Request request() {
  300. return request;
  301. }
  302. public int shardId() {
  303. return shardId;
  304. }
  305. @Override
  306. public void readFrom(StreamInput in) throws IOException {
  307. super.readFrom(in);
  308. request = newRequest();
  309. request.readFrom(in);
  310. shardId = in.readVInt();
  311. }
  312. @Override
  313. public void writeTo(StreamOutput out) throws IOException {
  314. super.writeTo(out);
  315. request.writeTo(out);
  316. out.writeVInt(shardId);
  317. }
  318. }
  319. }