/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate licenses * this file to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package org.elasticsearch.action.bulk; import org.apache.logging.log4j.Logger; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterStateListener; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.routing.IndexRoutingTable; import org.elasticsearch.cluster.routing.IndexShardRoutingTable; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Singleton; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardNotFoundException; import org.elasticsearch.threadpool.ThreadPool; import java.util.HashMap; import java.util.Map; @Singleton public class BulkRetryCoordinatorPool extends AbstractLifecycleComponent implements ClusterStateListener { private static final Logger LOGGER = Loggers.getLogger(BulkRetryCoordinatorPool.class); private final Map<String, BulkRetryCoordinator> coordinatorsByNodeId; private final Map<ShardId, BulkRetryCoordinator> coordinatorsByShardId; private final ClusterService clusterService; private final ThreadPool threadPool; @Inject public BulkRetryCoordinatorPool(Settings settings, ClusterService clusterService, ThreadPool threadPool) { super(settings); this.threadPool = threadPool; this.coordinatorsByShardId = new HashMap<>(); this.coordinatorsByNodeId = new HashMap<>(); this.clusterService = clusterService; } public BulkRetryCoordinator coordinator(ShardId shardId) throws IndexNotFoundException, ShardNotFoundException { synchronized (coordinatorsByShardId) { BulkRetryCoordinator coordinator = coordinatorsByShardId.get(shardId); if (coordinator == null) { IndexRoutingTable indexRoutingTable = clusterService.state().routingTable() .index(shardId.getIndex()); if (indexRoutingTable == null) { throw new IndexNotFoundException(shardId.getIndex()); } IndexShardRoutingTable shardRoutingTable = indexRoutingTable.shard(shardId.id()); if (shardRoutingTable == null) { throw new ShardNotFoundException(shardId); } String nodeId = shardRoutingTable.primaryShard().currentNodeId(); // for currently unassigned shards the nodeId will be null // so we at some point we will always keep one coordinator around // for all the orphaned unassigned shards that might end up here // The requests for unassigned shards will be retried at the transport action level // so no problem here :) // wow, that is a long comment! synchronized (coordinatorsByNodeId) { coordinator = coordinatorsByNodeId.get(nodeId); if (coordinator == null) { LOGGER.debug("create new coordinator for node {} and shard {}", nodeId, shardId); coordinator = new BulkRetryCoordinator(threadPool); coordinatorsByNodeId.put(nodeId, coordinator); } } coordinatorsByShardId.put(shardId, coordinator); } return coordinator; } } @Override protected void doStart() throws ElasticsearchException { clusterService.addLast(this); } @Override protected void doStop() throws ElasticsearchException { clusterService.remove(this); coordinatorsByShardId.clear(); } @Override protected void doClose() throws ElasticsearchException { doStop(); coordinatorsByNodeId.clear(); } @Override public void clusterChanged(ClusterChangedEvent event) { if (event.routingTableChanged()) { coordinatorsByShardId.clear(); } if (event.nodesRemoved()) { // remove retrycoordinators of removed nodes synchronized (coordinatorsByNodeId) { for (DiscoveryNode node : event.nodesDelta().removedNodes()) { coordinatorsByNodeId.remove(node.getId()); } } } } }