This is an automated email from the ASF dual-hosted git repository.

jiangtian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 1e495354fe5 Avoid the NPE problem occur that tsTable is null (#15618)
1e495354fe5 is described below

commit 1e495354fe5cb2708712360b1e032350d54a1e84
Author: libo <[email protected]>
AuthorDate: Tue Jun 3 10:24:11 2025 +0800

    Avoid the NPE problem occur that tsTable is null (#15618)
    
    * Avoid the NPE problem occur that tsTable is null, and ensure if table is 
not exist and catch this exception to tell leader datanode for retry or do 
nothing.
    
    * Avoid the NPE problem occur that tsTable is null via retry to get the 
tsTable.
    
    * Add license description
---
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |  1 +
 .../dataregion/DataExecutionVisitor.java           |  5 +++
 .../dataregion/DataRegionStateMachine.java         |  4 ++
 .../runtime/TableLostRuntimeException.java         | 36 +++++++++++++++++
 .../runtime/TableNotExistsRuntimeException.java    | 36 +++++++++++++++++
 .../db/storageengine/dataregion/DataRegion.java    | 47 ++++++++++++++++++++--
 6 files changed, 126 insertions(+), 3 deletions(-)

diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
index d054a31e74d..3f7eb8f6507 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
@@ -91,6 +91,7 @@ public enum TSStatusCode {
   TABLE_NOT_EXISTS(550),
   TABLE_ALREADY_EXISTS(551),
   COLUMN_ALREADY_EXISTS(552),
+  TABLE_IS_LOST(553),
   ONLY_LOGICAL_VIEW(560),
 
   // Storage Engine
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataExecutionVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataExecutionVisitor.java
index 43d58119b00..7431aa9a79d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataExecutionVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataExecutionVisitor.java
@@ -27,6 +27,8 @@ import org.apache.iotdb.db.exception.BatchProcessException;
 import org.apache.iotdb.db.exception.WriteProcessException;
 import org.apache.iotdb.db.exception.WriteProcessRejectException;
 import org.apache.iotdb.db.exception.query.OutOfTTLException;
+import org.apache.iotdb.db.exception.runtime.TableLostRuntimeException;
+import org.apache.iotdb.db.exception.runtime.TableNotExistsRuntimeException;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.pipe.PipeEnrichedDeleteDataNode;
@@ -160,6 +162,9 @@ public class DataExecutionVisitor extends 
PlanVisitor<TSStatus, DataRegion> {
         }
       }
       return firstStatus;
+    } catch (TableNotExistsRuntimeException | TableLostRuntimeException e) {
+      LOGGER.error("Error in executing plan node: {}, caused by {}", node, 
e.getMessage());
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
     }
   }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
index c430be4b174..cfee2b54a6e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
@@ -230,6 +230,10 @@ public class DataRegionStateMachine extends 
BaseStateMachine {
           Thread.currentThread().interrupt();
         }
       } else {
+        if (TSStatusCode.TABLE_NOT_EXISTS.getStatusCode() == result.getCode()
+            || TSStatusCode.TABLE_IS_LOST.getStatusCode() == result.getCode()) 
{
+          logger.info("table is not exists or lost, result code is {}", 
result.getCode());
+        }
         break;
       }
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/runtime/TableLostRuntimeException.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/runtime/TableLostRuntimeException.java
new file mode 100644
index 00000000000..572be2f0974
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/runtime/TableLostRuntimeException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.iotdb.db.exception.runtime;
+
+import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class TableLostRuntimeException extends IoTDBRuntimeException {
+
+  public TableLostRuntimeException(final String databaseName, final String 
tableName) {
+    super(
+        String.format("Table %s in the database %s is lost unexpected.", 
tableName, databaseName),
+        TSStatusCode.TABLE_IS_LOST.getStatusCode());
+  }
+
+  public TableLostRuntimeException(final Throwable cause) {
+    super(cause, TSStatusCode.TABLE_IS_LOST.getStatusCode());
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/runtime/TableNotExistsRuntimeException.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/runtime/TableNotExistsRuntimeException.java
new file mode 100644
index 00000000000..8590b4c70cf
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/runtime/TableNotExistsRuntimeException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.iotdb.db.exception.runtime;
+
+import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class TableNotExistsRuntimeException extends IoTDBRuntimeException {
+
+  public TableNotExistsRuntimeException(final String databaseName, final 
String tableName) {
+    super(
+        String.format("Table %s in the database %s is not exists.", tableName, 
databaseName),
+        TSStatusCode.TABLE_NOT_EXISTS.getStatusCode());
+  }
+
+  public TableNotExistsRuntimeException(final Throwable cause) {
+    super(cause, TSStatusCode.TABLE_NOT_EXISTS.getStatusCode());
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
index b698469b51d..0f81908a435 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
@@ -20,6 +20,7 @@
 package org.apache.iotdb.db.storageengine.dataregion;
 
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.client.exception.ClientManagerException;
 import org.apache.iotdb.commons.cluster.NodeStatus;
 import org.apache.iotdb.commons.concurrent.IoTDBThreadPoolFactory;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
@@ -29,6 +30,8 @@ import org.apache.iotdb.commons.file.SystemFileFactory;
 import org.apache.iotdb.commons.path.IFullPath;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.schema.SchemaConstant;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.commons.schema.table.TsTableInternalRPCUtil;
 import org.apache.iotdb.commons.service.metric.MetricService;
 import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
 import org.apache.iotdb.commons.service.metric.enums.Metric;
@@ -37,6 +40,7 @@ import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
 import org.apache.iotdb.commons.utils.RetryUtils;
 import org.apache.iotdb.commons.utils.TestOnly;
 import org.apache.iotdb.commons.utils.TimePartitionUtils;
+import org.apache.iotdb.confignode.rpc.thrift.TDescTableResp;
 import org.apache.iotdb.consensus.ConsensusFactory;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
@@ -50,11 +54,15 @@ import org.apache.iotdb.db.exception.load.LoadFileException;
 import org.apache.iotdb.db.exception.query.OutOfTTLException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.exception.quota.ExceedQuotaException;
+import org.apache.iotdb.db.exception.runtime.TableLostRuntimeException;
+import org.apache.iotdb.db.exception.runtime.TableNotExistsRuntimeException;
 import org.apache.iotdb.db.pipe.consensus.deletion.DeletionResource;
 import org.apache.iotdb.db.pipe.consensus.deletion.DeletionResource.Status;
 import org.apache.iotdb.db.pipe.consensus.deletion.DeletionResourceManager;
 import 
org.apache.iotdb.db.pipe.consensus.deletion.persist.PageCacheDeletionBuffer;
 import 
org.apache.iotdb.db.pipe.extractor.dataregion.realtime.listener.PipeInsertionDataNodeListener;
+import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
+import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
 import org.apache.iotdb.db.queryengine.common.DeviceContext;
 import org.apache.iotdb.db.queryengine.execution.fragment.QueryContext;
 import org.apache.iotdb.db.queryengine.metric.QueryResourceMetricSet;
@@ -147,6 +155,7 @@ import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.thrift.TException;
 import org.apache.tsfile.file.metadata.ChunkMetadata;
 import org.apache.tsfile.file.metadata.IDeviceID;
 import org.apache.tsfile.fileSystem.FSFactoryProducer;
@@ -1399,9 +1408,41 @@ public class DataRegion implements IDataRegionForQuery {
     if (tableName != null) {
       tsFileProcessor.registerToTsFile(
           tableName,
-          t ->
-              
TableSchema.of(DataNodeTableCache.getInstance().getTable(getDatabaseName(), t))
-                  .toTsFileTableSchemaNoAttribute());
+          t -> {
+            TsTable tsTable = 
DataNodeTableCache.getInstance().getTable(getDatabaseName(), t);
+            if (tsTable == null) {
+              // There is a high probability that the leader node has been 
executed and is currently
+              // located in the follower node.
+              if (node.isGeneratedByRemoteConsensusLeader()) {
+                // If current node is follower, after request config node and 
get the answer that
+                // table is exist or not, then tell leader node when table is 
not exist.
+                try {
+                  TDescTableResp resp =
+                      ConfigNodeClientManager.getInstance()
+                          .borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)
+                          .describeTable(getDatabaseName(), tableName, false);
+                  tsTable =
+                      (resp != null) && (resp.tableInfo != null)
+                          ? 
TsTableInternalRPCUtil.deserializeSingleTsTable(resp.getTableInfo())
+                          : null;
+                } catch (TException | ClientManagerException e) {
+                  logger.error(
+                      "Remote request config node failed that judgment if 
table is exist, occur exception. {}",
+                      e.getMessage());
+                }
+                if (tsTable == null) {
+                  throw new TableNotExistsRuntimeException(getDatabaseName(), 
tableName);
+                }
+              } else {
+                // Here may be invoked by leader node, the table is very 
unexpected not exist in the
+                // DataNodeTableCache
+                logger.error(
+                    "Due tsTable is null, table schema can't be got, leader 
node occur special situation need to resolve.");
+                throw new TableLostRuntimeException(getDatabaseName(), 
tableName);
+              }
+            }
+            return TableSchema.of(tsTable).toTsFileTableSchemaNoAttribute();
+          });
     }
   }
 

Reply via email to