This is an automated email from the ASF dual-hosted git repository.
rong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 56e21e4fee1 support config snapshot parser (#12211)
56e21e4fee1 is described below
commit 56e21e4fee1ff85ba27db904957be3bb742f4cef
Author: Colin Li <[email protected]>
AuthorDate: Fri Mar 22 21:01:11 2024 +0800
support config snapshot parser (#12211)
---
.../consensus/request/auth/AuthorPlan.java | 2 +-
.../schema/CNPhysicalPlanGenerator.java | 393 ++++++++++++++++++
.../persistence/schema/CNSnapshotFileType.java | 28 ++
.../schema/ConfignodeSnapshotParser.java | 168 ++++++++
.../persistence/CNPhysicalPlanGeneratorTest.java | 446 +++++++++++++++++++++
.../db/tools/schema/SRStatementGenerator.java | 13 +-
.../db/utils/SchemaRegionSnapshotParserTest.java | 2 +-
.../iotdb/commons/auth/entity/PathPrivilege.java | 41 +-
.../org/apache/iotdb/commons/auth/entity/Role.java | 63 +--
.../org/apache/iotdb/commons/utils/AuthUtils.java | 85 ++++
10 files changed, 1143 insertions(+), 98 deletions(-)
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/auth/AuthorPlan.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/auth/AuthorPlan.java
index fb624ff03ff..61c76320007 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/auth/AuthorPlan.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/auth/AuthorPlan.java
@@ -290,6 +290,6 @@ public class AuthorPlan extends ConfigPhysicalPlan {
@Override
public int hashCode() {
return Objects.hash(
- authorType, userName, roleName, password, newPassword, permissions,
nodeNameList);
+ authorType, userName, roleName, password, newPassword, permissions,
nodeNameList, grantOpt);
}
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java
new file mode 100644
index 00000000000..742ad457ed4
--- /dev/null
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java
@@ -0,0 +1,393 @@
+/*
+ * 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.confignode.persistence.schema;
+
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.node.role.IDatabaseMNode;
+import org.apache.iotdb.commons.schema.node.utils.IMNodeFactory;
+import org.apache.iotdb.commons.utils.AuthUtils;
+import org.apache.iotdb.commons.utils.ThriftConfigNodeSerDeUtils;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
+import org.apache.iotdb.confignode.consensus.request.auth.AuthorPlan;
+import
org.apache.iotdb.confignode.consensus.request.write.database.DatabaseSchemaPlan;
+import org.apache.iotdb.confignode.consensus.request.write.database.SetTTLPlan;
+import
org.apache.iotdb.confignode.consensus.request.write.template.CommitSetSchemaTemplatePlan;
+import
org.apache.iotdb.confignode.consensus.request.write.template.CreateSchemaTemplatePlan;
+import org.apache.iotdb.confignode.persistence.schema.mnode.IConfigMNode;
+import
org.apache.iotdb.confignode.persistence.schema.mnode.factory.ConfigMNodeFactory;
+import org.apache.iotdb.db.schemaengine.template.Template;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_ROOT;
+import static
org.apache.iotdb.commons.schema.SchemaConstant.INTERNAL_MNODE_TYPE;
+import static
org.apache.iotdb.commons.schema.SchemaConstant.STORAGE_GROUP_MNODE_TYPE;
+import static org.apache.iotdb.commons.utils.IOUtils.readAuthString;
+import static org.apache.iotdb.commons.utils.IOUtils.readString;
+
+public class CNPhysicalPlanGenerator
+ implements Iterator<ConfigPhysicalPlan>, Iterable<ConfigPhysicalPlan> {
+
+ private final Logger logger =
LoggerFactory.getLogger(CNPhysicalPlanGenerator.class);
+ private final IMNodeFactory<IConfigMNode> nodeFactory =
ConfigMNodeFactory.getInstance();
+
+ // File input stream.
+ private InputStream inputStream = null;
+ private InputStream templateInputStream = null;
+
+ private static final String STRING_ENCODING = "utf-8";
+
+ // For default password
+ private static final String DEFAULT_PASSWORD = "password";
+ private final ThreadLocal<byte[]> strBufferLocal = new ThreadLocal<>();
+
+ private final HashMap<Integer, String> templateTable = new HashMap<>();
+
+ // All plan will be stored at this deque
+ private final Deque<ConfigPhysicalPlan> planDeque = new ArrayDeque<>();
+
+ private CNSnapshotFileType snapshotFileType = CNSnapshotFileType.INVALID;
+
+ private Exception latestException = null;
+ private String userName;
+
+ public CNPhysicalPlanGenerator(Path snapshotFilePath, CNSnapshotFileType
fileType)
+ throws IOException {
+ if (fileType == CNSnapshotFileType.SCHEMA_TEMPLATE) {
+ logger.warn("schema_template need two files");
+ return;
+ }
+ if (fileType == CNSnapshotFileType.USER_ROLE) {
+ userName =
snapshotFilePath.getFileName().toString().split("_role.profile")[0];
+ }
+ snapshotFileType = fileType;
+ inputStream = Files.newInputStream(snapshotFilePath);
+ }
+
+ public CNPhysicalPlanGenerator(Path schemaInfoFile, Path templateFile)
throws IOException {
+ inputStream = Files.newInputStream(schemaInfoFile);
+ templateInputStream = Files.newInputStream(templateFile);
+ snapshotFileType = CNSnapshotFileType.SCHEMA_TEMPLATE;
+ }
+
+ @Override
+ public Iterator<ConfigPhysicalPlan> iterator() {
+ return this;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (!planDeque.isEmpty()) {
+ return true;
+ }
+
+ if (snapshotFileType == CNSnapshotFileType.USER) {
+ generateUserRolePhysicalPlan(true);
+ } else if (snapshotFileType == CNSnapshotFileType.ROLE) {
+ generateUserRolePhysicalPlan(false);
+ } else if (snapshotFileType == CNSnapshotFileType.USER_ROLE) {
+ generateGrantRolePhysicalPlan();
+ } else if (snapshotFileType == CNSnapshotFileType.SCHEMA_TEMPLATE) {
+ generateTemplatePlan();
+ if (latestException != null) {
+ return false;
+ }
+ generateDatabasePhysicalPlan();
+ }
+ snapshotFileType = CNSnapshotFileType.INVALID;
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ inputStream = null;
+ }
+ if (templateInputStream != null) {
+ templateInputStream.close();
+ templateInputStream = null;
+ }
+ } catch (IOException ioException) {
+ latestException = ioException;
+ }
+
+ if (latestException != null) {
+ return false;
+ }
+ return !planDeque.isEmpty();
+ }
+
+ @Override
+ public ConfigPhysicalPlan next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return planDeque.pop();
+ }
+
+ public void checkException() throws Exception {
+ if (latestException != null) {
+ throw new Exception(latestException.getMessage());
+ }
+ }
+
+ private void generateUserRolePhysicalPlan(boolean isUser) {
+ try (DataInputStream dataInputStream =
+ new DataInputStream(new BufferedInputStream(inputStream))) {
+ Pair<String, Boolean> versionAndName =
+ readAuthString(dataInputStream, STRING_ENCODING, strBufferLocal);
+ if (versionAndName == null) {
+ return;
+ }
+ String user = versionAndName.left;
+ if (isUser) {
+ // skip password
+ readString(dataInputStream, STRING_ENCODING, strBufferLocal);
+ AuthorPlan createUser = new
AuthorPlan(ConfigPhysicalPlanType.CreateUser);
+ createUser.setUserName(user);
+ createUser.setPassword(DEFAULT_PASSWORD);
+ planDeque.add(createUser);
+ } else {
+ AuthorPlan createRole = new
AuthorPlan(ConfigPhysicalPlanType.CreateRole);
+ createRole.setRoleName(user);
+ planDeque.add(createRole);
+ }
+
+ int privilegeMask = dataInputStream.readInt();
+ // translate sys privileges
+ generateGrantSysPlan(user, isUser, privilegeMask);
+ // translate path privileges
+ while (dataInputStream.available() != 0) {
+ String path = readString(dataInputStream, STRING_ENCODING,
strBufferLocal);
+ PartialPath priPath;
+ try {
+ priPath = new PartialPath(path);
+ } catch (IllegalPathException exception) {
+ latestException = exception;
+ return;
+ }
+ int privileges = dataInputStream.readInt();
+ generateGrantPathPlan(user, isUser, priPath, privileges);
+ }
+ } catch (IOException ioException) {
+ logger.error(
+ "Got IOException when deserialize userole file, type:{}",
snapshotFileType, ioException);
+ latestException = ioException;
+ } finally {
+ strBufferLocal.remove();
+ }
+ }
+
+ private void generateGrantRolePhysicalPlan() {
+ try (DataInputStream roleInputStream =
+ new DataInputStream(new BufferedInputStream((inputStream)))) {
+ while (roleInputStream.available() != 0) {
+ String roleName = readString(roleInputStream, STRING_ENCODING,
strBufferLocal);
+ AuthorPlan plan = new
AuthorPlan(ConfigPhysicalPlanType.GrantRoleToUser);
+ plan.setUserName(userName);
+ plan.setRoleName(roleName);
+ planDeque.add(plan);
+ }
+ } catch (IOException ioException) {
+ logger.error("Got IOException when deserialize roleList", ioException);
+ latestException = ioException;
+ } finally {
+ strBufferLocal.remove();
+ }
+ }
+
+ private void generateGrantSysPlan(String userName, boolean isUser, int
sysMask) {
+ for (int i = 0; i < PrivilegeType.getSysPriCount(); i++) {
+ if ((sysMask & (1 << i)) != 0) {
+ AuthorPlan plan =
+ new AuthorPlan(
+ isUser ? ConfigPhysicalPlanType.GrantUser :
ConfigPhysicalPlanType.GrantRole);
+ if (isUser) {
+ plan.setUserName(userName);
+ } else {
+ plan.setRoleName(userName);
+ }
+ plan.setPermissions(Collections.singleton(AuthUtils.posToSysPri(i)));
+ if ((sysMask & (1 << (i + 16))) != 0) {
+ plan.setGrantOpt(true);
+ }
+ plan.setNodeNameList(new ArrayList<>());
+ planDeque.add(plan);
+ }
+ }
+ }
+
+ private void generateGrantPathPlan(
+ String userName, boolean isUser, PartialPath path, int priMask) {
+ for (int pos = 0; pos < PrivilegeType.getPathPriCount(); pos++) {
+ if (((1 << pos) & priMask) != 0) {
+ AuthorPlan plan =
+ new AuthorPlan(
+ isUser ? ConfigPhysicalPlanType.GrantUser :
ConfigPhysicalPlanType.GrantRole);
+ if (isUser) {
+ plan.setUserName(userName);
+ } else {
+ plan.setRoleName(userName);
+ }
+
plan.setPermissions(Collections.singleton(AuthUtils.pathPosToPri(pos)));
+ plan.setNodeNameList(Collections.singletonList(path));
+ if ((1 << (pos + 16) & priMask) != 0) {
+ plan.setGrantOpt(true);
+ }
+ planDeque.add(plan);
+ }
+ }
+ }
+
+ private void generateDatabasePhysicalPlan() {
+ try (BufferedInputStream bufferedInputStream = new
BufferedInputStream(inputStream)) {
+ byte type = ReadWriteIOUtils.readByte(bufferedInputStream);
+ String name = null;
+ int childNum = 0;
+ Stack<Pair<IConfigMNode, Boolean>> stack = new Stack<>();
+ IConfigMNode databaseMNode;
+ IConfigMNode internalMNode;
+
+ if (type == STORAGE_GROUP_MNODE_TYPE) {
+ databaseMNode = deserializeDatabaseMNode(bufferedInputStream);
+ name = databaseMNode.getName();
+ stack.push(new Pair<>(databaseMNode, true));
+ } else {
+ internalMNode = deserializeInternalMNode(bufferedInputStream);
+ childNum = ReadWriteIOUtils.readInt(bufferedInputStream);
+ name = internalMNode.getName();
+ stack.push(new Pair<>(internalMNode, false));
+ }
+
+ while (!PATH_ROOT.equals(name)) {
+ type = ReadWriteIOUtils.readByte(bufferedInputStream);
+ switch (type) {
+ case INTERNAL_MNODE_TYPE:
+ internalMNode = deserializeInternalMNode(bufferedInputStream);
+ childNum = ReadWriteIOUtils.readInt(bufferedInputStream);
+ boolean hasDB = false;
+ while (childNum > 0) {
+ hasDB = stack.peek().right;
+ internalMNode.addChild(stack.pop().left);
+ childNum--;
+ }
+ stack.push(new Pair<>(internalMNode, hasDB));
+ name = internalMNode.getName();
+ break;
+ case STORAGE_GROUP_MNODE_TYPE:
+ databaseMNode =
deserializeDatabaseMNode(bufferedInputStream).getAsMNode();
+ while (!stack.isEmpty() && !stack.peek().right) {
+ databaseMNode.addChild(stack.pop().left);
+ }
+ stack.push(new Pair<>(databaseMNode, true));
+ name = databaseMNode.getName();
+ break;
+ default:
+ logger.error("Unrecognized node type. Cannot deserialize MTree
from given buffer");
+ return;
+ }
+ }
+ } catch (IOException ioException) {
+ logger.error("Got IOException when construct database Tree",
ioException);
+ latestException = ioException;
+ }
+ }
+
+ private void generateTemplatePlan() {
+ try (BufferedInputStream bufferedInputStream = new
BufferedInputStream(templateInputStream)) {
+ ByteBuffer byteBuffer =
ByteBuffer.wrap(IOUtils.toByteArray(bufferedInputStream));
+ // skip id
+ ReadWriteIOUtils.readInt(byteBuffer);
+ int size = ReadWriteIOUtils.readInt(byteBuffer);
+ while (size > 0) {
+ Template template = new Template();
+ template.deserialize(byteBuffer);
+ template.setId(0);
+ templateTable.put(template.getId(), template.getName());
+ CreateSchemaTemplatePlan plan = new
CreateSchemaTemplatePlan(template.serialize().array());
+ planDeque.add(plan);
+ size--;
+ }
+ } catch (IOException ioException) {
+ logger.error("Got IOException when deserialize template info",
ioException);
+ latestException = ioException;
+ }
+ }
+
+ private IConfigMNode deserializeDatabaseMNode(InputStream inputStream)
throws IOException {
+ IDatabaseMNode<IConfigMNode> databaseMNode =
+ nodeFactory.createDatabaseMNode(null,
ReadWriteIOUtils.readString(inputStream));
+
databaseMNode.getAsMNode().setSchemaTemplateId(ReadWriteIOUtils.readInt(inputStream));
+ databaseMNode
+ .getAsMNode()
+
.setDatabaseSchema(ThriftConfigNodeSerDeUtils.deserializeTDatabaseSchema(inputStream));
+ if (databaseMNode.getAsMNode().getDatabaseSchema().isSetTTL()) {
+ SetTTLPlan plan =
+ new SetTTLPlan(
+
Collections.singletonList(databaseMNode.getAsMNode().getDatabaseSchema().getName()),
+ databaseMNode.getAsMNode().getDatabaseSchema().getTTL());
+ planDeque.add(plan);
+ databaseMNode.getAsMNode().getDatabaseSchema().unsetTTL();
+ }
+
+ DatabaseSchemaPlan createDBPlan =
+ new DatabaseSchemaPlan(
+ ConfigPhysicalPlanType.CreateDatabase,
databaseMNode.getAsMNode().getDatabaseSchema());
+ planDeque.add(createDBPlan);
+
+ return databaseMNode.getAsMNode();
+ }
+
+ private IConfigMNode deserializeInternalMNode(InputStream inputStream)
throws IOException {
+ IConfigMNode basicMNode =
+ nodeFactory.createInternalMNode(null,
ReadWriteIOUtils.readString(inputStream));
+ basicMNode.setSchemaTemplateId(ReadWriteIOUtils.readInt(inputStream));
+ if (basicMNode.getSchemaTemplateId() >= 0) {
+ if (!templateTable.isEmpty()) {
+ String templateName =
templateTable.get(basicMNode.getSchemaTemplateId());
+ // ignore preset plan.
+ CommitSetSchemaTemplatePlan plan =
+ new CommitSetSchemaTemplatePlan(templateName,
basicMNode.getFullPath());
+ planDeque.add(plan);
+ }
+ }
+ return basicMNode;
+ }
+}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNSnapshotFileType.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNSnapshotFileType.java
new file mode 100644
index 00000000000..ee8f6f9bb79
--- /dev/null
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNSnapshotFileType.java
@@ -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.confignode.persistence.schema;
+
+public enum CNSnapshotFileType {
+ INVALID,
+ USER,
+ ROLE,
+ USER_ROLE,
+ SCHEMA_TEMPLATE
+}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfignodeSnapshotParser.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfignodeSnapshotParser.java
new file mode 100644
index 00000000000..1f6aea04cfe
--- /dev/null
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfignodeSnapshotParser.java
@@ -0,0 +1,168 @@
+/*
+ * 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.confignode.persistence.schema;
+
+import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.file.SystemFileFactory;
+import org.apache.iotdb.confignode.conf.ConfigNodeConfig;
+import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ConfignodeSnapshotParser {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ConfignodeSnapshotParser.class);
+ private static final ConfigNodeConfig CONF =
ConfigNodeDescriptor.getInstance().getConf();
+
+ private static final String SNAPSHOT_CLUSTER_SCHEMA_FILENAME =
"cluster_schema.bin";
+
+ private static final String SNAPSHOT_TEMPLATE_FILENAME = "template_info.bin";
+
+ private ConfignodeSnapshotParser() {
+ // Empty constructor
+ }
+
+ private static Path getLatestSnapshotPath(List<Path> snapshotPathList) {
+ if (snapshotPathList.isEmpty()) {
+ return null;
+ }
+ Path[] pathArray = snapshotPathList.toArray(new Path[0]);
+ Arrays.sort(
+ pathArray,
+ (o1, o2) -> {
+ String index1 = o1.toFile().getName().split("_")[1];
+ String index2 = o2.toFile().getName().split("_")[1];
+ return Long.compare(Long.parseLong(index2), Long.parseLong(index1));
+ });
+ return pathArray[0];
+ }
+
+ public static List<Pair<Pair<Path, Path>, CNSnapshotFileType>>
getSnapshots() throws IOException {
+ List<Pair<Pair<Path, Path>, CNSnapshotFileType>> snapshotPairList = new
ArrayList<>();
+ String snapshotPath = CONF.getConsensusDir();
+ try (DirectoryStream<Path> stream =
+ Files.newDirectoryStream(Paths.get(snapshotPath),
"[0-9]*-[0-9]*-[0-9]*-[0-9]*-[0-9]*")) {
+ // In confignode there is only one consensus dir.
+ // Get into confignode consensus dir
+ for (Path path : stream) {
+ try (DirectoryStream<Path> filestream =
+ Files.newDirectoryStream(Paths.get(path.toString() +
File.separator + "sm"))) {
+ // find the latest snapshots
+ ArrayList<Path> snapshotList = new ArrayList<>();
+ for (Path snapshotFolder : filestream) {
+ if (snapshotFolder.toFile().isDirectory()) {
+ snapshotList.add(snapshotFolder);
+ }
+ }
+ Path latestSnapshotPath = getLatestSnapshotPath(snapshotList);
+
+ if (latestSnapshotPath != null) {
+ // Get role files.
+ String rolePath =
+ latestSnapshotPath
+ + File.separator
+ + IoTDBConstant.SYSTEM_FOLDER_NAME
+ + File.separator
+ + "roles";
+ try (DirectoryStream<Path> roleStream =
Files.newDirectoryStream(Paths.get(rolePath))) {
+ for (Path role : roleStream) {
+ Pair<Path, Path> roleFile = new Pair<>(role, null);
+ snapshotPairList.add(new Pair<>(roleFile,
CNSnapshotFileType.ROLE));
+ }
+ }
+ // Get user files.
+ String userPath =
+ latestSnapshotPath
+ + File.separator
+ + IoTDBConstant.SYSTEM_FOLDER_NAME
+ + File.separator
+ + "users";
+ try (DirectoryStream<Path> userStream =
Files.newDirectoryStream(Paths.get(userPath))) {
+ List<Path> userFilePath = new ArrayList<>();
+ List<Path> userRoleFilePath = new ArrayList<>();
+ for (Path user : userStream) {
+ if (user.getFileName().toString().contains("_role.profile")) {
+ userRoleFilePath.add(user);
+ } else {
+ userFilePath.add(user);
+ }
+ }
+ // We should add user file firstly.
+ for (Path user : userFilePath) {
+ snapshotPairList.add(new Pair<>(new Pair<>(user, null),
CNSnapshotFileType.USER));
+ }
+ for (Path roleList : userRoleFilePath) {
+ snapshotPairList.add(
+ new Pair<>(new Pair<>(roleList, null),
CNSnapshotFileType.USER_ROLE));
+ }
+ }
+
+ // Get cluster schema info file and template file.
+ File schemaInfoFile =
+ SystemFileFactory.INSTANCE.getFile(
+ latestSnapshotPath + File.separator +
SNAPSHOT_CLUSTER_SCHEMA_FILENAME);
+ File templateInfoFile =
+ SystemFileFactory.INSTANCE.getFile(
+ latestSnapshotPath + File.separator +
SNAPSHOT_TEMPLATE_FILENAME);
+ if (schemaInfoFile.exists() && templateInfoFile.exists()) {
+ snapshotPairList.add(
+ new Pair<>(
+ new Pair<>(schemaInfoFile.toPath(),
templateInfoFile.toPath()),
+ CNSnapshotFileType.SCHEMA_TEMPLATE));
+ }
+ }
+ }
+ }
+ }
+ return snapshotPairList;
+ }
+
+ public static CNPhysicalPlanGenerator translate2PhysicalPlan(
+ Path path1, Path path2, CNSnapshotFileType type) throws IOException {
+ if (type == CNSnapshotFileType.SCHEMA_TEMPLATE && (path1 == null || path2
== null)) {
+ LOGGER.warn("schema_template require schemainfo file and template file");
+ return null;
+ } else if (path1 == null) {
+ LOGGER.warn("path1 should not be null");
+ return null;
+ }
+
+ if (path1.toFile().exists()) {
+ LOGGER.warn("file {} not exists", path1.toFile().getName());
+ return null;
+ }
+
+ if (type == CNSnapshotFileType.SCHEMA_TEMPLATE) {
+ return new CNPhysicalPlanGenerator(path1, path2);
+ } else {
+ return new CNPhysicalPlanGenerator(path1, type);
+ }
+ }
+}
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
new file mode 100644
index 00000000000..f7b7700c244
--- /dev/null
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/CNPhysicalPlanGeneratorTest.java
@@ -0,0 +1,446 @@
+/*
+ * 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.confignode.persistence;
+
+import org.apache.iotdb.commons.auth.AuthException;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.file.SystemFileFactory;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.utils.FileUtils;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
+import org.apache.iotdb.confignode.consensus.request.auth.AuthorPlan;
+import
org.apache.iotdb.confignode.consensus.request.write.database.DatabaseSchemaPlan;
+import org.apache.iotdb.confignode.consensus.request.write.database.SetTTLPlan;
+import
org.apache.iotdb.confignode.consensus.request.write.template.CommitSetSchemaTemplatePlan;
+import
org.apache.iotdb.confignode.consensus.request.write.template.CreateSchemaTemplatePlan;
+import
org.apache.iotdb.confignode.consensus.request.write.template.PreSetSchemaTemplatePlan;
+import org.apache.iotdb.confignode.persistence.schema.CNPhysicalPlanGenerator;
+import org.apache.iotdb.confignode.persistence.schema.CNSnapshotFileType;
+import org.apache.iotdb.confignode.persistence.schema.ClusterSchemaInfo;
+import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
+import org.apache.iotdb.db.schemaengine.template.Template;
+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.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static org.apache.iotdb.db.utils.constant.TestConstant.BASE_OUTPUT_PATH;
+
+public class CNPhysicalPlanGeneratorTest {
+ private static AuthorInfo authorInfo;
+ private static ClusterSchemaInfo clusterSchemaInfo;
+
+ private static final File snapshotDir = new File(BASE_OUTPUT_PATH,
"authorInfo-snapshot");
+ private static final String USER_SNAPSHOT_FILE_NAME = "system" +
File.separator + "users";
+ private static final String ROLE_SNAPSHOT_FILE_NAME = "system" +
File.separator + "roles";
+
+ private static final String SCHEMA_INFO_FILE_NAME = "cluster_schema.bin";
+ private static final String TEMPLATE_INFO_FILE_NAME = "template_info.bin";
+
+ private static void setupAuthorInfo() {
+ authorInfo = new AuthorInfo();
+ if (!snapshotDir.exists()) {
+ snapshotDir.mkdir();
+ }
+ }
+
+ private static void setupClusterSchemaInfo() throws IOException {
+ clusterSchemaInfo = new ClusterSchemaInfo();
+ if (!snapshotDir.exists()) {
+ snapshotDir.mkdir();
+ }
+ }
+
+ @After
+ public void cleanUpInfo() throws AuthException {
+ if (authorInfo != null) {
+ authorInfo.clear();
+ }
+ if (clusterSchemaInfo != null) {
+ clusterSchemaInfo.clear();
+ }
+ FileUtils.deleteDirectory(snapshotDir);
+ }
+
+ @Test
+ public void roleGeneratorTest() throws Exception {
+ HashSet<Integer> answerSet = new HashSet<>();
+ String roleName = "test1";
+ setupAuthorInfo();
+ AuthorPlan plan = new AuthorPlan(ConfigPhysicalPlanType.CreateRole);
+ plan.setRoleName(roleName);
+ answerSet.add(plan.hashCode());
+ // step 1: create role - plan1
+ authorInfo.authorNonQuery(plan);
+
+ // step 2: grant role path privileges - plan2
+ plan = new AuthorPlan(ConfigPhysicalPlanType.GrantRole);
+ plan.setRoleName(roleName);
+ plan.setNodeNameList(Collections.singletonList(new
PartialPath("root.db.t1")));
+ Set<Integer> pathPris = new HashSet<>();
+ pathPris.add(PrivilegeType.WRITE_DATA.ordinal());
+ pathPris.add(PrivilegeType.WRITE_SCHEMA.ordinal());
+ plan.setPermissions(pathPris);
+ authorInfo.authorNonQuery(plan);
+
+ // answer set
+ plan.getPermissions().clear();
+ plan.getPermissions().add(PrivilegeType.WRITE_DATA.ordinal());
+ answerSet.add(plan.hashCode());
+ plan.getPermissions().clear();
+ plan.getPermissions().add(PrivilegeType.WRITE_SCHEMA.ordinal());
+ answerSet.add(plan.hashCode());
+
+ // step 3: grant role sys privileges - plan3
+ plan = new AuthorPlan(ConfigPhysicalPlanType.GrantRole);
+ plan.setRoleName(roleName);
+ plan.setNodeNameList(Collections.emptyList());
+ Set<Integer> sysPris = new HashSet<>();
+ sysPris.add(PrivilegeType.MANAGE_DATABASE.ordinal());
+ sysPris.add(PrivilegeType.MANAGE_ROLE.ordinal());
+ plan.setPermissions(sysPris);
+ plan.setGrantOpt(true);
+ authorInfo.authorNonQuery(plan);
+
+ // answer set
+ plan.getPermissions().clear();
+ plan.getPermissions().add(PrivilegeType.MANAGE_ROLE.ordinal());
+ answerSet.add(plan.hashCode());
+ plan.getPermissions().clear();
+ plan.getPermissions().add(PrivilegeType.MANAGE_DATABASE.ordinal());
+ answerSet.add(plan.hashCode());
+
+ // PhysicalPlan gnerator will return five plans:
+ // 1. create role plan
+ // 2. grant path privileges plan * 2
+ // 3. grant system privileges plan * 2
+ boolean success = authorInfo.processTakeSnapshot(snapshotDir);
+
+ File roleProfile =
+ SystemFileFactory.INSTANCE.getFile(
+ snapshotDir
+ + File.separator
+ + ROLE_SNAPSHOT_FILE_NAME
+ + File.separator
+ + roleName
+ + ".profile");
+
+ CNPhysicalPlanGenerator planGenerator =
+ new CNPhysicalPlanGenerator(roleProfile.toPath(),
CNSnapshotFileType.ROLE);
+ int count = 0;
+ for (ConfigPhysicalPlan authPlan : planGenerator) {
+ Assert.assertTrue(answerSet.contains(authPlan.hashCode()));
+ count++;
+ }
+ Assert.assertEquals(5, count);
+ }
+
+ @Test
+ public void userGeneratorTest() throws Exception {
+ String userName = "test1";
+ Set<Integer> answerSet = new HashSet<>();
+ setupAuthorInfo();
+ AuthorPlan plan = new AuthorPlan(ConfigPhysicalPlanType.CreateUser);
+ plan.setPassword("password");
+ plan.setUserName(userName);
+ // create user plan 1
+ authorInfo.authorNonQuery(plan);
+ answerSet.add(plan.hashCode());
+
+ plan = new AuthorPlan(ConfigPhysicalPlanType.CreateRole);
+ plan.setRoleName("role1");
+ authorInfo.authorNonQuery(plan);
+
+ // grant path privileges, plan 2 , plan 3
+ plan = new AuthorPlan(ConfigPhysicalPlanType.GrantUser);
+ plan.setUserName(userName);
+ plan.setNodeNameList(Collections.singletonList(new
PartialPath("root.db1.t2")));
+ Set<Integer> priSet = new HashSet<>();
+ priSet.add(PrivilegeType.WRITE_SCHEMA.ordinal());
+ priSet.add(PrivilegeType.READ_DATA.ordinal());
+ plan.setPermissions(priSet);
+ plan.setGrantOpt(true);
+ authorInfo.authorNonQuery(plan);
+
+ plan.getPermissions().clear();
+ plan.getPermissions().add(PrivilegeType.WRITE_SCHEMA.ordinal());
+ answerSet.add(plan.hashCode());
+
+ plan.getPermissions().clear();
+ plan.getPermissions().add(PrivilegeType.READ_DATA.ordinal());
+ answerSet.add(plan.hashCode());
+
+ // grant system privileges, plan 4
+ plan = new AuthorPlan(ConfigPhysicalPlanType.GrantUser);
+ plan.setUserName(userName);
+ plan.setNodeNameList(Collections.emptyList());
+
plan.setPermissions(Collections.singleton(PrivilegeType.MANAGE_DATABASE.ordinal()));
+ plan.setGrantOpt(false);
+ authorInfo.authorNonQuery(plan);
+ answerSet.add(plan.hashCode());
+
+ // grant role to user, plan 5
+ plan = new AuthorPlan(ConfigPhysicalPlanType.GrantRoleToUser);
+ plan.setRoleName("role1");
+ plan.setUserName(userName);
+ authorInfo.authorNonQuery(plan);
+ answerSet.add(plan.hashCode());
+
+ boolean success = authorInfo.processTakeSnapshot(snapshotDir);
+
+ File userProfile =
+ SystemFileFactory.INSTANCE.getFile(
+ snapshotDir
+ + File.separator
+ + USER_SNAPSHOT_FILE_NAME
+ + File.separator
+ + userName
+ + ".profile");
+
+ CNPhysicalPlanGenerator planGenerator =
+ new CNPhysicalPlanGenerator(userProfile.toPath(),
CNSnapshotFileType.USER);
+ int count = 0;
+ // plan 1-4
+ for (ConfigPhysicalPlan authPlan : planGenerator) {
+ Assert.assertTrue(answerSet.contains(authPlan.hashCode()));
+ count++;
+ }
+ Assert.assertEquals(4, count);
+ File roleListProfile =
+ SystemFileFactory.INSTANCE.getFile(
+ snapshotDir
+ + File.separator
+ + USER_SNAPSHOT_FILE_NAME
+ + File.separator
+ + userName
+ + "_role.profile");
+ planGenerator =
+ new CNPhysicalPlanGenerator(roleListProfile.toPath(),
CNSnapshotFileType.USER_ROLE);
+ count = 0;
+ // plan 5
+ for (ConfigPhysicalPlan authPlan : planGenerator) {
+ Assert.assertTrue(answerSet.contains(authPlan.hashCode()));
+ count++;
+ }
+ Assert.assertEquals(1, count);
+ }
+
+ @Test
+ public void databaseWithoutTemplateGeneratorTest() throws Exception {
+ setupClusterSchemaInfo();
+ Set<Integer> answerSet = new HashSet<>();
+ Set<String> storageGroupPathList = new TreeSet<>();
+ storageGroupPathList.add("root.sg");
+ storageGroupPathList.add("root.a.sg");
+ storageGroupPathList.add("root.a.b.sg");
+ storageGroupPathList.add("root.a.a.a.b.sg");
+
+ int i = 0;
+ for (String path : storageGroupPathList) {
+ TDatabaseSchema tDatabaseSchema = new TDatabaseSchema();
+ tDatabaseSchema.setName(path);
+ tDatabaseSchema.setTTL(i);
+ tDatabaseSchema.setDataReplicationFactor(i);
+ tDatabaseSchema.setSchemaReplicationFactor(i);
+ tDatabaseSchema.setTimePartitionInterval(i);
+ clusterSchemaInfo.createDatabase(
+ new DatabaseSchemaPlan(ConfigPhysicalPlanType.CreateDatabase,
tDatabaseSchema));
+ SetTTLPlan plan = new SetTTLPlan(Collections.singletonList(path),
tDatabaseSchema.getTTL());
+ answerSet.add(plan.hashCode());
+ TDatabaseSchema tDatabaseSchemaBak = new
TDatabaseSchema(tDatabaseSchema);
+ tDatabaseSchemaBak.unsetTTL();
+ DatabaseSchemaPlan databaseSchemaPlan =
+ new DatabaseSchemaPlan(ConfigPhysicalPlanType.CreateDatabase,
tDatabaseSchemaBak);
+ answerSet.add(databaseSchemaPlan.hashCode());
+ i++;
+ }
+
+ boolean success = clusterSchemaInfo.processTakeSnapshot(snapshotDir);
+ Assert.assertTrue(success);
+ File schemaInfo =
+ SystemFileFactory.INSTANCE.getFile(snapshotDir + File.separator +
SCHEMA_INFO_FILE_NAME);
+ File templateInfo =
+ SystemFileFactory.INSTANCE.getFile(snapshotDir + File.separator +
TEMPLATE_INFO_FILE_NAME);
+
+ CNPhysicalPlanGenerator planGenerator =
+ new CNPhysicalPlanGenerator(schemaInfo.toPath(),
templateInfo.toPath());
+ int count = 0;
+ for (ConfigPhysicalPlan plan : planGenerator) {
+ if (plan.getType() == ConfigPhysicalPlanType.CreateDatabase) {
+ Assert.assertTrue(answerSet.contains(((DatabaseSchemaPlan)
plan).hashCode()));
+ } else if (plan.getType() == ConfigPhysicalPlanType.SetTTL) {
+ Assert.assertTrue(answerSet.contains(((SetTTLPlan) plan).hashCode()));
+ }
+ count++;
+ }
+ planGenerator.checkException();
+ Assert.assertEquals(8, count);
+ }
+
+ @Test
+ public void templateGneratorTest() throws Exception {
+ setupClusterSchemaInfo();
+ Template t1 =
+ new Template(
+ "t1",
+ Arrays.asList("s1", "s2"),
+ Arrays.asList(TSDataType.INT32, TSDataType.BOOLEAN),
+ Arrays.asList(TSEncoding.GORILLA, TSEncoding.PLAIN),
+ Arrays.asList(CompressionType.GZIP, CompressionType.SNAPPY));
+ Template t2 =
+ new Template(
+ "t2",
+ Arrays.asList("s1", "s2", "s3"),
+ Arrays.asList(TSDataType.INT32, TSDataType.BOOLEAN,
TSDataType.TEXT),
+ Arrays.asList(TSEncoding.GORILLA, TSEncoding.PLAIN,
TSEncoding.DIFF),
+ Arrays.asList(CompressionType.GZIP, CompressionType.SNAPPY,
CompressionType.LZ4));
+ Map<String, CreateSchemaTemplatePlan> answerPlan = new HashMap<>();
+
+ CreateSchemaTemplatePlan plan1 = new
CreateSchemaTemplatePlan(t1.serialize().array());
+ clusterSchemaInfo.createSchemaTemplate(plan1);
+ answerPlan.put(t1.getName(), plan1);
+
+ CreateSchemaTemplatePlan plan2 = new
CreateSchemaTemplatePlan(t2.serialize().array());
+ clusterSchemaInfo.createSchemaTemplate(plan2);
+ answerPlan.put(t2.getName(), plan2);
+
+ boolean success = clusterSchemaInfo.processTakeSnapshot(snapshotDir);
+ Assert.assertTrue(success);
+ File schemaInfo =
+ SystemFileFactory.INSTANCE.getFile(snapshotDir + File.separator +
SCHEMA_INFO_FILE_NAME);
+ File templateInfo =
+ SystemFileFactory.INSTANCE.getFile(snapshotDir + File.separator +
TEMPLATE_INFO_FILE_NAME);
+ CNPhysicalPlanGenerator planGenerator =
+ new CNPhysicalPlanGenerator(schemaInfo.toPath(),
templateInfo.toPath());
+ int count = 0;
+ for (ConfigPhysicalPlan plan : planGenerator) {
+ CreateSchemaTemplatePlan templatePlan = (CreateSchemaTemplatePlan) plan;
+
Assert.assertTrue(answerPlan.get(templatePlan.getTemplate().getName()).equals(templatePlan));
+ count++;
+ }
+ Assert.assertEquals(2, count);
+ }
+
+ @Test
+ public void templateAndDatabaseComplatedTest() throws Exception {
+ setupClusterSchemaInfo();
+ Set<Integer> answerSet = new HashSet<>();
+ Set<String> storageGroupPathList = new TreeSet<>();
+ storageGroupPathList.add("root.sg");
+ storageGroupPathList.add("root.a.sg");
+ storageGroupPathList.add("root.a.b.sg");
+ storageGroupPathList.add("root.a.a.a.b.sg");
+
+ int i = 0;
+ for (String path : storageGroupPathList) {
+ TDatabaseSchema tDatabaseSchema = new TDatabaseSchema();
+ tDatabaseSchema.setName(path);
+ tDatabaseSchema.setTTL(i);
+ tDatabaseSchema.setDataReplicationFactor(i);
+ tDatabaseSchema.setSchemaReplicationFactor(i);
+ tDatabaseSchema.setTimePartitionInterval(i);
+ clusterSchemaInfo.createDatabase(
+ new DatabaseSchemaPlan(ConfigPhysicalPlanType.CreateDatabase,
tDatabaseSchema));
+ SetTTLPlan plan = new SetTTLPlan(Collections.singletonList(path),
tDatabaseSchema.getTTL());
+ answerSet.add(plan.hashCode());
+ TDatabaseSchema tDatabaseSchemaBak = new
TDatabaseSchema(tDatabaseSchema);
+ tDatabaseSchemaBak.unsetTTL();
+ DatabaseSchemaPlan databaseSchemaPlan =
+ new DatabaseSchemaPlan(ConfigPhysicalPlanType.CreateDatabase,
tDatabaseSchemaBak);
+ answerSet.add(databaseSchemaPlan.hashCode());
+ i++;
+ }
+ Template t1 =
+ new Template(
+ "t1",
+ Arrays.asList("s1", "s2"),
+ Arrays.asList(TSDataType.INT32, TSDataType.BOOLEAN),
+ Arrays.asList(TSEncoding.GORILLA, TSEncoding.PLAIN),
+ Arrays.asList(CompressionType.GZIP, CompressionType.SNAPPY));
+ Template t2 =
+ new Template(
+ "t2",
+ Arrays.asList("s1", "s2", "s3"),
+ Arrays.asList(TSDataType.INT32, TSDataType.BOOLEAN,
TSDataType.TEXT),
+ Arrays.asList(TSEncoding.GORILLA, TSEncoding.PLAIN,
TSEncoding.DIFF),
+ Arrays.asList(CompressionType.GZIP, CompressionType.SNAPPY,
CompressionType.LZ4));
+ CreateSchemaTemplatePlan plan1 = new
CreateSchemaTemplatePlan(t1.serialize().array());
+ clusterSchemaInfo.createSchemaTemplate(plan1);
+ answerSet.add(plan1.hashCode());
+
+ CreateSchemaTemplatePlan plan2 = new
CreateSchemaTemplatePlan(t2.serialize().array());
+ clusterSchemaInfo.createSchemaTemplate(plan2);
+ answerSet.add(plan2.hashCode());
+
+ PreSetSchemaTemplatePlan preSetSchemaTemplatePlan1 =
+ new PreSetSchemaTemplatePlan("t1", "root.sg.t1");
+ PreSetSchemaTemplatePlan preSetSchemaTemplatePlan2 =
+ new PreSetSchemaTemplatePlan("t2", "root.a.sg.t1");
+ CommitSetSchemaTemplatePlan setSchemaTemplatePlan1 =
+ new CommitSetSchemaTemplatePlan("t1", "root.sg.t1");
+ CommitSetSchemaTemplatePlan setSchemaTemplatePlan2 =
+ new CommitSetSchemaTemplatePlan("t2", "root.a.sg.t1");
+ clusterSchemaInfo.preSetSchemaTemplate(preSetSchemaTemplatePlan1);
+ clusterSchemaInfo.preSetSchemaTemplate(preSetSchemaTemplatePlan2);
+ clusterSchemaInfo.commitSetSchemaTemplate(setSchemaTemplatePlan1);
+ clusterSchemaInfo.commitSetSchemaTemplate(setSchemaTemplatePlan2);
+ answerSet.add(setSchemaTemplatePlan1.hashCode());
+ answerSet.add(setSchemaTemplatePlan1.hashCode());
+
+ boolean success = clusterSchemaInfo.processTakeSnapshot(snapshotDir);
+ Assert.assertTrue(success);
+ File schemaInfo =
+ SystemFileFactory.INSTANCE.getFile(snapshotDir + File.separator +
SCHEMA_INFO_FILE_NAME);
+ File templateInfo =
+ SystemFileFactory.INSTANCE.getFile(snapshotDir + File.separator +
TEMPLATE_INFO_FILE_NAME);
+ CNPhysicalPlanGenerator planGenerator =
+ new CNPhysicalPlanGenerator(schemaInfo.toPath(),
templateInfo.toPath());
+ int count = 0;
+ for (ConfigPhysicalPlan plan : planGenerator) {
+ if (plan.getType() == ConfigPhysicalPlanType.CreateDatabase) {
+ Assert.assertTrue(answerSet.contains(((DatabaseSchemaPlan)
plan).hashCode()));
+ } else if (plan.getType() == ConfigPhysicalPlanType.SetTTL) {
+ Assert.assertTrue(answerSet.contains(((SetTTLPlan) plan).hashCode()));
+ } else if (plan.getType() ==
ConfigPhysicalPlanType.CreateSchemaTemplate) {
+ Assert.assertTrue(answerSet.contains(((CreateSchemaTemplatePlan)
plan).hashCode()));
+ } else if (plan.getType() ==
ConfigPhysicalPlanType.PreSetSchemaTemplate) {
+ Assert.assertTrue(answerSet.contains(((PreSetSchemaTemplatePlan)
plan).hashCode()));
+ } else if (plan.getType() ==
ConfigPhysicalPlanType.CommitSetSchemaTemplate) {
+ Assert.assertTrue(answerSet.contains(((CommitSetSchemaTemplatePlan)
plan).hashCode()));
+ }
+ count++;
+ }
+ Assert.assertEquals(12, count);
+ }
+}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/schema/SRStatementGenerator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/schema/SRStatementGenerator.java
index ced730c1d3c..78a42312d20 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/schema/SRStatementGenerator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/schema/SRStatementGenerator.java
@@ -26,10 +26,12 @@ import
org.apache.iotdb.commons.schema.node.common.AbstractDatabaseMNode;
import org.apache.iotdb.commons.schema.node.common.AbstractMeasurementMNode;
import org.apache.iotdb.commons.schema.node.utils.IMNodeContainer;
import org.apache.iotdb.commons.schema.node.visitor.MNodeVisitor;
+import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ActivateTemplateStatement;
+import
org.apache.iotdb.db.queryengine.plan.statement.metadata.view.CreateLogicalViewStatement;
import
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.IMemMNode;
import
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.snapshot.MemMTreeSnapshotUtil;
import org.apache.iotdb.tsfile.utils.Pair;
@@ -46,6 +48,7 @@ import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayDeque;
+import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
@@ -270,8 +273,14 @@ public class SRStatementGenerator implements
Iterator<Statement>, Iterable<State
@Override
public Statement visitMeasurementMNode(
AbstractMeasurementMNode<?, ? extends IMNode<?>> node, PartialPath
path) {
- if (node.isLogicalView() ||
node.getParent().getAsDeviceMNode().isAligned()) {
+ if (node.getParent().getAsDeviceMNode().isAligned()) {
return null;
+ } else if (node.isLogicalView()) {
+ CreateLogicalViewStatement stmt = new CreateLogicalViewStatement();
+ LogicalViewSchema viewSchema = (LogicalViewSchema)
node.getAsMeasurementMNode().getSchema();
+ stmt.setTargetFullPaths(Collections.singletonList(path));
+
stmt.setViewExpressions(Collections.singletonList(viewSchema.getExpression()));
+ return stmt;
} else {
CreateTimeSeriesStatement stmt = new CreateTimeSeriesStatement();
stmt.setPath(path);
@@ -279,7 +288,7 @@ public class SRStatementGenerator implements
Iterator<Statement>, Iterable<State
stmt.setCompressor(node.getAsMeasurementMNode().getSchema().getCompressor());
stmt.setDataType(node.getDataType());
stmt.setEncoding(node.getAsMeasurementMNode().getSchema().getEncodingType());
- if (node.getOffset() != 0) {
+ if (node.getOffset() >= 0) {
if (tagFileChannel != null) {
try {
ByteBuffer byteBuffer =
ByteBuffer.allocate(COMMON_CONFIG.getTagAttributeTotalSize());
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/SchemaRegionSnapshotParserTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/SchemaRegionSnapshotParserTest.java
index d0d48b09027..1a676aec9f6 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/SchemaRegionSnapshotParserTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/SchemaRegionSnapshotParserTest.java
@@ -588,7 +588,7 @@ public class SchemaRegionSnapshotParserTest {
}));
for (ISchemaRegionPlan plan : planMap.values()) {
if (plan instanceof ICreateTimeSeriesPlan) {
- schemaRegion.createTimeseries((ICreateTimeSeriesPlan) plan, 0);
+ schemaRegion.createTimeseries((ICreateTimeSeriesPlan) plan, -1);
} else if (plan instanceof ICreateAlignedTimeSeriesPlan) {
schemaRegion.createAlignedTimeSeries((ICreateAlignedTimeSeriesPlan)
plan);
} else if (plan instanceof IActivateTemplateInClusterPlan) {
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PathPrivilege.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PathPrivilege.java
index 4311be521f5..e54ca063199 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PathPrivilege.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PathPrivilege.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.commons.auth.entity;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.path.PathDeserializeUtil;
+import org.apache.iotdb.commons.utils.AuthUtils;
import org.apache.iotdb.commons.utils.SerializeUtils;
import org.slf4j.Logger;
@@ -113,43 +114,13 @@ public class PathPrivilege {
return false;
}
- private int posToPri(int pos) {
- switch (pos) {
- case 0:
- return PrivilegeType.READ_DATA.ordinal();
- case 1:
- return PrivilegeType.WRITE_DATA.ordinal();
- case 2:
- return PrivilegeType.READ_SCHEMA.ordinal();
- case 3:
- return PrivilegeType.WRITE_SCHEMA.ordinal();
- default:
- return -1;
- }
- }
-
- private int priToPos(PrivilegeType pri) {
- switch (pri) {
- case READ_DATA:
- return 0;
- case WRITE_DATA:
- return 1;
- case READ_SCHEMA:
- return 2;
- case WRITE_SCHEMA:
- return 3;
- default:
- return -1;
- }
- }
-
public void setAllPrivileges(int privs) {
for (int i = 0; i < PATH_PRI_SIZE; i++) {
if (((1 << i) & privs) != 0) {
- privileges.add(posToPri(i));
+ privileges.add(AuthUtils.pathPosToPri(i));
}
- if (((1 << (i + 16) & privs) != 0)) {
- grantOpts.add(posToPri(i));
+ if ((1 << (i + 16) & privs) != 0) {
+ grantOpts.add(AuthUtils.pathPosToPri(i));
}
}
}
@@ -157,10 +128,10 @@ public class PathPrivilege {
public int getAllPrivileges() {
int privilege = 0;
for (Integer pri : privileges) {
- privilege |= 1 << priToPos(PrivilegeType.values()[pri]);
+ privilege |= 1 << AuthUtils.pathPriToPos(PrivilegeType.values()[pri]);
}
for (Integer grantOpt : grantOpts) {
- privilege |= 1 << (priToPos(PrivilegeType.values()[grantOpt]) + 16);
+ privilege |= 1 <<
(AuthUtils.pathPriToPos(PrivilegeType.values()[grantOpt]) + 16);
}
return privilege;
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
index 2fbd4914af0..017d6d0db9f 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/Role.java
@@ -81,10 +81,10 @@ public class Role {
public int getAllSysPrivileges() {
int privs = 0;
for (Integer sysPri : sysPrivilegeSet) {
- privs |= 1 << sysPriTopos(sysPri);
+ privs |= 1 << AuthUtils.sysPriTopos(sysPri);
}
for (Integer sysGrantOpt : sysPriGrantOpt) {
- privs |= 1 << (sysPriTopos(sysGrantOpt) + 16);
+ privs |= 1 << (AuthUtils.sysPriTopos(sysGrantOpt) + 16);
}
return privs;
}
@@ -126,61 +126,6 @@ public class Role {
this.sysPriGrantOpt = grantOpt;
}
- private int posToSysPri(int pos) {
- switch (pos) {
- case 0:
- return PrivilegeType.MANAGE_DATABASE.ordinal();
- case 1:
- return PrivilegeType.MANAGE_USER.ordinal();
- case 2:
- return PrivilegeType.MANAGE_ROLE.ordinal();
- case 3:
- return PrivilegeType.USE_TRIGGER.ordinal();
- case 4:
- return PrivilegeType.USE_UDF.ordinal();
- case 5:
- return PrivilegeType.USE_CQ.ordinal();
- case 6:
- return PrivilegeType.USE_PIPE.ordinal();
- case 7:
- return PrivilegeType.EXTEND_TEMPLATE.ordinal();
- case 8:
- return PrivilegeType.MAINTAIN.ordinal();
- case 9:
- return PrivilegeType.USE_MODEL.ordinal();
- default:
- return -1;
- }
- }
-
- private int sysPriTopos(int privilegeId) {
- PrivilegeType type = PrivilegeType.values()[privilegeId];
- switch (type) {
- case MANAGE_DATABASE:
- return 0;
- case MANAGE_USER:
- return 1;
- case MANAGE_ROLE:
- return 2;
- case USE_TRIGGER:
- return 3;
- case USE_UDF:
- return 4;
- case USE_CQ:
- return 5;
- case USE_PIPE:
- return 6;
- case EXTEND_TEMPLATE:
- return 7;
- case MAINTAIN:
- return 8;
- case USE_MODEL:
- return 9;
- default:
- return -1;
- }
- }
-
public void setSysPrivilegeSet(int privilegeMask) {
if (sysPrivilegeSet == null) {
sysPrivilegeSet = new HashSet<>();
@@ -190,10 +135,10 @@ public class Role {
}
for (int i = 0; i < SYS_PRI_SIZE; i++) {
if ((privilegeMask & (1 << i)) != 0) {
- sysPrivilegeSet.add(posToSysPri(i));
+ sysPrivilegeSet.add(AuthUtils.posToSysPri(i));
}
if ((privilegeMask & (1 << (i + 16))) != 0) {
- sysPriGrantOpt.add(posToSysPri(i));
+ sysPriGrantOpt.add(AuthUtils.posToSysPri(i));
}
}
}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
index 87e277ac76e..f4079b4dd15 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java
@@ -490,4 +490,89 @@ public class AuthUtils {
}
role.setServiceReady(true);
}
+
+ public static int posToSysPri(int pos) {
+ switch (pos) {
+ case 0:
+ return PrivilegeType.MANAGE_DATABASE.ordinal();
+ case 1:
+ return PrivilegeType.MANAGE_USER.ordinal();
+ case 2:
+ return PrivilegeType.MANAGE_ROLE.ordinal();
+ case 3:
+ return PrivilegeType.USE_TRIGGER.ordinal();
+ case 4:
+ return PrivilegeType.USE_UDF.ordinal();
+ case 5:
+ return PrivilegeType.USE_CQ.ordinal();
+ case 6:
+ return PrivilegeType.USE_PIPE.ordinal();
+ case 7:
+ return PrivilegeType.EXTEND_TEMPLATE.ordinal();
+ case 8:
+ return PrivilegeType.MAINTAIN.ordinal();
+ case 9:
+ return PrivilegeType.USE_MODEL.ordinal();
+ default:
+ return -1;
+ }
+ }
+
+ public static int sysPriTopos(int privilegeId) {
+ PrivilegeType type = PrivilegeType.values()[privilegeId];
+ switch (type) {
+ case MANAGE_DATABASE:
+ return 0;
+ case MANAGE_USER:
+ return 1;
+ case MANAGE_ROLE:
+ return 2;
+ case USE_TRIGGER:
+ return 3;
+ case USE_UDF:
+ return 4;
+ case USE_CQ:
+ return 5;
+ case USE_PIPE:
+ return 6;
+ case EXTEND_TEMPLATE:
+ return 7;
+ case MAINTAIN:
+ return 8;
+ case USE_MODEL:
+ return 9;
+ default:
+ return -1;
+ }
+ }
+
+ public static int pathPosToPri(int pos) {
+ switch (pos) {
+ case 0:
+ return PrivilegeType.READ_DATA.ordinal();
+ case 1:
+ return PrivilegeType.WRITE_DATA.ordinal();
+ case 2:
+ return PrivilegeType.READ_SCHEMA.ordinal();
+ case 3:
+ return PrivilegeType.WRITE_SCHEMA.ordinal();
+ default:
+ return -1;
+ }
+ }
+
+ public static int pathPriToPos(PrivilegeType pri) {
+ switch (pri) {
+ case READ_DATA:
+ return 0;
+ case WRITE_DATA:
+ return 1;
+ case READ_SCHEMA:
+ return 2;
+ case WRITE_SCHEMA:
+ return 3;
+ default:
+ return -1;
+ }
+ }
}