Caideyipi commented on code in PR #18265:
URL: https://github.com/apache/iotdb/pull/18265#discussion_r3622283145


##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManager.java:
##########
@@ -625,6 +644,7 @@ public void updateTemplateInfo(byte[] templateInfo) {
   public void updateTemplateInfo(Template template) {
     readWriteLock.writeLock().lock();
     try {
+      failIfMetadataLeaseFenced();

Review Comment:
   Template propagation can fail during the asynchronous lease-recovery window.
   
   The heartbeat schedules cache recovery asynchronously, so the ConfigNode may 
already consider a DataNode reachable while its local metadata state is still 
fenced. A template update then throws from `failIfMetadataLeaseFenced()`.
   
   The added regression test reproduces the actual RPC path: the Thrift 
application exception is converted by `DataNodeTSStatusRPCHandler` to 
EXECUTE_STATEMENT_ERROR (301), after which `ClusterCachePropagator` returns 
FAIL instead of WAIT.
   
   This causes SET/UNSET/ALTER to fail transiently while the DataNode is 
recovering. Please preserve/classify the fenced condition as retryable and 
retry until cache recovery completes.



##########
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java:
##########
@@ -3308,7 +3308,8 @@ public TDataNodeLeaseRecoveryResp 
reloadCacheAfterLeaseRecovery() {
     }
     return new TDataNodeLeaseRecoveryResp()
         .setStatus(RpcUtils.SUCCESS_STATUS)
-        
.setTableInfo(clusterSchemaManager.getAllTableInfoForDataNodeActivation());
+        
.setTableInfo(clusterSchemaManager.getAllTableInfoForDataNodeActivation())
+        .setTemplateInfo(clusterSchemaManager.getAllTemplateSetInfo());

Review Comment:
   `reloadCacheAfterLeaseRecovery()` should not return SUCCESS when the 
template snapshot cannot be read.
   
   `ClusterSchemaManager#getAllTemplateSetInfo()` catches `ConsensusException` 
and returns `new byte[0]`. The recovery RPC then returns SUCCESS with that 
empty value. On the DataNode side, the field is considered set, so the template 
cache is cleared and the metadata lease returns to NORMAL.
   
   The added regression tests reproduce both steps: an injected ConfigRegion 
read failure produces a zero-length template snapshot, and that snapshot still 
produces a SUCCESS (code 200) lease-recovery response.
   
   This can unfence a DataNode with all template metadata missing. Please 
propagate the snapshot read failure through the RPC status so the DataNode 
remains fenced.



##########
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/UnsetTemplateProcedure.java:
##########
@@ -154,30 +155,21 @@ private void invalidateCache(final ConfigNodeProcedureEnv 
env) {
     }
   }
 
-  private void executeInvalidateCache(final ConfigNodeProcedureEnv env) throws 
ProcedureException {
-    final Map<Integer, TDataNodeLocation> dataNodeLocationMap =
-        
env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations();
-    final TUpdateTemplateReq invalidateTemplateSetInfoReq = new 
TUpdateTemplateReq();
-    invalidateTemplateSetInfoReq.setType(
-        TemplateInternalRPCUpdateType.INVALIDATE_TEMPLATE_SET_INFO.toByte());
-    
invalidateTemplateSetInfoReq.setTemplateInfo(getInvalidateTemplateSetInfo());
-    final DataNodeAsyncRequestContext<TUpdateTemplateReq, TSStatus> 
clientHandler =
-        new DataNodeAsyncRequestContext<>(
-            CnToDnAsyncRequestType.UPDATE_TEMPLATE,
-            invalidateTemplateSetInfoReq,
-            dataNodeLocationMap);
-    
CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler);
-    final Map<Integer, TSStatus> statusMap = clientHandler.getResponseMap();
-    for (final TSStatus status : statusMap.values()) {
-      // all dataNodes must clear the related template cache
-      if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        LOGGER.error(
-            
ProcedureMessages.FAILED_TO_INVALIDATE_TEMPLATE_CACHE_OF_TEMPLATE_SET_ON,
-            template.getName(),
-            path);
-        throw new ProcedureException(
-            new 
MetadataException(ProcedureMessages.INVALIDATE_TEMPLATE_CACHE_FAILED));
-      }
+  void executeInvalidateCache(final ConfigNodeProcedureEnv env) throws 
ProcedureException {
+    final TUpdateTemplateReq req = new TUpdateTemplateReq();
+    
req.setType(TemplateInternalRPCUpdateType.INVALIDATE_TEMPLATE_SET_INFO.toByte());
+    req.setTemplateInfo(getInvalidateTemplateSetInfo());
+
+    final boolean proceed =
+        new 
ClusterCachePropagator(SchemaUtils.filterFencedDataNode(env.getConfigManager()))

Review Comment:
   The rollback path is not HA-safe after allowing the forward invalidation to 
skip fenced DataNodes.
   
   If UNSET reaches the activation check and finds that the template is still 
in use, rollback calls `executeRollbackInvalidateCache()` before 
`rollbackPreUnsetSchemaTemplate()`. The former still broadcasts to every 
registered DataNode and fails when one DataNode is offline. Because of that 
exception, the ConfigNode PRE_UNSET state is never restored.
   
   The added regression test injects the DataNode rollback failure and confirms 
that `rollbackPreUnsetSchemaTemplate()` is called zero times.
   
   Please restore the authoritative ConfigNode state independently of DataNode 
acknowledgements, and then use fence-aware propagation to repair the caches of 
reachable DataNodes.



-- 
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]

Reply via email to