imbajin commented on code in PR #3356:
URL: https://github.com/apache/hugegraph/pull/3356#discussion_r4289857957


##########
hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/TaskScheduleService.java:
##########
@@ -582,6 +605,61 @@ public synchronized Map<Integer, Long> 
balancePartitionLeader(boolean immediatel
         return results;
     }
 
+    /**
+     * The periodic entry of leader balancing. Calls balancePartitionLeader 
only when the
+     * leader count per store has drifted further apart than 
pd.balance-leader-max-skew, so a
+     * balanced cluster sees no transfers. Skipped while a shard group is not 
Normal or a store
+     * that holds a shard is not active, because the target distribution would 
include a store
+     * that cannot take a leader.
+     *
+     * @return shard group id -> the store id its leader was moved to; empty 
when skipped
+     */
+    public Map<Integer, Long> autoBalancePartitionLeader() throws PDException {
+        if (!isLeader()) {
+            return new HashMap<>();
+        }
+
+        List<Metapb.ShardGroup> shardGroups = storeService.getShardGroups();
+        if (shardGroups.isEmpty()) {
+            return new HashMap<>();
+        }
+
+        Set<Long> activeStores = storeService.getActiveStores().stream()
+                                             .map(Metapb.Store::getId)
+                                             .collect(Collectors.toSet());
+        Map<Long, Integer> leaderCount = new HashMap<>();
+        for (Metapb.ShardGroup group : shardGroups) {
+            // A store stays active for keepAlive-timeout after it stops, but 
partition
+            // heartbeats from the surviving replicas already mark its groups 
Warn.
+            // balancePartitionLeader plans over all groups, so skip the whole 
run.
+            if (group.getState() != Metapb.PartitionState.PState_Normal) {

Review Comment:
   ⚠️ A shard group that loses quorum can stop sending PartitionStats, leaving 
its last PState_Normal in metadata; keepStoreAlive keeps each Store marked 
active until its TTL expires. With the 300-second defaults, the scheduled tick 
can run while both snapshots still look healthy and call the global planner on 
stale membership. Please also require fresh partition health evidence before 
balancing and add a no-quorum regression.



##########
hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/TaskScheduleService.java:
##########
@@ -582,6 +605,61 @@ public synchronized Map<Integer, Long> 
balancePartitionLeader(boolean immediatel
         return results;
     }
 
+    /**
+     * The periodic entry of leader balancing. Calls balancePartitionLeader 
only when the
+     * leader count per store has drifted further apart than 
pd.balance-leader-max-skew, so a
+     * balanced cluster sees no transfers. Skipped while a shard group is not 
Normal or a store
+     * that holds a shard is not active, because the target distribution would 
include a store
+     * that cannot take a leader.
+     *
+     * @return shard group id -> the store id its leader was moved to; empty 
when skipped
+     */
+    public Map<Integer, Long> autoBalancePartitionLeader() throws PDException {
+        if (!isLeader()) {
+            return new HashMap<>();
+        }
+
+        List<Metapb.ShardGroup> shardGroups = storeService.getShardGroups();
+        if (shardGroups.isEmpty()) {
+            return new HashMap<>();
+        }
+
+        Set<Long> activeStores = storeService.getActiveStores().stream()
+                                             .map(Metapb.Store::getId)
+                                             .collect(Collectors.toSet());
+        Map<Long, Integer> leaderCount = new HashMap<>();
+        for (Metapb.ShardGroup group : shardGroups) {
+            // A store stays active for keepAlive-timeout after it stops, but 
partition
+            // heartbeats from the surviving replicas already mark its groups 
Warn.
+            // balancePartitionLeader plans over all groups, so skip the whole 
run.
+            if (group.getState() != Metapb.PartitionState.PState_Normal) {
+                log.info("periodic leader balance skipped, shard group {} is 
{}",
+                         group.getId(), group.getState());
+                return new HashMap<>();
+            }
+            for (Metapb.Shard shard : group.getShardsList()) {
+                if (!activeStores.contains(shard.getStoreId())) {
+                    log.info("periodic leader balance skipped, store {} of 
shard group {} is " +
+                             "not active", shard.getStoreId(), group.getId());
+                    return new HashMap<>();
+                }
+                int leader = shard.getRole() == Metapb.ShardRole.Leader ? 1 : 
0;

Review Comment:
   ⚠️ This counts every non-Leader shard as eligible, but 
StoreNodeService.reallocShards can add a shard with the default ShardRole.None, 
preserve the group state, and start CONF_CHANGE_TYPE_ADJUST. The existing 
planner treats any non-Leader shard as a transfer target, so a tick during that 
adjustment can request leadership transfer to a non-voting or Learner peer. 
Please skip pending membership changes/non-voting roles or restrict targets to 
eligible followers.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to