Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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;

/** An invalid tree path cannot be repaired by converting the TsFile to tablets. */
public class LoadAnalyzeInvalidPathException extends LoadAnalyzeException {

public LoadAnalyzeInvalidPathException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.exception.LoadAnalyzeException;
import org.apache.iotdb.db.exception.LoadAnalyzeInvalidPathException;
import org.apache.iotdb.db.exception.LoadAnalyzeMissingSchemaException;
import org.apache.iotdb.db.exception.LoadAnalyzeTypeMismatchException;
import org.apache.iotdb.db.exception.load.LoadEmptyFileException;
Expand Down Expand Up @@ -111,6 +112,7 @@
import java.util.Set;
import java.util.stream.Collectors;

import static org.apache.iotdb.db.storageengine.load.LoadTsFilePathUtils.getValidatedDevicePath;
import static org.apache.iotdb.db.storageengine.load.metrics.LoadTsFileCostMetricsSet.ANALYSIS;
import static org.apache.iotdb.db.storageengine.load.metrics.LoadTsFileCostMetricsSet.ANALYSIS_ASYNC_MOVE;

Expand Down Expand Up @@ -611,8 +613,9 @@ boolean isTemporaryUnavailableDueToPipeSchemaNotReady(final Throwable throwable)
}

private boolean shouldSkipConversion(LoadAnalyzeException e) {
return (e instanceof LoadAnalyzeTypeMismatchException)
&& !loadTsFileStatement.isConvertOnTypeMismatch();
return e instanceof LoadAnalyzeInvalidPathException
|| (e instanceof LoadAnalyzeTypeMismatchException)
&& !loadTsFileStatement.isConvertOnTypeMismatch();
}

@Override
Expand Down Expand Up @@ -643,6 +646,8 @@ public void autoCreateAndVerify(
device2TimeSeriesMetadataList.entrySet()) {
final IDeviceID device = entry.getKey();

getValidatedDevicePath(device);

try {
if (schemaCache.isDeviceDeletedByMods(device)) {
continue;
Expand Down Expand Up @@ -706,11 +711,13 @@ public void autoCreateAndVerify(

public void checkWritePermission(
Map<IDeviceID, List<TimeseriesMetadata>> device2TimeseriesMetadataList)
throws AuthException {
throws AuthException, LoadAnalyzeInvalidPathException {
for (final Map.Entry<IDeviceID, List<TimeseriesMetadata>> entry :
device2TimeseriesMetadataList.entrySet()) {
final IDeviceID device = entry.getKey();

getValidatedDevicePath(device);

try {
if (schemaCache.isDeviceDeletedByMods(device)) {
continue;
Expand Down Expand Up @@ -813,7 +820,9 @@ private void doAutoCreateAndVerify()
if (isVerifySchema) {
verifySchema(schemaTree);
}
} catch (AuthException | LoadAnalyzeTypeMismatchException e) {
} catch (AuthException
| LoadAnalyzeInvalidPathException
| LoadAnalyzeTypeMismatchException e) {
throw e;
} catch (LoadAnalyzeMissingSchemaException e) {
if (isTemporaryUnavailableDueToPipeSchemaNotReady(e)) {
Expand Down Expand Up @@ -858,18 +867,9 @@ private void autoCreateDatabase()
final Set<PartialPath> databasesNeededToBeSet = new HashSet<>();

for (final IDeviceID device : schemaCache.getDevice2TimeSeries().keySet()) {
final PartialPath devicePath;
try {
devicePath = new PartialPath(device);
} catch (final IllegalPathException e) {
throw new LoadAnalyzeException(e.getMessage());
}
final PartialPath devicePath = getValidatedDevicePath(device);

final String[] devicePrefixNodes = devicePath.getNodes();
if (hasEmptyPathNode(devicePath)) {
throw new LoadAnalyzeException(
new IllegalPathException(devicePath.getFullPath()).getMessage());
}
if (devicePrefixNodes.length < databasePrefixNodesLength) {
throw new LoadAnalyzeException(
String.format(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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.storageengine.load;

import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.exception.LoadAnalyzeInvalidPathException;

import org.apache.tsfile.file.metadata.IDeviceID;

public class LoadTsFilePathUtils {

private LoadTsFilePathUtils() {}

public static PartialPath getValidatedDevicePath(final IDeviceID device)
throws LoadAnalyzeInvalidPathException {
try {
final PartialPath devicePath = new PartialPath(device);
// Validate the original nodes before converting to a string, which loses null nodes.
for (final String node : devicePath.getNodes()) {
if (node == null || node.isEmpty()) {
throw new IllegalPathException(devicePath.getFullPath());
}
}
return devicePath;
} catch (final IllegalPathException e) {
throw new LoadAnalyzeInvalidPathException(e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@

package org.apache.iotdb.db.storageengine.load.converter;

import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.exception.pipe.PipeRuntimeOutOfMemoryCriticalException;
import org.apache.iotdb.commons.pipe.datastructure.pattern.IoTDBPipePattern;
import org.apache.iotdb.commons.pipe.datastructure.pattern.PipePattern;
import org.apache.iotdb.db.exception.LoadAnalyzeInvalidPathException;
import org.apache.iotdb.db.exception.load.LoadRuntimeOutOfMemoryException;
import org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent;
import org.apache.iotdb.db.pipe.event.common.tsfile.container.query.TsFileInsertionQueryDataContainer;
import org.apache.iotdb.db.pipe.event.common.tsfile.container.scan.TsFileInsertionScanDataContainer;
import org.apache.iotdb.db.storageengine.load.memory.LoadTsFileParserMemoryManager;
import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent;

import org.apache.tsfile.exception.PathParseException;
import org.apache.tsfile.file.metadata.IDeviceID;
import org.apache.tsfile.file.metadata.PlainDeviceID;
import org.apache.tsfile.file.metadata.TimeseriesMetadata;
Expand All @@ -54,6 +57,8 @@
import java.util.Set;
import java.util.stream.Collectors;

import static org.apache.iotdb.db.storageengine.load.LoadTsFilePathUtils.getValidatedDevicePath;

/**
* Load uses scan parsing first for throughput. If scan parsing hits corruption, fall back to query
* parsing for the remaining measurements and devices so later data can still be loaded.
Expand All @@ -63,7 +68,18 @@ class LoadTreeTsFileTabletIterator

private static final Logger LOGGER = LoggerFactory.getLogger(LoadTreeTsFileTabletIterator.class);

private static final PipePattern LOAD_TREE_PATTERN = new IoTDBPipePattern(null);
private static final PipePattern LOAD_TREE_PATTERN =
new IoTDBPipePattern(null) {
@Override
public boolean mayOverlapWithDevice(final String device) {
try {
getValidatedDevicePath(new PlainDeviceID(device));
} catch (final LoadAnalyzeInvalidPathException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
return super.mayOverlapWithDevice(device);
}
};

private final File file;
private final boolean isWithMod;
Expand Down Expand Up @@ -333,6 +349,7 @@ private boolean activateNextQueryParser() {
while (!pendingQueryTasks.isEmpty()) {
activeQueryTask = pendingQueryTasks.removeFirst();
try {
getValidatedDevicePath(activeQueryTask.device);
activeQueryParser =
new TsFileInsertionQueryDataContainer(
file,
Expand Down Expand Up @@ -412,6 +429,10 @@ private boolean shouldRethrow(final Exception e) {
Throwable current = e;
while (Objects.nonNull(current)) {
if (current instanceof InterruptedException
// Invalid paths cannot be recovered by query parsing or splitting measurements.
|| current instanceof PathParseException
|| current instanceof IllegalPathException
|| current instanceof LoadAnalyzeInvalidPathException
|| current instanceof PipeRuntimeOutOfMemoryCriticalException
|| current instanceof LoadRuntimeOutOfMemoryException) {
return true;
Expand All @@ -422,6 +443,9 @@ private boolean shouldRethrow(final Exception e) {
}

private RuntimeException toRuntimeException(final Exception e) {
if (e instanceof LoadAnalyzeInvalidPathException) {
return new IllegalArgumentException(e.getMessage(), e);
}
return e instanceof RuntimeException
? (RuntimeException) e
: new IllegalStateException("Failed to iterate tablets while loading TsFile.", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.exception.LoadAnalyzeException;
import org.apache.iotdb.db.exception.LoadAnalyzeInvalidPathException;
import org.apache.iotdb.db.exception.LoadAnalyzeMissingSchemaException;
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
import org.apache.iotdb.db.queryengine.common.QueryId;
Expand Down Expand Up @@ -65,7 +65,7 @@ public void testSchemaVerifierShouldRejectDeviceWithEmptyPathNode() throws Excep
() -> getAutoCreateDatabaseMethod(verifier).invoke(verifier));
Assert.assertTrue(
String.valueOf(exception.getCause()),
exception.getCause() instanceof LoadAnalyzeException);
exception.getCause() instanceof LoadAnalyzeInvalidPathException);
} finally {
Assert.assertTrue(tsFile.delete());
}
Expand Down Expand Up @@ -97,6 +97,13 @@ public void testSchemaVerifierShouldIgnoreLegacyDatabaseWithEmptyPathNode() thro
Collections.singleton(databaseWithSameStringPrefix), databasesNeededToBeSet);
Assert.assertEquals(
Collections.singleton(database), getAlreadySetDatabases(getSchemaCache(verifier)));

addTimeSeries(
getSchemaCache(verifier),
new PlainDeviceID("root.sg.d1"),
new MeasurementSchema("s1", TSDataType.INT32));
// A valid device still uses its existing database despite the legacy root. entry.
getAutoCreateDatabaseMethod(verifier).invoke(verifier);
} finally {
Assert.assertTrue(tsFile.delete());
}
Expand Down
Loading
Loading