You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2020/04/14 14:25:43 UTC

[incubator-doris] branch master updated: [New Feature] Support setting replica quota in db level (#3283)

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

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 9257535  [New Feature] Support setting replica quota in db level (#3283)
9257535 is described below

commit 9257535f913bea152c81dc9e94b7e2935f8de631
Author: caiconghui <55...@users.noreply.github.com>
AuthorDate: Tue Apr 14 09:25:32 2020 -0500

    [New Feature] Support setting replica quota in db level (#3283)
    
    This PR is to limit the replica usage, admin need to know the replica usage for every db and
    table, be able to set replica quota for every db.
    
    ```
    ALTER DATABASE db_name SET REPLICA QUOTA quota;
    ```
---
 .../Data Definition/ALTER DATABASE.md              |   9 +-
 .../sql-statements/Data Manipulation/SHOW DATA.md  |  10 +-
 .../Data Definition/ALTER DATABASE_EN.md           |   1 +
 .../Data Manipulation/SHOW DATA_EN.md              |  10 +-
 fe/src/main/cup/sql_parser.cup                     |   8 +-
 .../doris/analysis/AlterDatabaseQuotaStmt.java     |  28 ++++--
 .../org/apache/doris/analysis/ShowDataStmt.java    |  27 ++++--
 .../java/org/apache/doris/catalog/Catalog.java     |  22 +++--
 .../java/org/apache/doris/catalog/Database.java    |  88 ++++++++++++-----
 .../apache/doris/catalog/MaterializedIndex.java    |   8 ++
 .../java/org/apache/doris/catalog/OlapTable.java   |   8 ++
 .../java/org/apache/doris/catalog/Partition.java   |   8 ++
 .../java/org/apache/doris/common/FeConstants.java  |   1 +
 .../org/apache/doris/common/FeMetaVersion.java     |   6 +-
 .../org/apache/doris/common/proc/DbsProcDir.java   |  10 +-
 .../apache/doris/common/proc/TablesProcDir.java    |   6 +-
 .../org/apache/doris/common/util/ParseUtil.java    |  15 ++-
 fe/src/main/java/org/apache/doris/load/Load.java   |   2 +-
 .../org/apache/doris/persist/DatabaseInfo.java     |  14 ++-
 .../java/org/apache/doris/persist/EditLog.java     |   2 +-
 .../doris/analysis/AlterDatabaseQuotaStmtTest.java | 107 +++++++++++++--------
 .../apache/doris/analysis/ShowDataStmtTest.java    |   4 +-
 .../apache/doris/common/proc/DbsProcDirTest.java   |   8 +-
 23 files changed, 288 insertions(+), 114 deletions(-)

diff --git a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER DATABASE.md b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER DATABASE.md
index 66b692c..f6f1c4c 100644
--- a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER DATABASE.md	
+++ b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER DATABASE.md	
@@ -27,8 +27,12 @@ under the License.
         2) 重命名数据库
             ALTER DATABASE db_name RENAME new_db_name;
             
+        3) 设置数据库的副本数量配额
+            ALTER DATABASE db_name SET REPLICA QUOTA quota; 
+            
     说明:
-        重命名数据库后,如需要,请使用 REVOKE 和 GRANT 命令修改相应的用户权限。 
+        重命名数据库后,如需要,请使用 REVOKE 和 GRANT 命令修改相应的用户权限。
+        数据库的默认数据量配额为1024GB,默认副本数量配额为1073741824。
 
 ## example
     1. 设置指定数据库数据量配额
@@ -42,6 +46,9 @@ under the License.
 
     2. 将数据库 example_db 重命名为 example_db2
         ALTER DATABASE example_db RENAME example_db2;
+        
+    3. 设定指定数据库副本数量配额
+        ALTER DATABASE example_db SET REPLICA QUOTA 102400; 
 
 ## keyword
     ALTER,DATABASE,RENAME
diff --git a/docs/documentation/cn/sql-reference/sql-statements/Data Manipulation/SHOW DATA.md b/docs/documentation/cn/sql-reference/sql-statements/Data Manipulation/SHOW DATA.md
index 48c0d70..74f7e2e 100644
--- a/docs/documentation/cn/sql-reference/sql-statements/Data Manipulation/SHOW DATA.md	
+++ b/docs/documentation/cn/sql-reference/sql-statements/Data Manipulation/SHOW DATA.md	
@@ -19,20 +19,20 @@ under the License.
 
 # SHOW DATA
 ## description
-    该语句用于展示数据量
+    该语句用于展示数据量和副本数量
     语法:
         SHOW DATA [FROM db_name[.table_name]];
         
     说明:
-        1. 如果不指定 FROM 子句,使用展示当前 db 下细分到各个 table 的数据量
-        2. 如果指定 FROM 子句,则展示 table 下细分到各个 index 的数据量
+        1. 如果不指定 FROM 子句,使用展示当前 db 下细分到各个 table 的数据量和副本数量
+        2. 如果指定 FROM 子句,则展示 table 下细分到各个 index 的数据量和副本数量
         3. 如果想查看各个 Partition 的大小,请参阅 help show partitions
 
 ## example
-    1. 展示默认 db 的各个 table 的数据量及汇总数据量
+    1. 展示默认 db 的各个 table 的数据量,副本数量,汇总数据量和汇总副本数量。
         SHOW DATA;
         
-    2. 展示指定 db 的下指定表的细分数据量
+    2. 展示指定 db 的下指定表的细分数据量和副本数量
         SHOW DATA FROM example_db.table_name;
 
 ## keyword
diff --git a/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER DATABASE_EN.md b/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER DATABASE_EN.md
index 01aae63..daadef1 100644
--- a/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER DATABASE_EN.md	
+++ b/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER DATABASE_EN.md	
@@ -29,6 +29,7 @@ ALTER DATABASE db_name RENAME new_db_name;
 
 Explain:
 After renaming the database, use REVOKE and GRANT commands to modify the corresponding user rights if necessary.
+The database's default data quota is 1024GB, and the default replica quota is 1073741824.
 
 ## example
 1. Setting the specified database data quota
diff --git a/docs/documentation/en/sql-reference/sql-statements/Data Manipulation/SHOW DATA_EN.md b/docs/documentation/en/sql-reference/sql-statements/Data Manipulation/SHOW DATA_EN.md
index 1f03374..d9af60c 100644
--- a/docs/documentation/en/sql-reference/sql-statements/Data Manipulation/SHOW DATA_EN.md	
+++ b/docs/documentation/en/sql-reference/sql-statements/Data Manipulation/SHOW DATA_EN.md	
@@ -19,20 +19,20 @@ under the License.
 
 # SHOW DATA
 ## Description
-This statement is used to show the amount of data
+This statement is used to show the amount of data and the number of replica
 Grammar:
 SHOW DATA [FROM db_name[.table_name]];
 
 Explain:
-1. If you do not specify the FROM clause, use the amount of data that shows the current DB subdivided into tables
-2. If the FROM clause is specified, the amount of data subdivided into indices under the table is shown.
+1. If you do not specify the FROM clause, use the amount of data and the number of replica that shows the current DB subdivided into tables
+2. If the FROM clause is specified, the amount of data and the number of replica subdivided into indices under the table is shown.
 3. If you want to see the size of individual Partitions, see help show partitions
 
 ## example
-1. Display the data volume and aggregate data volume of each table of default DB
+1. Display the data volume, replica size, aggregate data volume and aggregate replica count of each table of default DB
 SHOW DATA;
 
-2. Display the subdivision data volume of the specified table below the specified DB
+2. Display the subdivision data volume and replica count of the specified table below the specified DB
 SHOW DATA FROM example_db.table_name;
 
 ## keyword
diff --git a/fe/src/main/cup/sql_parser.cup b/fe/src/main/cup/sql_parser.cup
index 120fadf..69c1a6f 100644
--- a/fe/src/main/cup/sql_parser.cup
+++ b/fe/src/main/cup/sql_parser.cup
@@ -23,6 +23,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.doris.analysis.AlterDatabaseQuotaStmt.QuotaType;
 import org.apache.doris.analysis.SetOperationStmt.Qualifier;
 import org.apache.doris.analysis.SetOperationStmt.Operation;
 import org.apache.doris.analysis.SetOperationStmt.SetOperand;
@@ -711,8 +712,13 @@ alter_stmt ::=
     :}
     | KW_ALTER KW_DATABASE ident:dbName KW_SET KW_DATA KW_QUOTA quantity:quota_quantity
     {:
-        RESULT = new AlterDatabaseQuotaStmt(dbName, quota_quantity);
+        RESULT = new AlterDatabaseQuotaStmt(dbName, QuotaType.DATA, quota_quantity);
     :}
+    | KW_ALTER KW_DATABASE ident:dbName KW_SET KW_REPLICA KW_QUOTA INTEGER_LITERAL:number
+    {:
+        RESULT = new AlterDatabaseQuotaStmt(dbName, QuotaType.REPLICA, String.valueOf(number));
+    :}
+
     | KW_ALTER KW_DATABASE ident:dbName KW_RENAME ident:newDbName
     {:
         RESULT = new AlterDatabaseRename(dbName, newDbName);
diff --git a/fe/src/main/java/org/apache/doris/analysis/AlterDatabaseQuotaStmt.java b/fe/src/main/java/org/apache/doris/analysis/AlterDatabaseQuotaStmt.java
index 188a94c..725d3b0 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterDatabaseQuotaStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterDatabaseQuotaStmt.java
@@ -30,12 +30,20 @@ import com.google.common.base.Strings;
 
 public class AlterDatabaseQuotaStmt extends DdlStmt {
     private String dbName;
-    private String quotaQuantity;
+    private QuotaType quotaType;
+    private String quotaValue;
     private long quota;
 
-    public AlterDatabaseQuotaStmt(String dbName, String quotaQuantity) {
+    public enum QuotaType {
+        NONE,
+        DATA,
+        REPLICA
+    }
+
+    public AlterDatabaseQuotaStmt(String dbName, QuotaType quotaType, String quotaValue) {
         this.dbName = dbName;
-        this.quotaQuantity = quotaQuantity;
+        this.quotaType = quotaType;
+        this.quotaValue = quotaValue;
     }
 
     public String getDbName() {
@@ -46,7 +54,10 @@ public class AlterDatabaseQuotaStmt extends DdlStmt {
         return quota;
     }
 
-   
+    public QuotaType getQuotaType() {
+        return quotaType;
+    }
+
     @Override
     public void analyze(Analyzer analyzer) throws UserException {
         super.analyze(analyzer);
@@ -59,11 +70,16 @@ public class AlterDatabaseQuotaStmt extends DdlStmt {
             ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR);
         }
         dbName = ClusterNamespace.getFullName(getClusterName(), dbName);
-        quota = ParseUtil.analyzeDataVolumn(quotaQuantity);
+        if (quotaType == QuotaType.DATA) {
+            quota = ParseUtil.analyzeDataVolumn(quotaValue);
+        } else if (quotaType == QuotaType.REPLICA) {
+            quota = ParseUtil.analyzeReplicaNumber(quotaValue);
+        }
+
     }
 
     @Override
     public String toSql() {
-        return "ALTER DATABASE " + dbName + " SET DATA QUOTA " + quotaQuantity;
+        return "ALTER DATABASE " + dbName + " SET " + (quotaType == QuotaType.DATA ? "DATA" : "REPLICA") +" QUOTA " + quotaValue;
     }
 }
diff --git a/fe/src/main/java/org/apache/doris/analysis/ShowDataStmt.java b/fe/src/main/java/org/apache/doris/analysis/ShowDataStmt.java
index 6cfdecb..dc85665 100644
--- a/fe/src/main/java/org/apache/doris/analysis/ShowDataStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/ShowDataStmt.java
@@ -53,6 +53,7 @@ public class ShowDataStmt extends ShowStmt {
             ShowResultSetMetaData.builder()
                     .addColumn(new Column("TableName", ScalarType.createVarchar(20)))
                     .addColumn(new Column("Size", ScalarType.createVarchar(30)))
+                    .addColumn(new Column("ReplicaCount", ScalarType.createVarchar(20)))
                     .build();
 
     private static final ShowResultSetMetaData SHOW_INDEX_DATA_META_DATA =
@@ -60,6 +61,7 @@ public class ShowDataStmt extends ShowStmt {
                     .addColumn(new Column("TableName", ScalarType.createVarchar(20)))
                     .addColumn(new Column("IndexName", ScalarType.createVarchar(20)))
                     .addColumn(new Column("Size", ScalarType.createVarchar(30)))
+                    .addColumn(new Column("ReplicaCount", ScalarType.createVarchar(20)))
                     .build();
 
     private String dbName;
@@ -94,6 +96,7 @@ public class ShowDataStmt extends ShowStmt {
         try {
             if (tableName == null) {
                 long totalSize = 0;
+                long totalReplicaCount = 0;
 
                 // sort by table name
                 List<Table> tables = db.getTables();
@@ -120,36 +123,42 @@ public class ShowDataStmt extends ShowStmt {
 
                     OlapTable olapTable = (OlapTable) table;
                     long tableSize = olapTable.getDataSize();
+                    long replicaCount = olapTable.getReplicaCount();
+
                     Pair<Double, String> tableSizePair = DebugUtil.getByteUint(tableSize);
                     String readableSize = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(tableSizePair.first) + " "
                             + tableSizePair.second;
 
-                    List<String> row = Arrays.asList(table.getName(), readableSize);
+                    List<String> row = Arrays.asList(table.getName(), readableSize, String.valueOf(replicaCount));
                     totalRows.add(row);
 
                     totalSize += tableSize;
+                    totalReplicaCount += replicaCount;
                 } // end for tables
 
                 Pair<Double, String> totalSizePair = DebugUtil.getByteUint(totalSize);
                 String readableSize = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(totalSizePair.first) + " "
                         + totalSizePair.second;
-                List<String> total = Arrays.asList("Total", readableSize);
+                List<String> total = Arrays.asList("Total", readableSize, String.valueOf(totalReplicaCount));
                 totalRows.add(total);
 
                 // quota
                 long quota = db.getDataQuota();
+                long replicaQuota = db.getReplicaQuota();
                 Pair<Double, String> quotaPair = DebugUtil.getByteUint(quota);
                 String readableQuota = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(quotaPair.first) + " "
                         + quotaPair.second;
-                List<String> quotaRow = Arrays.asList("Quota", readableQuota);
+
+                List<String> quotaRow = Arrays.asList("Quota", readableQuota, String.valueOf(replicaQuota));
                 totalRows.add(quotaRow);
 
                 // left
                 long left = Math.max(0, quota - totalSize);
+                long replicaCountLeft = Math.max(0, replicaQuota - totalReplicaCount);
                 Pair<Double, String> leftPair = DebugUtil.getByteUint(left);
                 String readableLeft = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(leftPair.first) + " "
                         + leftPair.second;
-                List<String> leftRow = Arrays.asList("Left", readableLeft);
+                List<String> leftRow = Arrays.asList("Left", readableLeft, String.valueOf(replicaCountLeft));
                 totalRows.add(leftRow);
             } else {
                 if (!Catalog.getCurrentCatalog().getAuth().checkTblPriv(ConnectContext.get(), dbName,
@@ -173,6 +182,7 @@ public class ShowDataStmt extends ShowStmt {
                 OlapTable olapTable = (OlapTable) table;
                 int i = 0;
                 long totalSize = 0;
+                long totalReplicaCount = 0;
 
                 // sort by index name
                 Map<String, Long> indexNames = olapTable.getIndexNameToId();
@@ -183,9 +193,11 @@ public class ShowDataStmt extends ShowStmt {
 
                 for (Long indexId : sortedIndexNames.values()) {
                     long indexSize = 0;
+                    long indexReplicaCount = 0;
                     for (Partition partition : olapTable.getAllPartitions()) {
                         MaterializedIndex mIndex = partition.getIndex(indexId);
                         indexSize += mIndex.getDataSize();
+                        indexReplicaCount += mIndex.getReplicaCount();
                     }
 
                     Pair<Double, String> indexSizePair = DebugUtil.getByteUint(indexSize);
@@ -196,14 +208,15 @@ public class ShowDataStmt extends ShowStmt {
                     if (i == 0) {
                         row = Arrays.asList(tableName,
                                             olapTable.getIndexNameById(indexId),
-                                            readableSize);
+                                            readableSize, String.valueOf(indexReplicaCount));
                     } else {
                         row = Arrays.asList("",
                                             olapTable.getIndexNameById(indexId),
-                                            readableSize);
+                                            readableSize, String.valueOf(indexReplicaCount));
                     }
 
                     totalSize += indexSize;
+                    totalReplicaCount += indexReplicaCount;
                     totalRows.add(row);
 
                     i++;
@@ -212,7 +225,7 @@ public class ShowDataStmt extends ShowStmt {
                 Pair<Double, String> totalSizePair = DebugUtil.getByteUint(totalSize);
                 String readableSize = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(totalSizePair.first) + " "
                         + totalSizePair.second;
-                List<String> row = Arrays.asList("", "Total", readableSize);
+                List<String> row = Arrays.asList("", "Total", readableSize, String.valueOf(totalReplicaCount));
                 totalRows.add(row);
             }
         } finally {
diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
index 928b30b..a280e65 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -34,6 +34,7 @@ import org.apache.doris.analysis.AdminSetReplicaStatusStmt;
 import org.apache.doris.analysis.AlterClause;
 import org.apache.doris.analysis.AlterClusterStmt;
 import org.apache.doris.analysis.AlterDatabaseQuotaStmt;
+import org.apache.doris.analysis.AlterDatabaseQuotaStmt.QuotaType;
 import org.apache.doris.analysis.AlterDatabaseRename;
 import org.apache.doris.analysis.AlterSystemStmt;
 import org.apache.doris.analysis.AlterTableStmt;
@@ -2781,16 +2782,25 @@ public class Catalog {
             ErrorReport.reportDdlException(ErrorCode.ERR_BAD_DB_ERROR, dbName);
         }
 
-        db.setDataQuotaWithLock(stmt.getQuota());
-
-        DatabaseInfo dbInfo = new DatabaseInfo(dbName, "", db.getDataQuota());
+        QuotaType quotaType = stmt.getQuotaType();
+        if (quotaType == QuotaType.DATA) {
+            db.setDataQuotaWithLock(stmt.getQuota());
+        } else if (quotaType == QuotaType.REPLICA) {
+            db.setReplicaQuotaWithLock(stmt.getQuota());
+        }
+        long quota = stmt.getQuota();
+        DatabaseInfo dbInfo = new DatabaseInfo(dbName, "", quota, quotaType);
         editLog.logAlterDb(dbInfo);
     }
 
-    public void replayAlterDatabaseQuota(String dbName, long quota) {
+    public void replayAlterDatabaseQuota(String dbName, long quota, QuotaType quotaType) {
         Database db = getDb(dbName);
         Preconditions.checkNotNull(db);
-        db.setDataQuotaWithLock(quota);
+        if (quotaType == QuotaType.DATA) {
+            db.setDataQuotaWithLock(quota);
+        } else if (quotaType == QuotaType.REPLICA) {
+            db.setReplicaQuotaWithLock(quota);
+        }
     }
 
     public void renameDatabase(AlterDatabaseRename stmt) throws DdlException {
@@ -2835,7 +2845,7 @@ public class Catalog {
             fullNameToDb.remove(fullDbName);
             fullNameToDb.put(newFullDbName, db);
 
-            DatabaseInfo dbInfo = new DatabaseInfo(fullDbName, newFullDbName, -1L);
+            DatabaseInfo dbInfo = new DatabaseInfo(fullDbName, newFullDbName, -1L, QuotaType.NONE);
             editLog.logDatabaseRename(dbInfo);
         } finally {
             unlock();
diff --git a/fe/src/main/java/org/apache/doris/catalog/Database.java b/fe/src/main/java/org/apache/doris/catalog/Database.java
index c8c9d92..fa53e14 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Database.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Database.java
@@ -17,9 +17,6 @@
 
 package org.apache.doris.catalog;
 
-import org.apache.doris.catalog.MaterializedIndex.IndexExtState;
-import org.apache.doris.catalog.MaterializedIndex.IndexState;
-import org.apache.doris.catalog.Replica.ReplicaState;
 import org.apache.doris.catalog.Table.TableType;
 import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.DdlException;
@@ -95,6 +92,8 @@ public class Database extends MetaObject implements Writable {
 
     private long dataQuotaBytes;
 
+    private long replicaQuotaSize;
+
     public enum DbState {
         NORMAL, LINK, MOVE
     }
@@ -116,6 +115,7 @@ public class Database extends MetaObject implements Writable {
         this.idToTable = new ConcurrentHashMap<>();
         this.nameToTable = new HashMap<String, Table>();
         this.dataQuotaBytes = FeConstants.default_db_data_quota_bytes;
+        this.replicaQuotaSize = FeConstants.default_db_replica_quota_size;
         this.dbState = DbState.NORMAL;
         this.attachDbName = "";
         this.clusterName = "";
@@ -192,10 +192,25 @@ public class Database extends MetaObject implements Writable {
         }
     }
 
+    public void setReplicaQuotaWithLock(long newQuota) {
+        Preconditions.checkArgument(newQuota >= 0L);
+        LOG.info("database[{}] set replica quota from {} to {}", fullQualifiedName, replicaQuotaSize, newQuota);
+        writeLock();
+        try {
+            this.replicaQuotaSize = newQuota;
+        } finally {
+            writeUnlock();
+        }
+    }
+
     public long getDataQuota() {
         return dataQuotaBytes;
     }
 
+    public long getReplicaQuota() {
+        return replicaQuotaSize;
+    }
+
     public long getDataQuotaLeftWithLock() {
         long usedDataQuota = 0;
         readLock();
@@ -206,24 +221,8 @@ public class Database extends MetaObject implements Writable {
                 }
 
                 OlapTable olapTable = (OlapTable) table;
-                for (Partition partition : olapTable.getAllPartitions()) {
-                    for (MaterializedIndex mIndex : partition.getMaterializedIndices(IndexExtState.VISIBLE)) {
-                        // skip ROLLUP index
-                        if (mIndex.getState() == IndexState.ROLLUP) {
-                            continue;
-                        }
-
-                        for (Tablet tablet : mIndex.getTablets()) {
-                            for (Replica replica : tablet.getReplicas()) {
-                                if (replica.getState() == ReplicaState.NORMAL
-                                        || replica.getState() == ReplicaState.SCHEMA_CHANGE) {
-                                    usedDataQuota += replica.getDataSize();
-                                }
-                            } // end for replicas
-                        } // end for tablets
-                    } // end for tables
-                } // end for table families
-            } // end for groups
+                usedDataQuota = usedDataQuota + olapTable.getDataSize();
+            }
 
             long leftDataQuota = dataQuotaBytes - usedDataQuota;
             return Math.max(leftDataQuota, 0L);
@@ -232,7 +231,28 @@ public class Database extends MetaObject implements Writable {
         }
     }
 
-    public void checkQuota() throws DdlException {
+
+    public long getReplicaQuotaLeftWithLock() {
+        long usedReplicaQuota = 0;
+        readLock();
+        try {
+            for (Table table : this.idToTable.values()) {
+                if (table.getType() != TableType.OLAP) {
+                    continue;
+                }
+
+                OlapTable olapTable = (OlapTable) table;
+                usedReplicaQuota = usedReplicaQuota + olapTable.getReplicaCount();
+            }
+
+            long leftReplicaQuota = replicaQuotaSize - usedReplicaQuota;
+            return Math.max(leftReplicaQuota, 0L);
+        } finally {
+            readUnlock();
+        }
+    }
+
+    public void checkDataSizeQuota() throws DdlException {
         Pair<Double, String> quotaUnitPair = DebugUtil.getByteUint(dataQuotaBytes);
         String readableQuota = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(quotaUnitPair.first) + " "
                 + quotaUnitPair.second;
@@ -251,6 +271,22 @@ public class Database extends MetaObject implements Writable {
         }
     }
 
+    public void checkReplicaQuota() throws DdlException {
+        long leftReplicaQuota = getReplicaQuotaLeftWithLock();
+        LOG.info("database[{}] replica quota: left number: {} / total: {}",
+                fullQualifiedName, leftReplicaQuota, replicaQuotaSize);
+
+        if (leftReplicaQuota <= 0L) {
+            throw new DdlException("Database[" + fullQualifiedName
+                    + "] replica number exceeds quota[" + replicaQuotaSize + "]");
+        }
+    }
+
+    public void checkQuota() throws DdlException {
+        checkDataSizeQuota();
+        checkReplicaQuota();
+    }
+
     public boolean createTableWithLock(Table table, boolean isReplay, boolean setIfNotExist) {
         boolean result = true;
         writeLock();
@@ -408,6 +444,8 @@ public class Database extends MetaObject implements Writable {
                 function.write(out);
             }
         }
+
+        out.writeLong(replicaQuotaSize);
     }
 
     public void readFields(DataInput in) throws IOException {
@@ -450,6 +488,12 @@ public class Database extends MetaObject implements Writable {
                 name2Function.put(name, builder.build());
             }
         }
+
+        if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_81) {
+            replicaQuotaSize = in.readLong();
+        } else {
+            replicaQuotaSize = FeConstants.default_db_replica_quota_size;
+        }
     }
 
     public boolean equals(Object obj) {
diff --git a/fe/src/main/java/org/apache/doris/catalog/MaterializedIndex.java b/fe/src/main/java/org/apache/doris/catalog/MaterializedIndex.java
index 65a4d37..6f8abd9 100644
--- a/fe/src/main/java/org/apache/doris/catalog/MaterializedIndex.java
+++ b/fe/src/main/java/org/apache/doris/catalog/MaterializedIndex.java
@@ -180,6 +180,14 @@ public class MaterializedIndex extends MetaObject implements Writable, GsonPostP
         return dataSize;
     }
 
+    public long getReplicaCount() {
+        long replicaCount = 0;
+        for (Tablet tablet : getTablets()) {
+            replicaCount += tablet.getReplicas().size();
+        }
+        return replicaCount;
+    }
+
     public int getTabletOrderIdx(long tabletId) {
         int idx = 0;
         for (Tablet tablet : tablets) {
diff --git a/fe/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/src/main/java/org/apache/doris/catalog/OlapTable.java
index 44e54cd..725c640 100644
--- a/fe/src/main/java/org/apache/doris/catalog/OlapTable.java
+++ b/fe/src/main/java/org/apache/doris/catalog/OlapTable.java
@@ -1162,6 +1162,14 @@ public class OlapTable extends Table {
         return dataSize;
     }
 
+    public long getReplicaCount() {
+        long replicaCount = 0;
+        for (Partition partition : getAllPartitions()) {
+            replicaCount += partition.getReplicaCount();
+        }
+        return replicaCount;
+    }
+
     public void checkStableAndNormal(String clusterName) throws DdlException {
         if (state != OlapTableState.NORMAL) {
             throw new DdlException("Table[" + name + "]'s state is not NORMAL. "
diff --git a/fe/src/main/java/org/apache/doris/catalog/Partition.java b/fe/src/main/java/org/apache/doris/catalog/Partition.java
index babb939..51b4e9f 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Partition.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Partition.java
@@ -276,6 +276,14 @@ public class Partition extends MetaObject implements Writable {
         return dataSize;
     }
 
+    public long getReplicaCount() {
+        long replicaCount = 0;
+        for (MaterializedIndex mIndex : getMaterializedIndices(IndexExtState.VISIBLE)) {
+            replicaCount += mIndex.getReplicaCount();
+        }
+        return replicaCount;
+    }
+
     public boolean hasData() {
         return !(visibleVersion == PARTITION_INIT_VERSION && visibleVersionHash == PARTITION_INIT_VERSION_HASH);
     }
diff --git a/fe/src/main/java/org/apache/doris/common/FeConstants.java b/fe/src/main/java/org/apache/doris/common/FeConstants.java
index e4fef6f..86ae36b 100644
--- a/fe/src/main/java/org/apache/doris/common/FeConstants.java
+++ b/fe/src/main/java/org/apache/doris/common/FeConstants.java
@@ -31,6 +31,7 @@ public class FeConstants {
     public static int shortkey_max_column_count = 3;
     public static int shortkey_maxsize_bytes = 36;
     public static long default_db_data_quota_bytes = 1024 * 1024 * 1024 * 1024L; // 1TB
+    public static long default_db_replica_quota_size = 1024 * 1024 * 1024;
 
     public static int heartbeat_interval_second = 5;
     public static int checkpoint_interval_second = 60; // 1 minutes
diff --git a/fe/src/main/java/org/apache/doris/common/FeMetaVersion.java b/fe/src/main/java/org/apache/doris/common/FeMetaVersion.java
index 0e07c73..4e3a0f6 100644
--- a/fe/src/main/java/org/apache/doris/common/FeMetaVersion.java
+++ b/fe/src/main/java/org/apache/doris/common/FeMetaVersion.java
@@ -169,8 +169,10 @@ public final class FeMetaVersion {
     public static final int VERSION_78 = 78;
     // for transaction state in table level
     public static final int VERSION_79 = 79;
-      // optimize alterJobV2 memory consumption
+    // optimize alterJobV2 memory consumption
     public static final int VERSION_80 = 80;
+    // replica quota support
+    public static final int VERSION_81 = 81;
     // note: when increment meta version, should assign the latest version to VERSION_CURRENT
-    public static final int VERSION_CURRENT = VERSION_80;
+    public static final int VERSION_CURRENT = VERSION_81;
 }
diff --git a/fe/src/main/java/org/apache/doris/common/proc/DbsProcDir.java b/fe/src/main/java/org/apache/doris/common/proc/DbsProcDir.java
index f7945eb..9734a31 100644
--- a/fe/src/main/java/org/apache/doris/common/proc/DbsProcDir.java
+++ b/fe/src/main/java/org/apache/doris/common/proc/DbsProcDir.java
@@ -40,7 +40,7 @@ import java.util.List;
 public class DbsProcDir implements ProcDirInterface {
     public static final ImmutableList<String> TITLE_NAMES = new ImmutableList.Builder<String>()
             .add("DbId").add("DbName").add("TableNum").add("Quota")
-            .add("LastConsistencyCheckTime")
+            .add("LastConsistencyCheckTime").add("ReplicaQuota")
             .build();
 
     private Catalog catalog;
@@ -103,13 +103,17 @@ public class DbsProcDir implements ProcDirInterface {
                 dbInfo.add(dbName);
                 dbInfo.add(tableNum);
 
-                long quota = db.getDataQuota();
-                Pair<Double, String> quotaUnitPair = DebugUtil.getByteUint(quota);
+                long dataQuota = db.getDataQuota();
+                Pair<Double, String> quotaUnitPair = DebugUtil.getByteUint(dataQuota);
                 String readableQuota = DebugUtil.DECIMAL_FORMAT_SCALE_3.format(quotaUnitPair.first) + " "
                         + quotaUnitPair.second;
                 dbInfo.add(readableQuota);
 
                 dbInfo.add(TimeUtils.longToTimeString(db.getLastCheckTime()));
+
+                long replicaQuota = db.getReplicaQuota();
+                dbInfo.add(replicaQuota);
+
             } finally {
                 db.readUnlock();
             }
diff --git a/fe/src/main/java/org/apache/doris/common/proc/TablesProcDir.java b/fe/src/main/java/org/apache/doris/common/proc/TablesProcDir.java
index 2f0a5b7..68f0c53 100644
--- a/fe/src/main/java/org/apache/doris/common/proc/TablesProcDir.java
+++ b/fe/src/main/java/org/apache/doris/common/proc/TablesProcDir.java
@@ -43,7 +43,7 @@ import java.util.List;
 public class TablesProcDir implements ProcDirInterface {
     public static final ImmutableList<String> TITLE_NAMES = new ImmutableList.Builder<String>()
             .add("TableId").add("TableName").add("IndexNum").add("PartitionColumnName")
-            .add("PartitionNum").add("State").add("Type").add("LastConsistencyCheckTime")
+            .add("PartitionNum").add("State").add("Type").add("LastConsistencyCheckTime").add("ReplicaCount")
             .build();
 
     private Database db;
@@ -97,6 +97,7 @@ public class TablesProcDir implements ProcDirInterface {
                 List<Comparable> tableInfo = new ArrayList<Comparable>();
 
                 int partitionNum = 1;
+                long replicaCount = 0;
                 String partitionKey = "N/A";
                 if (table.getType() == TableType.OLAP) {
                     OlapTable olapTable = (OlapTable) table;
@@ -113,6 +114,7 @@ public class TablesProcDir implements ProcDirInterface {
                             ++idx;
                         }
                     }
+                    replicaCount = olapTable.getReplicaCount();
                     tableInfo.add(table.getId());
                     tableInfo.add(table.getName());
                     tableInfo.add(olapTable.getIndexNameToId().size());
@@ -132,7 +134,7 @@ public class TablesProcDir implements ProcDirInterface {
 
                 // last check time
                 tableInfo.add(TimeUtils.longToTimeString(table.getLastCheckTime()));
-
+                tableInfo.add(replicaCount);
                 tableInfos.add(tableInfo);
             }
         } finally {
diff --git a/fe/src/main/java/org/apache/doris/common/util/ParseUtil.java b/fe/src/main/java/org/apache/doris/common/util/ParseUtil.java
index 613cb95..e51aeed 100644
--- a/fe/src/main/java/org/apache/doris/common/util/ParseUtil.java
+++ b/fe/src/main/java/org/apache/doris/common/util/ParseUtil.java
@@ -51,7 +51,7 @@ public class ParseUtil {
             } catch (NumberFormatException nfe) {
                 throw new AnalysisException("invalid data volumn:" + m.group(1));
             }
-            if (dataVolumn < 0L) {
+            if (dataVolumn <= 0L) {
                 throw new AnalysisException("Data volumn must larger than 0");
             }
 
@@ -71,4 +71,17 @@ public class ParseUtil {
         return dataVolumn;
     }
 
+    public static long analyzeReplicaNumber(String replicaNumberStr) throws AnalysisException {
+        long replicaNumber = 0;
+        try {
+            replicaNumber = Long.parseLong(replicaNumberStr);
+        } catch (NumberFormatException nfe) {
+            throw new AnalysisException("invalid data volumn:" + replicaNumberStr);
+        }
+        if (replicaNumber <= 0L) {
+            throw new AnalysisException("Replica volumn must larger than 0");
+        }
+        return replicaNumber;
+    }
+
 }
diff --git a/fe/src/main/java/org/apache/doris/load/Load.java b/fe/src/main/java/org/apache/doris/load/Load.java
index 8b5e8b8..a7ad4cb 100644
--- a/fe/src/main/java/org/apache/doris/load/Load.java
+++ b/fe/src/main/java/org/apache/doris/load/Load.java
@@ -381,7 +381,7 @@ public class Load {
         // for original job, check quota
         // for delete job, not check
         if (!job.isSyncDeleteJob()) {
-            db.checkQuota();
+            db.checkDataSizeQuota();
         }
 
         // check if table is in restore process
diff --git a/fe/src/main/java/org/apache/doris/persist/DatabaseInfo.java b/fe/src/main/java/org/apache/doris/persist/DatabaseInfo.java
index 73f7235..204b1e9 100644
--- a/fe/src/main/java/org/apache/doris/persist/DatabaseInfo.java
+++ b/fe/src/main/java/org/apache/doris/persist/DatabaseInfo.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.persist;
 
+import org.apache.doris.analysis.AlterDatabaseQuotaStmt.QuotaType;
 import org.apache.doris.catalog.Catalog;
 import org.apache.doris.catalog.Database.DbState;
 import org.apache.doris.common.FeMetaVersion;
@@ -34,6 +35,7 @@ public class DatabaseInfo implements Writable {
     private long quota;
     private String clusterName;
     private DbState dbState;
+    private QuotaType quotaType;
 
     public DatabaseInfo() {
         // for persist
@@ -42,14 +44,16 @@ public class DatabaseInfo implements Writable {
         this.quota = 0;
         this.clusterName = "";
         this.dbState = DbState.NORMAL;
+        this.quotaType = QuotaType.DATA;
     }
 
-    public DatabaseInfo(String dbName, String newDbName, long quota) {
+    public DatabaseInfo(String dbName, String newDbName, long quota, QuotaType quotaType) {
         this.dbName = dbName;
         this.newDbName = newDbName;
         this.quota = quota;
         this.clusterName = "";
         this.dbState = DbState.NORMAL;
+        this.quotaType = quotaType;
     }
 
     public String getDbName() {
@@ -77,6 +81,7 @@ public class DatabaseInfo implements Writable {
         out.writeLong(quota);
         Text.writeString(out, this.clusterName);
         Text.writeString(out, this.dbState.name());
+        Text.writeString(out, this.quotaType.name());
     }
 
     public void readFields(DataInput in) throws IOException {
@@ -89,6 +94,9 @@ public class DatabaseInfo implements Writable {
             this.clusterName = Text.readString(in);
             this.dbState = DbState.valueOf(Text.readString(in));
         }
+        if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_81) {
+            this.quotaType = QuotaType.valueOf(Text.readString(in));
+        }
     }
 
     public String getClusterName() {
@@ -103,8 +111,8 @@ public class DatabaseInfo implements Writable {
         return dbState;
     }
 
-    public void setDbState(DbState dbState) {
-        this.dbState = dbState;
+    public QuotaType getQuotaType() {
+        return quotaType;
     }
 
 }
diff --git a/fe/src/main/java/org/apache/doris/persist/EditLog.java b/fe/src/main/java/org/apache/doris/persist/EditLog.java
index eea291a..df1b4c9 100644
--- a/fe/src/main/java/org/apache/doris/persist/EditLog.java
+++ b/fe/src/main/java/org/apache/doris/persist/EditLog.java
@@ -150,7 +150,7 @@ public class EditLog {
                     DatabaseInfo dbInfo = (DatabaseInfo) journal.getData();
                     String dbName = dbInfo.getDbName();
                     LOG.info("Begin to unprotect alter db info {}", dbName);
-                    catalog.replayAlterDatabaseQuota(dbName, dbInfo.getQuota());
+                    catalog.replayAlterDatabaseQuota(dbName, dbInfo.getQuota(), dbInfo.getQuotaType());
                     break;
                 }
                 case OperationType.OP_ERASE_DB: {
diff --git a/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java b/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java
index b71af04..590bc51 100644
--- a/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java
+++ b/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java
@@ -18,22 +18,19 @@
 package org.apache.doris.analysis;
 
 import mockit.Expectations;
+import mockit.Mocked;
+
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.analysis.AlterDatabaseQuotaStmt.QuotaType;
 import org.apache.doris.common.UserException;
 import org.apache.doris.mysql.privilege.PaloAuth;
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
 
-import com.google.common.collect.Lists;
-
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.List;
-
-import mockit.Mocked;
-
 public class AlterDatabaseQuotaStmtTest {
     private Analyzer analyzer;
 
@@ -61,9 +58,9 @@ public class AlterDatabaseQuotaStmtTest {
         };
     }
     
-    private void testAlterDatabaseQuotaStmt(String dbName, String quotaQuantity, long quotaSize)
+    private void testAlterDatabaseDataQuotaStmt(String dbName, String quotaQuantity, long quotaSize)
             throws AnalysisException, UserException {
-        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt(dbName, quotaQuantity);
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt(dbName, QuotaType.DATA, quotaQuantity);
         stmt.analyze(analyzer);
         String expectedSql = "ALTER DATABASE testCluster:testDb SET DATA QUOTA " + quotaQuantity;
         Assert.assertEquals(expectedSql, stmt.toSql());
@@ -71,65 +68,91 @@ public class AlterDatabaseQuotaStmtTest {
     }
 
     @Test
-    public void testNormal() throws AnalysisException, UserException {
+    public void testNormalAlterDatabaseDataQuotaStmt() throws AnalysisException, UserException {
         // byte
-        testAlterDatabaseQuotaStmt("testDb", "102400", 102400L);
-        testAlterDatabaseQuotaStmt("testDb", "102400b", 102400L);
+        testAlterDatabaseDataQuotaStmt("testDb", "102400", 102400L);
+        testAlterDatabaseDataQuotaStmt("testDb", "102400b", 102400L);
 
         // kb
-        testAlterDatabaseQuotaStmt("testDb", "100kb", 100L * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100Kb", 100L * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100KB", 100L * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100K", 100L * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100k", 100L * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100kb", 100L * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100Kb", 100L * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100KB", 100L * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100K", 100L * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100k", 100L * 1024);
 
         // mb
-        testAlterDatabaseQuotaStmt("testDb", "100mb", 100L * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100Mb", 100L * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100MB", 100L * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100M", 100L * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100m", 100L * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100mb", 100L * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100Mb", 100L * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100MB", 100L * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100M", 100L * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100m", 100L * 1024 * 1024);
 
         // gb
-        testAlterDatabaseQuotaStmt("testDb", "100gb", 100L * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100Gb", 100L * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100GB", 100L * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100G", 100L * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100g", 100L * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100gb", 100L * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100Gb", 100L * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100GB", 100L * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100G", 100L * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100g", 100L * 1024 * 1024 * 1024);
 
         // tb
-        testAlterDatabaseQuotaStmt("testDb", "100tb", 100L * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100Tb", 100L * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100TB", 100L * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100T", 100L * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100t", 100L * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100tb", 100L * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100Tb", 100L * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100TB", 100L * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100T", 100L * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100t", 100L * 1024 * 1024 * 1024 * 1024);
 
         // tb
-        testAlterDatabaseQuotaStmt("testDb", "100pb", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100Pb", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100PB", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100P", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
-        testAlterDatabaseQuotaStmt("testDb", "100p", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100pb", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100Pb", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100PB", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100P", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
+        testAlterDatabaseDataQuotaStmt("testDb", "100p", 100L * 1024 * 1024 * 1024 * 1024 * 1024);
+    }
+
+    @Test(expected = AnalysisException.class)
+    public void testDataMinusQuota() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", QuotaType.DATA, "-100mb");
+        stmt.analyze(analyzer);
+        Assert.fail("No exception throws.");
+    }
+
+    @Test(expected = AnalysisException.class)
+    public void testDataInvalidUnit() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", QuotaType.DATA, "100invalid_unit");
+        stmt.analyze(analyzer);
+        Assert.fail("No exception throws.");
     }
 
     @Test(expected = AnalysisException.class)
-    public void testMinusQuota() throws AnalysisException, UserException {
-        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", "-100mb");
+    public void testDataInvalidQuantity() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", QuotaType.DATA, "invalid_100mb_quota");
         stmt.analyze(analyzer);
         Assert.fail("No exception throws.");
     }
 
+
+    @Test
+    public void testNormalAlterDatabaseReplicaQuotaStmt() throws AnalysisException, UserException {
+        long quotaSize = 1000;
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", QuotaType.REPLICA, String.valueOf(quotaSize));
+        stmt.analyze(analyzer);
+        String expectedSql = "ALTER DATABASE testCluster:testDb SET REPLICA QUOTA 1000";
+        Assert.assertEquals(expectedSql, stmt.toSql());
+        Assert.assertEquals(quotaSize, stmt.getQuota());
+    }
+
     @Test(expected = AnalysisException.class)
-    public void testInvalidUnit() throws AnalysisException, UserException {
-        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", "100invalid_unit");
+    public void testReplicaMinusQuota() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", QuotaType.REPLICA, "-100");
         stmt.analyze(analyzer);
         Assert.fail("No exception throws.");
     }
 
     @Test(expected = AnalysisException.class)
-    public void testInvalidQuantity() throws AnalysisException, UserException {
-        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", "invalid_100mb_quota");
+    public void testReplicaInvalidQuantity() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", QuotaType.REPLICA, "invalid_100_quota");
         stmt.analyze(analyzer);
         Assert.fail("No exception throws.");
     }
+
 }
diff --git a/fe/src/test/java/org/apache/doris/analysis/ShowDataStmtTest.java b/fe/src/test/java/org/apache/doris/analysis/ShowDataStmtTest.java
index 600cf1d..edcff94 100644
--- a/fe/src/test/java/org/apache/doris/analysis/ShowDataStmtTest.java
+++ b/fe/src/test/java/org/apache/doris/analysis/ShowDataStmtTest.java
@@ -135,13 +135,13 @@ public class ShowDataStmtTest {
         ShowDataStmt stmt = new ShowDataStmt(null, null);
         stmt.analyze(analyzer);
         Assert.assertEquals("SHOW DATA FROM `testCluster:testDb`", stmt.toString());
-        Assert.assertEquals(2, stmt.getMetaData().getColumnCount());
+        Assert.assertEquals(3, stmt.getMetaData().getColumnCount());
         Assert.assertEquals(false, stmt.hasTable());
         
         stmt = new ShowDataStmt("testDb", "test_tbl");
         stmt.analyze(analyzer);
         Assert.assertEquals("SHOW DATA FROM `default_cluster:testDb`.`test_tbl`", stmt.toString());
-        Assert.assertEquals(3, stmt.getMetaData().getColumnCount());
+        Assert.assertEquals(4, stmt.getMetaData().getColumnCount());
         Assert.assertEquals(true, stmt.hasTable());
     }
 }
diff --git a/fe/src/test/java/org/apache/doris/common/proc/DbsProcDirTest.java b/fe/src/test/java/org/apache/doris/common/proc/DbsProcDirTest.java
index 208233e..fa63789 100644
--- a/fe/src/test/java/org/apache/doris/common/proc/DbsProcDirTest.java
+++ b/fe/src/test/java/org/apache/doris/common/proc/DbsProcDirTest.java
@@ -183,11 +183,11 @@ public class DbsProcDirTest {
         Assert.assertNotNull(result);
         Assert.assertTrue(result instanceof BaseProcResult);
 
-        Assert.assertEquals(Lists.newArrayList("DbId", "DbName", "TableNum", "Quota", "LastConsistencyCheckTime"),
+        Assert.assertEquals(Lists.newArrayList("DbId", "DbName", "TableNum", "Quota", "LastConsistencyCheckTime", "ReplicaQuota"),
                             result.getColumnNames());
         List<List<String>> rows = Lists.newArrayList();
-        rows.add(Arrays.asList(String.valueOf(db1.getId()), db1.getFullName(), "0", "1024.000 GB", "N/A"));
-        rows.add(Arrays.asList(String.valueOf(db2.getId()), db2.getFullName(), "0", "1024.000 GB", "N/A"));
+        rows.add(Arrays.asList(String.valueOf(db1.getId()), db1.getFullName(), "0", "1024.000 GB", "N/A", "1073741824"));
+        rows.add(Arrays.asList(String.valueOf(db2.getId()), db2.getFullName(), "0", "1024.000 GB", "N/A", "1073741824"));
         Assert.assertEquals(rows, result.getRows());
     }
 
@@ -213,7 +213,7 @@ public class DbsProcDirTest {
 
         dir = new DbsProcDir(catalog);
         result = dir.fetchResult();
-        Assert.assertEquals(Lists.newArrayList("DbId", "DbName", "TableNum", "Quota", "LastConsistencyCheckTime"),
+        Assert.assertEquals(Lists.newArrayList("DbId", "DbName", "TableNum", "Quota", "LastConsistencyCheckTime", "ReplicaQuota"),
                             result.getColumnNames());
         List<List<String>> rows = Lists.newArrayList();
         Assert.assertEquals(rows, result.getRows());


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org