/*
 * Licensed to ElasticSearch and Shay Banon under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. ElasticSearch 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.
 */

package org.elasticsearch.cluster.routing.allocation.decider;

import org.elasticsearch.cluster.routing.MutableShardRouting;
import org.elasticsearch.cluster.routing.RoutingNode;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;

/**
 * An allocation decider that prevents the more than prevents multiple instances
 * of the same shard to be allocated on a single <tt>host</tt>. The cluster setting can
 * be modified in real-time by updating the {@value #SAME_HOST_SETTING} value of
 * cluster setting API. The default is <code>false</code>.
 * <p>
 * Note: this setting only applies if multiple nodes are started on the same
 * <tt>host</tt>. Multiple allocations of the same shard on the same <tt>node</tt> are
 * not allowed independent of this setting.
 * </p>
 */
public class SameShardAllocationDecider extends AllocationDecider {

    public static final String SAME_HOST_SETTING = "cluster.routing.allocation.same_shard.host";

    private final boolean sameHost;

    @Inject
    public SameShardAllocationDecider(Settings settings) {
        super(settings);

        this.sameHost = settings.getAsBoolean(SAME_HOST_SETTING, false);
    }

    @Override
    public Decision canAllocate(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) {
        for (MutableShardRouting nodeShard : node) {
            // we do not allow for two shards of the same shard id to exists on the same node
            if (nodeShard.shardId().equals(shardRouting.shardId())) {
                return Decision.NO;
            }
        }
        if (sameHost) {
            if (node.node() != null) {
                for (RoutingNode checkNode : allocation.routingNodes()) {
                    if (checkNode.node() == null) {
                        continue;
                    }
                    // check if its on the same host as the one we want to allocate to
                    if (!checkNode.node().address().sameHost(node.node().address())) {
                        continue;
                    }
                    for (MutableShardRouting nodeShard : checkNode) {
                        if (nodeShard.shardId().equals(shardRouting.shardId())) {
                            return Decision.NO;
                        }
                    }
                }
            }
        }
        return Decision.YES;
    }
}

@@ -2248,37 +2248,41 @@
 tion) %7B%0A        
-for (
+Iterable%3C
 MutableShardRout
@@ -2288,122 +2288,149 @@
 ting
- nodeShard : node) %7B%0A            // we do not allow for two shards of the same shard id to exists on the same node
+%3E assignedShards = allocation.routingNodes().assignedShards(shardRouting);%0A        for (MutableShardRouting assignedShard : assignedShards) %7B
 %0A   
@@ -2442,35 +2442,29 @@
     if (node
-Shard.shard
+.node
 Id().equals(
@@ -2463,34 +2463,41 @@
 .equals(
-shardRouting.shard
+assignedShard.currentNode
 Id())) %7B
@@ -3081,29 +3081,38 @@
 ing 
-nodeShard : checkNode
+assignedShard : assignedShards
 ) %7B%0A
@@ -3143,53 +3143,59 @@
 if (
-nodeShard.shardId().equals(shardRouting.shard
+checkNode.nodeId().equals(assignedShard.currentNode
 Id()

use the computed data structure to optimize the same shard allocation decider