@Override public int sizeActive() { int count = 0; for (ShardRouting shard : shards) { if (shard.active()) { count++; } } return count; }
/** * Returns true if no primaries are active or initializing for this shard */ private boolean noPrimariesActive() { if (!primaryAsList.isEmpty() && !primaryAsList.get(0).active() && !primaryAsList.get(0).initializing()) { return true; } return false; }
/** * Calculates the number of primary shards in active state in routing table * * @return number of active primary shards */ public int primaryShardsActive() { int counter = 0; for (IndexShardRoutingTable shardRoutingTable : this) { if (shardRoutingTable.primaryShard().active()) { counter++; } } return counter; }
IndexRoutingTable(Index index, ImmutableOpenIntMap<IndexShardRoutingTable> shards) { this.index = index; this.shuffler = new RotationShardShuffler(Randomness.get().nextInt()); this.shards = shards; List<ShardRouting> allActiveShards = new ArrayList<>(); for (IntObjectCursor<IndexShardRoutingTable> cursor : shards) { for (ShardRouting shardRouting : cursor.value) { if (shardRouting.active()) { allActiveShards.add(shardRouting); } } } this.allActiveShards = Collections.unmodifiableList(allActiveShards); }
/** * Returns the active primary shard for the given shard id or <code>null</code> if * no primary is found or the primary is not active. */ public ShardRouting activePrimary(ShardId shardId) { for (ShardRouting shardRouting : assignedShards(shardId)) { if (shardRouting.primary() && shardRouting.active()) { return shardRouting; } } return null; }
/** * Make the active shard primary unless it's not primary * * @throws IllegalShardRoutingStateException if shard is already a primary */ public ShardRouting moveActiveReplicaToPrimary() { assert active(): "expected an active shard " + this; if (primary) { throw new IllegalShardRoutingStateException(this, "Already primary, can't move to primary"); } return new ShardRouting(shardId, currentNodeId, relocatingNodeId, true, state, recoverySource, unassignedInfo, allocationId, expectedShardSize); }
public ShardIterator replicaFirstActiveInitializingShardsIt() { // If the primaries are unassigned, return an empty list (there aren't // any replicas to query anyway) if (noPrimariesActive()) { return new PlainShardIterator(shardId, NO_SHARDS); } ArrayList<ShardRouting> ordered = new ArrayList<>(activeShards.size() + allInitializingShards.size()); // fill it in a randomized fashion with the active replicas for (ShardRouting replica : shuffler.shuffle(replicas)) { if (replica.active()) { ordered.add(replica); } } // Add the primary shard ordered.add(primary); // Add initializing shards last if (!allInitializingShards.isEmpty()) { ordered.addAll(allInitializingShards); } return new PlainShardIterator(shardId, ordered); }
/** * Returns <code>true</code> iff all replicas are active for the given shard routing. Otherwise <code>false</code> */ public boolean allReplicasActive(ShardId shardId, MetaData metaData) { final List<ShardRouting> shards = assignedShards(shardId); if (shards.isEmpty() || shards.size() < metaData.getIndexSafe(shardId.getIndex()).getNumberOfReplicas() + 1) { return false; // if we are empty nothing is active if we have less than total at least one is unassigned } for (ShardRouting shard : shards) { if (!shard.active()) { return false; } } return true; }
/** * Remove allocation id of this shard from the set of in-sync shard copies */ void removeAllocationId(ShardRouting shardRouting) { if (shardRouting.active()) { changes(shardRouting.shardId()).removedAllocationIds.add(shardRouting.allocationId().getId()); } }
/** * moves the assigned replica shard to primary. * * @param replicaShard the replica shard to be promoted to primary * @return the resulting primary shard */ private ShardRouting promoteActiveReplicaShardToPrimary(ShardRouting replicaShard) { assert replicaShard.active() : "non-active shard cannot be promoted to primary: " + replicaShard; assert replicaShard.primary() == false : "primary shard cannot be promoted to primary: " + replicaShard; ShardRouting primaryShard = replicaShard.moveActiveReplicaToPrimary(); updateAssigned(replicaShard, primaryShard); return primaryShard; }
public ShardIterator replicaActiveInitializingShardIt() { // If the primaries are unassigned, return an empty list (there aren't // any replicas to query anyway) if (noPrimariesActive()) { return new PlainShardIterator(shardId, NO_SHARDS); } LinkedList<ShardRouting> ordered = new LinkedList<>(); for (ShardRouting replica : shuffler.shuffle(replicas)) { if (replica.active()) { ordered.addFirst(replica); } else if (replica.initializing()) { ordered.addLast(replica); } } return new PlainShardIterator(shardId, ordered); }
/** * Returns one active replica shard for the given shard id or <code>null</code> if * no active replica is found. * * Since replicas could possibly be on nodes with a older version of ES than * the primary is, this will return replicas on the highest version of ES. * */ public ShardRouting activeReplicaWithHighestVersion(ShardId shardId) { // It's possible for replicaNodeVersion to be null, when deassociating dead nodes // that have been removed, the shards are failed, and part of the shard failing // calls this method with an out-of-date RoutingNodes, where the version might not // be accessible. Therefore, we need to protect against the version being null // (meaning the node will be going away). return assignedShards(shardId).stream() .filter(shr -> !shr.primary() && shr.active()) .filter(shr -> node(shr.currentNodeId()) != null) .max(Comparator.comparing(shr -> node(shr.currentNodeId()).node(), Comparator.nullsFirst(Comparator.comparing(DiscoveryNode::getVersion)))) .orElse(null); }
/** * Moves the shard to unassigned state. */ public ShardRouting moveToUnassigned(UnassignedInfo unassignedInfo) { assert state != ShardRoutingState.UNASSIGNED : this; final RecoverySource recoverySource; if (active()) { if (primary()) { recoverySource = ExistingStoreRecoverySource.INSTANCE; } else { recoverySource = PeerRecoverySource.INSTANCE; } } else { recoverySource = recoverySource(); } return new ShardRouting(shardId, null, null, primary, ShardRoutingState.UNASSIGNED, recoverySource, unassignedInfo, null, UNAVAILABLE_EXPECTED_SHARD_SIZE); }
/** * All the *active* primary shards for the provided indices grouped (each group is a single element, consisting * of the primary shard). This is handy for components that expect to get group iterators, but still want in some * cases to iterate over all primary shards (and not just one shard in replication group). * * @param indices The indices to return all the shards (replicas) * @return All the primary shards grouped into a single shard element group each * @throws IndexNotFoundException If an index passed does not exists */ public GroupShardsIterator<ShardIterator> activePrimaryShardsGrouped(String[] indices, boolean includeEmpty) { // use list here since we need to maintain identity across shards ArrayList<ShardIterator> set = new ArrayList<>(); for (String index : indices) { IndexRoutingTable indexRoutingTable = index(index); if (indexRoutingTable == null) { throw new IndexNotFoundException(index); } for (IndexShardRoutingTable indexShardRoutingTable : indexRoutingTable) { ShardRouting primary = indexShardRoutingTable.primaryShard(); if (primary.active()) { set.add(primary.shardsIt()); } else if (includeEmpty) { // we need this for counting properly, just make it an empty one set.add(new PlainShardIterator(primary.shardId(), Collections.<ShardRouting>emptyList())); } } } return new GroupShardsIterator<>(set); }
@Override public void shardFailed(ShardRouting failedShard, UnassignedInfo unassignedInfo) { if (failedShard.active() && failedShard.primary()) { Updates updates = changes(failedShard.shardId()); if (updates.firstFailedPrimary == null) { // more than one primary can be failed (because of batching, primary can be failed, replica promoted and then failed...) updates.firstFailedPrimary = failedShard; } increasePrimaryTerm(failedShard.shardId()); } }
@Nullable private ShardRouting findAssignedPrimaryIfPeerRecovery(ShardRouting routing) { ShardRouting primary = null; if (routing.recoverySource() != null && routing.recoverySource().getType() == RecoverySource.Type.PEER) { List<ShardRouting> shardRoutings = assignedShards.get(routing.shardId()); if (shardRoutings != null) { for (ShardRouting shardRouting : shardRoutings) { if (shardRouting.primary()) { if (shardRouting.active()) { return shardRouting; } else if (primary == null) { primary = shardRouting; } else if (primary.relocatingNodeId() != null) { primary = shardRouting; } } } } } return primary; }
/** * Finds the routing source node for peer recovery, return null if its not found. Note, this method expects the shard * routing to *require* peer recovery, use {@link ShardRouting#recoverySource()} to check if its needed or not. */ private static DiscoveryNode findSourceNodeForPeerRecovery(Logger logger, RoutingTable routingTable, DiscoveryNodes nodes, ShardRouting shardRouting) { DiscoveryNode sourceNode = null; if (!shardRouting.primary()) { ShardRouting primary = routingTable.shardRoutingTable(shardRouting.shardId()).primaryShard(); // only recover from started primary, if we can't find one, we will do it next round if (primary.active()) { sourceNode = nodes.get(primary.currentNodeId()); if (sourceNode == null) { logger.trace("can't find replica source node because primary shard {} is assigned to an unknown node.", primary); } } else { logger.trace("can't find replica source node because primary shard {} is not active.", primary); } } else if (shardRouting.relocatingNodeId() != null) { sourceNode = nodes.get(shardRouting.relocatingNodeId()); if (sourceNode == null) { logger.trace("can't find relocation source node for shard {} because it is assigned to an unknown node [{}].", shardRouting.shardId(), shardRouting.relocatingNodeId()); } } else { throw new IllegalStateException("trying to find source node for peer recovery when routing state means no peer recovery: " + shardRouting); } return sourceNode; }
/** * Checks if an inactive primary shard should cause the cluster health to go RED. * * An inactive primary shard in an index should cause the cluster health to be RED to make it visible that some of the existing data is * unavailable. In case of index creation, snapshot restore or index shrinking, which are unexceptional events in the cluster lifecycle, * cluster health should not turn RED for the time where primaries are still in the initializing state but go to YELLOW instead. * However, in case of exceptional events, for example when the primary shard cannot be assigned to a node or initialization fails at * some point, cluster health should still turn RED. * * NB: this method should *not* be called on active shards nor on non-primary shards. */ public static ClusterHealthStatus getInactivePrimaryHealth(final ShardRouting shardRouting) { assert shardRouting.primary() : "cannot invoke on a replica shard: " + shardRouting; assert shardRouting.active() == false : "cannot invoke on an active shard: " + shardRouting; assert shardRouting.unassignedInfo() != null : "cannot invoke on a shard with no UnassignedInfo: " + shardRouting; assert shardRouting.recoverySource() != null : "cannot invoke on a shard that has no recovery source" + shardRouting; final UnassignedInfo unassignedInfo = shardRouting.unassignedInfo(); RecoverySource.Type recoveryType = shardRouting.recoverySource().getType(); if (unassignedInfo.getLastAllocationStatus() != AllocationStatus.DECIDERS_NO && unassignedInfo.getNumFailedAllocations() == 0 && (recoveryType == RecoverySource.Type.EMPTY_STORE || recoveryType == RecoverySource.Type.LOCAL_SHARDS || recoveryType == RecoverySource.Type.SNAPSHOT)) { return ClusterHealthStatus.YELLOW; } else { return ClusterHealthStatus.RED; } }
private RecoveryResponse recover(final StartRecoveryRequest request) throws IOException { final IndexService indexService = indicesService.indexServiceSafe(request.shardId().getIndex()); final IndexShard shard = indexService.getShard(request.shardId().id()); final ShardRouting routingEntry = shard.routingEntry(); if (routingEntry.primary() == false || routingEntry.active() == false) { throw new DelayRecoveryException("source shard [" + routingEntry + "] is not an active primary"); } if (request.isPrimaryRelocation() && (routingEntry.relocating() == false || routingEntry.relocatingNodeId().equals(request.targetNode().getId()) == false)) { logger.debug("delaying recovery of {} as source shard is not marked yet as relocating to {}", request.shardId(), request.targetNode()); throw new DelayRecoveryException("source shard is not marked yet as relocating to [" + request.targetNode() + "]"); } RecoverySourceHandler handler = ongoingRecoveries.addNewRecovery(request, shard); logger.trace("[{}][{}] starting recovery to {}", request.shardId().getIndex().getName(), request.shardId().id(), request.targetNode()); try { return handler.recoverToTarget(); } finally { ongoingRecoveries.remove(shard, handler); } }
/** * Returns the expected shard size for the given shard or the default value provided if not enough information are available * to estimate the shards size. */ public static long getExpectedShardSize(ShardRouting shard, RoutingAllocation allocation, long defaultValue) { final IndexMetaData metaData = allocation.metaData().getIndexSafe(shard.index()); final ClusterInfo info = allocation.clusterInfo(); if (metaData.getResizeSourceIndex() != null && shard.active() == false && shard.recoverySource().getType() == RecoverySource.Type.LOCAL_SHARDS) { // in the shrink index case we sum up the source index shards since we basically make a copy of the shard in // the worst case long targetShardSize = 0; final Index mergeSourceIndex = metaData.getResizeSourceIndex(); final IndexMetaData sourceIndexMeta = allocation.metaData().index(mergeSourceIndex); if (sourceIndexMeta != null) { final Set<ShardId> shardIds = IndexMetaData.selectRecoverFromShards(shard.id(), sourceIndexMeta, metaData.getNumberOfShards()); for (IndexShardRoutingTable shardRoutingTable : allocation.routingTable().index(mergeSourceIndex.getName())) { if (shardIds.contains(shardRoutingTable.shardId())) { targetShardSize += info.getShardSize(shardRoutingTable.primaryShard(), 0); } } } return targetShardSize == 0 ? defaultValue : targetShardSize; } else { return info.getShardSize(shard, defaultValue); } } }