diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java b/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java
index 2ce349e2d3b61..b2b2e51f5db21 100644
--- a/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java
+++ b/server/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java
@@ -46,32 +46,11 @@ public final class ShardRouting implements Writeable, ToXContentObject {
private static final TransportVersion RELOCATION_FAILURE_INFO_VERSION = TransportVersions.V_8_6_0;
private final ShardId shardId;
- private final String currentNodeId;
- /**
- * This field contains
- * - node id this shard is relocating to iff state == RELOCATING
- * - node id this shard is relocating from iff state == INITIALIZING and this is relocation target
- * - {@code null} in other cases
- */
- @Nullable
- private final String relocatingNodeId;
private final boolean primary;
- private final ShardRoutingState state;
- @Nullable
- private final RecoverySource recoverySource;
- @Nullable
- private final UnassignedInfo unassignedInfo;
- private final RelocationFailureInfo relocationFailureInfo;
- private final AllocationId allocationId;
- private final long expectedShardSize;
- @Nullable
- private final ShardRouting targetRelocatingShard;
private final Role role;
+ private final RelocationFailureInfo relocationFailureInfo;
+ private final ShardState state;
- /**
- * A constructor to internally create shard routing instances, note, the internal flag should only be set to true
- * by either this class or tests. Visible for testing.
- */
ShardRouting(
ShardId shardId,
String currentNodeId,
@@ -86,18 +65,103 @@ public final class ShardRouting implements Writeable, ToXContentObject {
Role role
) {
this.shardId = shardId;
- this.currentNodeId = currentNodeId;
- this.relocatingNodeId = relocatingNodeId;
this.primary = primary;
- this.state = state;
- this.recoverySource = recoverySource;
- this.unassignedInfo = unassignedInfo;
- this.relocationFailureInfo = relocationFailureInfo;
- this.allocationId = allocationId;
- this.expectedShardSize = expectedShardSize;
this.role = role;
- this.targetRelocatingShard = initializeTargetRelocatingShard();
+ this.relocationFailureInfo = relocationFailureInfo;
+ this.state = switch (state) {
+ case UNASSIGNED -> new Unassigned(unassignedInfo, recoverySource);
+ case INITIALIZING -> new Initializing(
+ currentNodeId,
+ relocatingNodeId,
+ unassignedInfo,
+ recoverySource,
+ allocationId,
+ expectedShardSize
+ );
+ case STARTED -> new Started(currentNodeId, allocationId, expectedShardSize);
+ case RELOCATING -> newRelocatingState(
+ shardId,
+ primary,
+ role,
+ currentNodeId,
+ relocatingNodeId,
+ unassignedInfo,
+ allocationId,
+ expectedShardSize
+ );
+ };
+ }
+
+ sealed interface ShardState permits Initializing, Relocating, Started, Unassigned {
+ ShardRoutingState name();
+ }
+
+ sealed interface AssignedState permits Initializing, Relocating, Started {
+ String currentNodeId();
+ AllocationId allocationId();
+
+ long expectedShardSize();
+ }
+
+ sealed interface RecoveryState permits Unassigned, Initializing {
+ RecoverySource recoverySource();
+
+ UnassignedInfo unassignedInfo();
+ }
+
+ record Unassigned(UnassignedInfo unassignedInfo, RecoverySource recoverySource) implements ShardState, RecoveryState {
+ @Override
+ public ShardRoutingState name() {
+ return ShardRoutingState.UNASSIGNED;
+ }
+ }
+
+ record Initializing(
+ String currentNodeId,
+ @Nullable String relocatingNodeId,
+ @Nullable UnassignedInfo unassignedInfo,
+ RecoverySource recoverySource,
+ AllocationId allocationId,
+ long expectedShardSize
+ ) implements ShardState, AssignedState, RecoveryState {
+
+ @Override
+ public ShardRoutingState name() {
+ return ShardRoutingState.INITIALIZING;
+ }
+ }
+
+ record Started(String currentNodeId, AllocationId allocationId, long expectedShardSize) implements ShardState, AssignedState {
+ @Override
+ public ShardRoutingState name() {
+ return ShardRoutingState.STARTED;
+ }
+ }
+
+ record Relocating(
+ String currentNodeId,
+ String relocatingNodeId,
+ AllocationId allocationId,
+ ShardRouting targetRelocatingShard,
+ long expectedShardSize
+ ) implements ShardState, AssignedState {
+ @Override
+ public ShardRoutingState name() {
+ return ShardRoutingState.RELOCATING;
+ }
+ }
+
+ /**
+ * A constructor to internally create shard routing instances, note, the internal flag should only be set to true
+ * by either this class or tests. Visible for testing.
+ */
+ ShardRouting(ShardId shardId, boolean primary, Role role, RelocationFailureInfo relocationFailureInfo, ShardState shardState) {
+ this.shardId = shardId;
+ this.primary = primary;
+ this.role = role;
+ this.relocationFailureInfo = relocationFailureInfo;
+ this.state = shardState;
assert assertConsistent();
}
@@ -106,55 +170,56 @@ private boolean assertConsistent() {
assert role != null : "role must be always set";
assert primary == false || role.isPromotableToPrimary() : "shard with unpromotable role was promoted to primary: " + this;
switch (state) {
- case UNASSIGNED -> {
- assert currentNodeId == null : state + " shard must not be assigned to a node " + this;
- assert relocatingNodeId == null : state + " shard must not be relocating to a node " + this;
- assert unassignedInfo != null : state + " shard must be created with unassigned info " + this;
- assert recoverySource != null : state + " shard must be created with a recovery source" + this;
- assert primary ^ recoverySource == PeerRecoverySource.INSTANCE : "replica shards always recover from primary" + this;
+ case Unassigned unassigned -> {
+ assert primary ^ unassigned.recoverySource() == PeerRecoverySource.INSTANCE
+ : "replica shards always recover from primary" + this;
}
- case INITIALIZING -> {
- assert currentNodeId != null : state + " shard must be assigned to a node " + this;
- // relocatingNodeId is not set for initializing shard but set for relocating shard counterpart
- // unassignedInfo is kept after starting unassigned shard but not present for relocating shard counterpart
- assert recoverySource != null : state + "shard must be created with a recovery source" + this;
- assert primary || recoverySource == PeerRecoverySource.INSTANCE : "replica shards always recover from primary" + this;
+ case Initializing initializing -> {
+ assert initializing.currentNodeId != null : "shard must be assigned to a node " + this;
+ assert primary || initializing.recoverySource() == PeerRecoverySource.INSTANCE
+ : "replica shards always recover from primary" + this;
}
- case STARTED -> {
- assert currentNodeId != null : state + " shard must be assigned to a node " + this;
- assert relocatingNodeId == null : state + " shard must not be relocating to a node " + this;
- assert unassignedInfo == null : state + " shard must be created without unassigned info " + this;
- assert recoverySource == null : state + " shard must be created without a recovery source" + this;
+ case Started started -> {
+ assert started.currentNodeId() != null : "shard must be assigned to a node " + this;
}
- case RELOCATING -> {
- assert currentNodeId != null : state + " shard must be assigned to a node " + this;
- assert relocatingNodeId != null : state + " shard must be relocating to a node " + this;
- assert unassignedInfo == null : state + " shard must be created without unassigned info " + this;
- assert recoverySource == null : state + " shard must be created without a recovery source" + this;
+ case Relocating relocating -> {
+ assert relocating.currentNodeId() != null : "shard must be assigned to a node " + this;
+ assert relocating.relocatingNodeId() != null : "shard must be relocating to a node " + this;
}
}
return true;
}
- @Nullable
- private ShardRouting initializeTargetRelocatingShard() {
- if (state == ShardRoutingState.RELOCATING) {
- return new ShardRouting(
+ static Relocating newRelocatingState(
+ ShardId shardId,
+ boolean primary,
+ Role role,
+ String currentNodeId,
+ String relocatingNodeId,
+ UnassignedInfo unassignedInfo,
+ AllocationId allocationId,
+ long expectedShardSize
+ ) {
+ return new Relocating(
+ currentNodeId,
+ relocatingNodeId,
+ allocationId,
+ new ShardRouting(
shardId,
- relocatingNodeId,
- currentNodeId,
primary,
- ShardRoutingState.INITIALIZING,
- PeerRecoverySource.INSTANCE,
- unassignedInfo,
+ role,
RelocationFailureInfo.NO_FAILURES,
- AllocationId.newTargetRelocation(allocationId),
- expectedShardSize,
- role
- );
- } else {
- return null;
- }
+ new Initializing(
+ relocatingNodeId,
+ currentNodeId,
+ unassignedInfo,
+ PeerRecoverySource.INSTANCE,
+ AllocationId.newTargetRelocation(allocationId),
+ expectedShardSize
+ )
+ ),
+ expectedShardSize
+ );
}
/**
@@ -167,19 +232,7 @@ public static ShardRouting newUnassigned(
UnassignedInfo unassignedInfo,
Role role
) {
- return new ShardRouting(
- shardId,
- null,
- null,
- primary,
- ShardRoutingState.UNASSIGNED,
- recoverySource,
- unassignedInfo,
- RelocationFailureInfo.NO_FAILURES,
- null,
- UNAVAILABLE_EXPECTED_SHARD_SIZE,
- role
- );
+ return new ShardRouting(shardId, primary, role, RelocationFailureInfo.NO_FAILURES, new Unassigned(unassignedInfo, recoverySource));
}
public Index index() {
@@ -211,7 +264,7 @@ public int getId() {
* The shard is unassigned (not allocated to any node).
*/
public boolean unassigned() {
- return state == ShardRoutingState.UNASSIGNED;
+ return state instanceof Unassigned;
}
/**
@@ -219,7 +272,7 @@ public boolean unassigned() {
* or from gateway).
*/
public boolean initializing() {
- return state == ShardRoutingState.INITIALIZING;
+ return state instanceof Initializing;
}
/**
@@ -236,7 +289,7 @@ public boolean active() {
* The shard is in started mode.
*/
public boolean started() {
- return state == ShardRoutingState.STARTED;
+ return state instanceof Started;
}
/**
@@ -246,7 +299,7 @@ public boolean started() {
* @see ShardRoutingState#RELOCATING
*/
public boolean relocating() {
- return state == ShardRoutingState.RELOCATING;
+ return state instanceof Relocating;
}
/**
@@ -254,21 +307,29 @@ public boolean relocating() {
* {@link ShardRoutingState#UNASSIGNED unassigned}. Otherwise false
*/
public boolean assignedToNode() {
- return currentNodeId != null;
+ return unassigned() == false;
}
/**
* The current node id the shard is allocated on.
*/
public String currentNodeId() {
- return this.currentNodeId;
+ if (state instanceof AssignedState s) {
+ return s.currentNodeId();
+ } else {
+ return null;
+ }
}
/**
* The relocating node id the shard is either relocating to or relocating from.
*/
public String relocatingNodeId() {
- return this.relocatingNodeId;
+ return switch (state) {
+ case Relocating r -> r.relocatingNodeId;
+ case Initializing i -> i.relocatingNodeId;
+ default -> null;
+ };
}
/**
@@ -278,7 +339,7 @@ public String relocatingNodeId() {
*/
public ShardRouting getTargetRelocatingShard() {
assert relocating();
- return targetRelocatingShard;
+ return ((Relocating) state).targetRelocatingShard;
}
/**
@@ -287,7 +348,11 @@ public ShardRouting getTargetRelocatingShard() {
*/
@Nullable
public UnassignedInfo unassignedInfo() {
- return unassignedInfo;
+ if (state instanceof RecoveryState s) {
+ return s.unassignedInfo();
+ } else {
+ return null;
+ }
}
@Nullable
@@ -300,7 +365,10 @@ public RelocationFailureInfo relocationFailureInfo() {
*/
@Nullable
public AllocationId allocationId() {
- return this.allocationId;
+ if (state instanceof AssignedState s) {
+ return s.allocationId();
+ }
+ return null;
}
/**
@@ -314,7 +382,7 @@ public boolean primary() {
* The shard state.
*/
public ShardRoutingState state() {
- return this.state;
+ return this.state.name();
}
/**
@@ -333,35 +401,55 @@ public ShardIterator shardsIt() {
public ShardRouting(ShardId shardId, StreamInput in) throws IOException {
this.shardId = shardId;
- currentNodeId = DiscoveryNode.deduplicateNodeIdentifier(in.readOptionalString());
- relocatingNodeId = DiscoveryNode.deduplicateNodeIdentifier(in.readOptionalString());
+ var currentNodeId = DiscoveryNode.deduplicateNodeIdentifier(in.readOptionalString());
+ var relocatingNodeId = DiscoveryNode.deduplicateNodeIdentifier(in.readOptionalString());
primary = in.readBoolean();
- state = ShardRoutingState.fromValue(in.readByte());
- if (state == ShardRoutingState.UNASSIGNED || state == ShardRoutingState.INITIALIZING) {
+ var stateName = ShardRoutingState.fromValue(in.readByte());
+ RecoverySource recoverySource = null;
+ if (stateName == ShardRoutingState.UNASSIGNED || stateName == ShardRoutingState.INITIALIZING) {
recoverySource = RecoverySource.readFrom(in);
- } else {
- recoverySource = null;
}
- unassignedInfo = in.readOptionalWriteable(UnassignedInfo::fromStreamInput);
+ var unassignedInfo = in.readOptionalWriteable(UnassignedInfo::fromStreamInput);
if (in.getTransportVersion().onOrAfter(RELOCATION_FAILURE_INFO_VERSION)) {
relocationFailureInfo = RelocationFailureInfo.readFrom(in);
} else {
relocationFailureInfo = RelocationFailureInfo.NO_FAILURES;
}
- allocationId = in.readOptionalWriteable(AllocationId::new);
- if (state == ShardRoutingState.RELOCATING
- || state == ShardRoutingState.INITIALIZING
- || (state == ShardRoutingState.STARTED && in.getTransportVersion().onOrAfter(EXPECTED_SHARD_SIZE_FOR_STARTED_VERSION))) {
+ var allocationId = in.readOptionalWriteable(AllocationId::new);
+ var expectedShardSize = UNAVAILABLE_EXPECTED_SHARD_SIZE;
+ if (stateName == ShardRoutingState.RELOCATING
+ || stateName == ShardRoutingState.INITIALIZING
+ || (stateName == ShardRoutingState.STARTED && in.getTransportVersion().onOrAfter(EXPECTED_SHARD_SIZE_FOR_STARTED_VERSION))) {
expectedShardSize = in.readLong();
- } else {
- expectedShardSize = UNAVAILABLE_EXPECTED_SHARD_SIZE;
}
if (in.getTransportVersion().onOrAfter(TransportVersions.V_8_7_0)) {
role = Role.readFrom(in);
} else {
role = Role.DEFAULT;
}
- targetRelocatingShard = initializeTargetRelocatingShard();
+ switch (stateName) {
+ case UNASSIGNED -> this.state = new Unassigned(unassignedInfo, recoverySource);
+ case INITIALIZING -> this.state = new Initializing(
+ currentNodeId,
+ relocatingNodeId,
+ unassignedInfo,
+ recoverySource,
+ allocationId,
+ expectedShardSize
+ );
+ case STARTED -> this.state = new Started(currentNodeId, allocationId, expectedShardSize);
+ case RELOCATING -> this.state = newRelocatingState(
+ shardId,
+ primary,
+ role,
+ currentNodeId,
+ relocatingNodeId,
+ unassignedInfo,
+ allocationId,
+ expectedShardSize
+ );
+ default -> throw new IllegalStateException();
+ }
}
public ShardRouting(StreamInput in) throws IOException {
@@ -375,22 +463,20 @@ public ShardRouting(StreamInput in) throws IOException {
* @throws IOException if something happens during write
*/
public void writeToThin(StreamOutput out) throws IOException {
- out.writeOptionalString(currentNodeId);
- out.writeOptionalString(relocatingNodeId);
+ out.writeOptionalString(currentNodeId());
+ out.writeOptionalString(relocatingNodeId());
out.writeBoolean(primary);
- out.writeByte(state.value());
- if (state == ShardRoutingState.UNASSIGNED || state == ShardRoutingState.INITIALIZING) {
- recoverySource.writeTo(out);
+ out.writeByte(state.name().value());
+ if (state instanceof RecoveryState rs) {
+ rs.recoverySource().writeTo(out);
}
- out.writeOptionalWriteable(unassignedInfo);
+ out.writeOptionalWriteable(unassignedInfo());
if (out.getTransportVersion().onOrAfter(RELOCATION_FAILURE_INFO_VERSION)) {
relocationFailureInfo.writeTo(out);
}
- out.writeOptionalWriteable(allocationId);
- if (state == ShardRoutingState.RELOCATING
- || state == ShardRoutingState.INITIALIZING
- || (state == ShardRoutingState.STARTED && out.getTransportVersion().onOrAfter(EXPECTED_SHARD_SIZE_FOR_STARTED_VERSION))) {
- out.writeLong(expectedShardSize);
+ out.writeOptionalWriteable(allocationId());
+ if (relocating() || initializing() || (started() && out.getTransportVersion().onOrAfter(EXPECTED_SHARD_SIZE_FOR_STARTED_VERSION))) {
+ out.writeLong(getExpectedShardSize());
}
if (out.getTransportVersion().onOrAfter(TransportVersions.V_8_7_0)) {
@@ -409,45 +495,38 @@ public void writeTo(StreamOutput out) throws IOException {
}
public ShardRouting updateUnassigned(UnassignedInfo unassignedInfo, RecoverySource recoverySource) {
- assert this.unassignedInfo != null : "can only update unassigned info if it is already set";
- assert this.unassignedInfo.delayed() || (unassignedInfo.delayed() == false) : "cannot transition from non-delayed to delayed";
- return new ShardRouting(
- shardId,
- currentNodeId,
- relocatingNodeId,
- primary,
- state,
- recoverySource,
- unassignedInfo,
- relocationFailureInfo,
- allocationId,
- expectedShardSize,
- role
- );
+ assert state instanceof RecoveryState;
+ final var recoveryState = (RecoveryState) state;
+ assert recoveryState.unassignedInfo() != null : "can only update unassigned info if it is already set";
+ assert recoveryState.unassignedInfo().delayed() || (unassignedInfo.delayed() == false)
+ : "cannot transition from non-delayed to delayed";
+ return new ShardRouting(shardId, primary, role, relocationFailureInfo, switch (state) {
+ case Unassigned u -> new Unassigned(unassignedInfo, recoverySource);
+ case Initializing i -> new Initializing(
+ i.currentNodeId,
+ i.relocatingNodeId,
+ unassignedInfo,
+ recoverySource,
+ i.allocationId,
+ i.expectedShardSize
+ );
+ default -> {
+ assert false;
+ yield null;
+ }
+ });
}
public ShardRouting updateRelocationFailure(RelocationFailureInfo relocationFailureInfo) {
assert this.relocationFailureInfo != null : "can only update relocation failure info info if it is already set";
- return new ShardRouting(
- shardId,
- currentNodeId,
- relocatingNodeId,
- primary,
- state,
- recoverySource,
- unassignedInfo,
- relocationFailureInfo,
- allocationId,
- expectedShardSize,
- role
- );
+ return new ShardRouting(shardId, primary, role, relocationFailureInfo, state);
}
/**
* Moves the shard to unassigned state.
*/
public ShardRouting moveToUnassigned(UnassignedInfo unassignedInfo) {
- assert state != ShardRoutingState.UNASSIGNED : this;
+ assert unassigned() == false : this;
final RecoverySource recoverySource;
if (active()) {
if (primary()) {
@@ -458,19 +537,7 @@ public ShardRouting moveToUnassigned(UnassignedInfo unassignedInfo) {
} else {
recoverySource = recoverySource();
}
- return new ShardRouting(
- shardId,
- null,
- null,
- primary,
- ShardRoutingState.UNASSIGNED,
- recoverySource,
- unassignedInfo,
- RelocationFailureInfo.NO_FAILURES,
- null,
- UNAVAILABLE_EXPECTED_SHARD_SIZE,
- role
- );
+ return new ShardRouting(shardId, primary, role, RelocationFailureInfo.NO_FAILURES, new Unassigned(unassignedInfo, recoverySource));
}
/**
@@ -479,8 +546,8 @@ public ShardRouting moveToUnassigned(UnassignedInfo unassignedInfo) {
* @param existingAllocationId allocation id to use. If null, a fresh allocation id is generated.
*/
public ShardRouting initialize(String nodeId, @Nullable String existingAllocationId, long expectedShardSize) {
- assert state == ShardRoutingState.UNASSIGNED : this;
- assert relocatingNodeId == null : this;
+ assert unassigned() : this;
+ final var stateUnassigned = (Unassigned) state;
final AllocationId allocationId;
if (existingAllocationId == null) {
allocationId = AllocationId.newInitializing();
@@ -489,16 +556,10 @@ public ShardRouting initialize(String nodeId, @Nullable String existingAllocatio
}
return new ShardRouting(
shardId,
- nodeId,
- null,
primary,
- ShardRoutingState.INITIALIZING,
- recoverySource,
- unassignedInfo,
+ role,
RelocationFailureInfo.NO_FAILURES,
- allocationId,
- expectedShardSize,
- role
+ new Initializing(nodeId, null, stateUnassigned.unassignedInfo, stateUnassigned.recoverySource, allocationId, expectedShardSize)
);
}
@@ -508,19 +569,23 @@ public ShardRouting initialize(String nodeId, @Nullable String existingAllocatio
* @param relocatingNodeId id of the node to relocate the shard
*/
public ShardRouting relocate(String relocatingNodeId, long expectedShardSize) {
- assert state == ShardRoutingState.STARTED : "current shard has to be started in order to be relocated " + this;
+ assert started() : "current shard has to be started in order to be relocated " + this;
+ final var stateStarted = (Started) state;
return new ShardRouting(
shardId,
- currentNodeId,
- relocatingNodeId,
primary,
- ShardRoutingState.RELOCATING,
- recoverySource,
- null,
+ role,
relocationFailureInfo,
- AllocationId.newRelocation(allocationId),
- expectedShardSize,
- role
+ newRelocatingState(
+ shardId,
+ primary,
+ role,
+ stateStarted.currentNodeId,
+ relocatingNodeId,
+ null,
+ AllocationId.newRelocation(stateStarted.allocationId),
+ expectedShardSize
+ )
);
}
@@ -529,21 +594,20 @@ public ShardRouting relocate(String relocatingNodeId, long expectedShardSize) {
* to RELOCATING
.
*/
public ShardRouting cancelRelocation() {
- assert state == ShardRoutingState.RELOCATING : this;
+ assert relocating() : this;
assert assignedToNode() : this;
- assert relocatingNodeId != null : this;
+ final var stateRelocating = (Relocating) state;
+ assert stateRelocating.relocatingNodeId != null : this;
return new ShardRouting(
shardId,
- currentNodeId,
- null,
primary,
- ShardRoutingState.STARTED,
- recoverySource,
- null,
+ role,
relocationFailureInfo.incFailedRelocations(),
- AllocationId.cancelRelocation(allocationId),
- UNAVAILABLE_EXPECTED_SHARD_SIZE,
- role
+ new Started(
+ stateRelocating.currentNodeId,
+ AllocationId.cancelRelocation(stateRelocating.allocationId),
+ stateRelocating.expectedShardSize
+ )
);
}
@@ -554,21 +618,23 @@ public ShardRouting cancelRelocation() {
*/
public ShardRouting removeRelocationSource() {
assert primary == false : this;
- assert state == ShardRoutingState.INITIALIZING : this;
+ assert initializing() : this;
assert assignedToNode() : this;
- assert relocatingNodeId != null : this;
+ final var stateInit = (Initializing) state;
+ assert stateInit.relocatingNodeId != null : this;
return new ShardRouting(
shardId,
- currentNodeId,
- null,
primary,
- state,
- recoverySource,
- unassignedInfo,
+ role,
relocationFailureInfo,
- AllocationId.finishRelocation(allocationId),
- expectedShardSize,
- role
+ new Initializing(
+ stateInit.currentNodeId,
+ null,
+ stateInit.unassignedInfo,
+ stateInit.recoverySource,
+ AllocationId.finishRelocation(stateInit.allocationId),
+ stateInit.expectedShardSize
+ )
);
}
@@ -576,21 +642,23 @@ public ShardRouting removeRelocationSource() {
* Reinitializes a replica shard, giving it a fresh allocation id
*/
public ShardRouting reinitializeReplicaShard() {
- assert state == ShardRoutingState.INITIALIZING : this;
+ assert initializing() : this;
assert primary == false : this;
- assert isRelocationTarget() == false : this;
+ final var stateInit = (Initializing) state;
+ assert stateInit.relocatingNodeId == null : this;
return new ShardRouting(
shardId,
- currentNodeId,
- null,
primary,
- ShardRoutingState.INITIALIZING,
- recoverySource,
- unassignedInfo,
+ role,
relocationFailureInfo,
- AllocationId.newInitializing(),
- expectedShardSize,
- role
+ new Initializing(
+ stateInit.currentNodeId,
+ null,
+ stateInit.unassignedInfo,
+ stateInit.recoverySource,
+ AllocationId.newInitializing(),
+ stateInit.expectedShardSize
+ )
);
}
@@ -600,25 +668,19 @@ public ShardRouting reinitializeReplicaShard() {
* canceled.
*/
public ShardRouting moveToStarted(long expectedShardSize) {
- assert state == ShardRoutingState.INITIALIZING : "expected an initializing shard " + this;
- AllocationId allocationId = this.allocationId;
+ assert initializing() : "expected an initializing shard " + this;
+ final var stateInit = (Initializing) state;
+ var allocationId = stateInit.allocationId;
if (allocationId.getRelocationId() != null) {
// relocation target
allocationId = AllocationId.finishRelocation(allocationId);
}
-
return new ShardRouting(
shardId,
- currentNodeId,
- null,
primary,
- ShardRoutingState.STARTED,
- null,
- null,
+ role,
RelocationFailureInfo.NO_FAILURES,
- allocationId,
- expectedShardSize,
- role
+ new Started(stateInit.currentNodeId, allocationId, expectedShardSize)
);
}
@@ -632,19 +694,7 @@ public ShardRouting moveActiveReplicaToPrimary() {
if (primary) {
throw new IllegalShardRoutingStateException(this, "Already primary, can't move to primary");
}
- return new ShardRouting(
- shardId,
- currentNodeId,
- relocatingNodeId,
- true,
- state,
- recoverySource,
- unassignedInfo,
- relocationFailureInfo,
- allocationId,
- expectedShardSize,
- role
- );
+ return new ShardRouting(shardId, true, role, relocationFailureInfo, state);
}
/**
@@ -653,22 +703,17 @@ public ShardRouting moveActiveReplicaToPrimary() {
* @throws IllegalShardRoutingStateException if shard is already a replica
*/
public ShardRouting moveUnassignedFromPrimary() {
- assert state == ShardRoutingState.UNASSIGNED : "expected an unassigned shard " + this;
+ assert unassigned() : "expected an unassigned shard " + this;
if (primary == false) {
throw new IllegalShardRoutingStateException(this, "Not primary, can't move to replica");
}
+ final var stateUnassigned = (Unassigned) state;
return new ShardRouting(
shardId,
- currentNodeId,
- relocatingNodeId,
false,
- state,
- PeerRecoverySource.INSTANCE,
- unassignedInfo,
+ role,
relocationFailureInfo,
- allocationId,
- expectedShardSize,
- role
+ new Unassigned(stateUnassigned.unassignedInfo, PeerRecoverySource.INSTANCE)
);
}
@@ -679,31 +724,43 @@ public ShardRouting moveUnassignedFromPrimary() {
* no allocation at all..
**/
public boolean isSameAllocation(ShardRouting other) {
- boolean b = this.allocationId != null && other.allocationId != null && this.allocationId.getId().equals(other.allocationId.getId());
- assert b == false || this.currentNodeId.equals(other.currentNodeId)
- : "ShardRoutings have the same allocation id but not the same node. This [" + this + "], other [" + other + "]";
- return b;
+ if (state instanceof AssignedState thisState && other.state instanceof AssignedState otherState) {
+ boolean b = thisState.allocationId() != null
+ && otherState.allocationId() != null
+ && thisState.allocationId().getId().equals(otherState.allocationId().getId());
+ assert b == false || thisState.currentNodeId().equals(otherState.currentNodeId())
+ : "ShardRoutings have the same allocation id but not the same node. This [" + this + "], other [" + other + "]";
+ return b;
+ } else {
+ return false;
+ }
}
/**
* Returns true
if this shard is a relocation target for another shard
- * (i.e., was created with {@link #initializeTargetRelocatingShard()}
*/
public boolean isRelocationTarget() {
- return state == ShardRoutingState.INITIALIZING && relocatingNodeId != null;
+ if (state instanceof Initializing i) {
+ return i.relocatingNodeId != null;
+ } else {
+ return false;
+ }
}
/** returns true if the routing is the relocation target of the given routing */
public boolean isRelocationTargetOf(ShardRouting other) {
- boolean b = this.allocationId != null
- && other.allocationId != null
- && this.state == ShardRoutingState.INITIALIZING
- && this.allocationId.getId().equals(other.allocationId.getRelocationId());
- assert b == false || other.state == ShardRoutingState.RELOCATING
+ boolean b = false;
+ if (this.state instanceof Initializing thisState && other.state instanceof Relocating otherState) {
+ b = thisState.allocationId != null
+ && otherState.allocationId != null
+ && thisState.allocationId.getId().equals(otherState.allocationId.getRelocationId());
+ }
+
+ assert b == false || other.relocating()
: "ShardRouting is a relocation target but the source shard state isn't relocating. This [" + this + "], other [" + other + "]";
- assert b == false || other.allocationId.getId().equals(this.allocationId.getRelocationId())
+ assert b == false || other.allocationId().getId().equals(this.allocationId().getRelocationId())
: "ShardRouting is a relocation target but the source id isn't equal to source's allocationId.getRelocationId."
+ " This ["
+ this
@@ -711,7 +768,7 @@ public boolean isRelocationTargetOf(ShardRouting other) {
+ other
+ "]";
- assert b == false || other.currentNodeId().equals(this.relocatingNodeId)
+ assert b == false || other.currentNodeId().equals(this.relocatingNodeId())
: "ShardRouting is a relocation target but source current node id isn't equal to target relocating node."
+ " This ["
+ this
@@ -719,7 +776,7 @@ public boolean isRelocationTargetOf(ShardRouting other) {
+ other
+ "]";
- assert b == false || this.currentNodeId().equals(other.relocatingNodeId)
+ assert b == false || this.currentNodeId().equals(other.relocatingNodeId())
: "ShardRouting is a relocation target but current node id isn't equal to source relocating node."
+ " This ["
+ this
@@ -743,15 +800,17 @@ public boolean isRelocationTargetOf(ShardRouting other) {
/** returns true if the routing is the relocation source for the given routing */
public boolean isRelocationSourceOf(ShardRouting other) {
- boolean b = this.allocationId != null
- && other.allocationId != null
- && other.state == ShardRoutingState.INITIALIZING
- && other.allocationId.getId().equals(this.allocationId.getRelocationId());
+ boolean b = false;
+ if (this.state instanceof Relocating thisState && other.state instanceof Initializing otherState) {
+ b = thisState.allocationId != null
+ && otherState.allocationId != null
+ && otherState.allocationId.getId().equals(thisState.allocationId.getRelocationId());
+ }
- assert b == false || this.state == ShardRoutingState.RELOCATING
+ assert b == false || relocating()
: "ShardRouting is a relocation source but shard state isn't relocating. This [" + this + "], other [" + other + "]";
- assert b == false || this.allocationId.getId().equals(other.allocationId.getRelocationId())
+ assert b == false || this.allocationId().getId().equals(other.allocationId().getRelocationId())
: "ShardRouting is a relocation source but the allocation id isn't equal to other.allocationId.getRelocationId."
+ " This ["
+ this
@@ -759,7 +818,7 @@ public boolean isRelocationSourceOf(ShardRouting other) {
+ other
+ "]";
- assert b == false || this.currentNodeId().equals(other.relocatingNodeId)
+ assert b == false || this.currentNodeId().equals(other.relocatingNodeId())
: "ShardRouting is a relocation source but current node isn't equal to other's relocating node."
+ " This ["
+ this
@@ -767,7 +826,7 @@ public boolean isRelocationSourceOf(ShardRouting other) {
+ other
+ "]";
- assert b == false || other.currentNodeId().equals(this.relocatingNodeId)
+ assert b == false || other.currentNodeId().equals(this.relocatingNodeId())
: "ShardRouting is a relocation source but relocating node isn't equal to other's current node."
+ " This ["
+ this
@@ -793,12 +852,11 @@ public boolean isRelocationSourceOf(ShardRouting other) {
public boolean equalsIgnoringMetadata(ShardRouting other) {
return primary == other.primary
&& shardId.equals(other.shardId)
- && Objects.equals(currentNodeId, other.currentNodeId)
- && Objects.equals(relocatingNodeId, other.relocatingNodeId)
- && Objects.equals(allocationId, other.allocationId)
- && state == other.state
- && Objects.equals(recoverySource, other.recoverySource)
- && role == other.role;
+ && role == other.role
+ && Objects.equals(currentNodeId(), other.currentNodeId())
+ && Objects.equals(relocatingNodeId(), other.relocatingNodeId())
+ && Objects.equals(allocationId(), other.allocationId())
+ && Objects.equals(recoverySource(), other.recoverySource());
}
@Override
@@ -811,7 +869,7 @@ public boolean equals(Object o) {
}
ShardRouting that = (ShardRouting) o;
return equalsIgnoringMetadata(that)
- && Objects.equals(unassignedInfo, that.unassignedInfo)
+ && Objects.equals(unassignedInfo(), that.unassignedInfo())
&& Objects.equals(relocationFailureInfo, that.relocationFailureInfo);
}
@@ -824,6 +882,11 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
int h = hashCode;
+ var currentNodeId = currentNodeId();
+ var relocatingNodeId = relocatingNodeId();
+ var recoverySource = recoverySource();
+ var allocationId = allocationId();
+ var unassignedInfo = unassignedInfo();
if (h == 0) {
h = shardId.hashCode();
h = 31 * h + (currentNodeId != null ? currentNodeId.hashCode() : 0);
@@ -851,6 +914,12 @@ public String toString() {
public String shortSummary() {
StringBuilder sb = new StringBuilder();
sb.append('[').append(shardId.getIndexName()).append(']').append('[').append(shardId.getId()).append(']');
+ var currentNodeId = currentNodeId();
+ var relocatingNodeId = relocatingNodeId();
+ var recoverySource = recoverySource();
+ var allocationId = allocationId();
+ var unassignedInfo = unassignedInfo();
+ var expectedShardSize = getExpectedShardSize();
sb.append(", node[").append(currentNodeId).append("], ");
if (relocatingNodeId != null) {
sb.append("relocating [").append(relocatingNodeId).append("], ");
@@ -866,7 +935,7 @@ public String shortSummary() {
if (recoverySource != null) {
sb.append(", recovery_source[").append(recoverySource).append("]");
}
- sb.append(", s[").append(state).append("]");
+ sb.append(", s[").append(state.name()).append("]");
if (allocationId != null) {
sb.append(", a").append(allocationId);
}
@@ -889,16 +958,20 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
.field("relocating_node", relocatingNodeId())
.field("shard", id())
.field("index", getIndexName());
- if (expectedShardSize != UNAVAILABLE_EXPECTED_SHARD_SIZE && state != ShardRoutingState.STARTED) {
+ var expectedShardSize = getExpectedShardSize();
+ if (expectedShardSize != UNAVAILABLE_EXPECTED_SHARD_SIZE && started() == false) {
builder.field("expected_shard_size_in_bytes", expectedShardSize);
}
+ var recoverySource = recoverySource();
if (recoverySource != null) {
builder.field("recovery_source", recoverySource);
}
+ var allocationId = allocationId();
if (allocationId != null) {
builder.field("allocation_id");
allocationId.toXContent(builder, params);
}
+ var unassignedInfo = unassignedInfo();
if (unassignedInfo != null) {
unassignedInfo.toXContent(builder, params);
}
@@ -912,7 +985,11 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
* shards. If it's size is not available {@value #UNAVAILABLE_EXPECTED_SHARD_SIZE} will be returned.
*/
public long getExpectedShardSize() {
- return expectedShardSize;
+ if (state instanceof AssignedState s) {
+ return s.expectedShardSize();
+ } else {
+ return UNAVAILABLE_EXPECTED_SHARD_SIZE;
+ }
}
/**
@@ -922,7 +999,11 @@ public long getExpectedShardSize() {
*/
@Nullable
public RecoverySource recoverySource() {
- return recoverySource;
+ if (state instanceof RecoveryState rs) {
+ return rs.recoverySource();
+ } else {
+ return null;
+ }
}
public Role role() {