You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@asterixdb.apache.org by AsterixDB Code Review <do...@asterix-gerrit.ics.uci.edu> on 2026/10/13 14:38:42 UTC
[M] Change in asterixdb[master]: [ASTERIXDB-3956][HYR] Don't ack a heartbeat from an unauthorized node
From Michael Blow <mb...@apache.org>:
Michael Blow has uploaded this change for review. ( https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/22083?usp=email )
Change subject: [ASTERIXDB-3956][HYR] Don't ack a heartbeat from an unauthorized node
......................................................................
[ASTERIXDB-3956][HYR] Don't ack a heartbeat from an unauthorized node
- user model changes: no
- storage format changes: no
- interface changes: no
Details: A node deauthorized on its way out of the cluster keeps
heartbeating until it is stopped. The negative ack it got for being
unregistered sent it to re-register, which addNode refuses for an
unauthorized node, and a refused registration halts the node. Leave such
heartbeats unanswered; if the node is authorized again, its next
heartbeat gets the negative ack and it re-registers as before.
Ext-ref: MB-74446
Generated-by: Claude Opus 5.5 <no...@anthropic.com>
Change-Id: Id9745a4144e2568383b74eb2c6d7f4e72d2d3028
---
M hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWork.java
A hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWorkTest.java
2 files changed, 80 insertions(+), 0 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/83/22083/1
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWork.java
index 481c2e0..c59901e 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWork.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWork.java
@@ -49,6 +49,10 @@
final NodeControllerState ncState = nodeManager.getNodeControllerState(nodeId);
if (ncState != null) {
ncState.getNodeController().heartbeatAck(ccs.getCcId(), null);
+ } else if (!ccs.getApplication().getGatekeeper().isAuthorized(nodeId)) {
+ // a node deauthorized on its way out of the cluster keeps heartbeating until it is stopped; a negative
+ // ack would send it to re-register, which addNode refuses, and a refused registration halts the node
+ LOGGER.info("received a heartbeat from unauthorized node {}; not acking", nodeId);
} else {
// unregistered nc- let him know
InetSocketAddress refreshedNcAddress = NetworkUtil.refresh(ncAddress);
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWorkTest.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWorkTest.java
new file mode 100644
index 0000000..c7f9cb3
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/work/NodeHeartbeatWorkTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.hyracks.control.cc.work;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetSocketAddress;
+
+import org.apache.hyracks.api.application.ICCApplication;
+import org.apache.hyracks.api.control.CcId;
+import org.apache.hyracks.api.exceptions.ErrorCode;
+import org.apache.hyracks.control.cc.ClusterControllerService;
+import org.apache.hyracks.control.cc.cluster.INodeManager;
+import org.apache.hyracks.control.common.ipc.CCNCFunctions;
+import org.apache.hyracks.ipc.api.IIPCHandle;
+import org.apache.hyracks.ipc.impl.IPCSystem;
+import org.junit.Test;
+
+public class NodeHeartbeatWorkTest {
+
+ private static final String NODE = "nc1";
+ private static final InetSocketAddress NC_ADDRESS = new InetSocketAddress("127.0.0.1", 9115);
+
+ private final IPCSystem clusterIpc = mock(IPCSystem.class);
+ private final IIPCHandle ncHandle = mock(IIPCHandle.class);
+
+ @Test
+ public void unregisteredAuthorizedNodeIsToldToReregister() throws Exception {
+ heartbeat(true);
+ verify(ncHandle).send(anyLong(), argThat(
+ f -> ((CCNCFunctions.NodeHeartbeatAckFunction) f).getException().matches(ErrorCode.NO_SUCH_NODE)),
+ any());
+ }
+
+ @Test
+ public void unauthorizedNodeIsNotAcked() throws Exception {
+ heartbeat(false);
+ verify(clusterIpc, never()).getReconnectingHandle(any());
+ verify(ncHandle, never()).send(anyLong(), any(), any());
+ }
+
+ private void heartbeat(boolean authorized) throws Exception {
+ ClusterControllerService ccs = mock(ClusterControllerService.class);
+ INodeManager nodeManager = mock(INodeManager.class);
+ ICCApplication app = mock(ICCApplication.class);
+ when(ccs.getNodeManager()).thenReturn(nodeManager);
+ when(ccs.getApplication()).thenReturn(app);
+ when(app.getGatekeeper()).thenReturn(nodeId -> authorized);
+ when(ccs.getCcId()).thenReturn(CcId.valueOf(0));
+ when(ccs.getClusterIPC()).thenReturn(clusterIpc);
+ when(clusterIpc.getReconnectingHandle(any())).thenReturn(ncHandle);
+ new NodeHeartbeatWork(ccs, NODE, null, NC_ADDRESS).doRun();
+ }
+}
--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/22083?usp=email
To unsubscribe, or for help writing mail filters, visit https://asterix-gerrit.ics.uci.edu/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: Id9745a4144e2568383b74eb2c6d7f4e72d2d3028
Gerrit-Change-Number: 22083
Gerrit-PatchSet: 1
Gerrit-Owner: Michael Blow <mb...@apache.org>