You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ha...@apache.org on 2022/07/28 03:01:27 UTC

[iotdb] branch rel/0.13 updated: [To rel/0.13][IOTDB-3969]Fix timeseries statistic bug (#6808)

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

haonan pushed a commit to branch rel/0.13
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/0.13 by this push:
     new 010e65d5f1 [To rel/0.13][IOTDB-3969]Fix timeseries statistic bug (#6808)
010e65d5f1 is described below

commit 010e65d5f15583201d6eabb2ae63792d63891016
Author: Marcos_Zyk <38...@users.noreply.github.com>
AuthorDate: Thu Jul 28 11:01:21 2022 +0800

    [To rel/0.13][IOTDB-3969]Fix timeseries statistic bug (#6808)
---
 docs/UserGuide/Maintenance-Tools/Metric-Tool.md    |  2 +-
 docs/zh/UserGuide/Maintenance-Tools/Metric-Tool.md |  2 +-
 .../MeasurementInsideTemplateException.java        | 34 ++++++++
 .../org/apache/iotdb/db/metadata/MManager.java     | 74 ++++++++++++------
 .../org/apache/iotdb/db/metadata/mtree/MTree.java  | 10 ++-
 .../db/metadata/mtree/traverser/Traverser.java     |  4 +
 .../iotdb/db/metadata/MManagerBasicTest.java       | 90 +++++++++++++++++++++-
 7 files changed, 183 insertions(+), 33 deletions(-)

diff --git a/docs/UserGuide/Maintenance-Tools/Metric-Tool.md b/docs/UserGuide/Maintenance-Tools/Metric-Tool.md
index d7fa3ef222..689e91aaa9 100644
--- a/docs/UserGuide/Maintenance-Tools/Metric-Tool.md
+++ b/docs/UserGuide/Maintenance-Tools/Metric-Tool.md
@@ -111,7 +111,7 @@ Next, we will choose Prometheus format data as samples to describe each kind of
 
 | Metric   | Tag                                   | level     | Description                                                   | Sample                           |
 | -------- | ------------------------------------- | --------- | ------------------------------------------------------------- | -------------------------------- |
-| quantity | name="timeSeries/storageGroup/device" | important | The current count of timeSeries/storageGroup/devices in IoTDB | quantity{name="timeSeries",} 1.0 |
+| quantity | name="storageGroup/device";<br/>name="timeSeries", type="normal/template" | important | The current count of timeSeries/storageGroup/devices in IoTDB | quantity{name="timeSeries",type="normal"} 1.0 |
 
 #### 4.3.6. Cluster
 
diff --git a/docs/zh/UserGuide/Maintenance-Tools/Metric-Tool.md b/docs/zh/UserGuide/Maintenance-Tools/Metric-Tool.md
index 44be673b9c..05b68d2296 100644
--- a/docs/zh/UserGuide/Maintenance-Tools/Metric-Tool.md
+++ b/docs/zh/UserGuide/Maintenance-Tools/Metric-Tool.md
@@ -110,7 +110,7 @@ IoTDB对外提供JMX和Prometheus格式的监控指标,对于JMX,可以通
 
 | Metric   | Tag                                   | level     | 说明                                         | 示例                             |
 | -------- | ------------------------------------- | --------- | -------------------------------------------- | -------------------------------- |
-| quantity | name="timeSeries/storageGroup/device" | important | 当前时间timeSeries/storageGroup/device的数量 | quantity{name="timeSeries",} 1.0 |
+| quantity | name="timeSeries/storageGroup/device";<br/>name="timeSeries", type="normal/template"  | important | 当前时间timeSeries/storageGroup/device的数量 | quantity{name="timeSeries",type="normal"} 1.0 |
 
 #### 4.3.6. 集群
 
diff --git a/server/src/main/java/org/apache/iotdb/db/exception/metadata/MeasurementInsideTemplateException.java b/server/src/main/java/org/apache/iotdb/db/exception/metadata/MeasurementInsideTemplateException.java
new file mode 100644
index 0000000000..ba900102de
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/exception/metadata/MeasurementInsideTemplateException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.exception.metadata;
+
+public class MeasurementInsideTemplateException extends MetadataException {
+
+  private String path;
+
+  public MeasurementInsideTemplateException(String path) {
+    super(String.format("Cannot delete a timeseries inside a template: %s", path));
+    this.path = path;
+  }
+
+  public String getPath() {
+    return path;
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
index 2bb80ce64c..6996430acc 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.db.exception.metadata.DataTypeMismatchException;
 import org.apache.iotdb.db.exception.metadata.DeleteFailedException;
 import org.apache.iotdb.db.exception.metadata.DifferentTemplateException;
 import org.apache.iotdb.db.exception.metadata.MNodeTypeMismatchException;
+import org.apache.iotdb.db.exception.metadata.MeasurementInsideTemplateException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.metadata.NoTemplateOnMNodeException;
 import org.apache.iotdb.db.exception.metadata.PathAlreadyExistException;
@@ -185,7 +186,8 @@ public class MManager {
   private boolean initialized;
   private boolean allowToCreateNewSeries = true;
 
-  private AtomicLong totalSeriesNumber = new AtomicLong();
+  private AtomicLong totalNormalSeriesNumber = new AtomicLong();
+  private AtomicLong totalTemplateSeriesNumber = new AtomicLong();
 
   private final int mtreeSnapshotInterval;
   private final long mtreeSnapshotThresholdTime;
@@ -319,10 +321,24 @@ public class MManager {
         .getOrCreateAutoGauge(
             Metric.QUANTITY.toString(),
             MetricLevel.IMPORTANT,
-            totalSeriesNumber,
+            totalNormalSeriesNumber,
             AtomicLong::get,
             Tag.NAME.toString(),
-            "timeSeries");
+            "timeSeries",
+            Tag.TYPE.toString(),
+            "normal");
+
+    MetricsService.getInstance()
+        .getMetricManager()
+        .getOrCreateAutoGauge(
+            Metric.QUANTITY.toString(),
+            MetricLevel.IMPORTANT,
+            totalTemplateSeriesNumber,
+            AtomicLong::get,
+            Tag.NAME.toString(),
+            "timeSeries",
+            Tag.TYPE.toString(),
+            "template");
 
     MetricsService.getInstance()
         .getMetricManager()
@@ -445,7 +461,8 @@ public class MManager {
       if (this.mNodeCache != null) {
         this.mNodeCache.invalidateAll();
       }
-      this.totalSeriesNumber.set(0);
+      this.totalNormalSeriesNumber.set(0);
+      this.totalTemplateSeriesNumber.set(0);
       this.templateManager.clear();
       if (logWriter != null) {
         logWriter.close();
@@ -596,9 +613,9 @@ public class MManager {
       }
 
       // update statistics and schemaDataTypeNumMap
-      totalSeriesNumber.addAndGet(1);
-      if (totalSeriesNumber.get() * ESTIMATED_SERIES_SIZE >= MTREE_SIZE_THRESHOLD) {
-        logger.warn("Current series number {} is too large...", totalSeriesNumber);
+      totalNormalSeriesNumber.addAndGet(1);
+      if (totalNormalSeriesNumber.get() * ESTIMATED_SERIES_SIZE >= MTREE_SIZE_THRESHOLD) {
+        logger.warn("Current series number {} is too large...", totalNormalSeriesNumber);
         allowToCreateNewSeries = false;
       }
 
@@ -700,9 +717,9 @@ public class MManager {
       mNodeCache.invalidate(prefixPath);
 
       // update statistics and schemaDataTypeNumMap
-      totalSeriesNumber.addAndGet(measurements.size());
-      if (totalSeriesNumber.get() * ESTIMATED_SERIES_SIZE >= MTREE_SIZE_THRESHOLD) {
-        logger.warn("Current series number {} is too large...", totalSeriesNumber);
+      totalNormalSeriesNumber.addAndGet(measurements.size());
+      if (totalNormalSeriesNumber.get() * ESTIMATED_SERIES_SIZE >= MTREE_SIZE_THRESHOLD) {
+        logger.warn("Current series number {} is too large...", totalNormalSeriesNumber);
         allowToCreateNewSeries = false;
       }
       // write log
@@ -793,6 +810,8 @@ public class MManager {
         deleteTimeSeriesPlan.setDeletePathList(Collections.singletonList(p));
         logWriter.deleteTimeseries(deleteTimeSeriesPlan);
       }
+    } catch (MeasurementInsideTemplateException e) {
+      failedNames.add(e.getMessage());
     } catch (DeleteFailedException e) {
       failedNames.add(e.getName());
     }
@@ -825,10 +844,10 @@ public class MManager {
       mNodeCache.invalidate(node.getPartialPath());
       node = node.getParent();
     }
-    totalSeriesNumber.addAndGet(-1);
+    totalNormalSeriesNumber.addAndGet(-1);
     if (!allowToCreateNewSeries
-        && totalSeriesNumber.get() * ESTIMATED_SERIES_SIZE < MTREE_SIZE_THRESHOLD) {
-      logger.info("Current series number {} come back to normal level", totalSeriesNumber);
+        && totalNormalSeriesNumber.get() * ESTIMATED_SERIES_SIZE < MTREE_SIZE_THRESHOLD) {
+      logger.info("Current series number {} come back to normal level", totalNormalSeriesNumber);
       allowToCreateNewSeries = true;
     }
     return storageGroupPath;
@@ -865,12 +884,14 @@ public class MManager {
   public void deleteStorageGroups(List<PartialPath> storageGroups) throws MetadataException {
     try {
       for (PartialPath storageGroup : storageGroups) {
-        totalSeriesNumber.addAndGet(
-            -mtree.getAllTimeseriesCount(storageGroup.concatNode(MULTI_LEVEL_PATH_WILDCARD)));
+        totalNormalSeriesNumber.addAndGet(
+            -mtree.getAllTimeseriesCount(
+                storageGroup.concatNode(MULTI_LEVEL_PATH_WILDCARD), false, false));
         // clear cached MNode
         if (!allowToCreateNewSeries
-            && totalSeriesNumber.get() * ESTIMATED_SERIES_SIZE < MTREE_SIZE_THRESHOLD) {
-          logger.info("Current series number {} come back to normal level", totalSeriesNumber);
+            && totalNormalSeriesNumber.get() * ESTIMATED_SERIES_SIZE < MTREE_SIZE_THRESHOLD) {
+          logger.info(
+              "Current series number {} come back to normal level", totalNormalSeriesNumber);
           allowToCreateNewSeries = true;
         }
         mNodeCache.invalidateAll();
@@ -998,8 +1019,12 @@ public class MManager {
 
   // region Interfaces for metadata count
 
-  public long getTotalSeriesNumber() {
-    return totalSeriesNumber.get();
+  public long getTotalNormalSeriesNumber() {
+    return totalNormalSeriesNumber.get();
+  }
+
+  public long getTotalTemplateSeriesNumber() {
+    return totalTemplateSeriesNumber.get();
   }
 
   /**
@@ -1009,7 +1034,7 @@ public class MManager {
    */
   public int getAllTimeseriesCount(PartialPath pathPattern, boolean isPrefixMatch)
       throws MetadataException {
-    return mtree.getAllTimeseriesCount(pathPattern, isPrefixMatch);
+    return mtree.getAllTimeseriesCount(pathPattern, isPrefixMatch, true);
   }
 
   /**
@@ -2452,6 +2477,8 @@ public class MManager {
       }
 
       node.setUseTemplate(false);
+      totalTemplateSeriesNumber.addAndGet(-node.getUpperTemplate().getMeasurementsCount());
+
       // clear caches within MManger
       mNodeCache.invalidate(node);
       if (node.isEntity()) {
@@ -2470,7 +2497,8 @@ public class MManager {
 
   IMNode setUsingSchemaTemplate(IMNode node) throws MetadataException {
     // check whether any template has been set on designated path
-    if (node.getUpperTemplate() == null) {
+    Template template = node.getUpperTemplate();
+    if (template == null) {
       throw new MetadataException(
           String.format("Path [%s] has not been set any template.", node.getFullPath()));
     }
@@ -2480,8 +2508,7 @@ public class MManager {
 
     // check alignment of template and mounted node
     // if direct measurement exists, node will be replaced
-    IMNode mountedMNode =
-        mtree.checkTemplateAlignmentWithMountedNode(node, node.getUpperTemplate());
+    IMNode mountedMNode = mtree.checkTemplateAlignmentWithMountedNode(node, template);
 
     // if has direct measurement (be a EntityNode), to ensure alignment adapt with former node or
     // template
@@ -2494,6 +2521,7 @@ public class MManager {
                   : node.getUpperTemplate().isDirectAligned());
     }
     mountedMNode.setUseTemplate(true);
+    totalTemplateSeriesNumber.addAndGet(template.getMeasurementsCount());
 
     if (node != mountedMNode) {
       mNodeCache.invalidate(mountedMNode.getPartialPath());
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
index eb38dd6cc6..6cdbac93b4 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.AlignedTimeseriesException;
 import org.apache.iotdb.db.exception.metadata.IllegalPathException;
 import org.apache.iotdb.db.exception.metadata.MNodeTypeMismatchException;
+import org.apache.iotdb.db.exception.metadata.MeasurementInsideTemplateException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.metadata.PathAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.PathNotExistException;
@@ -540,8 +541,7 @@ public class MTree implements Serializable {
     }
 
     if (isPathExistsWithinTemplate(path)) {
-      throw new MetadataException(
-          "Cannot delete a timeseries inside a template: " + path.toString());
+      throw new MeasurementInsideTemplateException(path.getFullPath());
     }
 
     IMeasurementMNode deletedNode = getMeasurementMNode(path);
@@ -1272,9 +1272,11 @@ public class MTree implements Serializable {
    *
    * @param pathPattern a path pattern or a full path, may contain wildcard
    */
-  public int getAllTimeseriesCount(PartialPath pathPattern, boolean isPrefixMatch)
+  public int getAllTimeseriesCount(
+      PartialPath pathPattern, boolean isPrefixMatch, boolean traverseTemplate)
       throws MetadataException {
     CounterTraverser counter = new MeasurementCounter(root, pathPattern);
+    counter.setShouldTraverseTemplate(traverseTemplate);
     counter.setPrefixMatch(isPrefixMatch);
     counter.traverse();
     return counter.getCount();
@@ -1286,7 +1288,7 @@ public class MTree implements Serializable {
    * @param pathPattern a path pattern or a full path, may contain wildcard
    */
   public int getAllTimeseriesCount(PartialPath pathPattern) throws MetadataException {
-    return getAllTimeseriesCount(pathPattern, false);
+    return getAllTimeseriesCount(pathPattern, false, true);
   }
 
   /**
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java
index ef3a0c1203..85b31a4403 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java
@@ -279,6 +279,10 @@ public abstract class Traverser {
     this.isPrefixMatch = isPrefixMatch;
   }
 
+  public void setShouldTraverseTemplate(boolean shouldTraverseTemplate) {
+    this.shouldTraverseTemplate = shouldTraverseTemplate;
+  }
+
   /**
    * @param currentNode the node need to get the full path of
    * @return full path from traverse start node to the current node
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
index fb6c0505d2..21b1ca63c6 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
@@ -35,6 +35,7 @@ import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.AppendTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
@@ -1918,13 +1919,13 @@ public class MManagerBasicTest {
           CompressionType.GZIP,
           null);
 
-      assertEquals(6, manager.getTotalSeriesNumber());
+      assertEquals(6, manager.getTotalNormalSeriesNumber());
       EnvironmentUtils.restartDaemon();
-      assertEquals(6, manager.getTotalSeriesNumber());
+      assertEquals(6, manager.getTotalNormalSeriesNumber());
       manager.deleteTimeseries(new PartialPath("root.laptop.d2.s1"));
-      assertEquals(5, manager.getTotalSeriesNumber());
+      assertEquals(5, manager.getTotalNormalSeriesNumber());
       manager.deleteStorageGroups(Collections.singletonList(new PartialPath("root.laptop")));
-      assertEquals(0, manager.getTotalSeriesNumber());
+      assertEquals(0, manager.getTotalNormalSeriesNumber());
     } catch (MetadataException e) {
       e.printStackTrace();
       fail(e.getMessage());
@@ -2582,4 +2583,85 @@ public class MManagerBasicTest {
     Assert.assertEquals(1, result.size());
     Assert.assertTrue(result.contains("d1"));
   }
+
+  @Test
+  public void testTimeseriesNumberStatistic() throws Exception {
+    MManager manager = IoTDB.metaManager;
+
+    try {
+      manager.setStorageGroup(new PartialPath("root.laptop"));
+      manager.createTimeseries(
+          new PartialPath("root.laptop.d0"),
+          TSDataType.INT32,
+          TSEncoding.PLAIN,
+          CompressionType.GZIP,
+          null);
+      manager.createTimeseries(
+          new PartialPath("root.laptop.d1.s1"),
+          TSDataType.INT32,
+          TSEncoding.PLAIN,
+          CompressionType.GZIP,
+          null);
+      manager.createTimeseries(
+          new PartialPath("root.laptop.d1.s2.t1"),
+          TSDataType.INT32,
+          TSEncoding.PLAIN,
+          CompressionType.GZIP,
+          null);
+      manager.createTimeseries(
+          new PartialPath("root.laptop.d1.s3"),
+          TSDataType.INT32,
+          TSEncoding.PLAIN,
+          CompressionType.GZIP,
+          null);
+      manager.createTimeseries(
+          new PartialPath("root.laptop.d2.s1"),
+          TSDataType.INT32,
+          TSEncoding.PLAIN,
+          CompressionType.GZIP,
+          null);
+      manager.createTimeseries(
+          new PartialPath("root.laptop.d2.s2"),
+          TSDataType.INT32,
+          TSEncoding.PLAIN,
+          CompressionType.GZIP,
+          null);
+
+      assertEquals(6, manager.getTotalNormalSeriesNumber());
+
+      manager.setStorageGroup(new PartialPath("root.sg"));
+
+      CreateTemplatePlan plan = getCreateTemplatePlan("s0");
+      manager.createSchemaTemplate(plan);
+      SetTemplatePlan setPlan = new SetTemplatePlan("template1", "root.sg.d1");
+      manager.setSchemaTemplate(setPlan);
+
+      manager.setUsingSchemaTemplate(manager.getDeviceNode(new PartialPath("root.sg.d1")));
+
+      assertEquals(6, manager.getTotalNormalSeriesNumber());
+      assertEquals(1, manager.getTotalTemplateSeriesNumber());
+
+      manager.deleteTimeseries(new PartialPath("root.laptop.d2.s1"));
+      assertEquals(5, manager.getTotalNormalSeriesNumber());
+      assertEquals(1, manager.getTotalTemplateSeriesNumber());
+
+      manager.deleteStorageGroups(Collections.singletonList(new PartialPath("root.laptop")));
+      assertEquals(0, manager.getTotalNormalSeriesNumber());
+      assertEquals(1, manager.getTotalTemplateSeriesNumber());
+
+      String failedName = manager.deleteTimeseries(new PartialPath("root.sg.d1.s0"));
+      assertTrue(failedName.contains("root.sg.d1.s0"));
+      assertEquals(1, manager.getTotalTemplateSeriesNumber());
+
+      DeactivateTemplatePlan deactivateTemplatePlan =
+          new DeactivateTemplatePlan("template1", "root.sg.d1");
+      deactivateTemplatePlan.setPaths(Collections.singletonList(new PartialPath("root.sg.d1")));
+      manager.deactivateSchemaTemplate(deactivateTemplatePlan);
+      assertEquals(0, manager.getTotalTemplateSeriesNumber());
+
+    } catch (MetadataException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
 }