diff --git a/server/src/main/java/org/elasticsearch/cluster/ClusterModule.java b/server/src/main/java/org/elasticsearch/cluster/ClusterModule.java index 48c67d8520e59..361b98bcc86b4 100644 --- a/server/src/main/java/org/elasticsearch/cluster/ClusterModule.java +++ b/server/src/main/java/org/elasticsearch/cluster/ClusterModule.java @@ -37,6 +37,8 @@ import org.elasticsearch.cluster.routing.allocation.AllocationStatsService; import org.elasticsearch.cluster.routing.allocation.ExistingShardsAllocator; import org.elasticsearch.cluster.routing.allocation.NodeAllocationStatsAndWeightsCalculator; +import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; +import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision; import org.elasticsearch.cluster.routing.allocation.WriteLoadForecaster; import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator; import org.elasticsearch.cluster.routing.allocation.allocator.BalancerSettings; @@ -107,6 +109,8 @@ import java.util.Objects; import java.util.function.Supplier; +import static org.elasticsearch.cluster.routing.allocation.allocator.DesiredBalanceShardsAllocator.ShardAllocationExplainer; + /** * Configures classes and services that affect the entire cluster. */ @@ -171,7 +175,8 @@ public ClusterModule( this::reconcile, writeLoadForecaster, telemetryProvider, - nodeAllocationStatsAndWeightsCalculator + nodeAllocationStatsAndWeightsCalculator, + this::explainShardAllocation ); this.clusterService = clusterService; this.indexNameExpressionResolver = new IndexNameExpressionResolver(threadPool.getThreadContext(), systemIndices, projectResolver); @@ -237,6 +242,10 @@ private ClusterState reconcile(ClusterState clusterState, RerouteStrategy rerout return allocationService.executeWithRoutingAllocation(clusterState, "reconcile-desired-balance", rerouteStrategy); } + private ShardAllocationDecision explainShardAllocation(ShardRouting shardRouting, RoutingAllocation allocation) { + return allocationService.explainShardAllocation(shardRouting, allocation); + } + public static List getNamedWriteables() { List entries = new ArrayList<>(); // Cluster State @@ -489,7 +498,8 @@ private static ShardsAllocator createShardsAllocator( DesiredBalanceReconcilerAction reconciler, WriteLoadForecaster writeLoadForecaster, TelemetryProvider telemetryProvider, - NodeAllocationStatsAndWeightsCalculator nodeAllocationStatsAndWeightsCalculator + NodeAllocationStatsAndWeightsCalculator nodeAllocationStatsAndWeightsCalculator, + ShardAllocationExplainer shardAllocationExplainer ) { Map> allocators = new HashMap<>(); allocators.put( @@ -505,7 +515,8 @@ private static ShardsAllocator createShardsAllocator( clusterService, reconciler, telemetryProvider, - nodeAllocationStatsAndWeightsCalculator + nodeAllocationStatsAndWeightsCalculator, + shardAllocationExplainer ) ); diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputer.java b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputer.java index a0e103edf97c7..33a592ef05524 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputer.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputer.java @@ -17,6 +17,8 @@ import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.UnassignedInfo; import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; +import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision; +import org.elasticsearch.cluster.routing.allocation.allocator.DesiredBalanceShardsAllocator.ShardAllocationExplainer; import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand; import org.elasticsearch.cluster.routing.allocation.decider.Decision; import org.elasticsearch.common.metrics.MeanMetric; @@ -24,6 +26,7 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.time.TimeProvider; import org.elasticsearch.common.util.Maps; +import org.elasticsearch.common.xcontent.ChunkedToXContentHelper; import org.elasticsearch.core.Strings; import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.shard.ShardId; @@ -39,6 +42,7 @@ import java.util.TreeMap; import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Stream; import static java.util.stream.Collectors.toUnmodifiableSet; @@ -48,9 +52,13 @@ public class DesiredBalanceComputer { private static final Logger logger = LogManager.getLogger(DesiredBalanceComputer.class); + private static final Logger allocationExplainLogger = LogManager.getLogger( + DesiredBalanceComputer.class.getCanonicalName() + ".allocation_explain" + ); private final ShardsAllocator delegateAllocator; private final TimeProvider timeProvider; + private final ShardAllocationExplainer shardAllocationExplainer; // stats protected final MeanMetric iterations = new MeanMetric(); @@ -77,10 +85,17 @@ public class DesiredBalanceComputer { private long lastConvergedTimeMillis; private long lastNotConvergedLogMessageTimeMillis; private Level convergenceLogMsgLevel; + private ShardRouting lastTrackedUnassignedShard; - public DesiredBalanceComputer(ClusterSettings clusterSettings, TimeProvider timeProvider, ShardsAllocator delegateAllocator) { + public DesiredBalanceComputer( + ClusterSettings clusterSettings, + TimeProvider timeProvider, + ShardsAllocator delegateAllocator, + ShardAllocationExplainer shardAllocationExplainer + ) { this.delegateAllocator = delegateAllocator; this.timeProvider = timeProvider; + this.shardAllocationExplainer = shardAllocationExplainer; this.numComputeCallsSinceLastConverged = 0; this.numIterationsSinceLastConverged = 0; this.lastConvergedTimeMillis = timeProvider.relativeTimeInMillis(); @@ -462,10 +477,59 @@ public DesiredBalance compute( ); } + maybeLogAllocationExplainForUnassigned(finishReason, routingNodes, routingAllocation); + long lastConvergedIndex = hasChanges ? previousDesiredBalance.lastConvergedIndex() : desiredBalanceInput.index(); return new DesiredBalance(lastConvergedIndex, assignments, routingNodes.getBalanceWeightStatsPerNode(), finishReason); } + private void maybeLogAllocationExplainForUnassigned( + DesiredBalance.ComputationFinishReason finishReason, + RoutingNodes routingNodes, + RoutingAllocation routingAllocation + ) { + if (allocationExplainLogger.isDebugEnabled()) { + if (lastTrackedUnassignedShard != null) { + if (Stream.concat(routingNodes.unassigned().stream(), routingNodes.unassigned().ignored().stream()) + .noneMatch(shardRouting -> shardRouting.equals(lastTrackedUnassignedShard))) { + allocationExplainLogger.debug("previously tracked unassigned shard [{}] is now assigned", lastTrackedUnassignedShard); + lastTrackedUnassignedShard = null; + } else { + return; // The last tracked unassigned shard is still unassigned, keep tracking it + } + } + + assert lastTrackedUnassignedShard == null : "unexpected non-null lastTrackedUnassignedShard " + lastTrackedUnassignedShard; + if (routingNodes.hasUnassignedShards() && finishReason == DesiredBalance.ComputationFinishReason.CONVERGED) { + final Predicate predicate = routingNodes.hasUnassignedPrimaries() ? ShardRouting::primary : shard -> true; + lastTrackedUnassignedShard = Stream.concat(routingNodes.unassigned().stream(), routingNodes.unassigned().ignored().stream()) + .filter(predicate) + .findFirst() + .orElseThrow(); + + final var originalDebugMode = routingAllocation.getDebugMode(); + routingAllocation.setDebugMode(RoutingAllocation.DebugMode.EXCLUDE_YES_DECISIONS); + final ShardAllocationDecision shardAllocationDecision; + try { + shardAllocationDecision = shardAllocationExplainer.explain(lastTrackedUnassignedShard, routingAllocation); + } finally { + routingAllocation.setDebugMode(originalDebugMode); + } + allocationExplainLogger.debug( + "unassigned shard [{}] with allocation decision {}", + lastTrackedUnassignedShard, + org.elasticsearch.common.Strings.toString( + p -> ChunkedToXContentHelper.object("node_allocation_decision", shardAllocationDecision.toXContentChunked(p)) + ) + ); + } + } else { + if (lastTrackedUnassignedShard != null) { + lastTrackedUnassignedShard = null; + } + } + } + // visible for testing boolean hasEnoughIterations(int currentIteration) { return true; diff --git a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocator.java b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocator.java index e0b927a84519c..bcc9b3c58eabf 100644 --- a/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocator.java +++ b/server/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocator.java @@ -109,6 +109,11 @@ public interface DesiredBalanceReconcilerAction { ClusterState apply(ClusterState clusterState, RerouteStrategy rerouteStrategy); } + @FunctionalInterface + public interface ShardAllocationExplainer { + ShardAllocationDecision explain(ShardRouting shard, RoutingAllocation allocation); + } + public DesiredBalanceShardsAllocator( ClusterSettings clusterSettings, ShardsAllocator delegateAllocator, @@ -116,13 +121,14 @@ public DesiredBalanceShardsAllocator( ClusterService clusterService, DesiredBalanceReconcilerAction reconciler, TelemetryProvider telemetryProvider, - NodeAllocationStatsAndWeightsCalculator nodeAllocationStatsAndWeightsCalculator + NodeAllocationStatsAndWeightsCalculator nodeAllocationStatsAndWeightsCalculator, + ShardAllocationExplainer shardAllocationExplainer ) { this( delegateAllocator, threadPool, clusterService, - new DesiredBalanceComputer(clusterSettings, threadPool, delegateAllocator), + new DesiredBalanceComputer(clusterSettings, threadPool, delegateAllocator, shardAllocationExplainer), reconciler, telemetryProvider, nodeAllocationStatsAndWeightsCalculator diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/allocation/TransportDeleteDesiredBalanceActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/allocation/TransportDeleteDesiredBalanceActionTests.java index 999845fa73610..3955842010503 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/allocation/TransportDeleteDesiredBalanceActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/allocation/TransportDeleteDesiredBalanceActionTests.java @@ -99,7 +99,7 @@ public void testDeleteDesiredBalance() throws Exception { var clusterSettings = ClusterSettings.createBuiltInClusterSettings(settings); var delegate = new BalancedShardsAllocator(); - var computer = new DesiredBalanceComputer(clusterSettings, threadPool, delegate) { + var computer = new DesiredBalanceComputer(clusterSettings, threadPool, delegate, TEST_ONLY_EXPLAINER) { final AtomicReference lastComputationInput = new AtomicReference<>(); diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/AllocationStatsServiceTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/AllocationStatsServiceTests.java index 4ce195721b228..9794e22df3db7 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/AllocationStatsServiceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/AllocationStatsServiceTests.java @@ -176,7 +176,8 @@ public void testUndesiredShardCount() { clusterService, (innerState, strategy) -> innerState, TelemetryProvider.NOOP, - EMPTY_NODE_ALLOCATION_STATS + EMPTY_NODE_ALLOCATION_STATS, + TEST_ONLY_EXPLAINER ) { @Override public DesiredBalance getDesiredBalance() { diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/ClusterAllocationSimulationTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/ClusterAllocationSimulationTests.java index 6ef622948f5c5..4cb9e2b10a97e 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/ClusterAllocationSimulationTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/ClusterAllocationSimulationTests.java @@ -490,7 +490,8 @@ private Map.Entry createNewAllocationSer (clusterState, routingAllocationAction) -> strategyRef.get() .executeWithRoutingAllocation(clusterState, "reconcile-desired-balance", routingAllocationAction), TelemetryProvider.NOOP, - EMPTY_NODE_ALLOCATION_STATS + EMPTY_NODE_ALLOCATION_STATS, + TEST_ONLY_EXPLAINER ) { @Override public void allocate(RoutingAllocation allocation, ActionListener listener) { diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputerTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputerTests.java index d204c1c925d40..99a419a66f3be 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputerTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceComputerTests.java @@ -22,6 +22,9 @@ import org.elasticsearch.cluster.TestShardRoutingRoleStrategies; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.cluster.metadata.NodesShutdownMetadata; +import org.elasticsearch.cluster.metadata.SingleNodeShutdownMetadata; +import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodeRole; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.routing.AllocationId; @@ -60,6 +63,7 @@ import org.elasticsearch.snapshots.SnapshotId; import org.elasticsearch.snapshots.SnapshotShardSizeInfo; import org.elasticsearch.test.MockLog; +import org.elasticsearch.test.junit.annotations.TestLogging; import java.util.ArrayList; import java.util.HashMap; @@ -1288,7 +1292,7 @@ public void allocate(RoutingAllocation allocation) { public ShardAllocationDecision decideShardAllocation(ShardRouting shard, RoutingAllocation allocation) { throw new AssertionError("only used for allocation explain"); } - }); + }, TEST_ONLY_EXPLAINER); assertLoggerExpectationsFor(() -> { var iteration = new AtomicInteger(0); @@ -1320,7 +1324,8 @@ public void testLoggingOfComputeCallsAndIterationsSinceConvergence() { final var computer = new DesiredBalanceComputer( clusterSettings, TimeProviderUtils.create(timeInMillis::incrementAndGet), - new BalancedShardsAllocator(Settings.EMPTY) + new BalancedShardsAllocator(Settings.EMPTY), + TEST_ONLY_EXPLAINER ) { @Override boolean hasEnoughIterations(int currentIteration) { @@ -1441,6 +1446,139 @@ record LogExpectationData( assertDesiredAssignments(desiredBalance.get(), expectedAssignmentsMap); } + @TestLogging( + value = "org.elasticsearch.cluster.routing.allocation.allocator.DesiredBalanceComputer.allocation_explain:DEBUG", + reason = "test logging for allocation explain" + ) + public void testLogAllocationExplainForUnassigned() { + final ClusterSettings clusterSettings = createBuiltInClusterSettings(); + final var computer = new DesiredBalanceComputer( + clusterSettings, + TimeProviderUtils.create(() -> 0L), + new BalancedShardsAllocator(Settings.EMPTY), + createAllocationService()::explainShardAllocation + ); + final String loggerName = DesiredBalanceComputer.class.getCanonicalName() + ".allocation_explain"; + + // No logging since no unassigned shard + { + final var allocation = new RoutingAllocation( + randomAllocationDeciders(Settings.EMPTY, clusterSettings), + createInitialClusterState(1, 1, 0), + ClusterInfo.EMPTY, + SnapshotShardSizeInfo.EMPTY, + 0L + ); + try (var mockLog = MockLog.capture(loggerName)) { + mockLog.addExpectation( + new MockLog.UnseenEventExpectation( + "Should NOT log allocation explain since all shards are assigned", + loggerName, + Level.DEBUG, + "unassigned shard * with allocation decision *" + ) + ); + computer.compute(DesiredBalance.BECOME_MASTER_INITIAL, DesiredBalanceInput.create(1, allocation), queue(), ignore -> true); + mockLog.assertAllExpectationsMatched(); + } + } + + var initialState = createInitialClusterState(1, 1, 1); + // Logging for unassigned primary shard (preferred over unassigned replica) + { + final DiscoveryNode dataNode = initialState.nodes().getDataNodes().values().iterator().next(); + final var clusterState = initialState.copyAndUpdateMetadata( + b -> b.putCustom( + NodesShutdownMetadata.TYPE, + new NodesShutdownMetadata( + Map.of( + dataNode.getId(), + SingleNodeShutdownMetadata.builder() + .setNodeId(dataNode.getId()) + .setType(SingleNodeShutdownMetadata.Type.REMOVE) + .setReason("test") + .setStartedAtMillis(0L) + .build() + ) + ) + ) + ); + final var allocation = new RoutingAllocation( + randomAllocationDeciders(Settings.EMPTY, clusterSettings), + clusterState, + ClusterInfo.EMPTY, + SnapshotShardSizeInfo.EMPTY, + 0L + ); + final DesiredBalance newDesiredBalance; + try (var mockLog = MockLog.capture(loggerName)) { + mockLog.addExpectation( + new MockLog.SeenEventExpectation( + "Should log allocation explain for unassigned primary shard", + loggerName, + Level.DEBUG, + "unassigned shard [[test-index][0], node[null], [P], * with allocation decision *" + + "\"decider\":\"node_shutdown\",\"decision\":\"NO\"*" + ) + ); + newDesiredBalance = computer.compute( + DesiredBalance.BECOME_MASTER_INITIAL, + DesiredBalanceInput.create(1, allocation), + queue(), + ignore -> true + ); + mockLog.assertAllExpectationsMatched(); + } + + // No logging since the same tracked primary is still unassigned + try (var mockLog = MockLog.capture(loggerName)) { + mockLog.addExpectation( + new MockLog.UnseenEventExpectation( + "Should NOT log allocation explain again for existing tracked unassigned shard", + loggerName, + Level.DEBUG, + "unassigned shard [[test-index][0], node[null], [P], * with allocation decision *" + + "\"decider\":\"node_shutdown\",\"decision\":\"NO\"*" + ) + ); + computer.compute(newDesiredBalance, DesiredBalanceInput.create(2, allocation), queue(), ignore -> true); + mockLog.assertAllExpectationsMatched(); + } + } + + // Logging for unassigned replica shard (since primary is now assigned) + { + final var allocation = new RoutingAllocation( + randomAllocationDeciders(Settings.EMPTY, clusterSettings), + initialState, + ClusterInfo.EMPTY, + SnapshotShardSizeInfo.EMPTY, + 0L + ); + try (var mockLog = MockLog.capture(loggerName)) { + mockLog.addExpectation( + new MockLog.SeenEventExpectation( + "Should log for previously unassigned shard becomes assigned", + loggerName, + Level.DEBUG, + "previously tracked unassigned shard [[test-index][0], node[null], [P],* is now assigned" + ) + ); + mockLog.addExpectation( + new MockLog.SeenEventExpectation( + "Should log allocation explain for unassigned replica shard", + loggerName, + Level.DEBUG, + "unassigned shard [[test-index][0], node[null], [R], * with allocation decision *" + + "\"decider\":\"same_shard\",\"decision\":\"NO\"*" + ) + ); + computer.compute(DesiredBalance.BECOME_MASTER_INITIAL, DesiredBalanceInput.create(1, allocation), queue(), ignore -> true); + mockLog.assertAllExpectationsMatched(); + } + } + } + private static ShardId findShardId(ClusterState clusterState, String name) { return clusterState.getRoutingTable().index(name).shard(0).shardId(); } @@ -1542,7 +1680,12 @@ public ShardAllocationDecision decideShardAllocation(ShardRouting shard, Routing } private static DesiredBalanceComputer createDesiredBalanceComputer(ShardsAllocator allocator) { - return new DesiredBalanceComputer(createBuiltInClusterSettings(), TimeProviderUtils.create(() -> 0L), allocator); + return new DesiredBalanceComputer( + createBuiltInClusterSettings(), + TimeProviderUtils.create(() -> 0L), + allocator, + TEST_ONLY_EXPLAINER + ); } private static void assertDesiredAssignments(DesiredBalance desiredBalance, Map expected) { diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocatorTests.java b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocatorTests.java index 21d547c1593b8..bedbbc7b1f639 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocatorTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceShardsAllocatorTests.java @@ -174,7 +174,8 @@ public ClusterState apply(ClusterState clusterState, RerouteStrategy routingAllo clusterService, reconcileAction, TelemetryProvider.NOOP, - EMPTY_NODE_ALLOCATION_STATS + EMPTY_NODE_ALLOCATION_STATS, + TEST_ONLY_EXPLAINER ); assertValidStats(desiredBalanceShardsAllocator.getStats()); var allocationService = createAllocationService(desiredBalanceShardsAllocator, createGatewayAllocator(allocateUnassigned)); @@ -302,7 +303,8 @@ public ClusterState apply(ClusterState clusterState, RerouteStrategy routingAllo clusterService, reconcileAction, TelemetryProvider.NOOP, - EMPTY_NODE_ALLOCATION_STATS + EMPTY_NODE_ALLOCATION_STATS, + TEST_ONLY_EXPLAINER ); var allocationService = new AllocationService( new AllocationDeciders(List.of()), @@ -403,7 +405,7 @@ public ShardAllocationDecision decideShardAllocation(ShardRouting shard, Routing shardsAllocator, threadPool, clusterService, - new DesiredBalanceComputer(clusterSettings, TimeProviderUtils.create(time::get), shardsAllocator) { + new DesiredBalanceComputer(clusterSettings, TimeProviderUtils.create(time::get), shardsAllocator, TEST_ONLY_EXPLAINER) { @Override public DesiredBalance compute( DesiredBalance previousDesiredBalance, @@ -530,7 +532,7 @@ public ClusterState apply(ClusterState clusterState, RerouteStrategy routingAllo shardsAllocator, threadPool, clusterService, - new DesiredBalanceComputer(clusterSettings, threadPool, shardsAllocator) { + new DesiredBalanceComputer(clusterSettings, threadPool, shardsAllocator, TEST_ONLY_EXPLAINER) { @Override public DesiredBalance compute( DesiredBalance previousDesiredBalance, @@ -634,7 +636,7 @@ public ClusterState apply(ClusterState clusterState, RerouteStrategy routingAllo shardsAllocator, threadPool, clusterService, - new DesiredBalanceComputer(clusterSettings, threadPool, shardsAllocator) { + new DesiredBalanceComputer(clusterSettings, threadPool, shardsAllocator, TEST_ONLY_EXPLAINER) { @Override public DesiredBalance compute( DesiredBalance previousDesiredBalance, @@ -723,7 +725,7 @@ public void testResetDesiredBalance() { var delegateAllocator = createShardsAllocator(); var clusterSettings = createBuiltInClusterSettings(); - var desiredBalanceComputer = new DesiredBalanceComputer(clusterSettings, threadPool, delegateAllocator) { + var desiredBalanceComputer = new DesiredBalanceComputer(clusterSettings, threadPool, delegateAllocator, TEST_ONLY_EXPLAINER) { final AtomicReference lastComputationInput = new AtomicReference<>(); @@ -792,7 +794,12 @@ public void testResetDesiredBalanceOnNoLongerMaster() { var clusterService = ClusterServiceUtils.createClusterService(clusterState, threadPool); var delegateAllocator = createShardsAllocator(); - var desiredBalanceComputer = new DesiredBalanceComputer(createBuiltInClusterSettings(), threadPool, delegateAllocator); + var desiredBalanceComputer = new DesiredBalanceComputer( + createBuiltInClusterSettings(), + threadPool, + delegateAllocator, + TEST_ONLY_EXPLAINER + ); var desiredBalanceShardsAllocator = new DesiredBalanceShardsAllocator( delegateAllocator, threadPool, @@ -842,7 +849,12 @@ public void testResetDesiredBalanceOnNodeShutdown() { final var resetCalled = new AtomicBoolean(); var delegateAllocator = createShardsAllocator(); - var desiredBalanceComputer = new DesiredBalanceComputer(createBuiltInClusterSettings(), threadPool, delegateAllocator); + var desiredBalanceComputer = new DesiredBalanceComputer( + createBuiltInClusterSettings(), + threadPool, + delegateAllocator, + TEST_ONLY_EXPLAINER + ); var desiredBalanceAllocator = new DesiredBalanceShardsAllocator( delegateAllocator, threadPool, @@ -932,7 +944,7 @@ public void testNotReconcileEagerlyForEmptyRoutingTable() { shardsAllocator, threadPool, clusterService, - new DesiredBalanceComputer(clusterSettings, TimeProviderUtils.create(() -> 1L), shardsAllocator) { + new DesiredBalanceComputer(clusterSettings, TimeProviderUtils.create(() -> 1L), shardsAllocator, TEST_ONLY_EXPLAINER) { @Override public DesiredBalance compute( DesiredBalance previousDesiredBalance, diff --git a/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java b/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java index a2d81e0203f15..9ebc25fef9a8f 100644 --- a/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/cluster/ESAllocationTestCase.java @@ -29,6 +29,7 @@ import org.elasticsearch.cluster.routing.allocation.FailedShard; import org.elasticsearch.cluster.routing.allocation.NodeAllocationStatsAndWeightsCalculator; import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; +import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision; import org.elasticsearch.cluster.routing.allocation.WriteLoadForecaster; import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator; import org.elasticsearch.cluster.routing.allocation.allocator.BalancerSettings; @@ -98,6 +99,10 @@ public OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata) { public void refreshLicense() {} }; + public static final DesiredBalanceShardsAllocator.ShardAllocationExplainer TEST_ONLY_EXPLAINER = ( + shard, + allocation) -> ShardAllocationDecision.NOT_TAKEN; + public static MockAllocationService createAllocationService() { return createAllocationService(Settings.EMPTY); } @@ -176,7 +181,8 @@ private static DesiredBalanceShardsAllocator createDesiredBalanceShardsAllocator clusterService, null, TelemetryProvider.NOOP, - EMPTY_NODE_ALLOCATION_STATS + EMPTY_NODE_ALLOCATION_STATS, + TEST_ONLY_EXPLAINER ) { private RoutingAllocation lastAllocation;