Skip to content

Commit 2806466

Browse files
authored
[To dev/1.3] Improve schema metadata error messages and recovery logs (#18937) (#18975)
1 parent 1107fe6 commit 2806466

9 files changed

Lines changed: 349 additions & 33 deletions

File tree

‎integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSimpleQueryIT.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public void testFailedToCreateTimeseriesSDTProperties() {
9999
} catch (Exception e) {
100100
assertEquals(
101101
TSStatusCode.ILLEGAL_PARAMETER.getStatusCode()
102-
+ ": SDT compression deviation cannot be negative. Failed to create timeseries for path root.sg1.d0.s1",
102+
+ ": SDT property compdev must be non-negative, but was [-2]. Failed to create timeseries for path root.sg1.d0.s1",
103103
e.getMessage());
104104
}
105105

‎iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,30 @@ private DataNodeSchemaMessages() {}
2626
public static final String
2727
EXCEPTION_CANNOT_RECOVER_DUPLICATED_SCHEMAREGION_ARG_FOUND_IN_DATABASES_ARG_AND_ARG_D9F60E05 =
2828
"Cannot recover duplicated SchemaRegion [%s] found in databases [%s] and [%s].";
29+
30+
public static final String FAILED_TO_RECOVER_TAG_INDEX =
31+
"Failed to recover tag index for measurement [{}] in database [{}], SchemaRegion [{}], tag offset [{}].";
32+
public static final String SCHEMA_REGION_FAILED_TO_RECOVER =
33+
"SchemaRegion [%d] in StorageGroup [%s] failed to recover.";
34+
public static final String SDT_COMPRESSION_DEVIATION_REQUIRED =
35+
"SDT compression requires the compdev property";
36+
public static final String SDT_COMPRESSION_DEVIATION_NEGATIVE =
37+
"SDT property compdev must be non-negative, but was [%s]";
38+
public static final String SDT_COMPRESSION_DEVIATION_FORMAT_ERROR =
39+
"SDT property compdev must be a number, but was [%s]";
40+
public static final String SDT_COMPRESSION_MAX_GREATER_THAN_MIN =
41+
"SDT property compmaxtime [%s] must be greater than compmintime [%s]";
42+
public static final String SDT_COMPRESSION_TIME_NEGATIVE =
43+
"SDT property %s must be non-negative, but was [%s]";
44+
public static final String SDT_COMPRESSION_TIME_FORMAT_ERROR =
45+
"SDT property %s must be a 64-bit integer, but was [%s]";
46+
public static final String SDT_ENABLED_NO_COMPRESSION_TIME =
47+
"Timeseries [{}] uses SDT without property [{}]; using default [{}].";
48+
public static final String CREATE_TEMPLATE_ERROR =
49+
"Failed to create schema template [%s] on ConfigNode: %s";
50+
public static final String GET_ALL_TEMPLATE_ERROR =
51+
"Failed to get schema templates from ConfigNode: %s";
52+
public static final String GET_TEMPLATE_INFO_ERROR =
53+
"Failed to get schema template [%s] from ConfigNode: %s";
54+
public static final String ILLEGAL_PATH_LOG = "illegal path {}";
2955
}

‎iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeSchemaMessages.java‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,23 @@ private DataNodeSchemaMessages() {}
2626
public static final String
2727
EXCEPTION_CANNOT_RECOVER_DUPLICATED_SCHEMAREGION_ARG_FOUND_IN_DATABASES_ARG_AND_ARG_D9F60E05 =
2828
"无法恢复重复的 SchemaRegion [%s],其同时存在于数据库 [%s] 和 [%s] 中。";
29+
30+
public static final String FAILED_TO_RECOVER_TAG_INDEX =
31+
"恢复测点 [{}] 的 tag 索引失败,数据库为 [{}],SchemaRegion 为 [{}],tag 偏移量为 [{}]。";
32+
public static final String SCHEMA_REGION_FAILED_TO_RECOVER =
33+
"SchemaRegion [%d] 在 StorageGroup [%s] 中恢复失败。";
34+
public static final String SDT_COMPRESSION_DEVIATION_REQUIRED = "SDT 压缩必须设置 compdev 属性";
35+
public static final String SDT_COMPRESSION_DEVIATION_NEGATIVE = "SDT 属性 compdev 必须为非负数,实际值为 [%s]";
36+
public static final String SDT_COMPRESSION_DEVIATION_FORMAT_ERROR =
37+
"SDT 属性 compdev 必须为数字,实际值为 [%s]";
38+
public static final String SDT_COMPRESSION_MAX_GREATER_THAN_MIN =
39+
"SDT 属性 compmaxtime [%s] 必须大于 compmintime [%s]";
40+
public static final String SDT_COMPRESSION_TIME_NEGATIVE = "SDT 属性 %s 必须为非负数,实际值为 [%s]";
41+
public static final String SDT_COMPRESSION_TIME_FORMAT_ERROR = "SDT 属性 %s 必须为 64 位整数,实际值为 [%s]";
42+
public static final String SDT_ENABLED_NO_COMPRESSION_TIME =
43+
"时间序列 [{}] 已启用 SDT 但未设置属性 [{}],使用默认值 [{}]。";
44+
public static final String CREATE_TEMPLATE_ERROR = "在 ConfigNode 上创建元数据模板 [%s] 失败:%s";
45+
public static final String GET_ALL_TEMPLATE_ERROR = "从 ConfigNode 获取元数据模板列表失败:%s";
46+
public static final String GET_TEMPLATE_INFO_ERROR = "从 ConfigNode 获取元数据模板 [%s] 失败:%s";
47+
public static final String ILLEGAL_PATH_LOG = "非法路径 {}";
2948
}

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,11 +342,12 @@ private Callable<ISchemaRegion> recoverSchemaRegionTask(
342342
timeRecord);
343343
return schemaRegion;
344344
} catch (MetadataException e) {
345-
logger.error(
345+
throw new RuntimeException(
346346
String.format(
347-
"SchemaRegion [%d] in StorageGroup [%s] failed to recover.",
348-
schemaRegionId.getId(), storageGroup.getFullPath()));
349-
throw new RuntimeException(e);
347+
DataNodeSchemaMessages.SCHEMA_REGION_FAILED_TO_RECOVER,
348+
schemaRegionId.getId(),
349+
storageGroup.getFullPath()),
350+
e);
350351
}
351352
};
352353
}

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.apache.iotdb.db.exception.metadata.SchemaDirCreationFailureException;
3838
import org.apache.iotdb.db.exception.metadata.SchemaQuotaExceededException;
3939
import org.apache.iotdb.db.exception.metadata.SeriesOverflowException;
40+
import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
4041
import org.apache.iotdb.db.queryengine.common.schematree.ClusterSchemaTree;
4142
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.write.CreateTimeSeriesNode;
4243
import org.apache.iotdb.db.schemaengine.metric.ISchemaRegionMetric;
@@ -109,8 +110,6 @@
109110
import java.util.Set;
110111
import java.util.concurrent.atomic.AtomicBoolean;
111112

112-
import static org.apache.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR;
113-
114113
/**
115114
* This class takes the responsibility of serialization of all the metadata info of one certain
116115
* schema region and persistent it into files. This class contains the interfaces to modify the
@@ -508,9 +507,12 @@ public void loadSnapshot(File latestSnapshotRootDir) {
508507
tagManager.recoverIndex(measurementMNode.getOffset(), measurementMNode);
509508
} catch (IOException e) {
510509
logger.error(
511-
"Failed to recover tagIndex for {} in schemaRegion {}.",
512-
storageGroupFullPath + PATH_SEPARATOR + measurementMNode.getFullPath(),
513-
schemaRegionId);
510+
DataNodeSchemaMessages.FAILED_TO_RECOVER_TAG_INDEX,
511+
measurementMNode.getName(),
512+
storageGroupFullPath,
513+
schemaRegionId,
514+
measurementMNode.getOffset(),
515+
e);
514516
}
515517
},
516518
deviceMNode -> {

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/utils/MetaFormatUtils.java‎

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.iotdb.db.conf.IoTDBConfig;
2525
import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
2626
import org.apache.iotdb.db.exception.metadata.IllegalParameterOfPathException;
27+
import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
2728

2829
import org.slf4j.Logger;
2930
import org.slf4j.LoggerFactory;
@@ -145,25 +146,36 @@ public static void checkTimeseriesProps(String path, Map<String, String> props)
145146
private static void checkSDTFormat(String path, Map<String, String> props)
146147
throws IllegalParameterOfPathException {
147148
if (!props.containsKey(SDT_COMP_DEV)) {
148-
throw new IllegalParameterOfPathException("SDT compression deviation is required", path);
149+
throw new IllegalParameterOfPathException(
150+
DataNodeSchemaMessages.SDT_COMPRESSION_DEVIATION_REQUIRED, path);
149151
}
150152

151153
try {
152154
double d = Double.parseDouble(props.get(SDT_COMP_DEV));
153155
if (d < 0) {
154156
throw new IllegalParameterOfPathException(
155-
"SDT compression deviation cannot be negative", path);
157+
String.format(
158+
DataNodeSchemaMessages.SDT_COMPRESSION_DEVIATION_NEGATIVE, props.get(SDT_COMP_DEV)),
159+
path);
156160
}
157161
} catch (NumberFormatException e) {
158-
throw new IllegalParameterOfPathException("SDT compression deviation formatting error", path);
162+
throw new IllegalParameterOfPathException(
163+
String.format(
164+
DataNodeSchemaMessages.SDT_COMPRESSION_DEVIATION_FORMAT_ERROR,
165+
props.get(SDT_COMP_DEV)),
166+
path);
159167
}
160168

161169
long compMinTime = sdtCompressionTimeFormat(SDT_COMP_MIN_TIME, props, path);
162170
long compMaxTime = sdtCompressionTimeFormat(SDT_COMP_MAX_TIME, props, path);
163171

164172
if (compMaxTime <= compMinTime) {
165173
throw new IllegalParameterOfPathException(
166-
"SDT compression maximum time needs to be greater than compression minimum time", path);
174+
String.format(
175+
DataNodeSchemaMessages.SDT_COMPRESSION_MAX_GREATER_THAN_MIN,
176+
compMaxTime,
177+
compMinTime),
178+
path);
167179
}
168180
}
169181

@@ -172,20 +184,23 @@ private static long sdtCompressionTimeFormat(
172184
throws IllegalParameterOfPathException {
173185
boolean isCompMaxTime = compTime.equals(SDT_COMP_MAX_TIME);
174186
long time = isCompMaxTime ? Long.MAX_VALUE : 0;
175-
String s = isCompMaxTime ? "maximum" : "minimum";
176187
if (props.containsKey(compTime)) {
188+
String value = props.get(compTime);
177189
try {
178-
time = Long.parseLong(props.get(compTime));
179-
if (time < 0) {
180-
throw new IllegalParameterOfPathException(
181-
String.format("SDT compression %s time cannot be negative", s), path);
182-
}
183-
} catch (IllegalParameterOfPathException e) {
190+
time = Long.parseLong(value);
191+
} catch (NumberFormatException e) {
192+
throw new IllegalParameterOfPathException(
193+
String.format(
194+
DataNodeSchemaMessages.SDT_COMPRESSION_TIME_FORMAT_ERROR, compTime, value),
195+
path);
196+
}
197+
if (time < 0) {
184198
throw new IllegalParameterOfPathException(
185-
String.format("SDT compression %s time formatting error", s), path);
199+
String.format(DataNodeSchemaMessages.SDT_COMPRESSION_TIME_NEGATIVE, compTime, value),
200+
path);
186201
}
187202
} else {
188-
logger.info("{} enabled SDT but did not set compression {} time", path, s);
203+
logger.debug(DataNodeSchemaMessages.SDT_ENABLED_NO_COMPRESSION_TIME, path, compTime, time);
189204
}
190205
return time;
191206
}

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/template/ClusterTemplateManager.java‎

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.apache.iotdb.confignode.rpc.thrift.TGetPathsSetTemplatesResp;
3939
import org.apache.iotdb.confignode.rpc.thrift.TGetTemplateResp;
4040
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaTemplateReq;
41+
import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
4142
import org.apache.iotdb.db.protocol.client.ConfigNodeClient;
4243
import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
4344
import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
@@ -130,9 +131,11 @@ public TSStatus createSchemaTemplate(CreateSchemaTemplateStatement statement) {
130131
e,
131132
TSStatusCode.CREATE_TEMPLATE_ERROR.getStatusCode()));
132133
} catch (ClientManagerException | TException e) {
133-
throw new RuntimeException(
134-
new IoTDBException(
135-
"create template error.", e, TSStatusCode.CREATE_TEMPLATE_ERROR.getStatusCode()));
134+
throw wrapTemplateRpcException(
135+
String.format(
136+
DataNodeSchemaMessages.CREATE_TEMPLATE_ERROR, statement.getName(), e.getMessage()),
137+
e,
138+
TSStatusCode.CREATE_TEMPLATE_ERROR);
136139
}
137140
}
138141

@@ -175,9 +178,10 @@ public List<Template> getAllTemplates() {
175178
throw new IoTDBRuntimeException(resp.getStatus());
176179
}
177180
} catch (ClientManagerException | TException e) {
178-
throw new RuntimeException(
179-
new IoTDBException(
180-
"get all template error.", TSStatusCode.UNDEFINED_TEMPLATE.getStatusCode()));
181+
throw wrapTemplateRpcException(
182+
String.format(DataNodeSchemaMessages.GET_ALL_TEMPLATE_ERROR, e.getMessage()),
183+
e,
184+
TSStatusCode.UNDEFINED_TEMPLATE);
181185
}
182186
return templatesList;
183187
}
@@ -196,12 +200,20 @@ public Template getTemplate(String name) throws IoTDBException {
196200
throw new IoTDBException(resp.status);
197201
}
198202
} catch (ClientManagerException | TException e) {
199-
throw new RuntimeException(
200-
new IoTDBException(
201-
"get template info error.", TSStatusCode.UNDEFINED_TEMPLATE.getStatusCode()));
203+
throw wrapTemplateRpcException(
204+
String.format(DataNodeSchemaMessages.GET_TEMPLATE_INFO_ERROR, name, e.getMessage()),
205+
e,
206+
TSStatusCode.UNDEFINED_TEMPLATE);
202207
}
203208
}
204209

210+
private static RuntimeException wrapTemplateRpcException(
211+
String message, Exception cause, TSStatusCode statusCode) {
212+
IoTDBException exception = new IoTDBException(message, statusCode.getStatusCode());
213+
exception.addSuppressed(cause);
214+
return new RuntimeException(exception);
215+
}
216+
205217
@Override
206218
public void setSchemaTemplate(String queryId, String name, PartialPath path) {
207219
try (ConfigNodeClient configNodeClient =
@@ -256,7 +268,7 @@ public List<PartialPath> getPathsSetTemplate(String name, PathPatternTree scope)
256268
try {
257269
listPath.add(new PartialPath(item));
258270
} catch (IllegalPathException e) {
259-
e.printStackTrace();
271+
LOGGER.error(DataNodeSchemaMessages.ILLEGAL_PATH_LOG, item, e);
260272
}
261273
});
262274
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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 "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.iotdb.db.metadata;
20+
21+
import org.apache.iotdb.db.exception.metadata.IllegalParameterOfPathException;
22+
import org.apache.iotdb.db.schemaengine.schemaregion.utils.MetaFormatUtils;
23+
import org.apache.iotdb.rpc.TSStatusCode;
24+
25+
import org.junit.Test;
26+
27+
import java.util.HashMap;
28+
import java.util.Map;
29+
30+
import static org.junit.Assert.assertEquals;
31+
import static org.junit.Assert.assertThrows;
32+
import static org.junit.Assert.assertTrue;
33+
34+
public class MetaFormatUtilsTest {
35+
36+
private static final String PATH = "root.sg.d.s";
37+
38+
@Test
39+
public void testNonNumericSdtProperties() {
40+
for (String property : new String[] {"compdev", "compmintime", "compmaxtime"}) {
41+
assertInvalidProperty(property, "invalid");
42+
}
43+
}
44+
45+
@Test
46+
public void testNegativeSdtProperties() {
47+
for (String property : new String[] {"compdev", "compmintime", "compmaxtime"}) {
48+
assertInvalidProperty(property, "-1");
49+
}
50+
}
51+
52+
@Test
53+
public void testSdtTimeOverflow() {
54+
for (String property : new String[] {"compmintime", "compmaxtime"}) {
55+
assertInvalidProperty(property, "9223372036854775808");
56+
assertInvalidProperty(property, "-9223372036854775809");
57+
}
58+
}
59+
60+
@Test
61+
public void testInvalidSdtTimeRange() {
62+
Map<String, String> props = sdtProps();
63+
props.put("compmintime", "20");
64+
props.put("compmaxtime", "10");
65+
IllegalParameterOfPathException exception =
66+
assertThrows(
67+
IllegalParameterOfPathException.class,
68+
() -> MetaFormatUtils.checkTimeseriesProps(PATH, props));
69+
70+
assertUserParameterError(exception);
71+
assertTrue(exception.getMessage().contains("compmintime [20]"));
72+
assertTrue(exception.getMessage().contains("compmaxtime [10]"));
73+
}
74+
75+
@Test
76+
public void testValidSdtTimeBoundsAndDefaults() throws IllegalParameterOfPathException {
77+
Map<String, String> props = sdtProps();
78+
MetaFormatUtils.checkTimeseriesProps(PATH, props);
79+
props.put("compmintime", "0");
80+
MetaFormatUtils.checkTimeseriesProps(PATH, props);
81+
props.put("compmaxtime", Long.toString(Long.MAX_VALUE));
82+
MetaFormatUtils.checkTimeseriesProps(PATH, props);
83+
}
84+
85+
private static void assertInvalidProperty(String property, String value) {
86+
Map<String, String> props = sdtProps();
87+
props.put(property, value);
88+
IllegalParameterOfPathException exception =
89+
assertThrows(
90+
IllegalParameterOfPathException.class,
91+
() -> MetaFormatUtils.checkTimeseriesProps(PATH, props));
92+
93+
assertUserParameterError(exception);
94+
assertTrue(exception.getMessage().contains(property));
95+
assertTrue(exception.getMessage().contains("[" + value + "]"));
96+
}
97+
98+
private static void assertUserParameterError(IllegalParameterOfPathException exception) {
99+
assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), exception.getErrorCode());
100+
assertTrue(exception.isUserException());
101+
assertTrue(exception.getMessage().contains(PATH));
102+
}
103+
104+
private static Map<String, String> sdtProps() {
105+
Map<String, String> props = new HashMap<>();
106+
props.put("loss", "sdt");
107+
props.put("compdev", "0.01");
108+
return props;
109+
}
110+
}

0 commit comments

Comments
 (0)