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

jt2594838 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 f7be88e0c48 Added table metric & Improved the database / view metric & 
Added "count databases" for table model (#15587)
f7be88e0c48 is described below

commit f7be88e0c48fa2cf908e5eb28d8885187c6af6ac
Author: Caideyipi <[email protected]>
AuthorDate: Thu Jul 23 11:08:10 2026 +0800

    Added table metric & Improved the database / view metric & Added "count 
databases" for table model (#15587)
    
    * Update SchemaRegionMemMetric.java
    
    * partial
    
    * May be final
    
    * partially
    
    * Next fix
    
    * Partial
    
    * Partial completion
    
    * Update PartitionMetrics.java
    
    * Refactor
    
    * Implement countDB
    
    * Update Coordinator.java
    
    * Next
    
    * Update IoTDBDatabaseIT.java
    
    * Update ConfigMTreeTest.java
    
    * Fix
    
    * partial
    
    * partial
    
    * fixfix
    
    * apply
    
    * fix
    
    * partial
    
    * fix
    
    * Fix ConfigMTree snapshot test compilation
    
    * Fix dynamic table device metric binding
    
    * Keep schema metrics consistent across lifecycle changes
---
 .../relational/it/schema/IoTDBDatabaseIT.java      |   3 +
 .../manager/partition/PartitionMetrics.java        |  94 ++++++++++++++++--
 .../manager/schema/ClusterSchemaManager.java       |   9 ++
 .../schema/CNPhysicalPlanGenerator.java            |   2 +-
 .../persistence/schema/ClusterSchemaInfo.java      |  78 ++++++++++++---
 .../confignode/persistence/schema/ConfigMTree.java |  29 +++++-
 .../persistence/schema/ConfigSchemaStatistics.java | 109 +++++++++++++++++++++
 .../impl/schema/DeleteDatabaseProcedure.java       |   2 +
 .../persistence/schema/ClusterSchemaInfoTest.java  |  40 ++++++++
 .../persistence/schema/ConfigMTreeTest.java        |   8 +-
 .../config/metadata/CountDatabaseTask.java         |   4 +-
 .../metadata/fetcher/TableDeviceSchemaFetcher.java |   2 +-
 .../apache/iotdb/db/schemaengine/SchemaEngine.java |   9 +-
 .../schemaengine/metric/ISchemaEngineMetric.java   |   7 +-
 .../schemaengine/metric/ISchemaRegionMetric.java   |   7 +-
 .../metric/SchemaEngineCachedMetric.java           |  10 ++
 .../schemaengine/metric/SchemaEngineMemMetric.java |  34 ++++++-
 .../schemaengine/metric/SchemaMetricManager.java   |   4 +
 .../metric/SchemaRegionCachedMetric.java           |  10 ++
 .../schemaengine/metric/SchemaRegionMemMetric.java |  56 +++++++++++
 .../rescon/ISchemaEngineStatistics.java            |   2 +
 .../rescon/MemSchemaEngineStatistics.java          |  43 ++++++++
 .../rescon/MemSchemaRegionStatistics.java          |  25 ++++-
 .../iotdb/commons/service/metric/enums/Metric.java |   2 +
 24 files changed, 545 insertions(+), 44 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
index 22483ab43a6..e011915de0e 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDatabaseIT.java
@@ -142,6 +142,9 @@ public class IoTDBDatabaseIT {
         assertEquals(databaseNames.length, cnt);
       }
 
+      TestUtils.assertResultSetEqual(
+          statement.executeQuery("count databases"), "count,", 
Collections.singleton("2,"));
+
       final int[] schemaRegionGroupNum = new int[] {0};
       final int[] dataRegionGroupNum = new int[] {0};
       final int[] defaultSchemaRegionGroupNum = new int[] {1};
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionMetrics.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionMetrics.java
index 3a6939d1dcc..3ecb08e1bda 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionMetrics.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionMetrics.java
@@ -22,15 +22,19 @@ package org.apache.iotdb.confignode.manager.partition;
 import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeConfiguration;
 import org.apache.iotdb.commons.cluster.RegionStatus;
+import org.apache.iotdb.commons.schema.table.InformationSchema;
+import org.apache.iotdb.commons.schema.table.TableType;
 import org.apache.iotdb.commons.service.metric.enums.Metric;
 import org.apache.iotdb.commons.service.metric.enums.Tag;
 import org.apache.iotdb.commons.utils.NodeUrlUtils;
+import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.i18n.ManagerMessages;
 import org.apache.iotdb.confignode.manager.IManager;
 import org.apache.iotdb.confignode.manager.load.LoadManager;
 import org.apache.iotdb.confignode.manager.node.NodeManager;
 import org.apache.iotdb.confignode.manager.schema.ClusterSchemaManager;
+import org.apache.iotdb.confignode.persistence.schema.ConfigSchemaStatistics;
 import org.apache.iotdb.metrics.AbstractMetricService;
 import org.apache.iotdb.metrics.metricsets.IMetricSet;
 import org.apache.iotdb.metrics.utils.MetricLevel;
@@ -268,18 +272,34 @@ public class PartitionMetrics implements IMetricSet {
 
   // region Database Partition Metrics
 
-  private void bindDatabaseRelatedMetrics(AbstractMetricService metricService) 
{
-    ClusterSchemaManager clusterSchemaManager = getClusterSchemaManager();
+  private void bindDatabaseRelatedMetrics(final AbstractMetricService 
metricService) {
+    final ClusterSchemaManager clusterSchemaManager = 
getClusterSchemaManager();
+    final ConfigSchemaStatistics statistics = 
clusterSchemaManager.getConfigSchemaStatistics();
     // Count the number of Databases
     metricService.createAutoGauge(
         Metric.DATABASE_NUM.toString(),
         MetricLevel.CORE,
-        clusterSchemaManager,
-        // Add 1 for information schema
-        c -> c.getDatabaseNames(null).size() + 1);
+        statistics,
+        s -> s.getTableDatabaseNum() + s.getTreeDatabaseNum());
+    metricService.createAutoGauge(
+        Metric.TABLE_DATABASE_NUM.toString(),
+        MetricLevel.CORE,
+        statistics,
+        ConfigSchemaStatistics::getTableDatabaseNum);
 
-    List<String> databases = clusterSchemaManager.getDatabaseNames(null);
-    for (String database : databases) {
+    // Enable table num gauge for information_schema
+    metricService
+        .getOrCreateGauge(
+            Metric.TABLE_NUM.toString(),
+            MetricLevel.CORE,
+            Tag.TYPE.toString(),
+            TableType.SYSTEM_VIEW.getName(),
+            Tag.DATABASE.toString(),
+            InformationSchema.INFORMATION_DATABASE)
+        .set(InformationSchema.getSchemaTables().size());
+
+    final List<String> databases = clusterSchemaManager.getDatabaseNames(null);
+    for (final String database : databases) {
       int dataReplicationFactor = 1;
       int schemaReplicationFactor = 1;
       try {
@@ -292,16 +312,28 @@ public class PartitionMetrics implements IMetricSet {
       }
       bindDatabaseRelatedMetricsWhenUpdate(
           metricService, configManager, database, dataReplicationFactor, 
schemaReplicationFactor);
+      bindDatabaseTableMetrics(metricService, statistics, database);
     }
   }
 
   private void unbindDatabaseRelatedMetrics(AbstractMetricService 
metricService) {
     // Remove the number of Databases
     metricService.remove(MetricType.AUTO_GAUGE, 
Metric.DATABASE_NUM.toString());
+    metricService.remove(MetricType.AUTO_GAUGE, 
Metric.TABLE_DATABASE_NUM.toString());
+
+    // Remove gauge for information_schema
+    metricService.remove(
+        MetricType.GAUGE,
+        Metric.TABLE_NUM.toString(),
+        Tag.TYPE.toString(),
+        TableType.SYSTEM_VIEW.getName(),
+        Tag.DATABASE.toString(),
+        InformationSchema.INFORMATION_DATABASE);
 
     List<String> databases = getClusterSchemaManager().getDatabaseNames(null);
     for (String database : databases) {
       unbindDatabaseRelatedMetricsWhenUpdate(metricService, database);
+      unbindDatabaseTableMetrics(metricService, database);
     }
   }
 
@@ -449,6 +481,54 @@ public class PartitionMetrics implements IMetricSet {
         .set(schemaReplicationFactor);
   }
 
+  public static void bindDatabaseTableMetrics(
+      final AbstractMetricService metricService,
+      final ConfigSchemaStatistics statistics,
+      final String database) {
+    if (!PathUtils.isTableModelDatabase(database)) {
+      return;
+    }
+    metricService.createAutoGauge(
+        Metric.TABLE_NUM.toString(),
+        MetricLevel.CORE,
+        statistics,
+        s -> s.getTreeViewTableNum(database),
+        Tag.TYPE.toString(),
+        TableType.VIEW_FROM_TREE.getName(),
+        Tag.DATABASE.toString(),
+        database);
+    metricService.createAutoGauge(
+        Metric.TABLE_NUM.toString(),
+        MetricLevel.CORE,
+        statistics,
+        s -> s.getBaseTableNum(database),
+        Tag.TYPE.toString(),
+        TableType.BASE_TABLE.getName(),
+        Tag.DATABASE.toString(),
+        database);
+  }
+
+  public static void unbindDatabaseTableMetrics(
+      final AbstractMetricService metricService, final String database) {
+    if (!PathUtils.isTableModelDatabase(database)) {
+      return;
+    }
+    metricService.remove(
+        MetricType.AUTO_GAUGE,
+        Metric.TABLE_NUM.toString(),
+        Tag.TYPE.toString(),
+        TableType.VIEW_FROM_TREE.getName(),
+        Tag.DATABASE.toString(),
+        database);
+    metricService.remove(
+        MetricType.AUTO_GAUGE,
+        Metric.TABLE_NUM.toString(),
+        Tag.TYPE.toString(),
+        TableType.BASE_TABLE.getName(),
+        Tag.DATABASE.toString(),
+        database);
+  }
+
   // endregion
 
   private NodeManager getNodeManager() {
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
index 357c14eca4a..a0284445ea2 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
@@ -98,6 +98,7 @@ import 
org.apache.iotdb.confignode.manager.partition.PartitionManager;
 import org.apache.iotdb.confignode.manager.partition.PartitionMetrics;
 import 
org.apache.iotdb.confignode.manager.partition.RegionGroupExtensionPolicy;
 import org.apache.iotdb.confignode.persistence.schema.ClusterSchemaInfo;
+import org.apache.iotdb.confignode.persistence.schema.ConfigSchemaStatistics;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseInfo;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.confignode.rpc.thrift.TDescTable4InformationSchemaResp;
@@ -207,6 +208,10 @@ public class ClusterSchemaManager {
           schema.getName(),
           schema.getDataReplicationFactor(),
           schema.getSchemaReplicationFactor());
+      PartitionMetrics.bindDatabaseTableMetrics(
+          MetricService.getInstance(),
+          clusterSchemaInfo.getConfigSchemaStatistics(),
+          schema.getName());
       // Adjust the maximum RegionGroup number of each Database
       adjustMaxRegionGroupNum();
     } catch (final ConsensusException e) {
@@ -646,6 +651,10 @@ public class ClusterSchemaManager {
         .collect(Collectors.toList());
   }
 
+  public ConfigSchemaStatistics getConfigSchemaStatistics() {
+    return clusterSchemaInfo.getConfigSchemaStatistics();
+  }
+
   /**
    * Only leader use this interface. Get the specified Database's schemaengine
    *
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
index 698676f54e2..e4366c45fc4 100644
--- 
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
@@ -479,7 +479,7 @@ public class CNPhysicalPlanGenerator
             name = internalMNode.getName();
             break;
           case DATABASE_MNODE_TYPE:
-            databaseMNode = 
deserializeDatabaseMNode(bufferedInputStream).getAsMNode();
+            databaseMNode = deserializeDatabaseMNode(bufferedInputStream);
             while (!stack.isEmpty() && !stack.peek().right) {
               databaseMNode.addChild(stack.pop().left);
             }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
index 89f44d489d4..b758631316d 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
@@ -39,6 +39,7 @@ import org.apache.iotdb.commons.snapshot.SnapshotProcessor;
 import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.commons.utils.StatusUtils;
 import org.apache.iotdb.commons.utils.TestOnly;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
 import 
org.apache.iotdb.confignode.consensus.request.read.database.CountDatabasePlan;
 import 
org.apache.iotdb.confignode.consensus.request.read.database.GetDatabasePlan;
 import org.apache.iotdb.confignode.consensus.request.read.table.DescTablePlan;
@@ -157,6 +158,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor 
{
   private final ReentrantReadWriteLock databaseReadWriteLock;
   private final ConfigMTree treeModelMTree;
   private final ConfigMTree tableModelMTree;
+  private final ConfigSchemaStatistics configSchemaStatistics;
 
   private static final String TREE_SNAPSHOT_FILENAME = "cluster_schema.bin";
   private static final String TABLE_SNAPSHOT_FILENAME = 
"table_cluster_schema.bin";
@@ -172,6 +174,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor 
{
     try {
       treeModelMTree = new ConfigMTree(false);
       tableModelMTree = new ConfigMTree(true);
+      configSchemaStatistics = new ConfigSchemaStatistics();
       templateTable = new TemplateTable();
       templatePreSetTable = new TemplatePreSetTable();
     } catch (final MetadataException e) {
@@ -207,6 +210,12 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
           .getAsMNode()
           .setDatabaseSchema(databaseSchema);
 
+      if (databaseSchema.isIsTableModel()) {
+        configSchemaStatistics.increaseTableDatabaseNum();
+      } else {
+        configSchemaStatistics.increaseTreeDatabaseNum();
+      }
+
       result.setCode(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     } catch (final MetadataException e) {
       LOGGER.error(ERROR_NAME, e);
@@ -291,6 +300,13 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
       (isTableModel ? tableModelMTree : treeModelMTree)
           .deleteDatabase(getQualifiedDatabasePartialPath(plan.getName()));
 
+      if (isTableModel) {
+        configSchemaStatistics.decreaseTableDatabaseNum();
+        configSchemaStatistics.removeTableStatistics(plan.getName());
+      } else {
+        configSchemaStatistics.decreaseTreeDatabaseNum();
+      }
+
       result.setCode(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     } catch (final MetadataException e) {
       LOGGER.warn(ConfigNodeMessages.DATABASE_NOT_EXIST, e);
@@ -774,19 +790,20 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
 
   @Override
   public void processLoadSnapshot(final File snapshotDir) throws IOException {
+    configSchemaStatistics.clear();
     processMTreeLoadSnapshot(
         snapshotDir,
         TREE_SNAPSHOT_FILENAME,
         stream -> {
           treeModelMTree.clear();
-          treeModelMTree.deserialize(stream);
+          treeModelMTree.deserialize(stream, configSchemaStatistics);
         });
     processMTreeLoadSnapshot(
         snapshotDir,
         TABLE_SNAPSHOT_FILENAME,
         stream -> {
           tableModelMTree.clear();
-          tableModelMTree.deserialize(stream);
+          tableModelMTree.deserialize(stream, configSchemaStatistics);
         });
     templateTable.processLoadSnapshot(snapshotDir);
     templatePreSetTable.processLoadSnapshot(snapshotDir);
@@ -1162,25 +1179,43 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
 
   public TSStatus preCreateTable(final PreCreateTablePlan plan) {
     return executeWithLock(
-        () ->
-            tableModelMTree.preCreateTable(
-                getQualifiedDatabasePartialPath(plan.getDatabase()), 
plan.getTable()));
+        () -> {
+          tableModelMTree.preCreateTable(
+              getQualifiedDatabasePartialPath(plan.getDatabase()), 
plan.getTable());
+          configSchemaStatistics.increaseBaseTableNum(plan.getDatabase());
+        });
   }
 
   public TSStatus preCreateTableView(final PreCreateTableViewPlan plan) {
     return executeWithLock(
-        () ->
-            tableModelMTree.preCreateTableView(
-                getQualifiedDatabasePartialPath(plan.getDatabase()),
-                plan.getTable(),
-                plan.getStatus()));
+        () -> {
+          tableModelMTree.preCreateTableView(
+              getQualifiedDatabasePartialPath(plan.getDatabase()),
+              plan.getTable(),
+              plan.getStatus());
+          configSchemaStatistics.increaseTreeViewTableNum(plan.getDatabase());
+        });
   }
 
   public TSStatus rollbackCreateTable(final RollbackCreateTablePlan plan) {
     return executeWithLock(
-        () ->
-            tableModelMTree.rollbackCreateTable(
-                getQualifiedDatabasePartialPath(plan.getDatabase()), 
plan.getTableName()));
+        () -> {
+          final PartialPath database = 
getQualifiedDatabasePartialPath(plan.getDatabase());
+          final String databaseName = plan.getDatabase();
+          final String tableName = plan.getTableName();
+          tableModelMTree
+              .getTableAndStatusIfExists(database, tableName)
+              .map(Pair::getLeft)
+              .ifPresent(
+                  table -> {
+                    if (TreeViewSchema.isTreeViewTable(table)) {
+                      
configSchemaStatistics.decreaseTreeViewTableNum(databaseName);
+                    } else {
+                      
configSchemaStatistics.decreaseBaseTableNum(databaseName);
+                    }
+                  });
+          tableModelMTree.rollbackCreateTable(database, tableName);
+        });
   }
 
   public TSStatus commitCreateTable(final CommitCreateTablePlan plan) {
@@ -1208,9 +1243,15 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
 
   public TSStatus dropTable(final CommitDeleteTablePlan plan) {
     return executeWithLock(
-        () ->
-            tableModelMTree.dropTable(
-                getQualifiedDatabasePartialPath(plan.getDatabase()), 
plan.getTableName()));
+        () -> {
+          tableModelMTree.dropTable(
+              getQualifiedDatabasePartialPath(plan.getDatabase()), 
plan.getTableName());
+          if (plan.getType() == ConfigPhysicalPlanType.CommitDeleteView) {
+            
configSchemaStatistics.decreaseTreeViewTableNum(plan.getDatabase());
+          } else {
+            configSchemaStatistics.decreaseBaseTableNum(plan.getDatabase());
+          }
+        });
   }
 
   public TSStatus renameTable(final RenameTablePlan plan) {
@@ -1594,11 +1635,16 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
     }
   }
 
+  public ConfigSchemaStatistics getConfigSchemaStatistics() {
+    return configSchemaStatistics;
+  }
+
   // endregion
 
   @TestOnly
   public void clear() {
     treeModelMTree.clear();
     tableModelMTree.clear();
+    configSchemaStatistics.clear();
   }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
index 43e72240a04..7456f339af7 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
@@ -1193,7 +1193,8 @@ public class ConfigMTree {
     }
   }
 
-  public void deserialize(final InputStream inputStream) throws IOException {
+  public void deserialize(final InputStream inputStream, final 
ConfigSchemaStatistics statistics)
+      throws IOException {
     byte type = ReadWriteIOUtils.readByte(inputStream);
 
     String name;
@@ -1201,11 +1202,16 @@ public class ConfigMTree {
     final Stack<Pair<IConfigMNode, Boolean>> stack = new Stack<>();
     IConfigMNode databaseMNode;
     IConfigMNode internalMNode;
-    IConfigMNode tableNode;
+    ConfigTableNode tableNode;
 
     if (type == DATABASE_MNODE_TYPE) {
       databaseMNode = deserializeDatabaseMNode(inputStream);
       name = databaseMNode.getName();
+      if (isTableModel) {
+        statistics.increaseTableDatabaseNum();
+      } else {
+        statistics.increaseTreeDatabaseNum();
+      }
       stack.push(new Pair<>(databaseMNode, true));
     } else if (type == TABLE_MNODE_TYPE) {
       tableNode = deserializeTableMNode(inputStream);
@@ -1234,15 +1240,28 @@ public class ConfigMTree {
           name = internalMNode.getName();
           break;
         case DATABASE_MNODE_TYPE:
-          databaseMNode = deserializeDatabaseMNode(inputStream).getAsMNode();
+          databaseMNode = deserializeDatabaseMNode(inputStream);
           while (!stack.isEmpty() && Boolean.FALSE.equals(stack.peek().right)) 
{
-            databaseMNode.addChild(stack.pop().left);
+            final IConfigMNode node = stack.pop().left;
+            databaseMNode.addChild(node);
+            if (node instanceof ConfigTableNode) {
+              if (TreeViewSchema.isTreeViewTable(((ConfigTableNode) 
node).getTable())) {
+                statistics.increaseTreeViewTableNum(databaseMNode.getName());
+              } else {
+                statistics.increaseBaseTableNum(databaseMNode.getName());
+              }
+            }
+          }
+          if (isTableModel) {
+            statistics.increaseTableDatabaseNum();
+          } else {
+            statistics.increaseTreeDatabaseNum();
           }
           stack.push(new Pair<>(databaseMNode, true));
           name = databaseMNode.getName();
           break;
         case TABLE_MNODE_TYPE:
-          tableNode = deserializeTableMNode(inputStream).getAsMNode();
+          tableNode = deserializeTableMNode(inputStream);
           stack.push(new Pair<>(tableNode, false));
           name = tableNode.getName();
           break;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigSchemaStatistics.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigSchemaStatistics.java
new file mode 100644
index 00000000000..3f1f07909f0
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigSchemaStatistics.java
@@ -0,0 +1,109 @@
+/*
+ * 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 java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * The {@link ConfigSchemaStatistics} is used to:
+ *
+ * <p>1. Serve the {@link 
org.apache.iotdb.confignode.manager.partition.PartitionMetrics} for schema
+ * related metrics, to prevent too much scanning and lock acquisition, and to 
simplify the metric
+ * getter logic.
+ *
+ * <p>2. Be reserved for potential mem-control and quota functionalities 
expansion.
+ *
+ * <p>3. Be in consistency with SchemaRegionMemMetric in dataNode.
+ */
+public class ConfigSchemaStatistics {
+  private final AtomicLong treeDatabaseNum = new AtomicLong(0);
+
+  // Add 1 for information_schema
+  private final AtomicLong tableDatabaseNum = new AtomicLong(1);
+
+  private final ConcurrentMap<String, Long> treeViewTableNum = new 
ConcurrentHashMap<>();
+  private final ConcurrentMap<String, Long> baseTableNum = new 
ConcurrentHashMap<>();
+
+  // Getter
+
+  public long getTreeDatabaseNum() {
+    return treeDatabaseNum.get();
+  }
+
+  public long getTableDatabaseNum() {
+    return tableDatabaseNum.get();
+  }
+
+  public long getTreeViewTableNum(final String database) {
+    return treeViewTableNum.getOrDefault(database, 0L);
+  }
+
+  public long getBaseTableNum(final String database) {
+    return baseTableNum.getOrDefault(database, 0L);
+  }
+
+  // Setter
+
+  public void increaseTreeDatabaseNum() {
+    treeDatabaseNum.incrementAndGet();
+  }
+
+  public void decreaseTreeDatabaseNum() {
+    treeDatabaseNum.decrementAndGet();
+  }
+
+  public void increaseTableDatabaseNum() {
+    tableDatabaseNum.incrementAndGet();
+  }
+
+  public void decreaseTableDatabaseNum() {
+    tableDatabaseNum.decrementAndGet();
+  }
+
+  public void increaseTreeViewTableNum(final String database) {
+    treeViewTableNum.compute(database, (db, num) -> num == null ? 1 : num + 1);
+  }
+
+  public void decreaseTreeViewTableNum(final String database) {
+    treeViewTableNum.compute(database, (db, num) -> num != null && num > 1 ? 
num - 1 : null);
+  }
+
+  public void increaseBaseTableNum(final String database) {
+    baseTableNum.compute(database, (db, num) -> num == null ? 1 : num + 1);
+  }
+
+  public void decreaseBaseTableNum(final String database) {
+    baseTableNum.compute(database, (db, num) -> num != null && num > 1 ? num - 
1 : null);
+  }
+
+  public void removeTableStatistics(final String database) {
+    treeViewTableNum.remove(database);
+    baseTableNum.remove(database);
+  }
+
+  public void clear() {
+    treeDatabaseNum.set(0);
+    tableDatabaseNum.set(1);
+    treeViewTableNum.clear();
+    baseTableNum.clear();
+  }
+}
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java
index b547e8ebc7d..2af7bd7ad69 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java
@@ -149,6 +149,8 @@ public class DeleteDatabaseProcedure
           // Delete Database metrics
           PartitionMetrics.unbindDatabaseRelatedMetricsWhenUpdate(
               MetricService.getInstance(), deleteDatabaseSchema.getName());
+          PartitionMetrics.unbindDatabaseTableMetrics(
+              MetricService.getInstance(), deleteDatabaseSchema.getName());
 
           // Delete DatabasePartitionTable
           final TSStatus deleteConfigResult =
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
index 1cf0b2913a8..948a3c5a73d 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfoTest.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.confignode.persistence.schema;
 
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.schema.template.Template;
 import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
@@ -28,6 +29,9 @@ import 
org.apache.iotdb.confignode.consensus.request.read.database.GetDatabasePl
 import 
org.apache.iotdb.confignode.consensus.request.read.template.GetPathsSetTemplatePlan;
 import 
org.apache.iotdb.confignode.consensus.request.read.template.GetTemplateSetInfoPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.database.DatabaseSchemaPlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.database.DeleteDatabasePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.PreCreateTablePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.RollbackCreateTablePlan;
 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.consensus.request.write.template.SetSchemaTemplatePlan;
@@ -107,6 +111,13 @@ public class ClusterSchemaInfoTest {
     clusterSchemaInfo.clear();
     clusterSchemaInfo.processLoadSnapshot(snapshotDir);
 
+    Assert.assertEquals(4, 
clusterSchemaInfo.getConfigSchemaStatistics().getTreeDatabaseNum());
+    Assert.assertEquals(1, 
clusterSchemaInfo.getConfigSchemaStatistics().getTableDatabaseNum());
+
+    clusterSchemaInfo.processLoadSnapshot(snapshotDir);
+    Assert.assertEquals(4, 
clusterSchemaInfo.getConfigSchemaStatistics().getTreeDatabaseNum());
+    Assert.assertEquals(1, 
clusterSchemaInfo.getConfigSchemaStatistics().getTableDatabaseNum());
+
     Assert.assertEquals(
         storageGroupPathList.size(), 
clusterSchemaInfo.getDatabaseNames(null).size());
 
@@ -122,6 +133,35 @@ public class ClusterSchemaInfoTest {
     Assert.assertEquals(testMap, reloadResult);
   }
 
+  @Test
+  public void testTableStatisticsRollbackAndDatabaseRecreation() {
+    final String database = "database";
+    final String table = "table";
+    final TDatabaseSchema databaseSchema = new 
TDatabaseSchema(database).setIsTableModel(true);
+    clusterSchemaInfo.createDatabase(
+        new DatabaseSchemaPlan(ConfigPhysicalPlanType.CreateDatabase, 
databaseSchema));
+
+    final ConfigSchemaStatistics statistics = 
clusterSchemaInfo.getConfigSchemaStatistics();
+    Assert.assertEquals(2, statistics.getTableDatabaseNum());
+    Assert.assertEquals(0, statistics.getBaseTableNum(database));
+
+    clusterSchemaInfo.preCreateTable(new PreCreateTablePlan(database, new 
TsTable(table)));
+    Assert.assertEquals(1, statistics.getBaseTableNum(database));
+
+    clusterSchemaInfo.rollbackCreateTable(new 
RollbackCreateTablePlan(database, table));
+    Assert.assertEquals(0, statistics.getBaseTableNum(database));
+
+    clusterSchemaInfo.preCreateTable(new PreCreateTablePlan(database, new 
TsTable(table)));
+    clusterSchemaInfo.deleteDatabase(new DeleteDatabasePlan(database));
+    Assert.assertEquals(1, statistics.getTableDatabaseNum());
+    Assert.assertEquals(0, statistics.getBaseTableNum(database));
+
+    clusterSchemaInfo.createDatabase(
+        new DatabaseSchemaPlan(ConfigPhysicalPlanType.CreateDatabase, 
databaseSchema));
+    Assert.assertEquals(2, statistics.getTableDatabaseNum());
+    Assert.assertEquals(0, statistics.getBaseTableNum(database));
+  }
+
   @Test
   public void testSetTemplate() throws IllegalPathException {
     String templateName = "template_name";
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
index f4dbd9a3972..c2519dcbfae 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
@@ -291,7 +291,7 @@ public class ConfigMTreeTest {
 
     final ConfigMTree newTree = new ConfigMTree(false);
     final ByteArrayInputStream inputStream = new 
ByteArrayInputStream(outputStream.toByteArray());
-    newTree.deserialize(inputStream);
+    newTree.deserialize(inputStream, new ConfigSchemaStatistics());
 
     for (int i = 0; i < pathList.length; i++) {
       final TDatabaseSchema storageGroupSchema =
@@ -367,7 +367,7 @@ public class ConfigMTreeTest {
 
     final ConfigMTree newTree = new ConfigMTree(true);
     final ByteArrayInputStream inputStream = new 
ByteArrayInputStream(outputStream.toByteArray());
-    newTree.deserialize(inputStream);
+    newTree.deserialize(inputStream, new ConfigSchemaStatistics());
 
     for (int i = 0; i < pathList.length; i++) {
       final TDatabaseSchema storageGroupSchema =
@@ -497,7 +497,7 @@ public class ConfigMTreeTest {
     File schemaFile = new File(pathStr);
     try (InputStream inputStream = 
Files.newInputStream(schemaFile.getAbsoluteFile().toPath())) {
       ConfigMTree treeMTree = new ConfigMTree(false);
-      treeMTree.deserialize(inputStream);
+      treeMTree.deserialize(inputStream, new ConfigSchemaStatistics());
 
       Set<String> databaseSet = new HashSet<>();
       for (PartialPath path : treeMTree.getAllDatabasePaths(false)) {
@@ -515,7 +515,7 @@ public class ConfigMTreeTest {
     File schemaFile = new File(pathStr);
     try (InputStream inputStream = 
Files.newInputStream(schemaFile.getAbsoluteFile().toPath())) {
       ConfigMTree tableMTree = new ConfigMTree(true);
-      tableMTree.deserialize(inputStream);
+      tableMTree.deserialize(inputStream, new ConfigSchemaStatistics());
 
       Set<String> databaseSet = new HashSet<>();
       for (PartialPath path : tableMTree.getAllDatabasePaths(true)) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/CountDatabaseTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/CountDatabaseTask.java
index cc856078afc..720e2511dd0 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/CountDatabaseTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/CountDatabaseTask.java
@@ -54,10 +54,10 @@ public class CountDatabaseTask implements IConfigTask {
     builder.getTimeColumnBuilder().writeLong(0L);
     builder.getColumnBuilder(0).writeInt(storageGroupNum);
     builder.declarePosition();
-    ColumnHeader storageGroupColumnHeader =
+    ColumnHeader databaseColumnHeader =
         new ColumnHeader(IoTDBConstant.COLUMN_COUNT, TSDataType.INT32);
     DatasetHeader datasetHeader =
-        new DatasetHeader(Collections.singletonList(storageGroupColumnHeader), 
true);
+        new DatasetHeader(Collections.singletonList(databaseColumnHeader), 
true);
     future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS, 
builder.build(), datasetHeader));
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
index b65a0918855..024b9ef44ac 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
@@ -622,7 +622,7 @@ public class TableDeviceSchemaFetcher {
       mppQueryContext.reserveMemoryForFrontEnd(deviceEntry.ramBytesUsed());
       deviceEntryList.add(deviceEntry);
       // Only cache those exact device query
-      // Fetch paths is null iff there are fuzzy queries related to id columns
+      // Fetch paths is null iff there are fuzzy queries related to tag columns
       if (Objects.nonNull(statement.getPartitionKeyList())) {
         cache.putAttributes(statement.getDatabase(), deviceID, attributeMap);
       }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java
index a52330073d8..295813dc420 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/SchemaEngine.java
@@ -34,6 +34,7 @@ import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl;
 import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
+import org.apache.iotdb.db.schemaengine.metric.ISchemaEngineMetric;
 import org.apache.iotdb.db.schemaengine.metric.ISchemaRegionMetric;
 import org.apache.iotdb.db.schemaengine.metric.SchemaMetricManager;
 import org.apache.iotdb.db.schemaengine.rescon.CachedSchemaEngineStatistics;
@@ -495,7 +496,13 @@ public class SchemaEngine {
     return schemaEngineStatistics;
   }
 
+  public ISchemaEngineMetric getSchemaEngineMetric() {
+    return schemaMetricManager == null ? null : 
schemaMetricManager.getEngineMetric();
+  }
+
   public ISchemaRegionMetric getSchemaRegionMetric(int schemaRegionId) {
-    return schemaMetricManager.getSchemaRegionMetric(schemaRegionId);
+    return schemaMetricManager == null
+        ? null
+        : schemaMetricManager.getSchemaRegionMetric(schemaRegionId);
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaEngineMetric.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaEngineMetric.java
index b627098cfa7..9c22608dd10 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaEngineMetric.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaEngineMetric.java
@@ -21,4 +21,9 @@ package org.apache.iotdb.db.schemaengine.metric;
 
 import org.apache.iotdb.metrics.metricsets.IMetricSet;
 
-public interface ISchemaEngineMetric extends IMetricSet {}
+public interface ISchemaEngineMetric extends IMetricSet {
+
+  void bindTableMetrics(String tableName);
+
+  void unbindTableMetrics(String tableName);
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaRegionMetric.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaRegionMetric.java
index 667f079e064..44cdc802fc2 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaRegionMetric.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/ISchemaRegionMetric.java
@@ -21,4 +21,9 @@ package org.apache.iotdb.db.schemaengine.metric;
 
 import org.apache.iotdb.metrics.metricsets.IMetricSet;
 
-public interface ISchemaRegionMetric extends IMetricSet {}
+public interface ISchemaRegionMetric extends IMetricSet {
+
+  void bindTableMetrics(String tableName);
+
+  void unbindTableMetrics(String tableName);
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineCachedMetric.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineCachedMetric.java
index 8620cda8265..b9093c890ec 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineCachedMetric.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineCachedMetric.java
@@ -129,4 +129,14 @@ public class SchemaEngineCachedMetric implements 
ISchemaEngineMetric {
         Tag.NAME.toString(),
         RELEASE_FLUSH_THREAD_NUM);
   }
+
+  @Override
+  public void bindTableMetrics(final String tableName) {
+    schemaEngineMemMetric.bindTableMetrics(tableName);
+  }
+
+  @Override
+  public void unbindTableMetrics(final String tableName) {
+    schemaEngineMemMetric.unbindTableMetrics(tableName);
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineMemMetric.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineMemMetric.java
index 839477b434d..e91811c50ec 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineMemMetric.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaEngineMemMetric.java
@@ -38,17 +38,21 @@ public class SchemaEngineMemMetric implements 
ISchemaEngineMetric {
   private static final String MEM_CAPACITY = "schema_region_mem_capacity";
   private static final String REGION_NUMBER = "schema_region_number";
   private static final String DEVICE_NUMBER = "schema_region_total_device_cnt";
+  private static final String TABLE_DEVICE_NUMBER = 
"schema_region_total_table_device_cnt";
   private static final String SCHEMA_CONSENSUS = "schema_region_consensus";
   private static final String SCHEMA_ENGINE_MODE = "schema_engine_mode";
+  public static final String TABLE = "table";
 
   private final MemSchemaEngineStatistics engineStatistics;
+  private AbstractMetricService metricService;
 
-  public SchemaEngineMemMetric(MemSchemaEngineStatistics engineStatistics) {
+  public SchemaEngineMemMetric(final MemSchemaEngineStatistics 
engineStatistics) {
     this.engineStatistics = engineStatistics;
   }
 
   @Override
-  public void bindTo(AbstractMetricService metricService) {
+  public void bindTo(final AbstractMetricService metricService) {
+    this.metricService = metricService;
     metricService.createAutoGauge(
         Metric.SCHEMA_ENGINE.toString(),
         MetricLevel.IMPORTANT,
@@ -100,7 +104,20 @@ public class SchemaEngineMemMetric implements 
ISchemaEngineMetric {
   }
 
   @Override
-  public void unbindFrom(AbstractMetricService metricService) {
+  public void bindTableMetrics(final String tableName) {
+    metricService.createAutoGauge(
+        Metric.SCHEMA_ENGINE.toString(),
+        MetricLevel.IMPORTANT,
+        engineStatistics,
+        statistics -> statistics.getTableDeviceNumber(tableName),
+        Tag.NAME.toString(),
+        TABLE_DEVICE_NUMBER,
+        TABLE,
+        tableName);
+  }
+
+  @Override
+  public void unbindFrom(final AbstractMetricService metricService) {
     metricService.remove(
         MetricType.AUTO_GAUGE, Metric.SCHEMA_ENGINE.toString(), 
Tag.NAME.toString(), DEVICE_NUMBER);
     metricService.remove(
@@ -123,6 +140,17 @@ public class SchemaEngineMemMetric implements 
ISchemaEngineMetric {
         MetricType.GAUGE, Metric.SCHEMA_ENGINE.toString(), 
Tag.NAME.toString(), SCHEMA_CONSENSUS);
   }
 
+  @Override
+  public void unbindTableMetrics(final String tableName) {
+    metricService.remove(
+        MetricType.AUTO_GAUGE,
+        Metric.SCHEMA_ENGINE.toString(),
+        Tag.NAME.toString(),
+        TABLE_DEVICE_NUMBER,
+        TABLE,
+        tableName);
+  }
+
   /**
    * Encode SchemaRegionConsensusProtocol to ordinal.
    *
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaMetricManager.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaMetricManager.java
index 85791e7366d..ed1d57f5998 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaMetricManager.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaMetricManager.java
@@ -44,6 +44,10 @@ public class SchemaMetricManager {
     MetricService.getInstance().addMetricSet(engineMetric);
   }
 
+  public ISchemaEngineMetric getEngineMetric() {
+    return engineMetric;
+  }
+
   public void addSchemaRegionMetric(int schemaRegionId, ISchemaRegionMetric 
schemaRegionMetric) {
     schemaRegionMetricMap.put(schemaRegionId, schemaRegionMetric);
     MetricService.getInstance().addMetricSet(schemaRegionMetric);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionCachedMetric.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionCachedMetric.java
index 91ed7a54eec..aa0d2626b02 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionCachedMetric.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionCachedMetric.java
@@ -338,6 +338,16 @@ public class SchemaRegionCachedMetric implements 
ISchemaRegionMetric {
                     database));
   }
 
+  @Override
+  public void bindTableMetrics(final String tableName) {
+    memSchemaRegionMetric.bindTableMetrics(tableName);
+  }
+
+  @Override
+  public void unbindTableMetrics(final String tableName) {
+    memSchemaRegionMetric.unbindTableMetrics(tableName);
+  }
+
   public void recordRelease(long time, long mem, long node) {
     releaseTimer.update(time, TimeUnit.MILLISECONDS);
     releaseMem.inc(mem);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionMemMetric.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionMemMetric.java
index ae255cc0caa..31f02e9c353 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionMemMetric.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/metric/SchemaRegionMemMetric.java
@@ -34,10 +34,13 @@ public class SchemaRegionMemMetric implements 
ISchemaRegionMetric {
 
   private static final String MEM_USAGE = "schema_region_mem_usage";
   private static final String SERIES_CNT = "schema_region_series_cnt";
+  private static final String NON_VIEW_SERIES_CNT = 
"schema_region_non_view_series_cnt";
   private static final String DEVICE_NUMBER = "schema_region_device_cnt";
+  private static final String TABLE_DEVICE_NUMBER = 
"schema_region_table_device_cnt";
   private static final String TEMPLATE_CNT = "activated_template_cnt";
   private static final String TEMPLATE_SERIES_CNT = "template_series_cnt";
   private static final String TRAVERSER_TIMER = 
"schema_region_traverser_timer";
+  private AbstractMetricService metricService;
 
   private Timer traverserTimer = DoNothingMetricManager.DO_NOTHING_TIMER;
 
@@ -53,6 +56,7 @@ public class SchemaRegionMemMetric implements 
ISchemaRegionMetric {
 
   @Override
   public void bindTo(AbstractMetricService metricService) {
+    this.metricService = metricService;
     metricService.createAutoGauge(
         Metric.SCHEMA_REGION.toString(),
         MetricLevel.IMPORTANT,
@@ -86,6 +90,17 @@ public class SchemaRegionMemMetric implements 
ISchemaRegionMetric {
         regionTagValue,
         Tag.DATABASE.toString(),
         database);
+    metricService.createAutoGauge(
+        Metric.SCHEMA_REGION.toString(),
+        MetricLevel.IMPORTANT,
+        regionStatistics,
+        i -> i.getSeriesNumber(false),
+        Tag.NAME.toString(),
+        NON_VIEW_SERIES_CNT,
+        Tag.REGION.toString(),
+        regionTagValue,
+        Tag.DATABASE.toString(),
+        database);
     metricService.createAutoGauge(
         Metric.SCHEMA_REGION.toString(),
         MetricLevel.IMPORTANT,
@@ -120,6 +135,23 @@ public class SchemaRegionMemMetric implements 
ISchemaRegionMetric {
             database);
   }
 
+  @Override
+  public void bindTableMetrics(final String tableName) {
+    metricService.createAutoGauge(
+        Metric.SCHEMA_REGION.toString(),
+        MetricLevel.IMPORTANT,
+        regionStatistics,
+        statistics -> statistics.getTableDevicesNumber(tableName),
+        Tag.NAME.toString(),
+        TABLE_DEVICE_NUMBER,
+        Tag.REGION.toString(),
+        regionTagValue,
+        Tag.DATABASE.toString(),
+        database,
+        SchemaEngineMemMetric.TABLE,
+        tableName);
+  }
+
   @Override
   public void unbindFrom(AbstractMetricService metricService) {
     traverserTimer = DoNothingMetricManager.DO_NOTHING_TIMER;
@@ -150,6 +182,15 @@ public class SchemaRegionMemMetric implements 
ISchemaRegionMetric {
         regionTagValue,
         Tag.DATABASE.toString(),
         database);
+    metricService.remove(
+        MetricType.AUTO_GAUGE,
+        Metric.SCHEMA_REGION.toString(),
+        Tag.NAME.toString(),
+        NON_VIEW_SERIES_CNT,
+        Tag.REGION.toString(),
+        regionTagValue,
+        Tag.DATABASE.toString(),
+        database);
     metricService.remove(
         MetricType.AUTO_GAUGE,
         Metric.SCHEMA_REGION.toString(),
@@ -179,6 +220,21 @@ public class SchemaRegionMemMetric implements 
ISchemaRegionMetric {
         database);
   }
 
+  @Override
+  public void unbindTableMetrics(final String tableName) {
+    metricService.remove(
+        MetricType.AUTO_GAUGE,
+        Metric.SCHEMA_REGION.toString(),
+        Tag.NAME.toString(),
+        TABLE_DEVICE_NUMBER,
+        Tag.REGION.toString(),
+        regionTagValue,
+        Tag.DATABASE.toString(),
+        database,
+        SchemaEngineMemMetric.TABLE,
+        tableName);
+  }
+
   public void recordTraverser(long time) {
     traverserTimer.update(time, TimeUnit.MILLISECONDS);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/ISchemaEngineStatistics.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/ISchemaEngineStatistics.java
index cca3cecfc69..2389d4f2829 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/ISchemaEngineStatistics.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/ISchemaEngineStatistics.java
@@ -33,6 +33,8 @@ public interface ISchemaEngineStatistics {
 
   long getTotalDevicesNumber();
 
+  long getTableDeviceNumber(final String tableName);
+
   int getSchemaRegionNumber();
 
   long getTemplateSeriesNumber();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaEngineStatistics.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaEngineStatistics.java
index ad0fd7947db..7c8c2677841 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaEngineStatistics.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaEngineStatistics.java
@@ -25,13 +25,18 @@ import org.apache.iotdb.db.conf.DataNodeMemoryConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
 import org.apache.iotdb.db.schemaengine.SchemaEngine;
+import org.apache.iotdb.db.schemaengine.metric.ISchemaEngineMetric;
 import org.apache.iotdb.db.schemaengine.template.ClusterTemplateManager;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.annotation.Nonnull;
+
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
 
 /** This class is used to record the global statistics of SchemaEngine in 
Memory mode. */
@@ -50,6 +55,7 @@ public class MemSchemaEngineStatistics implements 
ISchemaEngineStatistics {
   private final AtomicLong totalMeasurementNumber = new AtomicLong(0);
   private final AtomicLong totalViewNumber = new AtomicLong(0);
   private final AtomicLong totalDeviceNumber = new AtomicLong(0);
+  private final ConcurrentMap<String, Long> tableDeviceNumber = new 
ConcurrentHashMap<>();
   private final Map<Integer, Integer> templateUsage = new 
ConcurrentHashMap<>();
   private volatile boolean allowToCreateNewSeries = true;
 
@@ -133,6 +139,11 @@ public class MemSchemaEngineStatistics implements 
ISchemaEngineStatistics {
     return totalDeviceNumber.get();
   }
 
+  @Override
+  public long getTableDeviceNumber(final String tableName) {
+    return tableDeviceNumber.getOrDefault(tableName, 0L);
+  }
+
   @Override
   public int getSchemaRegionNumber() {
     return SchemaEngine.getInstance().getSchemaRegionNumber();
@@ -190,6 +201,38 @@ public class MemSchemaEngineStatistics implements 
ISchemaEngineStatistics {
     totalDeviceNumber.addAndGet(-cnt);
   }
 
+  public void addTableDevice(final String table) {
+    tableDeviceNumber.compute(
+        table,
+        (tableName, num) -> {
+          if (Objects.nonNull(num)) {
+            return num + 1;
+          }
+          final ISchemaEngineMetric metric = 
SchemaEngine.getInstance().getSchemaEngineMetric();
+          if (Objects.nonNull(metric)) {
+            metric.bindTableMetrics(table);
+          }
+          return 1L;
+        });
+  }
+
+  public void decreaseTableDevice(final String table, final long decrease) {
+    tableDeviceNumber.computeIfPresent(table, (tableName, num) -> num - 
decrease);
+  }
+
+  // Reset table device, will alter the schema statistics as well
+  public void resetTableDevice(final @Nonnull String table) {
+    final Long num = tableDeviceNumber.remove(table);
+    if (Objects.isNull(num)) {
+      return;
+    }
+    totalDeviceNumber.addAndGet(-num);
+    final ISchemaEngineMetric metric = 
SchemaEngine.getInstance().getSchemaEngineMetric();
+    if (Objects.nonNull(metric)) {
+      metric.unbindTableMetrics(table);
+    }
+  }
+
   @Override
   public MemSchemaEngineStatistics getAsMemSchemaEngineStatistics() {
     return this;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaRegionStatistics.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaRegionStatistics.java
index 902eb24e94e..6eed27d2d8e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaRegionStatistics.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/rescon/MemSchemaRegionStatistics.java
@@ -21,6 +21,8 @@ package org.apache.iotdb.db.schemaengine.rescon;
 
 import org.apache.iotdb.commons.schema.template.Template;
 import org.apache.iotdb.db.i18n.DataNodeSchemaMessages;
+import org.apache.iotdb.db.schemaengine.SchemaEngine;
+import org.apache.iotdb.db.schemaengine.metric.ISchemaRegionMetric;
 import org.apache.iotdb.db.schemaengine.template.ClusterTemplateManager;
 
 import java.util.Map;
@@ -127,18 +129,37 @@ public class MemSchemaRegionStatistics implements 
ISchemaRegionStatistics {
   }
 
   public void addTableDevice(final String table) {
-    tableDeviceNumber.compute(table, (tableName, num) -> Objects.nonNull(num) 
? num + 1 : 1L);
+    tableDeviceNumber.compute(
+        table,
+        (tableName, num) -> {
+          if (Objects.nonNull(num)) {
+            return num + 1;
+          }
+          final ISchemaRegionMetric metric =
+              SchemaEngine.getInstance().getSchemaRegionMetric(schemaRegionId);
+          if (Objects.nonNull(metric)) {
+            metric.bindTableMetrics(table);
+          }
+          return 1L;
+        });
+    schemaEngineStatistics.addTableDevice(table);
   }
 
   public void decreaseTableDevice(final String table, final long decrease) {
     tableDeviceNumber.computeIfPresent(table, (tableName, num) -> num - 
decrease);
+    schemaEngineStatistics.decreaseTableDevice(table, decrease);
   }
 
   // Reset table device, will alter the schema statistics as well
   public void resetTableDevice(final String table) {
     final long num = tableDeviceNumber.remove(table);
     devicesNumber.addAndGet(-num);
-    schemaEngineStatistics.deleteDevice(num);
+    final ISchemaRegionMetric metric =
+        SchemaEngine.getInstance().getSchemaRegionMetric(schemaRegionId);
+    if (Objects.nonNull(metric)) {
+      metric.unbindTableMetrics(table);
+    }
+    schemaEngineStatistics.resetTableDevice(table);
   }
 
   public void addDevice() {
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java
index 238af422299..70c4976df28 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java
@@ -30,6 +30,8 @@ public enum Metric {
   // cluster related
   NODE_NUM("node_num"),
   DATABASE_NUM("database_num"),
+  TABLE_DATABASE_NUM("table_database_num"),
+  TABLE_NUM("table_num"),
   REGION_NUM("region_num"),
   REGION_NUM_IN_DATA_NODE("region_num_in_data_node"),
   REGION_GROUP_LEADER_NUM_IN_DATA_NODE("region_group_leader_num_in_data_node"),

Reply via email to