This is an automated email from the ASF dual-hosted git repository.

zyk 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 811f019a6e4 PBTree mode support logical view (#11401)
811f019a6e4 is described below

commit 811f019a6e40461a9f115282c7cf054fc7de2073
Author: Chen YZ <[email protected]>
AuthorDate: Mon Oct 30 14:48:36 2023 +0800

    PBTree mode support logical view (#11401)
---
 .../schema/mnode/factory/ConfigMNodeFactory.java   |   3 +-
 .../schemaregion/impl/SchemaRegionPBTreeImpl.java  |  74 +++++++++-
 .../mtree/impl/mem/MTreeBelowSGMemoryImpl.java     |   5 +-
 .../impl/mem/mnode/factory/MemMNodeFactory.java    |   3 +-
 .../impl/mem/snapshot/MemMTreeSnapshotUtil.java    |   3 +-
 .../mtree/impl/pbtree/MTreeBelowSGCachedImpl.java  | 164 ++++++++++++++++++++-
 .../mnode/container/ICachedMNodeContainer.java     |   2 +-
 .../pbtree/mnode/factory/CacheMNodeFactory.java    |   3 +-
 .../mtree/impl/pbtree/schemafile/RecordUtils.java  |  97 ++++++++++--
 .../commons/schema/node/utils/IMNodeFactory.java   |   3 +-
 10 files changed, 319 insertions(+), 38 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/factory/ConfigMNodeFactory.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/factory/ConfigMNodeFactory.java
index 362c39321d7..cd19f87d180 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/factory/ConfigMNodeFactory.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/factory/ConfigMNodeFactory.java
@@ -18,7 +18,6 @@
  */
 package org.apache.iotdb.confignode.persistence.schema.mnode.factory;
 
-import org.apache.iotdb.commons.schema.node.info.IMeasurementInfo;
 import org.apache.iotdb.commons.schema.node.role.IDatabaseMNode;
 import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
@@ -84,7 +83,7 @@ public class ConfigMNodeFactory implements 
IMNodeFactory<IConfigMNode> {
 
   @Override
   public IMeasurementMNode<IConfigMNode> createLogicalViewMNode(
-      IDeviceMNode<IConfigMNode> parent, String name, IMeasurementInfo 
measurementInfo) {
+      IDeviceMNode<IConfigMNode> parent, String name, IMeasurementSchema 
measurementSchema) {
     throw new UnsupportedOperationException("View is not supported.");
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
index 8e43a1c85b7..e6df581b29f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.commons.schema.SchemaConstant;
 import org.apache.iotdb.commons.schema.filter.SchemaFilterType;
 import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
+import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
 import org.apache.iotdb.consensus.ConsensusFactory;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
@@ -837,30 +838,89 @@ public class SchemaRegionPBTreeImpl implements 
ISchemaRegion {
   }
 
   @Override
-  public void createLogicalView(ICreateLogicalViewPlan createLogicalViewPlan)
-      throws MetadataException {
-    throw new UnsupportedOperationException("createLogicalView is 
unsupported.");
+  public void createLogicalView(ICreateLogicalViewPlan plan) throws 
MetadataException {
+    while (!regionStatistics.isAllowToCreateNewSeries()) {
+      CacheMemoryManager.getInstance().waitIfReleasing();
+    }
+    try {
+      List<PartialPath> pathList = plan.getViewPathList();
+      Map<PartialPath, ViewExpression> viewPathToSourceMap =
+          plan.getViewPathToSourceExpressionMap();
+      for (PartialPath path : pathList) {
+        ViewExpression viewExpression = viewPathToSourceMap.get(path);
+        mtree.createLogicalView(path, viewExpression);
+        // write log
+        if (!isRecovering) {
+          
writeToMLog(SchemaRegionWritePlanFactory.getCreateLogicalViewPlan(path, 
viewExpression));
+        }
+        regionStatistics.addTimeseries(1L);
+      }
+    } catch (IOException e) {
+      throw new MetadataException(e);
+    }
   }
 
   @Override
   public long constructLogicalViewBlackList(PathPatternTree patternTree) 
throws MetadataException {
-    throw new UnsupportedOperationException();
+    long preDeletedNum = 0;
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      // Given pathPatterns may match one logical view multi times, which may 
results in the
+      // preDeletedNum larger than the actual num of logical view. It doesn't 
matter since the main
+      // purpose is to check whether there's logical view to be deleted.
+      List<PartialPath> paths = 
mtree.constructLogicalViewBlackList(pathPattern);
+      preDeletedNum += paths.size();
+      for (PartialPath path : paths) {
+        try {
+          
writeToMLog(SchemaRegionWritePlanFactory.getPreDeleteLogicalViewPlan(path));
+        } catch (IOException e) {
+          throw new MetadataException(e);
+        }
+      }
+    }
+    return preDeletedNum;
   }
 
   @Override
   public void rollbackLogicalViewBlackList(PathPatternTree patternTree) throws 
MetadataException {
-    throw new UnsupportedOperationException();
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      List<PartialPath> paths = 
mtree.rollbackLogicalViewBlackList(pathPattern);
+      for (PartialPath path : paths) {
+        try {
+          
writeToMLog(SchemaRegionWritePlanFactory.getRollbackPreDeleteLogicalViewPlan(path));
+        } catch (IOException e) {
+          throw new MetadataException(e);
+        }
+      }
+    }
   }
 
   @Override
   public void deleteLogicalView(PathPatternTree patternTree) throws 
MetadataException {
-    throw new UnsupportedOperationException();
+    for (PartialPath pathPattern : patternTree.getAllPathPatterns()) {
+      for (PartialPath path : mtree.getPreDeletedLogicalView(pathPattern)) {
+        try {
+          deleteSingleTimeseriesInBlackList(path);
+          
writeToMLog(SchemaRegionWritePlanFactory.getDeleteLogicalViewPlan(path));
+        } catch (IOException e) {
+          throw new MetadataException(e);
+        }
+      }
+    }
   }
 
   @Override
   public void alterLogicalView(IAlterLogicalViewPlan alterLogicalViewPlan)
       throws MetadataException {
-    throw new UnsupportedOperationException();
+    mtree.alterLogicalView(
+        alterLogicalViewPlan.getViewPath(), 
alterLogicalViewPlan.getSourceExpression());
+    // write log
+    if (!isRecovering) {
+      try {
+        writeToMLog(alterLogicalViewPlan);
+      } catch (IOException e) {
+        throw new MetadataException(e);
+      }
+    }
   }
 
   private void deleteSingleTimeseriesInBlackList(PartialPath path)
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
index 2e5a2034fd6..7b9bae66af6 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java
@@ -44,7 +44,6 @@ import 
org.apache.iotdb.db.exception.metadata.template.TemplateIsInUseException;
 import org.apache.iotdb.db.exception.quota.ExceedQuotaException;
 import org.apache.iotdb.db.schemaengine.rescon.MemSchemaRegionStatistics;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.IMemMNode;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.info.LogicalViewInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.loader.MNodeFactoryLoader;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.traverser.collector.EntityCollector;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.traverser.collector.MNodeCollector;
@@ -348,7 +347,7 @@ public class MTreeBelowSGMemoryImpl {
         }
       }
 
-      // create a non-aligned timeseries
+      // create a aligned timeseries
       if (entityMNode.isAlignedNullable() == null) {
         entityMNode.setAligned(true);
       }
@@ -1125,7 +1124,7 @@ public class MTreeBelowSGMemoryImpl {
       String leafName = path.getMeasurement();
       IMeasurementMNode<IMemMNode> measurementMNode =
           nodeFactory.createLogicalViewMNode(
-              null, leafName, new LogicalViewInfo(new 
LogicalViewSchema(leafName, viewExpression)));
+              null, leafName, new LogicalViewSchema(leafName, viewExpression));
       IMemMNode device = 
checkAndAutoCreateDeviceNode(devicePath.getTailNode(), deviceParent);
 
       // no need to check alias, because logical view has no alias
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/mnode/factory/MemMNodeFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/mnode/factory/MemMNodeFactory.java
index 62f700c398c..05c3e403506 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/mnode/factory/MemMNodeFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/mnode/factory/MemMNodeFactory.java
@@ -18,7 +18,6 @@
  */
 package 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.factory;
 
-import org.apache.iotdb.commons.schema.node.info.IMeasurementInfo;
 import org.apache.iotdb.commons.schema.node.role.IDatabaseMNode;
 import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
@@ -75,7 +74,7 @@ public class MemMNodeFactory implements 
IMNodeFactory<IMemMNode> {
 
   @Override
   public IMeasurementMNode<IMemMNode> createLogicalViewMNode(
-      IDeviceMNode<IMemMNode> parent, String name, IMeasurementInfo 
measurementInfo) {
+      IDeviceMNode<IMemMNode> parent, String name, IMeasurementSchema 
measurementSchema) {
     throw new UnsupportedOperationException("View is not supported.");
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/snapshot/MemMTreeSnapshotUtil.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/snapshot/MemMTreeSnapshotUtil.java
index a0a887ce9a9..7b337246e7e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/snapshot/MemMTreeSnapshotUtil.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/snapshot/MemMTreeSnapshotUtil.java
@@ -36,7 +36,6 @@ import org.apache.iotdb.commons.utils.FileUtils;
 import org.apache.iotdb.db.schemaengine.rescon.MemSchemaRegionStatistics;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.MemMTreeStore;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.IMemMNode;
-import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.info.LogicalViewInfo;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.loader.MNodeFactoryLoader;
 import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
@@ -427,7 +426,7 @@ public class MemMTreeSnapshotUtil {
       LogicalViewSchema logicalViewSchema = 
LogicalViewSchema.deserializeFrom(inputStream);
       long tagOffset = ReadWriteIOUtils.readLong(inputStream);
       IMeasurementMNode<IMemMNode> node =
-          nodeFactory.createLogicalViewMNode(null, name, new 
LogicalViewInfo(logicalViewSchema));
+          nodeFactory.createLogicalViewMNode(null, name, logicalViewSchema);
       node.setOffset(tagOffset);
       node.setPreDeleted(ReadWriteIOUtils.readBool(inputStream));
       return node.getAsMNode();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java
index b7cd06744c8..138823eaf7b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java
@@ -29,6 +29,8 @@ import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
 import org.apache.iotdb.commons.schema.node.utils.IMNodeFactory;
 import org.apache.iotdb.commons.schema.node.utils.IMNodeIterator;
+import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
+import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
 import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.AlignedTimeseriesException;
 import org.apache.iotdb.db.exception.metadata.MNodeTypeMismatchException;
@@ -300,7 +302,9 @@ public class MTreeBelowSGCachedImpl {
             throw new PathAlreadyExistException(path.getFullPath());
           }
 
-          if (device.isDevice() && device.getAsDeviceMNode().isAligned()) {
+          if (device.isDevice()
+              && device.getAsDeviceMNode().isAlignedNullable() != null
+              && device.getAsDeviceMNode().isAligned()) {
             throw new AlignedTimeseriesException(
                 "timeseries under this device is aligned, please use 
createAlignedTimeseries or change device.",
                 device.getFullPath());
@@ -317,6 +321,11 @@ public class MTreeBelowSGCachedImpl {
             device = entityMNode.getAsMNode();
           }
 
+          // create a non-aligned timeseries
+          if (entityMNode.isAlignedNullable() == null) {
+            entityMNode.setAligned(false);
+          }
+
           IMeasurementMNode<ICachedMNode> measurementMNode =
               nodeFactory.createMeasurementMNode(
                   entityMNode,
@@ -382,7 +391,9 @@ public class MTreeBelowSGCachedImpl {
             }
           }
 
-          if (device.isDevice() && !device.getAsDeviceMNode().isAligned()) {
+          if (device.isDevice()
+              && device.getAsDeviceMNode().isAlignedNullable() != null
+              && !device.getAsDeviceMNode().isAligned()) {
             throw new AlignedTimeseriesException(
                 "Timeseries under this device is not aligned, please use 
createTimeseries or change device.",
                 devicePath.getFullPath());
@@ -400,6 +411,11 @@ public class MTreeBelowSGCachedImpl {
             device = entityMNode.getAsMNode();
           }
 
+          // create a aligned timeseries
+          if (entityMNode.isAlignedNullable() == null) {
+            entityMNode.setAligned(true);
+          }
+
           for (int i = 0; i < measurements.size(); i++) {
             IMeasurementMNode<ICachedMNode> measurementMNode =
                 nodeFactory.createMeasurementMNode(
@@ -602,6 +618,7 @@ public class MTreeBelowSGCachedImpl {
     ICachedMNode curNode = entityMNode.getAsMNode();
     if (!entityMNode.isUseTemplate()) {
       boolean hasMeasurement = false;
+      boolean hasNonViewMeasurement = false;
       ICachedMNode child;
       IMNodeIterator<ICachedMNode> iterator = 
store.getChildrenIterator(curNode);
       try {
@@ -610,7 +627,10 @@ public class MTreeBelowSGCachedImpl {
           unPinMNode(child);
           if (child.isMeasurement()) {
             hasMeasurement = true;
-            break;
+            if (!child.getAsMeasurementMNode().isLogicalView()) {
+              hasNonViewMeasurement = true;
+              break;
+            }
           }
         }
       } finally {
@@ -624,6 +644,10 @@ public class MTreeBelowSGCachedImpl {
             replaceStorageGroupMNode(curNode.getAsDatabaseMNode());
           }
         }
+      } else if (!hasNonViewMeasurement) {
+        // has some measurement but they are all logical view
+        entityMNode.setAligned(null);
+        updateMNode(entityMNode.getAsMNode());
       }
     }
 
@@ -863,6 +887,140 @@ public class MTreeBelowSGCachedImpl {
   }
   // endregion
 
+  // region Interfaces and Implementation for Logical View
+
+  public void createLogicalView(PartialPath path, ViewExpression 
viewExpression)
+      throws MetadataException {
+    String[] nodeNames = path.getNodes();
+    if (nodeNames.length <= 2) {
+      throw new IllegalPathException(path.getFullPath());
+    }
+    MetaFormatUtils.checkTimeseries(path);
+    PartialPath devicePath = path.getDevicePath();
+    ICachedMNode deviceParent = checkAndAutoCreateInternalPath(devicePath);
+
+    try {
+      // synchronize check and add, we need addChild and add Alias become 
atomic operation
+      // only write on mtree will be synchronized
+      synchronized (this) {
+        ICachedMNode device = 
checkAndAutoCreateDeviceNode(devicePath.getTailNode(), deviceParent);
+        try {
+          String leafName = path.getMeasurement();
+          if (device.hasChild(leafName)) {
+            ICachedMNode node = device.getChild(leafName);
+            if (node.isMeasurement()) {
+              if (node.getAsMeasurementMNode().isPreDeleted()) {
+                throw new MeasurementInBlackListException(path);
+              } else {
+                throw new MeasurementAlreadyExistException(
+                    path.getFullPath(), 
node.getAsMeasurementMNode().getMeasurementPath());
+              }
+            } else {
+              throw new PathAlreadyExistException(path.getFullPath());
+            }
+          }
+
+          IDeviceMNode<ICachedMNode> entityMNode;
+          if (device.isDevice()) {
+            entityMNode = device.getAsDeviceMNode();
+          } else {
+            entityMNode = store.setToEntity(device);
+            if (entityMNode.isDatabase()) {
+              replaceStorageGroupMNode(entityMNode.getAsDatabaseMNode());
+            }
+            device = entityMNode.getAsMNode();
+          }
+
+          IMeasurementMNode<ICachedMNode> viewMNode =
+              nodeFactory.createLogicalViewMNode(
+                  entityMNode, leafName, new LogicalViewSchema(leafName, 
viewExpression));
+          store.addChild(entityMNode.getAsMNode(), leafName, 
viewMNode.getAsMNode());
+          unPinMNode(viewMNode.getAsMNode());
+        } finally {
+          unPinMNode(device);
+        }
+      }
+    } finally {
+      if (deviceParent != null) {
+        unPinMNode(deviceParent);
+      }
+    }
+  }
+
+  public List<PartialPath> constructLogicalViewBlackList(PartialPath 
pathPattern)
+      throws MetadataException {
+    List<PartialPath> result = new ArrayList<>();
+    try (MeasurementUpdater<ICachedMNode> updater =
+        new MeasurementUpdater<ICachedMNode>(
+            rootNode, pathPattern, store, false, 
SchemaConstant.ALL_MATCH_SCOPE) {
+          protected void updateMeasurement(IMeasurementMNode<ICachedMNode> 
node)
+              throws MetadataException {
+            if (node.isLogicalView()) {
+              node.setPreDeleted(true);
+              store.updateMNode(node.getAsMNode());
+              result.add(getPartialPathFromRootToNode(node.getAsMNode()));
+            }
+          }
+        }) {
+      updater.update();
+    }
+    return result;
+  }
+
+  public List<PartialPath> rollbackLogicalViewBlackList(PartialPath 
pathPattern)
+      throws MetadataException {
+    List<PartialPath> result = new ArrayList<>();
+    try (MeasurementUpdater<ICachedMNode> updater =
+        new MeasurementUpdater<ICachedMNode>(
+            rootNode, pathPattern, store, false, 
SchemaConstant.ALL_MATCH_SCOPE) {
+          protected void updateMeasurement(IMeasurementMNode<ICachedMNode> 
node)
+              throws MetadataException {
+            if (node.isLogicalView()) {
+              node.setPreDeleted(false);
+              store.updateMNode(node.getAsMNode());
+              result.add(getPartialPathFromRootToNode(node.getAsMNode()));
+            }
+          }
+        }) {
+      updater.update();
+    }
+    return result;
+  }
+
+  public List<PartialPath> getPreDeletedLogicalView(PartialPath pathPattern)
+      throws MetadataException {
+    List<PartialPath> result = new LinkedList<>();
+    try (MeasurementCollector<Void, ICachedMNode> collector =
+        new MeasurementCollector<Void, ICachedMNode>(
+            rootNode, pathPattern, store, false, 
SchemaConstant.ALL_MATCH_SCOPE) {
+          protected Void collectMeasurement(IMeasurementMNode<ICachedMNode> 
node) {
+            if (node.isLogicalView() && node.isPreDeleted()) {
+              result.add(getPartialPathFromRootToNode(node.getAsMNode()));
+            }
+            return null;
+          }
+        }) {
+      collector.traverse();
+    }
+    return result;
+  }
+
+  public void alterLogicalView(PartialPath path, ViewExpression expression)
+      throws MetadataException {
+    IMeasurementMNode<ICachedMNode> leafMNode = getMeasurementMNode(path);
+    try {
+      if (!leafMNode.isLogicalView()) {
+        throw new MetadataException(String.format("[%s] is no view.", path));
+      }
+      leafMNode.setSchema(new LogicalViewSchema(leafMNode.getName(), 
expression));
+      updateMNode(leafMNode.getAsMNode());
+    } finally {
+      unPinMNode(leafMNode.getAsMNode());
+    }
+  }
+
+  // endregion
+
   // region Interfaces and Implementation for Template check and query
 
   public void activateTemplate(PartialPath activatePath, Template template)
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/container/ICachedMNodeContainer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/container/ICachedMNodeContainer.java
index 5f48ea5d706..719ea62a7dd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/container/ICachedMNodeContainer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/container/ICachedMNodeContainer.java
@@ -74,6 +74,6 @@ public interface ICachedMNodeContainer extends 
IMNodeContainer<ICachedMNode> {
   }
 
   static ICachedMNodeContainer getBelongedContainer(ICachedMNode node) {
-    return (ICachedMNodeContainer) node.getParent().getChildren();
+    return getCachedMNodeContainer(node.getParent());
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/factory/CacheMNodeFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/factory/CacheMNodeFactory.java
index c6beaea4efd..faa19842007 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/factory/CacheMNodeFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/mnode/factory/CacheMNodeFactory.java
@@ -18,7 +18,6 @@
  */
 package 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.pbtree.mnode.factory;
 
-import org.apache.iotdb.commons.schema.node.info.IMeasurementInfo;
 import org.apache.iotdb.commons.schema.node.role.IDatabaseMNode;
 import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
@@ -75,7 +74,7 @@ public class CacheMNodeFactory implements 
IMNodeFactory<ICachedMNode> {
 
   @Override
   public IMeasurementMNode<ICachedMNode> createLogicalViewMNode(
-      IDeviceMNode<ICachedMNode> parent, String name, IMeasurementInfo 
measurementInfo) {
+      IDeviceMNode<ICachedMNode> parent, String name, IMeasurementSchema 
measurementSchema) {
     throw new UnsupportedOperationException("View is not supported.");
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/schemafile/RecordUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/schemafile/RecordUtils.java
index 6dd056291a4..ac2e2b8c6bb 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/schemafile/RecordUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/schemafile/RecordUtils.java
@@ -22,6 +22,8 @@ import org.apache.iotdb.commons.exception.MetadataException;
 import org.apache.iotdb.commons.schema.SchemaConstant;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
 import org.apache.iotdb.commons.schema.node.utils.IMNodeFactory;
+import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
+import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
 import org.apache.iotdb.commons.utils.TestOnly;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.pbtree.mnode.ICachedMNode;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.pbtree.mnode.container.ICachedMNodeContainer;
@@ -33,6 +35,8 @@ import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Map;
 
@@ -50,6 +54,7 @@ public class RecordUtils {
       (short) 1 + 2 + 8 + 4 + 1; // always fixed length record
   private static final short MEASUREMENT_BASIC_LENGTH =
       (short) 1 + 2 + 8 + 8; // final length depends on its alias and props
+  private static final short VIEW_BASIC_LENGTH = (short) 1 + 2 + 8 + 1;
 
   /** These offset rather than magic number may also be used to track usage of 
related field. */
   private static final short LENGTH_OFFSET = 1;
@@ -62,13 +67,19 @@ public class RecordUtils {
   private static final byte INTERNAL_TYPE = 0;
   private static final byte ENTITY_TYPE = 1;
   private static final byte MEASUREMENT_TYPE = 4;
+  private static final byte VIEW_TYPE = 5;
 
   private static final IMNodeFactory<ICachedMNode> nodeFactory =
       MNodeFactoryLoader.getInstance().getCachedMNodeIMNodeFactory();
 
   public static ByteBuffer node2Buffer(ICachedMNode node) {
     if (node.isMeasurement()) {
-      return measurement2Buffer(node.getAsMeasurementMNode());
+      IMeasurementMNode<ICachedMNode> measurementMNode = 
node.getAsMeasurementMNode();
+      if (measurementMNode.isLogicalView()) {
+        return view2Buffer(measurementMNode);
+      } else {
+        return measurement2Buffer(measurementMNode);
+      }
     } else {
       return internal2Buffer(node);
     }
@@ -90,7 +101,7 @@ public class RecordUtils {
    *
    * <ul>
    *   <li>1 bit : usingTemplate, whether using template
-   *   <li>1 bit : isAligned
+   *   <li>2 bit : isAligned (00 for not aligned, 01 for aligned, 10 for null)
    * </ul>
    *
    * @param node
@@ -98,13 +109,13 @@ public class RecordUtils {
    */
   private static ByteBuffer internal2Buffer(ICachedMNode node) {
     byte nodeType = INTERNAL_TYPE;
-    boolean isAligned = false;
+    Boolean isAligned = null;
     int schemaTemplateIdWithState = SchemaConstant.NON_TEMPLATE;
     boolean isUseTemplate = false;
 
     if (node.isDevice()) {
       nodeType = ENTITY_TYPE;
-      isAligned = node.getAsDeviceMNode().isAligned();
+      isAligned = node.getAsDeviceMNode().isAlignedNullable();
       schemaTemplateIdWithState = 
node.getAsDeviceMNode().getSchemaTemplateIdWithState();
       isUseTemplate = node.getAsDeviceMNode().isUseTemplate();
     }
@@ -154,9 +165,8 @@ public class RecordUtils {
         bufferLength += 8 + e.getKey().getBytes().length + 
e.getValue().length();
       }
     }
-
+    // normal measurement
     ByteBuffer buffer = ByteBuffer.allocate(bufferLength);
-
     ReadWriteIOUtils.write(MEASUREMENT_TYPE, buffer);
     ReadWriteIOUtils.write((short) bufferLength, buffer);
     ReadWriteIOUtils.write(convertTags2Long(node), buffer);
@@ -166,6 +176,41 @@ public class RecordUtils {
     return buffer;
   }
 
+  /**
+   * LogicalView MNode Record Structure: <br>
+   * (var length record, with length member)
+   *
+   * <ul>
+   *   <li>1 byte: nodeType, as above
+   *   <li>1 short (2 bytes): recLength, length of whole record
+   *   <li>1 long (8 bytes): tagIndex, value of the offset within a measurement
+   *   <li>1 boolean (1 bytes): statusBytes, isPreDeleted
+   *   <li>var length ViewExpression
+   * </ul>
+   */
+  private static ByteBuffer view2Buffer(IMeasurementMNode<ICachedMNode> node) {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    try {
+      ViewExpression.serialize(
+          ((LogicalViewSchema) node.getSchema()).getExpression(), 
byteArrayOutputStream);
+    } catch (IOException e) {
+      // ByteArrayOutputStream is a memory-based output stream that does not 
involve disk IO and
+      // will not throw an IOException except for OOM.
+      throw new RuntimeException(e);
+    }
+    byte[] expressionData = byteArrayOutputStream.toByteArray();
+
+    int bufferLength = VIEW_BASIC_LENGTH + expressionData.length;
+
+    ByteBuffer buffer = ByteBuffer.allocate(bufferLength);
+    ReadWriteIOUtils.write(VIEW_TYPE, buffer);
+    ReadWriteIOUtils.write((short) bufferLength, buffer);
+    ReadWriteIOUtils.write(convertTags2Long(node), buffer);
+    ReadWriteIOUtils.write(node.isPreDeleted(), buffer);
+    buffer.put(expressionData);
+    return buffer;
+  }
+
   /**
    * NOTICE: Make sure that buffer has set its position and limit clearly 
before pass to this
    * method.<br>
@@ -193,7 +238,7 @@ public class RecordUtils {
       byte bitFlag = ReadWriteIOUtils.readByte(buffer);
 
       boolean usingTemplate = usingTemplate(bitFlag);
-      boolean isAligned = isAligned(bitFlag);
+      Boolean isAligned = isAligned(bitFlag);
 
       if (nodeType == 0) {
         resNode = nodeFactory.createInternalMNode(null, nodeName);
@@ -207,16 +252,22 @@ public class RecordUtils {
       
ICachedMNodeContainer.getCachedMNodeContainer(resNode).setSegmentAddress(segAddr);
 
       return resNode;
-    } else {
+    } else if (nodeType == MEASUREMENT_TYPE) {
       // measurement node
       short recLenth = ReadWriteIOUtils.readShort(buffer);
       long tagIndex = ReadWriteIOUtils.readLong(buffer);
       long schemaByte = ReadWriteIOUtils.readLong(buffer);
       String alias = ReadWriteIOUtils.readString(buffer);
       Map<String, String> props = ReadWriteIOUtils.readMap(buffer);
-
       return paddingMeasurement(nodeName, tagIndex, schemaByte, alias, props);
+    } else if (nodeType == VIEW_TYPE) {
+      short recLenth = ReadWriteIOUtils.readShort(buffer);
+      long tagIndex = ReadWriteIOUtils.readLong(buffer);
+      boolean isPreDeleted = ReadWriteIOUtils.readBool(buffer);
+      ViewExpression viewExpression = ViewExpression.deserialize(buffer);
+      return paddingLogicalView(nodeName, tagIndex, isPreDeleted, 
viewExpression);
     }
+    throw new MetadataException("Unrecognized node type: " + nodeType);
   }
 
   // region Getter and Setter to Record Buffer
@@ -314,7 +365,9 @@ public class RecordUtils {
     } else if (node.isDevice()) {
       builder.append("entityNode, ");
 
-      if (node.getAsDeviceMNode().isAligned()) {
+      if (node.getAsDeviceMNode().isAlignedNullable() == null) {
+        builder.append("aligned is null, ");
+      } else if (node.getAsDeviceMNode().isAligned()) {
         builder.append("aligned, ");
       } else {
         builder.append("not aligned, ");
@@ -375,23 +428,39 @@ public class RecordUtils {
     return res;
   }
 
+  private static ICachedMNode paddingLogicalView(
+      String nodeName, long tagIndex, boolean isPreDeleted, ViewExpression 
viewExpression) {
+    IMeasurementSchema schema = new LogicalViewSchema(nodeName, 
viewExpression);
+    IMeasurementMNode<ICachedMNode> res =
+        nodeFactory.createLogicalViewMNode(null, nodeName, schema);
+    res.setOffset(tagIndex);
+    res.setPreDeleted(isPreDeleted);
+    return res.getAsMNode();
+  }
+
   // endregion
 
   // region codex for bit flag
 
-  private static byte encodeInternalStatus(boolean usingTemplate, boolean 
isAligned) {
+  private static byte encodeInternalStatus(boolean usingTemplate, Boolean 
isAligned) {
     byte flag = 0;
     if (usingTemplate) {
       flag |= 0x01;
     }
-    if (isAligned) {
+    if (isAligned == null) {
+      flag |= 0x04;
+    } else if (isAligned) {
       flag |= 0x02;
     }
     return flag;
   }
 
-  private static boolean isAligned(byte flag) {
-    return (flag & 0x02) == 2;
+  private static Boolean isAligned(byte flag) {
+    if ((flag & 0x04) != 0) {
+      return null;
+    } else {
+      return (flag & 0x02) == 2;
+    }
   }
 
   private static boolean usingTemplate(byte flag) {
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/node/utils/IMNodeFactory.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/node/utils/IMNodeFactory.java
index da7a3c1dc58..77645d3b9af 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/node/utils/IMNodeFactory.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/node/utils/IMNodeFactory.java
@@ -19,7 +19,6 @@
 package org.apache.iotdb.commons.schema.node.utils;
 
 import org.apache.iotdb.commons.schema.node.IMNode;
-import org.apache.iotdb.commons.schema.node.info.IMeasurementInfo;
 import org.apache.iotdb.commons.schema.node.role.IDatabaseMNode;
 import org.apache.iotdb.commons.schema.node.role.IDeviceMNode;
 import org.apache.iotdb.commons.schema.node.role.IMeasurementMNode;
@@ -42,5 +41,5 @@ public interface IMNodeFactory<N extends IMNode<N>> {
   N createInternalMNode(N parent, String name);
 
   IMeasurementMNode<N> createLogicalViewMNode(
-      IDeviceMNode<N> parent, String name, IMeasurementInfo measurementInfo);
+      IDeviceMNode<N> parent, String name, IMeasurementSchema 
measurementSchema);
 }

Reply via email to