-
Notifications
You must be signed in to change notification settings - Fork 25.5k
Simulate shards moved by explicit commands #136066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
63e3ce8
966db3f
5cb04b5
3f69b4a
88a0bbe
b9dc835
5fbd0f9
d1be8b3
fcc6449
aba922e
4f87592
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pr: 136066 | ||
summary: Simulate shards moved by explicit commands | ||
area: Allocation | ||
type: enhancement | ||
issues: [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ | |
import org.elasticsearch.index.shard.ShardId; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.LinkedList; | ||
|
@@ -291,7 +292,23 @@ public DesiredBalance compute( | |
while ((commands = pendingDesiredBalanceMoves.poll()) != null) { | ||
for (MoveAllocationCommand command : commands) { | ||
try { | ||
command.execute(routingAllocation, false); | ||
final var rerouteExplanation = command.execute(routingAllocation, false); | ||
assert rerouteExplanation.decisions().type() != Decision.Type.NO; | ||
if (rerouteExplanation.decisions().type() != Decision.Type.NO) { | ||
final ShardRouting[] initializingShards = routingNodes.node( | ||
routingAllocation.nodes().resolveNode(command.toNode()).getId() | ||
).initializing(); | ||
assert initializingShards.length == 1 | ||
&& routingAllocation.nodes() | ||
|
||
.resolveNode(command.fromNode()) | ||
.getId() | ||
.equals(initializingShards[0].relocatingNodeId()) | ||
: "expect one relocating shard, but got : " + List.of(initializingShards); | ||
Arrays.stream(initializingShards).forEach(shard -> { | ||
DiannaHohensee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
clusterInfoSimulator.simulateShardStarted(shard); | ||
routingNodes.startShard(shard, changes, 0L); | ||
}); | ||
} | ||
} catch (RuntimeException e) { | ||
logger.debug( | ||
() -> "move shard [" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ | |
import org.elasticsearch.cluster.routing.IndexShardRoutingTable; | ||
import org.elasticsearch.cluster.routing.RecoverySource; | ||
import org.elasticsearch.cluster.routing.RoutingChangesObserver; | ||
import org.elasticsearch.cluster.routing.RoutingNode; | ||
import org.elasticsearch.cluster.routing.RoutingNodes; | ||
import org.elasticsearch.cluster.routing.RoutingTable; | ||
import org.elasticsearch.cluster.routing.ShardRouting; | ||
|
@@ -44,7 +45,9 @@ | |
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; | ||
import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision; | ||
import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand; | ||
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDecider; | ||
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders; | ||
import org.elasticsearch.cluster.routing.allocation.decider.Decision; | ||
import org.elasticsearch.cluster.routing.allocation.decider.ThrottlingAllocationDecider; | ||
import org.elasticsearch.common.Randomness; | ||
import org.elasticsearch.common.UUIDs; | ||
|
@@ -54,6 +57,7 @@ | |
import org.elasticsearch.common.time.TimeProviderUtils; | ||
import org.elasticsearch.common.unit.ByteSizeValue; | ||
import org.elasticsearch.common.util.Maps; | ||
import org.elasticsearch.common.util.set.Sets; | ||
import org.elasticsearch.core.Strings; | ||
import org.elasticsearch.core.TimeValue; | ||
import org.elasticsearch.core.Tuple; | ||
|
@@ -99,6 +103,7 @@ | |
import static org.hamcrest.Matchers.aMapWithSize; | ||
import static org.hamcrest.Matchers.allOf; | ||
import static org.hamcrest.Matchers.anyOf; | ||
import static org.hamcrest.Matchers.arrayWithSize; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.everyItem; | ||
import static org.hamcrest.Matchers.hasEntry; | ||
|
@@ -566,7 +571,22 @@ public void testNoDataNodes() { | |
} | ||
|
||
public void testAppliesMoveCommands() { | ||
var desiredBalanceComputer = createDesiredBalanceComputer(); | ||
var desiredBalanceComputer = createDesiredBalanceComputer(new ShardsAllocator() { | ||
@Override | ||
public void allocate(RoutingAllocation allocation) { | ||
assertThat( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps add a comment that this runs right after the moves are applied. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, perhaps this is actually better as an assertion? Which I sort of proposed above. Happy to keep it though for the test to have verification, but we'll probably hit the assertion first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added comment in fcc6449 In BalancedShardsAllocator, we do assert that the initial routingAlloction has no initializing shard. Is it similar to what you have in mind? It's not necessary that |
||
"unexpected relocating shards: " + allocation.routingNodes(), | ||
allocation.routingNodes().getRelocatingShardCount(), | ||
equalTo(0) | ||
); | ||
assertThat(allocation.routingNodes().node("node-2").started(), arrayWithSize(2)); | ||
} | ||
|
||
@Override | ||
public ShardAllocationDecision decideShardAllocation(ShardRouting shard, RoutingAllocation allocation) { | ||
throw new AssertionError("only used for allocation explain"); | ||
DiannaHohensee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}); | ||
var clusterState = createInitialClusterState(3); | ||
var index = clusterState.metadata().getProject().index(TEST_INDEX).getIndex(); | ||
|
||
|
@@ -578,23 +598,99 @@ public void testAppliesMoveCommands() { | |
} | ||
clusterState = rebuildRoutingTable(clusterState, routingNodes); | ||
|
||
final var dataNodeIds = clusterState.nodes().getDataNodes().keySet(); | ||
for (var nodeId : List.of("node-0", "node-1")) { | ||
final var desiredBalanceInput = new DesiredBalanceInput( | ||
randomInt(), | ||
DiannaHohensee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
new RoutingAllocation(new AllocationDeciders(List.of(new AllocationDecider() { | ||
@Override | ||
public Decision canAllocate(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) { | ||
// Move command works every decision except NO | ||
return randomFrom(Decision.YES, Decision.THROTTLE, Decision.THROTTLE); | ||
|
||
} | ||
})), clusterState, ClusterInfo.EMPTY, SnapshotShardSizeInfo.EMPTY, 0L), | ||
List.of() | ||
); | ||
var desiredBalance = desiredBalanceComputer.compute( | ||
DesiredBalance.BECOME_MASTER_INITIAL, | ||
desiredBalanceInput, | ||
queue( | ||
new MoveAllocationCommand(index.getName(), 0, nodeId, "node-2"), | ||
new MoveAllocationCommand(index.getName(), 1, nodeId, "node-2") | ||
), | ||
input -> true | ||
); | ||
|
||
final Set<String> expectedNodeIds = Sets.difference(dataNodeIds, Set.of(nodeId)); | ||
assertDesiredAssignments( | ||
desiredBalance, | ||
Map.of( | ||
new ShardId(index, 0), | ||
new ShardAssignment(expectedNodeIds, 2, 0, 0), | ||
new ShardId(index, 1), | ||
new ShardAssignment(expectedNodeIds, 2, 0, 0) | ||
) | ||
); | ||
} | ||
} | ||
|
||
public void testCannotApplyMoveCommand() { | ||
var desiredBalanceComputer = createDesiredBalanceComputer(new ShardsAllocator() { | ||
@Override | ||
public void allocate(RoutingAllocation allocation) { | ||
assertThat( | ||
"unexpected relocating shards: " + allocation.routingNodes(), | ||
allocation.routingNodes().getRelocatingShardCount(), | ||
equalTo(0) | ||
); | ||
assertThat(allocation.routingNodes().node("node-2").isEmpty(), equalTo(true)); | ||
} | ||
|
||
@Override | ||
public ShardAllocationDecision decideShardAllocation(ShardRouting shard, RoutingAllocation allocation) { | ||
throw new AssertionError("only used for allocation explain"); | ||
} | ||
}); | ||
var clusterState = createInitialClusterState(3); | ||
var index = clusterState.metadata().getProject().index(TEST_INDEX).getIndex(); | ||
|
||
var changes = new RoutingChangesObserver.DelegatingRoutingChangesObserver(); | ||
var routingNodes = clusterState.mutableRoutingNodes(); | ||
for (var iterator = routingNodes.unassigned().iterator(); iterator.hasNext();) { | ||
var shardRouting = iterator.next(); | ||
routingNodes.startShard(iterator.initialize(shardRouting.primary() ? "node-0" : "node-1", null, 0L, changes), changes, 0L); | ||
} | ||
clusterState = rebuildRoutingTable(clusterState, routingNodes); | ||
|
||
final var dataNodeIds = clusterState.nodes().getDataNodes().keySet(); | ||
final var desiredBalanceInput = new DesiredBalanceInput( | ||
randomInt(), | ||
new RoutingAllocation(new AllocationDeciders(List.of(new AllocationDecider() { | ||
@Override | ||
public Decision canAllocate(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) { | ||
return Decision.NO; | ||
DiannaHohensee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
})), clusterState, ClusterInfo.EMPTY, SnapshotShardSizeInfo.EMPTY, 0L), | ||
List.of() | ||
); | ||
var desiredBalance = desiredBalanceComputer.compute( | ||
DesiredBalance.BECOME_MASTER_INITIAL, | ||
createInput(clusterState), | ||
desiredBalanceInput, | ||
queue( | ||
new MoveAllocationCommand(index.getName(), 0, "node-1", "node-2"), | ||
new MoveAllocationCommand(index.getName(), 1, "node-1", "node-2") | ||
new MoveAllocationCommand(index.getName(), 0, randomFrom("node-0", "node-1"), "node-2"), | ||
new MoveAllocationCommand(index.getName(), 1, randomFrom("node-0", "node-1"), "node-2") | ||
), | ||
input -> true | ||
); | ||
|
||
final Set<String> expectedNodeIds = Set.of("node-0", "node-1"); | ||
assertDesiredAssignments( | ||
desiredBalance, | ||
Map.of( | ||
new ShardId(index, 0), | ||
new ShardAssignment(Set.of("node-0", "node-2"), 2, 0, 0), | ||
new ShardAssignment(expectedNodeIds, 2, 0, 0), | ||
new ShardId(index, 1), | ||
new ShardAssignment(Set.of("node-0", "node-2"), 2, 0, 0) | ||
new ShardAssignment(expectedNodeIds, 2, 0, 0) | ||
) | ||
); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we assert no initializing shards after the while loop in general? That helps understand this assertion without reading the prior code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is asserted inside BalancedShardAllocator to ensure each simulation call starts without any initialising shad.