Skip to content

Commit 1e49535

Browse files
authored
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
1 parent e0ae6c5 commit 1e49535

6 files changed

Lines changed: 126 additions & 3 deletions

File tree

iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public enum TSStatusCode {
9191
TABLE_NOT_EXISTS(550),
9292
TABLE_ALREADY_EXISTS(551),
9393
COLUMN_ALREADY_EXISTS(552),
94+
TABLE_IS_LOST(553),
9495
ONLY_LOGICAL_VIEW(560),
9596

9697
// Storage Engine

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataExecutionVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.apache.iotdb.db.exception.WriteProcessException;
2828
import org.apache.iotdb.db.exception.WriteProcessRejectException;
2929
import org.apache.iotdb.db.exception.query.OutOfTTLException;
30+
import org.apache.iotdb.db.exception.runtime.TableLostRuntimeException;
31+
import org.apache.iotdb.db.exception.runtime.TableNotExistsRuntimeException;
3032
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
3133
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
3234
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.pipe.PipeEnrichedDeleteDataNode;
@@ -160,6 +162,9 @@ public TSStatus visitInsertRows(InsertRowsNode node, DataRegion dataRegion) {
160162
}
161163
}
162164
return firstStatus;
165+
} catch (TableNotExistsRuntimeException | TableLostRuntimeException e) {
166+
LOGGER.error("Error in executing plan node: {}, caused by {}", node, e.getMessage());
167+
return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
163168
}
164169
}
165170

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ protected TSStatus write(PlanNode planNode) {
230230
Thread.currentThread().interrupt();
231231
}
232232
} else {
233+
if (TSStatusCode.TABLE_NOT_EXISTS.getStatusCode() == result.getCode()
234+
|| TSStatusCode.TABLE_IS_LOST.getStatusCode() == result.getCode()) {
235+
logger.info("table is not exists or lost, result code is {}", result.getCode());
236+
}
233237
break;
234238
}
235239
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.db.exception.runtime;
21+
22+
import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
23+
import org.apache.iotdb.rpc.TSStatusCode;
24+
25+
public class TableLostRuntimeException extends IoTDBRuntimeException {
26+
27+
public TableLostRuntimeException(final String databaseName, final String tableName) {
28+
super(
29+
String.format("Table %s in the database %s is lost unexpected.", tableName, databaseName),
30+
TSStatusCode.TABLE_IS_LOST.getStatusCode());
31+
}
32+
33+
public TableLostRuntimeException(final Throwable cause) {
34+
super(cause, TSStatusCode.TABLE_IS_LOST.getStatusCode());
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.db.exception.runtime;
21+
22+
import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
23+
import org.apache.iotdb.rpc.TSStatusCode;
24+
25+
public class TableNotExistsRuntimeException extends IoTDBRuntimeException {
26+
27+
public TableNotExistsRuntimeException(final String databaseName, final String tableName) {
28+
super(
29+
String.format("Table %s in the database %s is not exists.", tableName, databaseName),
30+
TSStatusCode.TABLE_NOT_EXISTS.getStatusCode());
31+
}
32+
33+
public TableNotExistsRuntimeException(final Throwable cause) {
34+
super(cause, TSStatusCode.TABLE_NOT_EXISTS.getStatusCode());
35+
}
36+
}

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.apache.iotdb.db.storageengine.dataregion;
2121

2222
import org.apache.iotdb.common.rpc.thrift.TSStatus;
23+
import org.apache.iotdb.commons.client.exception.ClientManagerException;
2324
import org.apache.iotdb.commons.cluster.NodeStatus;
2425
import org.apache.iotdb.commons.concurrent.IoTDBThreadPoolFactory;
2526
import org.apache.iotdb.commons.conf.CommonDescriptor;
@@ -29,6 +30,8 @@
2930
import org.apache.iotdb.commons.path.IFullPath;
3031
import org.apache.iotdb.commons.path.MeasurementPath;
3132
import org.apache.iotdb.commons.schema.SchemaConstant;
33+
import org.apache.iotdb.commons.schema.table.TsTable;
34+
import org.apache.iotdb.commons.schema.table.TsTableInternalRPCUtil;
3235
import org.apache.iotdb.commons.service.metric.MetricService;
3336
import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
3437
import org.apache.iotdb.commons.service.metric.enums.Metric;
@@ -37,6 +40,7 @@
3740
import org.apache.iotdb.commons.utils.RetryUtils;
3841
import org.apache.iotdb.commons.utils.TestOnly;
3942
import org.apache.iotdb.commons.utils.TimePartitionUtils;
43+
import org.apache.iotdb.confignode.rpc.thrift.TDescTableResp;
4044
import org.apache.iotdb.consensus.ConsensusFactory;
4145
import org.apache.iotdb.db.conf.IoTDBConfig;
4246
import org.apache.iotdb.db.conf.IoTDBDescriptor;
@@ -50,11 +54,15 @@
5054
import org.apache.iotdb.db.exception.query.OutOfTTLException;
5155
import org.apache.iotdb.db.exception.query.QueryProcessException;
5256
import org.apache.iotdb.db.exception.quota.ExceedQuotaException;
57+
import org.apache.iotdb.db.exception.runtime.TableLostRuntimeException;
58+
import org.apache.iotdb.db.exception.runtime.TableNotExistsRuntimeException;
5359
import org.apache.iotdb.db.pipe.consensus.deletion.DeletionResource;
5460
import org.apache.iotdb.db.pipe.consensus.deletion.DeletionResource.Status;
5561
import org.apache.iotdb.db.pipe.consensus.deletion.DeletionResourceManager;
5662
import org.apache.iotdb.db.pipe.consensus.deletion.persist.PageCacheDeletionBuffer;
5763
import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.listener.PipeInsertionDataNodeListener;
64+
import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
65+
import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
5866
import org.apache.iotdb.db.queryengine.common.DeviceContext;
5967
import org.apache.iotdb.db.queryengine.execution.fragment.QueryContext;
6068
import org.apache.iotdb.db.queryengine.metric.QueryResourceMetricSet;
@@ -147,6 +155,7 @@
147155
import org.apache.iotdb.rpc.TSStatusCode;
148156

149157
import org.apache.commons.io.FileUtils;
158+
import org.apache.thrift.TException;
150159
import org.apache.tsfile.file.metadata.ChunkMetadata;
151160
import org.apache.tsfile.file.metadata.IDeviceID;
152161
import org.apache.tsfile.fileSystem.FSFactoryProducer;
@@ -1399,9 +1408,41 @@ private void registerToTsFile(InsertNode node, TsFileProcessor tsFileProcessor)
13991408
if (tableName != null) {
14001409
tsFileProcessor.registerToTsFile(
14011410
tableName,
1402-
t ->
1403-
TableSchema.of(DataNodeTableCache.getInstance().getTable(getDatabaseName(), t))
1404-
.toTsFileTableSchemaNoAttribute());
1411+
t -> {
1412+
TsTable tsTable = DataNodeTableCache.getInstance().getTable(getDatabaseName(), t);
1413+
if (tsTable == null) {
1414+
// There is a high probability that the leader node has been executed and is currently
1415+
// located in the follower node.
1416+
if (node.isGeneratedByRemoteConsensusLeader()) {
1417+
// If current node is follower, after request config node and get the answer that
1418+
// table is exist or not, then tell leader node when table is not exist.
1419+
try {
1420+
TDescTableResp resp =
1421+
ConfigNodeClientManager.getInstance()
1422+
.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)
1423+
.describeTable(getDatabaseName(), tableName, false);
1424+
tsTable =
1425+
(resp != null) && (resp.tableInfo != null)
1426+
? TsTableInternalRPCUtil.deserializeSingleTsTable(resp.getTableInfo())
1427+
: null;
1428+
} catch (TException | ClientManagerException e) {
1429+
logger.error(
1430+
"Remote request config node failed that judgment if table is exist, occur exception. {}",
1431+
e.getMessage());
1432+
}
1433+
if (tsTable == null) {
1434+
throw new TableNotExistsRuntimeException(getDatabaseName(), tableName);
1435+
}
1436+
} else {
1437+
// Here may be invoked by leader node, the table is very unexpected not exist in the
1438+
// DataNodeTableCache
1439+
logger.error(
1440+
"Due tsTable is null, table schema can't be got, leader node occur special situation need to resolve.");
1441+
throw new TableLostRuntimeException(getDatabaseName(), tableName);
1442+
}
1443+
}
1444+
return TableSchema.of(tsTable).toTsFileTableSchemaNoAttribute();
1445+
});
14051446
}
14061447
}
14071448

0 commit comments

Comments
 (0)