You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@doris.apache.org by GitBox <gi...@apache.org> on 2018/11/15 06:03:54 UTC

[GitHub] imay closed pull request #309: Optimize quota unit

imay closed pull request #309: Optimize quota unit
URL: https://github.com/apache/incubator-doris/pull/309
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/docs/help/Contents/Data Definition/ddl_stmt.md b/docs/help/Contents/Data Definition/ddl_stmt.md
index ae6f7825..ad389ed7 100644
--- a/docs/help/Contents/Data Definition/ddl_stmt.md	
+++ b/docs/help/Contents/Data Definition/ddl_stmt.md	
@@ -677,7 +677,7 @@
 ## description
     该语句用于设置指定数据库的属性。(仅管理员使用)
     语法:
-        1) 设置数据库数据量配额,单位为字节
+        1) 设置数据库数据量配额,单位为B/K/KB/M/MB/G/GB/T/TB/P/PB
             ALTER DATABASE db_name SET DATA QUOTA quota;
             
         2) 重命名数据库
@@ -687,9 +687,15 @@
         重命名数据库后,如需要,请使用 REVOKE 和 GRANT 命令修改相应的用户权限。 
 
 ## example
-    1. 设置指定数据库数据量配额为 10 TB
+    1. 设置指定数据库数据量配额
         ALTER DATABASE example_db SET DATA QUOTA 10995116277760;
-        
+        上述单位为字节,等价于
+        ALTER DATABASE example_db SET DATA QUOTA 10T;
+
+        ALTER DATABASE example_db SET DATA QUOTA 100G;
+
+        ALTER DATABASE example_db SET DATA QUOTA 200M;
+
     2. 将数据库额 example_db 重命名为 example_db2
         ALTER DATABASE example_db RENAME example_db2;
 
diff --git a/fe/src/main/cup/sql_parser.cup b/fe/src/main/cup/sql_parser.cup
index b5a038ff..1e4db913 100644
--- a/fe/src/main/cup/sql_parser.cup
+++ b/fe/src/main/cup/sql_parser.cup
@@ -262,6 +262,7 @@ nonterminal describe_command, opt_full, opt_inner, opt_outer, from_or_in, keys_o
 // String
 nonterminal String user, opt_user;
 nonterminal UserIdentity user_identity;
+nonterminal String quantity;
 
 // Description of user
 nonterminal UserDesc grant_user;
@@ -587,9 +588,9 @@ alter_stmt ::=
     {:
         RESULT = new AlterClusterStmt(name, properties);
     :}
-    | KW_ALTER KW_DATABASE ident:dbName KW_SET KW_DATA KW_QUOTA INTEGER_LITERAL:quota
+    | KW_ALTER KW_DATABASE ident:dbName KW_SET KW_DATA KW_QUOTA quantity:quota_quantity
     {:
-        RESULT = new AlterDatabaseQuotaStmt(dbName, quota);
+        RESULT = new AlterDatabaseQuotaStmt(dbName, quota_quantity);
     :}
     | KW_ALTER KW_DATABASE ident:dbName KW_RENAME ident:newDbName
     {:
@@ -597,6 +598,17 @@ alter_stmt ::=
     :}
     ;
 
+quantity ::=
+    INTEGER_LITERAL:number
+    {:
+        RESULT = number.toString();
+    :}
+    | ident:number_unit
+    {:
+        RESULT = number_unit;
+    :}
+    ;
+
 opt_user ::=
     /* empty */
     | KW_FOR user:user
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 94ec9668..cd038ef9 100644
--- a/fe/src/main/java/org/apache/doris/analysis/AlterDatabaseQuotaStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/AlterDatabaseQuotaStmt.java
@@ -26,15 +26,35 @@
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
 
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
 
 public class AlterDatabaseQuotaStmt extends DdlStmt {
     private String dbName;
+    private String quotaQuantity;
     private long quota;
+    private static ImmutableMap<String, Long> validUnitMultiplier = 
+        ImmutableMap.<String, Long>builder().put("B", 1L)
+        .put("K", 1024L)
+        .put("KB", 1024L)
+        .put("M", 1024L * 1024)
+        .put("MB", 1024L * 1024)
+        .put("G", 1024L * 1024 * 1024)
+        .put("GB", 1024L * 1024 * 1024)
+        .put("T", 1024L * 1024 * 1024 * 1024)
+        .put("TB", 1024L * 1024 * 1024 * 1024)
+        .put("P", 1024L * 1024 * 1024 * 1024 * 1024)
+        .put("PB", 1024L * 1024 * 1024 * 1024 * 1024).build();
+
+    private String quotaPattern = "(\\d+)(\\D*)";
 
-    public AlterDatabaseQuotaStmt(String dbName, long quota) {
+    public AlterDatabaseQuotaStmt(String dbName, String quotaQuantity) {
         this.dbName = dbName;
-        this.quota = quota;
+        this.quotaQuantity = quotaQuantity;
     }
 
     public String getDbName() {
@@ -45,6 +65,34 @@ public long getQuota() {
         return quota;
     }
 
+    private void analyzeQuotaQuantity() throws UserException {
+        Pattern r = Pattern.compile(quotaPattern);
+        Matcher m = r.matcher(quotaQuantity);
+        if (m.matches()) {
+            try {
+                quota = Long.parseLong(m.group(1));
+            } catch(NumberFormatException nfe) {
+                throw new AnalysisException("invalid quota:" + m.group(1));
+            }
+            if (quota < 0L) {
+                throw new AnalysisException("Quota must larger than 0");
+            }
+
+            String unit = "B";
+            String tmpUnit = m.group(2);
+            if (!Strings.isNullOrEmpty(tmpUnit)) {
+                unit = tmpUnit.toUpperCase();
+            }
+            if (validUnitMultiplier.containsKey(unit)) {
+                quota = quota * validUnitMultiplier.get(unit);
+            } else {
+                throw new AnalysisException("invalid unit:" + tmpUnit);
+            }
+        } else {
+            throw new AnalysisException("invalid quota expression:" + quotaQuantity);
+        }
+    }
+
     @Override
     public void analyze(Analyzer analyzer) throws UserException {
         super.analyze(analyzer);
@@ -57,14 +105,11 @@ public void analyze(Analyzer analyzer) throws UserException {
             ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR);
         }
         dbName = ClusterNamespace.getFullName(getClusterName(), dbName);
-        if (quota < 0L) {
-            throw new AnalysisException("Quota must larger than 0");
-        }
+        analyzeQuotaQuantity();
     }
 
     @Override
     public String toSql() {
-        return "ALTER DATABASE " + dbName + " SET DATA QUOTA " + quota;
+        return "ALTER DATABASE " + dbName + " SET DATA QUOTA " + quotaQuantity;
     }
-
 }
diff --git a/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java b/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java
new file mode 100644
index 00000000..7de6b3d4
--- /dev/null
+++ b/fe/src/test/java/org/apache/doris/analysis/AlterDatabaseQuotaStmtTest.java
@@ -0,0 +1,137 @@
+// 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.doris.analysis;
+
+import org.apache.doris.common.AnalysisException;
+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;
+import mockit.NonStrictExpectations;
+import mockit.internal.startup.Startup;
+
+public class AlterDatabaseQuotaStmtTest {
+    private Analyzer analyzer;
+
+    @Mocked
+    private PaloAuth auth;
+
+    static {
+        Startup.initializeIfPossible();
+    }
+
+    @Before
+    public void setUp() {
+        analyzer = AccessTestUtil.fetchAdminAnalyzer(false);
+
+        new NonStrictExpectations() {
+            {
+                auth.checkGlobalPriv((ConnectContext) any, (PrivPredicate) any);
+                result = true;
+
+                auth.checkDbPriv((ConnectContext) any, anyString, (PrivPredicate) any);
+                result = true;
+
+                auth.checkTblPriv((ConnectContext) any, anyString, anyString, (PrivPredicate) any);
+                result = true;
+            }
+        };
+    }
+    
+    private void testAlterDatabaseQuotaStmt(String dbName, String quotaQuantity, long quotaSize)
+            throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt(dbName, quotaQuantity);
+        stmt.analyze(analyzer);
+        String expectedSql = "ALTER DATABASE testCluster:testDb SET DATA QUOTA " + quotaQuantity;
+        Assert.assertEquals(expectedSql, stmt.toSql());
+        Assert.assertEquals(quotaSize, stmt.getQuota());
+    }
+
+    @Test
+    public void testNormal() throws AnalysisException, UserException {
+        // byte
+        testAlterDatabaseQuotaStmt("testDb", "102400", 102400L);
+        testAlterDatabaseQuotaStmt("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);
+
+        // 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);
+
+        // 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);
+
+        // 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);
+
+        // 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);
+    }
+
+    @Test(expected = AnalysisException.class)
+    public void testMinusQuota() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", "-100mb");
+        stmt.analyze(analyzer);
+        Assert.fail("No exception throws.");
+    }
+
+    @Test(expected = AnalysisException.class)
+    public void testInvalidUnit() throws AnalysisException, UserException {
+        AlterDatabaseQuotaStmt stmt = new AlterDatabaseQuotaStmt("testDb", "100invalid_unit");
+        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");
+        stmt.analyze(analyzer);
+        Assert.fail("No exception throws.");
+    }
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

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