diff --git a/compute/src/main/java/org/zstack/compute/host/HostBase.java b/compute/src/main/java/org/zstack/compute/host/HostBase.java
index 919d92631fc..3787541a39d 100755
--- a/compute/src/main/java/org/zstack/compute/host/HostBase.java
+++ b/compute/src/main/java/org/zstack/compute/host/HostBase.java
@@ -955,7 +955,7 @@ private void handle(final PingHostMsg msg) {
thdf.chainSubmit(new ChainTask(msg) {
@Override
public String getSyncSignature() {
- return "do-ping-host";
+ return String.format("do-ping-host-%s", msg.getHostUuid());
}
@Override
@@ -979,13 +979,9 @@ public void fail(ErrorCode errorCode) {
@Override
public String getName() {
- return String.format("do-ping-host-%s", msg.getHostUuid());
+ return getSyncSignature();
}
- @Override
- protected int getSyncLevel() {
- return HostGlobalConfig.HOST_TRACK_PARALLELISM_DEGREE.value(Integer.class);
- }
});
}
diff --git a/conf/globalConfig/host.xml b/conf/globalConfig/host.xml
index ac15a50e580..c31bcbdb7e7 100755
--- a/conf/globalConfig/host.xml
+++ b/conf/globalConfig/host.xml
@@ -24,7 +24,7 @@
host
ping.parallelismDegree
- The max hosts management server sends ping command to host in parallel
+ The max hosts management server sends ping command to host in parallel. With per-host sync signature, this now controls per-host parallelism (one host does not block another).
100
java.lang.Integer
diff --git a/test/src/test/groovy/org/zstack/test/integration/kvm/host/KVMPingCase.groovy b/test/src/test/groovy/org/zstack/test/integration/kvm/host/KVMPingCase.groovy
index 1709790ab08..3fb55ec2b00 100755
--- a/test/src/test/groovy/org/zstack/test/integration/kvm/host/KVMPingCase.groovy
+++ b/test/src/test/groovy/org/zstack/test/integration/kvm/host/KVMPingCase.groovy
@@ -24,6 +24,7 @@ import org.zstack.testlib.SubCase
import org.zstack.utils.FieldUtils
import org.zstack.utils.gson.JSONObjectUtil
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
class KVMPingCase extends SubCase {
@@ -460,6 +461,50 @@ class KVMPingCase extends SubCase {
}
}
+ void testDifferentHostPingsNotBlocked() {
+ canDoReconnectFunc = { HostReconnectTask.CanDoAnswer.Ready }
+
+ HostInventory kvm1 = env.inventoryByName("kvm1")
+ HostInventory kvm2 = env.inventoryByName("kvm2")
+
+ waitHostConnected(kvm1.uuid)
+ waitHostConnected(kvm2.uuid)
+
+ // Set parallelism to 1 so the test proves per-host isolation:
+ // old code (shared do-ping-host + level=1) → kvm2 blocked by kvm1
+ // new code (per-host do-ping-host- + level=1) → kvm2 unblocked
+ HostGlobalConfig.HOST_TRACK_PARALLELISM_DEGREE.updateValue(1)
+
+ CountDownLatch blockKvm1 = new CountDownLatch(1)
+ CountDownLatch kvm2Pinged = new CountDownLatch(1)
+
+ env.simulator(KVMConstant.KVM_PING_PATH) { HttpEntity e, EnvSpec espec ->
+ KVMAgentCommands.PingCmd cmd = JSONObjectUtil.toObject(e.getBody(), KVMAgentCommands.PingCmd.class)
+ def rsp = new KVMAgentCommands.PingResponse()
+
+ if (cmd.hostUuid == kvm1.uuid) {
+ blockKvm1.await(30, TimeUnit.SECONDS)
+ }
+
+ if (cmd.hostUuid == kvm2.uuid) {
+ kvm2Pinged.countDown()
+ }
+
+ rsp.hostUuid = cmd.hostUuid
+ return rsp
+ }
+
+ try {
+ assert kvm2Pinged.await(30, TimeUnit.SECONDS)
+ } finally {
+ blockKvm1.countDown()
+ env.cleanSimulatorHandlers()
+ HostGlobalConfig.HOST_TRACK_PARALLELISM_DEGREE.updateValue(100)
+ recoverHostToConnected(kvm1.uuid)
+ recoverHostToConnected(kvm2.uuid)
+ }
+ }
+
@Override
void test() {
bus = bean(CloudBus.class)
@@ -490,6 +535,7 @@ class KVMPingCase extends SubCase {
testHostReconnectAfterPingFailure()
testContinuePingIfHostNoReconnect()
testNoPingIfHostNotReadyToReconnect()
+ testDifferentHostPingsNotBlocked()
testManagementNodeReadyConnectAllHost()
testPingConnectingHost()