blob: e7038c3ec97396d1049994661a56b5d50e97c834 [file] [log] [blame]
/*
* 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.utils;
import org.apache.iotdb.db.conf.IoTDBConstant;
import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
import org.apache.iotdb.db.exception.metadata.IllegalPathException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.metadata.MetaUtils;
import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.qp.physical.crud.AggregationPlan;
import org.apache.iotdb.db.query.aggregation.AggregateResult;
import org.apache.iotdb.db.query.aggregation.AggregationType;
import org.apache.iotdb.db.query.aggregation.impl.AvgAggrResult;
import org.apache.iotdb.db.query.factory.AggregateResultFactory;
import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.common.RowRecord;
import org.apache.iotdb.tsfile.utils.Pair;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.apache.iotdb.db.conf.IoTDBConstant.FILE_NAME_SEPARATOR;
public class FilePathUtils {
private static final String PATH_SPLIT_STRING = File.separator.equals("\\") ? "\\\\" : "/";
private FilePathUtils() {
// forbidding instantiation
}
/**
* Format file path to end with File.separator
*
* @param filePath origin file path
* @return Regularized Path
*/
public static String regularizePath(String filePath) {
if (filePath.length() > 0 && filePath.charAt(filePath.length() - 1) != File.separatorChar) {
filePath = filePath + File.separatorChar;
}
return filePath;
}
/**
* IMPORTANT, when the path of TsFile changes, the following methods should be changed
* accordingly. The sequence TsFile is located at ${IOTDB_DATA_DIR}/data/sequence/. The unsequence
* TsFile is located at ${IOTDB_DATA_DIR}/data/unsequence/. Where different storage group's TsFile
* is located at <logicalStorageGroupName>/<virtualStorageGroupName>/<timePartitionId>/<fileName>.
* For example, one sequence TsFile may locate at
* /data/data/sequence/root.group_9/0/0/1611199237113-4-0.tsfile
*
* @param resource the tsFileResource
*/
public static String[] splitTsFilePath(TsFileResource resource) {
return resource.getTsFile().getAbsolutePath().split(PATH_SPLIT_STRING);
}
public static String getLogicalStorageGroupName(TsFileResource resource) {
String[] pathSegments = splitTsFilePath(resource);
return pathSegments[pathSegments.length - 4];
}
public static String getVirtualStorageGroupId(TsFileResource resource) {
String[] pathSegments = splitTsFilePath(resource);
return pathSegments[pathSegments.length - 3];
}
public static long getTimePartitionId(TsFileResource resource) {
String[] pathSegments = splitTsFilePath(resource);
return Long.parseLong(pathSegments[pathSegments.length - 2]);
}
/**
* @param resource the RemoteTsFileResource
* @return the file in the snapshot is a hardlink, remove the hardlink suffix
*/
public static String getTsFileNameWithoutHardLink(TsFileResource resource) {
String[] pathSegments = splitTsFilePath(resource);
return pathSegments[pathSegments.length - 1].substring(
0, pathSegments[pathSegments.length - 1].lastIndexOf(TsFileConstant.PATH_SEPARATOR));
}
public static String getTsFilePrefixPath(TsFileResource resource) {
String[] pathSegments = splitTsFilePath(resource);
int pathLength = pathSegments.length;
return pathSegments[pathLength - 4]
+ File.separator
+ pathSegments[pathLength - 3]
+ File.separator
+ pathSegments[pathLength - 2];
}
public static Pair<String, Long> getLogicalSgNameAndTimePartitionIdPair(TsFileResource resource) {
String[] pathSegments = splitTsFilePath(resource);
return new Pair<>(
pathSegments[pathSegments.length - 4],
Long.parseLong(pathSegments[pathSegments.length - 2]));
}
public static String[] splitTsFilePath(String tsFileAbsolutePath) {
return tsFileAbsolutePath.split(PATH_SPLIT_STRING);
}
/**
* Transform an originalPath to a partial path that satisfies given level. Path nodes exceed the
* given level will be replaced by "*", e.g. generatePartialPathByLevel("root.sg.dh.d1.s1", 2)
* will return "root.sg.dh.*.s1"
*
* @param originalPath the original timeseries path
* @param pathLevel the expected path level
* @return result partial path
*/
public static String generatePartialPathByLevel(String originalPath, int pathLevel)
throws IllegalPathException {
String[] tmpPath = MetaUtils.splitPathToDetachedPath(originalPath);
if (tmpPath.length <= pathLevel) {
return originalPath;
}
StringBuilder transformedPath = new StringBuilder();
transformedPath.append(tmpPath[0]);
for (int k = 1; k < tmpPath.length - 1; k++) {
if (k <= pathLevel) {
transformedPath.append(TsFileConstant.PATH_SEPARATOR).append(tmpPath[k]);
} else {
transformedPath.append(TsFileConstant.PATH_SEPARATOR).append(IoTDBConstant.PATH_WILDCARD);
}
}
transformedPath.append(TsFileConstant.PATH_SEPARATOR).append(tmpPath[tmpPath.length - 1]);
return transformedPath.toString();
}
/**
* merge the raw record by level, for example raw record [timestamp, root.sg1.d1.s0,
* root.sg1.d1.s1, root.sg1.d2.s2], level=1 and newRecord data is [100, 1, 1, 1] return [100, 3]
*
* @param newRecord
* @param finalPaths
* @return
*/
public static List<AggregateResult> mergeRecordByPath(
AggregationPlan plan, RowRecord newRecord, Map<String, AggregateResult> finalPaths)
throws QueryProcessException {
if (newRecord.getFields().size() < finalPaths.size()) {
return Collections.emptyList();
}
List<AggregateResult> aggregateResultList = new ArrayList<>();
for (int i = 0; i < newRecord.getFields().size(); i++) {
if (newRecord.getFields().get(i) == null) {
aggregateResultList.add(
AggregateResultFactory.getAggrResultByName(
plan.getDeduplicatedAggregations().get(i), plan.getDeduplicatedDataTypes().get(i)));
} else {
TSDataType dataType = newRecord.getFields().get(i).getDataType();
AggregateResult aggRet =
AggregateResultFactory.getAggrResultByName(
plan.getDeduplicatedAggregations().get(i), dataType);
if (aggRet.getAggregationType().equals(AggregationType.AVG)) {
((AvgAggrResult) aggRet)
.setAvgResult(dataType, newRecord.getFields().get(i).getDoubleV());
} else {
switch (dataType) {
case TEXT:
aggRet.setBinaryValue(newRecord.getFields().get(i).getBinaryV());
break;
case INT32:
aggRet.setIntValue(newRecord.getFields().get(i).getIntV());
break;
case INT64:
aggRet.setLongValue(newRecord.getFields().get(i).getLongV());
break;
case FLOAT:
aggRet.setFloatValue(newRecord.getFields().get(i).getFloatV());
break;
case DOUBLE:
aggRet.setDoubleValue(newRecord.getFields().get(i).getDoubleV());
break;
case BOOLEAN:
aggRet.setBooleanValue(newRecord.getFields().get(i).getBoolV());
break;
default:
throw new UnSupportedDataTypeException(dataType.toString());
}
}
aggregateResultList.add(aggRet);
}
}
return mergeRecordByPath(plan, aggregateResultList, finalPaths);
}
public static List<AggregateResult> mergeRecordByPath(
AggregationPlan plan,
List<AggregateResult> aggResults,
Map<String, AggregateResult> finalPaths)
throws QueryProcessException {
if (aggResults.size() < finalPaths.size()) {
return Collections.emptyList();
}
for (Map.Entry<String, AggregateResult> entry : finalPaths.entrySet()) {
finalPaths.put(entry.getKey(), null);
}
List<AggregateResult> resultSet = new ArrayList<>();
List<PartialPath> dupPaths = plan.getDeduplicatedPaths();
try {
for (int i = 0; i < aggResults.size(); i++) {
if (aggResults.get(i) != null) {
String transformedPath =
generatePartialPathByLevel(dupPaths.get(i).getFullPath(), plan.getLevel());
String key = plan.getDeduplicatedAggregations().get(i) + "(" + transformedPath + ")";
AggregateResult tempAggResult = finalPaths.get(key);
if (tempAggResult == null) {
finalPaths.put(key, aggResults.get(i));
} else {
tempAggResult.merge(aggResults.get(i));
finalPaths.put(key, tempAggResult);
}
}
}
} catch (IllegalPathException e) {
throw new QueryProcessException(e.getMessage());
}
for (Map.Entry<String, AggregateResult> entry : finalPaths.entrySet()) {
resultSet.add(entry.getValue());
}
return resultSet;
}
public static long splitAndGetTsFileVersion(String tsFileName) {
String[] names = tsFileName.split(FILE_NAME_SEPARATOR);
if (names.length != 4) {
return 0;
}
return Long.parseLong(names[1]);
}
}