2121import java .util .List ;
2222import java .util .Map ;
2323import java .util .concurrent .atomic .AtomicReference ;
24+ import java .util .function .ToLongFunction ;
2425
2526/**
2627 * Maintains balancer metrics and makes them accessible to the {@link MeterRegistry} and APM reporting. Metrics are updated
@@ -53,6 +54,19 @@ public long undesiredAllocationsExcludingShuttingDownNodes() {
5354 .mapToLong (RoleAllocationStats ::undesiredAllocationsExcludingShuttingDownNodes )
5455 .sum ();
5556 }
57+
58+ /**
59+ * Return the ratio of undesired allocations to the total number of allocations.
60+ *
61+ * @return a value in [0.0, 1.0]
62+ */
63+ public double undesiredAllocationsRatio () {
64+ long totalAllocations = totalAllocations ();
65+ if (totalAllocations == 0 ) {
66+ return 0 ;
67+ }
68+ return undesiredAllocationsExcludingShuttingDownNodes () / (double ) totalAllocations ;
69+ }
5670 }
5771
5872 /**
@@ -86,7 +100,7 @@ public record NodeWeightStats(long shardCount, double diskUsageInBytes, double w
86100 public static final String UNASSIGNED_SHARDS_METRIC_NAME = "es.allocator.desired_balance.shards.unassigned.current" ;
87101 /** See {@link #totalAllocations} */
88102 public static final String TOTAL_SHARDS_METRIC_NAME = "es.allocator.desired_balance.shards.current" ;
89- /** See {@link #undesiredAllocationsExcludingShuttingDownNodes } */
103+ /** See {@link #undesiredAllocations } */
90104 public static final String UNDESIRED_ALLOCATION_COUNT_METRIC_NAME = "es.allocator.desired_balance.allocations.undesired.current" ;
91105 /** {@link #UNDESIRED_ALLOCATION_COUNT_METRIC_NAME} / {@link #TOTAL_SHARDS_METRIC_NAME} */
92106 public static final String UNDESIRED_ALLOCATION_RATIO_METRIC_NAME = "es.allocator.desired_balance.allocations.undesired.ratio" ;
@@ -110,31 +124,14 @@ public record NodeWeightStats(long shardCount, double diskUsageInBytes, double w
110124 public static final String CURRENT_NODE_FORECASTED_DISK_USAGE_METRIC_NAME =
111125 "es.allocator.allocations.node.forecasted_disk_usage_bytes.current" ;
112126
113- public static final AllocationStats EMPTY_ALLOCATION_STATS = new AllocationStats (- 1 , Map .of ());
127+ public static final AllocationStats EMPTY_ALLOCATION_STATS = new AllocationStats (0 , Map .of ());
114128
115129 private volatile boolean nodeIsMaster = false ;
116130
117131 /**
118- * Number of unassigned shards during last reconciliation
119- */
120- private volatile long unassignedShards ;
121-
122- /**
123- * Total number of assigned shards during last reconciliation
124- */
125- private volatile long totalAllocations ;
126-
127- /**
128- * Number of assigned shards during last reconciliation that are not allocated on a desired node and need to be moved.
129- * This excludes shards that must be reassigned due to a shutting down node.
130- */
131- private volatile long undesiredAllocationsExcludingShuttingDownNodes ;
132-
133- /**
134- * A breakdown of shards assigned and the undesired allocations from the last reconciliation
135- * broken down by {@link ShardRouting.Role}.
132+ * The stats from the most recent reconciliation
136133 */
137- private volatile Map < ShardRouting . Role , RoleAllocationStats > allocationStatsByRole ;
134+ private volatile AllocationStats lastReconciliationAllocationStats = EMPTY_ALLOCATION_STATS ;
138135
139136 private final AtomicReference <Map <DiscoveryNode , NodeWeightStats >> weightStatsPerNodeRef = new AtomicReference <>(Map .of ());
140137 private final AtomicReference <Map <DiscoveryNode , NodeAllocationStatsAndWeight >> allocationStatsPerNodeRef = new AtomicReference <>(
@@ -149,10 +146,7 @@ public void updateMetrics(
149146 assert allocationStats != null : "allocation stats cannot be null" ;
150147 assert weightStatsPerNode != null : "node balance weight stats cannot be null" ;
151148 if (allocationStats != EMPTY_ALLOCATION_STATS ) {
152- this .unassignedShards = allocationStats .unassignedShards ;
153- this .totalAllocations = allocationStats .totalAllocations ();
154- this .undesiredAllocationsExcludingShuttingDownNodes = allocationStats .undesiredAllocationsExcludingShuttingDownNodes ();
155- this .allocationStatsByRole = allocationStats .allocationStatsByRole ();
149+ this .lastReconciliationAllocationStats = allocationStats ;
156150 }
157151 weightStatsPerNodeRef .set (weightStatsPerNode );
158152 allocationStatsPerNodeRef .set (nodeAllocationStats );
@@ -251,23 +245,23 @@ public void setNodeIsMaster(boolean nodeIsMaster) {
251245 }
252246
253247 public long unassignedShards () {
254- return unassignedShards ;
248+ return lastReconciliationAllocationStats . unassignedShards () ;
255249 }
256250
257251 public long totalAllocations () {
258- return totalAllocations ;
252+ return lastReconciliationAllocationStats . totalAllocations () ;
259253 }
260254
261255 public long undesiredAllocations () {
262- return undesiredAllocationsExcludingShuttingDownNodes ;
256+ return lastReconciliationAllocationStats . undesiredAllocationsExcludingShuttingDownNodes () ;
263257 }
264258
265259 public Map <ShardRouting .Role , RoleAllocationStats > allocationStatsByRole () {
266- return allocationStatsByRole ;
260+ return lastReconciliationAllocationStats . allocationStatsByRole () ;
267261 }
268262
269263 private List <LongWithAttributes > getUnassignedShardsMetrics () {
270- return getIfPublishing (unassignedShards );
264+ return getIfPublishing (AllocationStats :: unassignedShards );
271265 }
272266
273267 private List <DoubleWithAttributes > getDesiredBalanceNodeWeightMetrics () {
@@ -396,25 +390,25 @@ private Map<String, Object> getNodeAttributes(DiscoveryNode node) {
396390 }
397391
398392 private List <LongWithAttributes > getTotalAllocationsMetrics () {
399- return getIfPublishing (totalAllocations );
393+ return getIfPublishing (AllocationStats :: totalAllocations );
400394 }
401395
402396 private List <LongWithAttributes > getUndesiredAllocationsExcludingShuttingDownNodesMetrics () {
403- return getIfPublishing (undesiredAllocationsExcludingShuttingDownNodes );
397+ return getIfPublishing (AllocationStats :: undesiredAllocationsExcludingShuttingDownNodes );
404398 }
405399
406- private List <LongWithAttributes > getIfPublishing (long value ) {
407- if (nodeIsMaster ) {
408- return List .of (new LongWithAttributes (value ));
400+ private List <LongWithAttributes > getIfPublishing (ToLongFunction <AllocationStats > value ) {
401+ var currentStats = lastReconciliationAllocationStats ;
402+ if (currentStats != EMPTY_ALLOCATION_STATS ) {
403+ return List .of (new LongWithAttributes (value .applyAsLong (currentStats )));
409404 }
410405 return List .of ();
411406 }
412407
413408 private List <DoubleWithAttributes > getUndesiredAllocationsRatioMetrics () {
414- if (nodeIsMaster ) {
415- var total = totalAllocations ;
416- var undesired = undesiredAllocationsExcludingShuttingDownNodes ;
417- return List .of (new DoubleWithAttributes (total != 0 ? (double ) undesired / total : 0.0 ));
409+ var currentStats = lastReconciliationAllocationStats ;
410+ if (currentStats != EMPTY_ALLOCATION_STATS ) {
411+ return List .of (new DoubleWithAttributes (currentStats .undesiredAllocationsRatio ()));
418412 }
419413 return List .of ();
420414 }
@@ -424,9 +418,7 @@ private List<DoubleWithAttributes> getUndesiredAllocationsRatioMetrics() {
424418 * This is best-effort because it is possible for {@link #updateMetrics} to race with this method.
425419 */
426420 public void zeroAllMetrics () {
427- unassignedShards = 0 ;
428- totalAllocations = 0 ;
429- undesiredAllocationsExcludingShuttingDownNodes = 0 ;
421+ lastReconciliationAllocationStats = EMPTY_ALLOCATION_STATS ;
430422 weightStatsPerNodeRef .set (Map .of ());
431423 allocationStatsPerNodeRef .set (Map .of ());
432424 }
0 commit comments