From 4dbd59aa8a5e7b0c0528fc67e64b1657e57c2cda Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Wed, 21 Oct 2026 21:14:42 +0800 Subject: [PATCH] [To dev/1.3] Improve schema metadata error messages and recovery logs (#18937) --- .../iotdb/db/it/IoTDBSimpleQueryIT.java | 2 +- .../iotdb/db/i18n/DataNodeSchemaMessages.java | 26 ++++ .../iotdb/db/i18n/DataNodeSchemaMessages.java | 19 +++ .../iotdb/db/schemaengine/SchemaEngine.java | 9 +- .../impl/SchemaRegionMemoryImpl.java | 12 +- .../schemaregion/utils/MetaFormatUtils.java | 41 ++++-- .../template/ClusterTemplateManager.java | 32 +++-- .../db/metadata/MetaFormatUtilsTest.java | 110 +++++++++++++++ .../template/ClusterTemplateManagerTest.java | 131 ++++++++++++++++++ 9 files changed, 349 insertions(+), 33 deletions(-) create mode 100644 iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/MetaFormatUtilsTest.java create mode 100644 iotdb-core/datanode/src/test/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManagerTest.java diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java index ddb298da4f5a7..d69c62532ef5b 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java @@ -99,7 +99,7 @@ public void testFailedToCreateTimeseriesSDTProperties() { } catch (Exception e) { assertEquals( TSStatusCode.ILLEGAL_PARAMETER.getStatusCode() - + ": SDT compression deviation cannot be negative. Failed to create timeseries for path root.sg1.d0.s1", + + ": SDT property compdev must be non-negative, but was [-2]. Failed to create timeseries for path root.sg1.d0.s1", e.getMessage()); } diff --git a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java index df31f7e084ddb..4b027a8a64439 100644 --- a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java +++ b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java @@ -26,4 +26,30 @@ private DataNodeSchemaMessages() {} public static final String EXCEPTION_CANNOT_RECOVER_DUPLICATED_SCHEMAREGION_ARG_FOUND_IN_DATABASES_ARG_AND_ARG_D9F60E05 = "Cannot recover duplicated SchemaRegion [%s] found in databases [%s] and [%s]."; + + public static final String FAILED_TO_RECOVER_TAG_INDEX = + "Failed to recover tag index for measurement [{}] in database [{}], SchemaRegion [{}], tag offset [{}]."; + public static final String SCHEMA_REGION_FAILED_TO_RECOVER = + "SchemaRegion [%d] in StorageGroup [%s] failed to recover."; + public static final String SDT_COMPRESSION_DEVIATION_REQUIRED = + "SDT compression requires the compdev property"; + public static final String SDT_COMPRESSION_DEVIATION_NEGATIVE = + "SDT property compdev must be non-negative, but was [%s]"; + public static final String SDT_COMPRESSION_DEVIATION_FORMAT_ERROR = + "SDT property compdev must be a number, but was [%s]"; + public static final String SDT_COMPRESSION_MAX_GREATER_THAN_MIN = + "SDT property compmaxtime [%s] must be greater than compmintime [%s]"; + public static final String SDT_COMPRESSION_TIME_NEGATIVE = + "SDT property %s must be non-negative, but was [%s]"; + public static final String SDT_COMPRESSION_TIME_FORMAT_ERROR = + "SDT property %s must be a 64-bit integer, but was [%s]"; + public static final String SDT_ENABLED_NO_COMPRESSION_TIME = + "Timeseries [{}] uses SDT without property [{}]; using default [{}]."; + public static final String CREATE_TEMPLATE_ERROR = + "Failed to create schema template [%s] on ConfigNode: %s"; + public static final String GET_ALL_TEMPLATE_ERROR = + "Failed to get schema templates from ConfigNode: %s"; + public static final String GET_TEMPLATE_INFO_ERROR = + "Failed to get schema template [%s] from ConfigNode: %s"; + public static final String ILLEGAL_PATH_LOG = "illegal path {}"; } diff --git a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java index 5fd43c669fc95..7c94694932e65 100644 --- a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java +++ b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java @@ -26,4 +26,23 @@ private DataNodeSchemaMessages() {} public static final String EXCEPTION_CANNOT_RECOVER_DUPLICATED_SCHEMAREGION_ARG_FOUND_IN_DATABASES_ARG_AND_ARG_D9F60E05 = "无法恢复重复的 SchemaRegion [%s],其同时存在于数据库 [%s] 和 [%s] 中。"; + + public static final String FAILED_TO_RECOVER_TAG_INDEX = + "恢复测点 [{}] 的 tag 索引失败,数据库为 [{}],SchemaRegion 为 [{}],tag 偏移量为 [{}]。"; + public static final String SCHEMA_REGION_FAILED_TO_RECOVER = + "SchemaRegion [%d] 在 StorageGroup [%s] 中恢复失败。"; + public static final String SDT_COMPRESSION_DEVIATION_REQUIRED = "SDT 压缩必须设置 compdev 属性"; + public static final String SDT_COMPRESSION_DEVIATION_NEGATIVE = "SDT 属性 compdev 必须为非负数,实际值为 [%s]"; + public static final String SDT_COMPRESSION_DEVIATION_FORMAT_ERROR = + "SDT 属性 compdev 必须为数字,实际值为 [%s]"; + public static final String SDT_COMPRESSION_MAX_GREATER_THAN_MIN = + "SDT 属性 compmaxtime [%s] 必须大于 compmintime [%s]"; + public static final String SDT_COMPRESSION_TIME_NEGATIVE = "SDT 属性 %s 必须为非负数,实际值为 [%s]"; + public static final String SDT_COMPRESSION_TIME_FORMAT_ERROR = "SDT 属性 %s 必须为 64 位整数,实际值为 [%s]"; + public static final String SDT_ENABLED_NO_COMPRESSION_TIME = + "时间序列 [{}] 已启用 SDT 但未设置属性 [{}],使用默认值 [{}]。"; + public static final String CREATE_TEMPLATE_ERROR = "在 ConfigNode 上创建元数据模板 [%s] 失败:%s"; + public static final String GET_ALL_TEMPLATE_ERROR = "从 ConfigNode 获取元数据模板列表失败:%s"; + public static final String GET_TEMPLATE_INFO_ERROR = "从 ConfigNode 获取元数据模板 [%s] 失败:%s"; + public static final String ILLEGAL_PATH_LOG = "非法路径 {}"; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java index 504eed7b90480..abfc243ad91f3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java @@ -342,11 +342,12 @@ private Callable recoverSchemaRegionTask( timeRecord); return schemaRegion; } catch (MetadataException e) { - logger.error( + throw new RuntimeException( String.format( - "SchemaRegion [%d] in StorageGroup [%s] failed to recover.", - schemaRegionId.getId(), storageGroup.getFullPath())); - throw new RuntimeException(e); + DataNodeSchemaMessages.SCHEMA_REGION_FAILED_TO_RECOVER, + schemaRegionId.getId(), + storageGroup.getFullPath()), + e); } }; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java index 1c89a9b613b75..65e8e2f95ee17 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java @@ -37,6 +37,7 @@ import org.apache.iotdb.db.exception.metadata.SchemaDirCreationFailureException; import org.apache.iotdb.db.exception.metadata.SchemaQuotaExceededException; import org.apache.iotdb.db.exception.metadata.SeriesOverflowException; +import org.apache.iotdb.db.i18n.DataNodeSchemaMessages; import org.apache.iotdb.db.queryengine.common.schematree.ClusterSchemaTree; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.write.CreateTimeSeriesNode; import org.apache.iotdb.db.schemaengine.metric.ISchemaRegionMetric; @@ -109,8 +110,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import static org.apache.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR; - /** * This class takes the responsibility of serialization of all the metadata info of one certain * schema region and persistent it into files. This class contains the interfaces to modify the @@ -508,9 +507,12 @@ public void loadSnapshot(File latestSnapshotRootDir) { tagManager.recoverIndex(measurementMNode.getOffset(), measurementMNode); } catch (IOException e) { logger.error( - "Failed to recover tagIndex for {} in schemaRegion {}.", - storageGroupFullPath + PATH_SEPARATOR + measurementMNode.getFullPath(), - schemaRegionId); + DataNodeSchemaMessages.FAILED_TO_RECOVER_TAG_INDEX, + measurementMNode.getName(), + storageGroupFullPath, + schemaRegionId, + measurementMNode.getOffset(), + e); } }, deviceMNode -> { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/MetaFormatUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/MetaFormatUtils.java index 239a2e0bd4fce..b7f5c3d629eaf 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/MetaFormatUtils.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/MetaFormatUtils.java @@ -24,6 +24,7 @@ import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException; import org.apache.iotdb.db.exception.metadata.IllegalParameterOfPathException; +import org.apache.iotdb.db.i18n.DataNodeSchemaMessages; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -145,17 +146,24 @@ public static void checkTimeseriesProps(String path, Map props) private static void checkSDTFormat(String path, Map props) throws IllegalParameterOfPathException { if (!props.containsKey(SDT_COMP_DEV)) { - throw new IllegalParameterOfPathException("SDT compression deviation is required", path); + throw new IllegalParameterOfPathException( + DataNodeSchemaMessages.SDT_COMPRESSION_DEVIATION_REQUIRED, path); } try { double d = Double.parseDouble(props.get(SDT_COMP_DEV)); if (d < 0) { throw new IllegalParameterOfPathException( - "SDT compression deviation cannot be negative", path); + String.format( + DataNodeSchemaMessages.SDT_COMPRESSION_DEVIATION_NEGATIVE, props.get(SDT_COMP_DEV)), + path); } } catch (NumberFormatException e) { - throw new IllegalParameterOfPathException("SDT compression deviation formatting error", path); + throw new IllegalParameterOfPathException( + String.format( + DataNodeSchemaMessages.SDT_COMPRESSION_DEVIATION_FORMAT_ERROR, + props.get(SDT_COMP_DEV)), + path); } long compMinTime = sdtCompressionTimeFormat(SDT_COMP_MIN_TIME, props, path); @@ -163,7 +171,11 @@ private static void checkSDTFormat(String path, Map props) if (compMaxTime <= compMinTime) { throw new IllegalParameterOfPathException( - "SDT compression maximum time needs to be greater than compression minimum time", path); + String.format( + DataNodeSchemaMessages.SDT_COMPRESSION_MAX_GREATER_THAN_MIN, + compMaxTime, + compMinTime), + path); } } @@ -172,20 +184,23 @@ private static long sdtCompressionTimeFormat( throws IllegalParameterOfPathException { boolean isCompMaxTime = compTime.equals(SDT_COMP_MAX_TIME); long time = isCompMaxTime ? Long.MAX_VALUE : 0; - String s = isCompMaxTime ? "maximum" : "minimum"; if (props.containsKey(compTime)) { + String value = props.get(compTime); try { - time = Long.parseLong(props.get(compTime)); - if (time < 0) { - throw new IllegalParameterOfPathException( - String.format("SDT compression %s time cannot be negative", s), path); - } - } catch (IllegalParameterOfPathException e) { + time = Long.parseLong(value); + } catch (NumberFormatException e) { + throw new IllegalParameterOfPathException( + String.format( + DataNodeSchemaMessages.SDT_COMPRESSION_TIME_FORMAT_ERROR, compTime, value), + path); + } + if (time < 0) { throw new IllegalParameterOfPathException( - String.format("SDT compression %s time formatting error", s), path); + String.format(DataNodeSchemaMessages.SDT_COMPRESSION_TIME_NEGATIVE, compTime, value), + path); } } else { - logger.info("{} enabled SDT but did not set compression {} time", path, s); + logger.debug(DataNodeSchemaMessages.SDT_ENABLED_NO_COMPRESSION_TIME, path, compTime, time); } return time; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManager.java index 0350b7883e01a..8e19e191da54f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManager.java @@ -38,6 +38,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TGetPathsSetTemplatesResp; import org.apache.iotdb.confignode.rpc.thrift.TGetTemplateResp; import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaTemplateReq; +import org.apache.iotdb.db.i18n.DataNodeSchemaMessages; import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; @@ -130,9 +131,11 @@ public TSStatus createSchemaTemplate(CreateSchemaTemplateStatement statement) { e, TSStatusCode.CREATE_TEMPLATE_ERROR.getStatusCode())); } catch (ClientManagerException | TException e) { - throw new RuntimeException( - new IoTDBException( - "create template error.", e, TSStatusCode.CREATE_TEMPLATE_ERROR.getStatusCode())); + throw wrapTemplateRpcException( + String.format( + DataNodeSchemaMessages.CREATE_TEMPLATE_ERROR, statement.getName(), e.getMessage()), + e, + TSStatusCode.CREATE_TEMPLATE_ERROR); } } @@ -175,9 +178,10 @@ public List