-
Notifications
You must be signed in to change notification settings - Fork 25k
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
Speedup BalanceUnbalancedClusterTests #88794
Changes from 1 commit
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 |
---|---|---|
|
@@ -15,7 +15,6 @@ | |
import org.elasticsearch.index.shard.ShardId; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.Iterator; | ||
|
@@ -26,7 +25,6 @@ | |
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* A {@link RoutingNode} represents a cluster node associated with a single {@link DiscoveryNode} including all shards | ||
|
@@ -118,7 +116,14 @@ public int size() { | |
* @param shard Shard to create on this Node | ||
*/ | ||
void add(ShardRouting shard) { | ||
assert invariant(); | ||
addInternal(shard, true); | ||
} | ||
|
||
void addNoValidate(ShardRouting shard) { | ||
addInternal(shard, false); | ||
} | ||
|
||
private void addInternal(ShardRouting shard, boolean validate) { | ||
final ShardRouting existing = shards.putIfAbsent(shard.shardId(), shard); | ||
if (existing != null) { | ||
final IllegalStateException e = new IllegalStateException( | ||
|
@@ -142,11 +147,10 @@ void add(ShardRouting shard) { | |
relocatingShards.add(shard); | ||
} | ||
shardsByIndex.computeIfAbsent(shard.index(), k -> new HashSet<>()).add(shard); | ||
assert invariant(); | ||
assert validate == false || invariant(); | ||
} | ||
|
||
void update(ShardRouting oldShard, ShardRouting newShard) { | ||
assert invariant(); | ||
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. The invariant asserted after operation as well. I do not think it is required to do it twice. 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. Nice! |
||
if (shards.containsKey(oldShard.shardId()) == false) { | ||
// Shard was already removed by routing nodes iterator | ||
// TODO: change caller logic in RoutingNodes so that this check can go away | ||
|
@@ -174,7 +178,6 @@ void update(ShardRouting oldShard, ShardRouting newShard) { | |
} | ||
|
||
void remove(ShardRouting shard) { | ||
assert invariant(); | ||
ShardRouting previousValue = shards.remove(shard.shardId()); | ||
assert previousValue == shard : "expected shard " + previousValue + " but was " + shard; | ||
if (shard.initializing()) { | ||
|
@@ -342,20 +345,24 @@ public boolean isEmpty() { | |
return shards.isEmpty(); | ||
} | ||
|
||
private boolean invariant() { | ||
// initializingShards must consistent with that in shards | ||
Collection<ShardRouting> shardRoutingsInitializing = shards.values().stream().filter(ShardRouting::initializing).toList(); | ||
assert initializingShards.size() == shardRoutingsInitializing.size(); | ||
assert initializingShards.containsAll(shardRoutingsInitializing); | ||
boolean invariant() { | ||
var shardRoutingsInitializing = new ArrayList<ShardRouting>(shards.size()); | ||
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. WDYT about declaring
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. I was thinking about it, but then decided to keep Lists to avoid calculating hash for each item. 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.
|
||
var shardRoutingsRelocating = new ArrayList<ShardRouting>(shards.size()); | ||
// this guess assumes 1 shard per index, this is not precise, but okay for assertion | ||
var shardRoutingsByIndex = Maps.<Index, Set<ShardRouting>>newHashMapWithExpectedSize(shards.size()); | ||
|
||
// relocatingShards must consistent with that in shards | ||
Collection<ShardRouting> shardRoutingsRelocating = shards.values().stream().filter(ShardRouting::relocating).toList(); | ||
assert relocatingShards.size() == shardRoutingsRelocating.size(); | ||
assert relocatingShards.containsAll(shardRoutingsRelocating); | ||
for (var shard : shards.values()) { | ||
if (shard.initializing()) { | ||
shardRoutingsInitializing.add(shard); | ||
} | ||
if (shard.relocating()) { | ||
shardRoutingsRelocating.add(shard); | ||
} | ||
shardRoutingsByIndex.computeIfAbsent(shard.index(), k -> new HashSet<>(10)).add(shard); | ||
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. Does it make sense to use 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. Unfortunately we do not know expected size here. I used some random number to avoid initial resize(s) |
||
} | ||
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. This was rebuild for assertion twice after any shard addition to the routing node. |
||
|
||
final Map<Index, Set<ShardRouting>> shardRoutingsByIndex = shards.values() | ||
.stream() | ||
.collect(Collectors.groupingBy(ShardRouting::index, Collectors.toSet())); | ||
assert initializingShards.size() == shardRoutingsInitializing.size() && initializingShards.containsAll(shardRoutingsInitializing); | ||
assert relocatingShards.size() == shardRoutingsRelocating.size() && relocatingShards.containsAll(shardRoutingsRelocating); | ||
assert shardRoutingsByIndex.equals(shardsByIndex); | ||
|
||
return true; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -122,15 +122,15 @@ private RoutingNodes(RoutingTable routingTable, DiscoveryNodes discoveryNodes, b | |
// A replica Set might have one (and not more) replicas with the state of RELOCATING. | ||
if (shard.assignedToNode()) { | ||
// LinkedHashMap to preserve order | ||
nodesToShards.computeIfAbsent(shard.currentNodeId(), createRoutingNode).add(shard); | ||
nodesToShards.computeIfAbsent(shard.currentNodeId(), createRoutingNode).addNoValidate(shard); | ||
assignedShardsAdd(shard); | ||
if (shard.relocating()) { | ||
relocatingShards++; | ||
ShardRouting targetShardRouting = shard.getTargetRelocatingShard(); | ||
addInitialRecovery(targetShardRouting, indexShard.primary); | ||
// LinkedHashMap to preserve order. | ||
// Add the counterpart shard with relocatingNodeId reflecting the source from which it's relocating from. | ||
nodesToShards.computeIfAbsent(shard.relocatingNodeId(), createRoutingNode).add(targetShardRouting); | ||
nodesToShards.computeIfAbsent(shard.relocatingNodeId(), createRoutingNode).addNoValidate(targetShardRouting); | ||
assignedShardsAdd(targetShardRouting); | ||
} else if (shard.initializing()) { | ||
if (shard.primary()) { | ||
|
@@ -145,6 +145,9 @@ private RoutingNodes(RoutingTable routingTable, DiscoveryNodes discoveryNodes, b | |
} | ||
} | ||
} | ||
for (var node : nodesToShards.values()) { | ||
assert node.invariant(); | ||
} | ||
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. Invariant checking is expensive in case of big collections so it is verified once in the end instead of after every operation. This is constructing 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. That makes sense. One suggestion: I think we do the invariant check in one line with method references:
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. Link #88951 :) |
||
} | ||
|
||
private RoutingNodes(RoutingNodes routingNodes) { | ||
|
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.
How about
addWithoutValidation
? It sounds more natural for me.