/** Initializes an index, to be restored from snapshot */
 private Builder initializeAsRestore(
     IndexMetaData indexMetaData, RestoreSource restoreSource, boolean asNew) {
   if (!shards.isEmpty()) {
     throw new ElasticSearchIllegalStateException(
         "trying to initialize an index with fresh shards, but already has shards created");
   }
   for (int shardId = 0; shardId < indexMetaData.numberOfShards(); shardId++) {
     IndexShardRoutingTable.Builder indexShardRoutingBuilder =
         new IndexShardRoutingTable.Builder(
             new ShardId(indexMetaData.index(), shardId), asNew ? false : true);
     for (int i = 0; i <= indexMetaData.numberOfReplicas(); i++) {
       indexShardRoutingBuilder.addShard(
           new ImmutableShardRouting(
               index,
               shardId,
               null,
               null,
               i == 0 ? restoreSource : null,
               i == 0,
               ShardRoutingState.UNASSIGNED,
               0));
     }
     shards.put(shardId, indexShardRoutingBuilder.build());
   }
   return this;
 }
 /**
  * Writes an {@link IndexRoutingTable} to a {@link StreamOutput}.
  *
  * @param index {@link IndexRoutingTable} to write
  * @param out {@link StreamOutput} to write to
  * @throws IOException if something happens during write
  */
 public static void writeTo(IndexRoutingTable index, StreamOutput out) throws IOException {
   out.writeString(index.index());
   out.writeVInt(index.shards.size());
   for (IndexShardRoutingTable indexShard : index) {
     IndexShardRoutingTable.Builder.writeToThin(indexShard, out);
   }
 }
  /** Creates cluster state with several shards and one replica and all shards STARTED. */
  public static ClusterState stateWithAssignedPrimariesAndOneReplica(
      String index, int numberOfShards) {

    int numberOfNodes = 2; // we need a non-local master to test shard failures
    DiscoveryNodes.Builder discoBuilder = DiscoveryNodes.builder();
    for (int i = 0; i < numberOfNodes + 1; i++) {
      final DiscoveryNode node = newNode(i);
      discoBuilder = discoBuilder.put(node);
    }
    discoBuilder.localNodeId(newNode(0).getId());
    discoBuilder.masterNodeId(
        newNode(1).getId()); // we need a non-local master to test shard failures
    IndexMetaData indexMetaData =
        IndexMetaData.builder(index)
            .settings(
                Settings.builder()
                    .put(SETTING_VERSION_CREATED, Version.CURRENT)
                    .put(SETTING_NUMBER_OF_SHARDS, numberOfShards)
                    .put(SETTING_NUMBER_OF_REPLICAS, 1)
                    .put(SETTING_CREATION_DATE, System.currentTimeMillis()))
            .build();
    ClusterState.Builder state = ClusterState.builder(new ClusterName("test"));
    state.nodes(discoBuilder);
    state.metaData(MetaData.builder().put(indexMetaData, false).generateClusterUuidIfNeeded());
    IndexRoutingTable.Builder indexRoutingTableBuilder =
        IndexRoutingTable.builder(indexMetaData.getIndex());
    for (int i = 0; i < numberOfShards; i++) {
      RoutingTable.Builder routing = new RoutingTable.Builder();
      routing.addAsNew(indexMetaData);
      final ShardId shardId = new ShardId(index, "_na_", i);
      IndexShardRoutingTable.Builder indexShardRoutingBuilder =
          new IndexShardRoutingTable.Builder(shardId);
      indexShardRoutingBuilder.addShard(
          TestShardRouting.newShardRouting(
              index, i, newNode(0).getId(), null, null, true, ShardRoutingState.STARTED, null));
      indexShardRoutingBuilder.addShard(
          TestShardRouting.newShardRouting(
              index, i, newNode(1).getId(), null, null, false, ShardRoutingState.STARTED, null));
      indexRoutingTableBuilder.addIndexShard(indexShardRoutingBuilder.build());
    }
    state.routingTable(RoutingTable.builder().add(indexRoutingTableBuilder.build()).build());
    return state.build();
  }
    /**
     * Reads an {@link IndexRoutingTable} from an {@link StreamInput}
     *
     * @param in {@link StreamInput} to read the {@link IndexRoutingTable} from
     * @return {@link IndexRoutingTable} read
     * @throws IOException if something happens during read
     */
    public static IndexRoutingTable readFrom(StreamInput in) throws IOException {
      String index = in.readString();
      Builder builder = new Builder(index);

      int size = in.readVInt();
      for (int i = 0; i < size; i++) {
        builder.addIndexShard(IndexShardRoutingTable.Builder.readFromThin(in, index));
      }

      return builder.build();
    }
 public Builder removeReplica() {
   for (IntCursor cursor : shards.keys()) {
     int shardId = cursor.value;
     IndexShardRoutingTable indexShard = shards.get(shardId);
     if (indexShard.replicaShards().isEmpty()) {
       // nothing to do here!
       return this;
     }
     // re-add all the current ones
     IndexShardRoutingTable.Builder builder =
         new IndexShardRoutingTable.Builder(
             indexShard.shardId(), indexShard.primaryAllocatedPostApi());
     for (ShardRouting shardRouting : indexShard) {
       builder.addShard(new ImmutableShardRouting(shardRouting));
     }
     // first check if there is one that is not assigned to a node, and remove it
     boolean removed = false;
     for (ShardRouting shardRouting : indexShard) {
       if (!shardRouting.primary() && !shardRouting.assignedToNode()) {
         builder.removeShard(shardRouting);
         removed = true;
         break;
       }
     }
     if (!removed) {
       for (ShardRouting shardRouting : indexShard) {
         if (!shardRouting.primary()) {
           builder.removeShard(shardRouting);
           removed = true;
           break;
         }
       }
     }
     shards.put(shardId, builder.build());
   }
   return this;
 }
  /**
   * Creates cluster state with and index that has one shard and #(replicaStates) replicas
   *
   * @param index name of the index
   * @param activePrimaryLocal if active primary should coincide with the local node in the cluster
   *     state
   * @param primaryState state of primary
   * @param replicaStates states of the replicas. length of this array determines also the number of
   *     replicas
   */
  public static ClusterState state(
      String index,
      boolean activePrimaryLocal,
      ShardRoutingState primaryState,
      ShardRoutingState... replicaStates) {
    final int numberOfReplicas = replicaStates.length;

    int numberOfNodes = numberOfReplicas + 1;
    if (primaryState == ShardRoutingState.RELOCATING) {
      numberOfNodes++;
    }
    for (ShardRoutingState state : replicaStates) {
      if (state == ShardRoutingState.RELOCATING) {
        numberOfNodes++;
      }
    }
    numberOfNodes = Math.max(2, numberOfNodes); // we need a non-local master to test shard failures
    final ShardId shardId = new ShardId(index, "_na_", 0);
    DiscoveryNodes.Builder discoBuilder = DiscoveryNodes.builder();
    Set<String> unassignedNodes = new HashSet<>();
    for (int i = 0; i < numberOfNodes + 1; i++) {
      final DiscoveryNode node = newNode(i);
      discoBuilder = discoBuilder.put(node);
      unassignedNodes.add(node.getId());
    }
    discoBuilder.localNodeId(newNode(0).getId());
    discoBuilder.masterNodeId(
        newNode(1).getId()); // we need a non-local master to test shard failures
    final int primaryTerm = 1 + randomInt(200);
    IndexMetaData indexMetaData =
        IndexMetaData.builder(index)
            .settings(
                Settings.builder()
                    .put(SETTING_VERSION_CREATED, Version.CURRENT)
                    .put(SETTING_NUMBER_OF_SHARDS, 1)
                    .put(SETTING_NUMBER_OF_REPLICAS, numberOfReplicas)
                    .put(SETTING_CREATION_DATE, System.currentTimeMillis()))
            .primaryTerm(0, primaryTerm)
            .build();

    RoutingTable.Builder routing = new RoutingTable.Builder();
    routing.addAsNew(indexMetaData);
    IndexShardRoutingTable.Builder indexShardRoutingBuilder =
        new IndexShardRoutingTable.Builder(shardId);

    String primaryNode = null;
    String relocatingNode = null;
    UnassignedInfo unassignedInfo = null;
    if (primaryState != ShardRoutingState.UNASSIGNED) {
      if (activePrimaryLocal) {
        primaryNode = newNode(0).getId();
        unassignedNodes.remove(primaryNode);
      } else {
        Set<String> unassignedNodesExecludingPrimary = new HashSet<>(unassignedNodes);
        unassignedNodesExecludingPrimary.remove(newNode(0).getId());
        primaryNode = selectAndRemove(unassignedNodesExecludingPrimary);
      }
      if (primaryState == ShardRoutingState.RELOCATING) {
        relocatingNode = selectAndRemove(unassignedNodes);
      }
    } else {
      unassignedInfo = new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, null);
    }
    indexShardRoutingBuilder.addShard(
        TestShardRouting.newShardRouting(
            index, 0, primaryNode, relocatingNode, null, true, primaryState, unassignedInfo));

    for (ShardRoutingState replicaState : replicaStates) {
      String replicaNode = null;
      relocatingNode = null;
      unassignedInfo = null;
      if (replicaState != ShardRoutingState.UNASSIGNED) {
        assert primaryNode != null : "a replica is assigned but the primary isn't";
        replicaNode = selectAndRemove(unassignedNodes);
        if (replicaState == ShardRoutingState.RELOCATING) {
          relocatingNode = selectAndRemove(unassignedNodes);
        }
      } else {
        unassignedInfo = new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, null);
      }
      indexShardRoutingBuilder.addShard(
          TestShardRouting.newShardRouting(
              index,
              shardId.id(),
              replicaNode,
              relocatingNode,
              null,
              false,
              replicaState,
              unassignedInfo));
    }

    ClusterState.Builder state = ClusterState.builder(new ClusterName("test"));
    state.nodes(discoBuilder);
    state.metaData(MetaData.builder().put(indexMetaData, false).generateClusterUuidIfNeeded());
    state.routingTable(
        RoutingTable.builder()
            .add(
                IndexRoutingTable.builder(indexMetaData.getIndex())
                    .addIndexShard(indexShardRoutingBuilder.build()))
            .build());
    return state.build();
  }