blob: c9730feab9eee82926564a89e30fdb1cc22ffde1 [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.metadata;
import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.exception.MetadataException;
import org.apache.iotdb.commons.path.MeasurementPath;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.exception.metadata.PathNotExistException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.metadata.mnode.IMNode;
import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
import org.apache.iotdb.db.metadata.template.Template;
import org.apache.iotdb.db.qp.executor.PlanExecutor;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
import org.apache.iotdb.db.service.IoTDB;
import org.apache.iotdb.db.utils.EnvironmentUtils;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class TemplateTest {
@Before
public void setUp() {
EnvironmentUtils.envSetUp();
}
@After
public void tearDown() throws Exception {
EnvironmentUtils.cleanEnv();
}
@Test
public void testTemplate() throws MetadataException {
CreateTemplatePlan plan = getCreateTemplatePlan();
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
schemaProcessor.createSchemaTemplate(plan);
// set device template
SetTemplatePlan setTemplatePlan = new SetTemplatePlan("template1", "root.sg1.d1");
schemaProcessor.setSchemaTemplate(setTemplatePlan);
schemaProcessor.setUsingSchemaTemplate(
new ActivateTemplatePlan(new PartialPath("root.sg1.d1")));
IMNode node = schemaProcessor.getDeviceNode(new PartialPath("root.sg1.d1"));
MeasurementSchema s11 =
new MeasurementSchema("s11", TSDataType.INT64, TSEncoding.RLE, CompressionType.SNAPPY);
assertNotNull(node.getSchemaTemplate());
Set<IMeasurementSchema> allSchema =
new HashSet<>(node.getSchemaTemplate().getSchemaMap().values());
schemaProcessor.getAllMeasurementByDevicePath(new PartialPath("root.sg1.d1")).stream()
.map(MeasurementPath::getMeasurementSchema)
.forEach(allSchema::remove);
assertTrue(allSchema.isEmpty());
IMeasurementMNode mNode =
schemaProcessor.getMeasurementMNode(new PartialPath("root.sg1.d1.s11"));
IMeasurementMNode mNode2 =
schemaProcessor.getMeasurementMNode(new PartialPath("root.sg1.d1.vector.s2"));
assertNotNull(mNode);
assertEquals(mNode.getSchema(), s11);
assertNotNull(mNode2);
assertEquals(
mNode2.getSchema(),
schemaProcessor.getTemplate("template1").getSchemaMap().get("vector.s2"));
try {
schemaProcessor.getMeasurementMNode(new PartialPath("root.sg1.d1.s100"));
fail();
} catch (PathNotExistException e) {
assertEquals("Path [root.sg1.d1.s100] does not exist", e.getMessage());
}
}
@Test
public void testTemplateInnerTree() {
CreateTemplatePlan plan = getTreeTemplatePlan();
Template template;
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
try {
schemaProcessor.createSchemaTemplate(plan);
template = schemaProcessor.getTemplate("treeTemplate");
assertEquals(4, template.getMeasurementsCount());
assertEquals("d1", template.getPathNodeInTemplate("d1").getName());
assertEquals(null, template.getPathNodeInTemplate("notExists"));
assertEquals("[GPS]", template.getAllAlignedPrefix().toString());
String[] alignedMeasurements = {"to.be.prefix.s1", "to.be.prefix.s2"};
TSDataType[] dataTypes = {TSDataType.INT32, TSDataType.INT32};
TSEncoding[] encodings = {TSEncoding.RLE, TSEncoding.RLE};
CompressionType[] compressionTypes = {CompressionType.SNAPPY, CompressionType.SNAPPY};
template.addAlignedMeasurements(alignedMeasurements, dataTypes, encodings, compressionTypes);
assertEquals("[to.be.prefix, GPS]", template.getAllAlignedPrefix().toString());
assertEquals("[s1, s2]", template.getAlignedMeasurements("to.be.prefix").toString());
template.deleteAlignedPrefix("to.be.prefix");
assertEquals("[GPS]", template.getAllAlignedPrefix().toString());
assertEquals(null, template.getDirectNode("prefix"));
assertEquals("to", template.getDirectNode("to").getName());
try {
template.deleteMeasurements("a.single");
fail();
} catch (MetadataException e) {
assertEquals("Path [a.single] does not exist", e.getMessage());
}
assertEquals(
"[d1.s1, GPS.x, to.be.prefix.s2, GPS.y, to.be.prefix.s1, s2]",
template.getAllMeasurementsPaths().toString());
template.deleteSeriesCascade("to");
assertEquals("[d1.s1, GPS.x, GPS.y, s2]", template.getAllMeasurementsPaths().toString());
} catch (MetadataException e) {
e.printStackTrace();
}
}
@Test
public void testCreateSchemaTemplateSerialization() throws IOException {
CreateTemplatePlan plan = getTreeTemplatePlan();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
plan.serialize(dos);
byte[] byteArray = baos.toByteArray();
ByteBuffer buffer = ByteBuffer.wrap(byteArray);
assertEquals(PhysicalPlan.PhysicalPlanType.CREATE_TEMPLATE.ordinal(), buffer.get());
CreateTemplatePlan deserializedPlan = new CreateTemplatePlan();
deserializedPlan.deserialize(buffer);
assertEquals(
plan.getCompressors().get(0).get(0), deserializedPlan.getCompressors().get(0).get(0));
assertEquals(plan.getMeasurements().size(), deserializedPlan.getMeasurements().size());
assertEquals(plan.getName(), deserializedPlan.getName());
}
private CreateTemplatePlan getTreeTemplatePlan() {
/**
* Construct a template like: create schema template treeTemplate ( (d1.s1 INT32 GORILLA
* SNAPPY), (s2 INT32 GORILLA SNAPPY), (GPS.x FLOAT RLE SNAPPY), (GPS.y FLOAT RLE SNAPPY), )with
* aligned (GPS)
*/
List<List<String>> measurementList = new ArrayList<>();
measurementList.add(Collections.singletonList("d1.s1"));
measurementList.add(Collections.singletonList("s2"));
measurementList.add(Arrays.asList("GPS.x", "GPS.y"));
List<List<TSDataType>> dataTypeList = new ArrayList<>();
dataTypeList.add(Collections.singletonList(TSDataType.INT64));
dataTypeList.add(Collections.singletonList(TSDataType.INT64));
dataTypeList.add(Arrays.asList(TSDataType.FLOAT, TSDataType.FLOAT));
List<List<TSEncoding>> encodingList = new ArrayList<>();
encodingList.add(Collections.singletonList(TSEncoding.GORILLA));
encodingList.add(Collections.singletonList(TSEncoding.GORILLA));
encodingList.add(Arrays.asList(TSEncoding.RLE, TSEncoding.RLE));
List<List<CompressionType>> compressionTypes = new ArrayList<>();
compressionTypes.add(Collections.singletonList(CompressionType.UNCOMPRESSED));
compressionTypes.add(Collections.singletonList(CompressionType.SNAPPY));
compressionTypes.add(Arrays.asList(CompressionType.SNAPPY, CompressionType.SNAPPY));
return new CreateTemplatePlan(
"treeTemplate", measurementList, dataTypeList, encodingList, compressionTypes);
}
private CreateTemplatePlan getCreateTemplatePlan() {
List<List<String>> measurementList = new ArrayList<>();
measurementList.add(Collections.singletonList("s11"));
List<String> measurements = new ArrayList<>();
for (int i = 0; i < 10; i++) {
measurements.add("vector.s" + i);
}
measurementList.add(measurements);
List<List<TSDataType>> dataTypeList = new ArrayList<>();
dataTypeList.add(Collections.singletonList(TSDataType.INT64));
List<TSDataType> dataTypes = new ArrayList<>();
for (int i = 0; i < 10; i++) {
dataTypes.add(TSDataType.INT64);
}
dataTypeList.add(dataTypes);
List<List<TSEncoding>> encodingList = new ArrayList<>();
encodingList.add(Collections.singletonList(TSEncoding.RLE));
List<TSEncoding> encodings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
encodings.add(TSEncoding.RLE);
}
encodingList.add(encodings);
List<List<CompressionType>> compressionTypes = new ArrayList<>();
List<CompressionType> compressorList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
compressorList.add(CompressionType.SNAPPY);
}
compressionTypes.add(Collections.singletonList(CompressionType.SNAPPY));
compressionTypes.add(compressorList);
List<String> schemaNames = new ArrayList<>();
schemaNames.add("s21");
schemaNames.add("vector");
return new CreateTemplatePlan(
"template1", schemaNames, measurementList, dataTypeList, encodingList, compressionTypes);
}
private CreateTemplatePlan getDirectAlignedTemplate() {
List<List<String>> measurementList = new ArrayList<>();
List<String> measurements = new ArrayList<>();
for (int i = 0; i < 10; i++) {
measurements.add("vs" + i);
}
measurementList.add(measurements);
List<List<TSDataType>> dataTypeList = new ArrayList<>();
List<TSDataType> dataTypes = new ArrayList<>();
for (int i = 0; i < 10; i++) {
dataTypes.add(TSDataType.INT64);
}
dataTypeList.add(dataTypes);
List<List<TSEncoding>> encodingList = new ArrayList<>();
List<TSEncoding> encodings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
encodings.add(TSEncoding.RLE);
}
encodingList.add(encodings);
List<List<CompressionType>> compressionTypes = new ArrayList<>();
List<CompressionType> compressorList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
compressorList.add(CompressionType.SNAPPY);
}
compressionTypes.add(compressorList);
List<String> schemaNames = new ArrayList<>();
schemaNames.add("vector");
return new CreateTemplatePlan(
"templateDA", schemaNames, measurementList, dataTypeList, encodingList, compressionTypes);
}
/**
* Test for show templates, including all templates, paths set or using designated template
*
* @throws MetadataException
*/
@Test
public void testShowTemplates() throws MetadataException, QueryProcessException {
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
assertEquals(0, schemaProcessor.getAllTemplates().size());
CreateTemplatePlan plan1 = getTreeTemplatePlan();
CreateTemplatePlan plan2 = getCreateTemplatePlan();
schemaProcessor.createSchemaTemplate(plan1);
schemaProcessor.createSchemaTemplate(plan2);
assertEquals("[template1, treeTemplate]", schemaProcessor.getAllTemplates().toString());
for (int i = 0; i < 3; i++) {
SetTemplatePlan setTemplatePlan =
new SetTemplatePlan("template1", String.format("root.sg%d.d%d", i, i + 1));
schemaProcessor.setSchemaTemplate(setTemplatePlan);
}
assertEquals(
new HashSet<>(Arrays.asList("root.sg1.d2", "root.sg0.d1", "root.sg2.d3")),
schemaProcessor.getPathsSetTemplate("*"));
assertEquals(
new HashSet<>(Arrays.asList()), schemaProcessor.getPathsSetTemplate("treeTemplate"));
for (int i = 0; i < 3; i++) {
SetTemplatePlan setTemplatePlan =
new SetTemplatePlan("treeTemplate", String.format("root.tsg%d.d%d", i + 9, i + 10));
schemaProcessor.setSchemaTemplate(setTemplatePlan);
}
assertEquals(
new HashSet<>(Arrays.asList("root.tsg10.d11", "root.tsg11.d12", "root.tsg9.d10")),
schemaProcessor.getPathsSetTemplate("treeTemplate"));
assertEquals(
new HashSet<>(
Arrays.asList(
"root.tsg10.d11",
"root.tsg11.d12",
"root.tsg9.d10",
"root.sg1.d2",
"root.sg0.d1",
"root.sg2.d3")),
schemaProcessor.getPathsSetTemplate("*"));
PlanExecutor exe1 = new PlanExecutor();
exe1.insert(getInsertRowPlan("root.sg0.d1", "s11"));
exe1.insert(getInsertRowPlan("root.sg1.d2", "s11"));
exe1.insert(getInsertRowPlan("root.tsg10.d11.d1", "s1"));
assertEquals(
new HashSet<>(Arrays.asList("root.tsg10.d11", "root.sg1.d2", "root.sg0.d1")),
schemaProcessor.getPathsUsingTemplate("*"));
try {
schemaProcessor.createSchemaTemplate(plan1);
fail();
} catch (MetadataException e) {
assertEquals("Duplicated template name: treeTemplate", e.getMessage());
}
try {
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("treeTemplate"));
fail();
} catch (MetadataException e) {
assertEquals(
"Template [treeTemplate] has been set on MTree, cannot be dropped now.", e.getMessage());
}
}
@Test
public void testShowAllSchemas() throws MetadataException {
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
CreateTemplatePlan plan1 = getTreeTemplatePlan();
CreateTemplatePlan plan2 = getCreateTemplatePlan();
schemaProcessor.createSchemaTemplate(plan1);
schemaProcessor.createSchemaTemplate(plan2);
assertEquals(4, schemaProcessor.getSchemasInTemplate("treeTemplate", "").size());
assertEquals(2, schemaProcessor.getSchemasInTemplate("treeTemplate", "GPS").size());
assertEquals(11, schemaProcessor.getSchemasInTemplate("template1", "").size());
assertEquals(10, schemaProcessor.getSchemasInTemplate("template1", "vector").size());
}
@Test
public void testDropTemplate() throws MetadataException {
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
CreateTemplatePlan plan1 = getTreeTemplatePlan();
CreateTemplatePlan plan2 = getCreateTemplatePlan();
schemaProcessor.createSchemaTemplate(plan1);
schemaProcessor.createSchemaTemplate(plan2);
assertEquals("[template1, treeTemplate]", schemaProcessor.getAllTemplates().toString());
try {
schemaProcessor.createSchemaTemplate(plan2);
fail();
} catch (MetadataException e) {
assertEquals("Duplicated template name: template1", e.getMessage());
}
SetTemplatePlan setTemplatePlan = new SetTemplatePlan("template1", "root.sg.d0");
schemaProcessor.setSchemaTemplate(setTemplatePlan);
try {
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("template1"));
fail();
} catch (MetadataException e) {
assertEquals(
"Template [template1] has been set on MTree, cannot be dropped now.", e.getMessage());
}
UnsetTemplatePlan unsetPlan = new UnsetTemplatePlan("root.sg.d0", "template1");
schemaProcessor.unsetSchemaTemplate(unsetPlan);
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("template1"));
assertEquals("[treeTemplate]", schemaProcessor.getAllTemplates().toString());
schemaProcessor.createSchemaTemplate(plan2);
assertEquals("[template1, treeTemplate]", schemaProcessor.getAllTemplates().toString());
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("template1"));
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("treeTemplate"));
}
@Test
public void testDropTemplateWithStorageGroupDeleted() throws MetadataException {
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
schemaProcessor.createSchemaTemplate(getTreeTemplatePlan());
schemaProcessor.setSchemaTemplate(new SetTemplatePlan("treeTemplate", "root.sg1.d1"));
try {
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("treeTemplate"));
fail();
} catch (MetadataException e) {
assertEquals(
"Template [treeTemplate] has been set on MTree, cannot be dropped now.", e.getMessage());
}
schemaProcessor.deleteStorageGroups(Arrays.asList(new PartialPath("root.sg1")));
schemaProcessor.dropSchemaTemplate(new DropTemplatePlan("treeTemplate"));
assertEquals(0, schemaProcessor.getAllTemplates().size());
}
@Test
public void testTemplateAlignment() throws MetadataException {
LocalSchemaProcessor schemaProcessor = IoTDB.schemaProcessor;
schemaProcessor.createTimeseries(
new PartialPath("root.laptop.d0"),
TSDataType.INT32,
TSEncoding.PLAIN,
CompressionType.GZIP,
null);
schemaProcessor.createTimeseries(
new PartialPath("root.laptop.d1.s1"),
TSDataType.INT32,
TSEncoding.PLAIN,
CompressionType.GZIP,
null);
schemaProcessor.createTimeseries(
new PartialPath("root.laptop.d1.s2"),
TSDataType.INT32,
TSEncoding.PLAIN,
CompressionType.GZIP,
null);
schemaProcessor.createTimeseries(
new PartialPath("root.laptop.d1.ss.t1"),
TSDataType.INT32,
TSEncoding.PLAIN,
CompressionType.GZIP,
null);
schemaProcessor.createSchemaTemplate(getDirectAlignedTemplate());
try {
schemaProcessor.setSchemaTemplate(new SetTemplatePlan("templateDA", "root.laptop.d1"));
fail();
} catch (Exception e) {
assertEquals(
"Template[templateDA] and mounted node[root.laptop.d1.vs0] has different alignment.",
e.getMessage());
}
}
private InsertRowPlan getInsertRowPlan(String prefixPath, String measurement)
throws IllegalPathException {
long time = 110L;
TSDataType[] dataTypes = new TSDataType[] {TSDataType.INT64};
String[] columns = new String[1];
columns[0] = "1";
return new InsertRowPlan(
new PartialPath(prefixPath), time, new String[] {measurement}, dataTypes, columns);
}
}