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 2022/10/27 02:03:44 UTC

[doris] branch master updated: [Improvement][SET-PROPERTY] Support for set query_timeout property (#13444)

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/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 2697f72d77 [Improvement][SET-PROPERTY] Support for set query_timeout property  (#13444)
2697f72d77 is described below

commit 2697f72d778df16ab3da6e538f62fa6de25ab3cb
Author: DongLiang-0 <46...@users.noreply.github.com>
AuthorDate: Thu Oct 27 10:03:39 2022 +0800

    [Improvement][SET-PROPERTY] Support for set query_timeout property  (#13444)
---
 .../Account-Management-Statements/SET-PROPERTY.md  |  8 +++++++
 .../Account-Management-Statements/SET-PROPERTY.md  |  8 +++++++
 .../org/apache/doris/mysql/nio/AcceptListener.java |  2 ++
 .../mysql/privilege/CommonUserProperties.java      | 11 +++++++++
 .../org/apache/doris/mysql/privilege/PaloAuth.java |  9 ++++++++
 .../apache/doris/mysql/privilege/UserProperty.java | 20 ++++++++++++++++
 .../doris/mysql/privilege/UserPropertyMgr.java     |  9 ++++++++
 .../java/org/apache/doris/qe/ConnectContext.java   | 27 ++++++++++++++++++----
 .../java/org/apache/doris/qe/ConnectScheduler.java |  1 +
 .../org/apache/doris/catalog/UserPropertyTest.java |  4 ++++
 .../apache/doris/planner/ResourceTagQueryTest.java |  2 +-
 .../org/apache/doris/qe/ConnectContextTest.java    | 13 +++++++++++
 12 files changed, 108 insertions(+), 6 deletions(-)

diff --git a/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md b/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md
index 100064fb4a..aa16dbbed9 100644
--- a/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md
+++ b/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md
@@ -60,6 +60,8 @@ Super user privileges:
 
  resource_tags: Specifies the user's resource tag permissions.
 
+ query_timeout: Specifies the user's query timeout permissions.
+
     Note: If the attributes `cpu_resource_limit`, `exec_mem_limit` are not set, the value in the session variable will be used by default.
 
 Ordinary user rights:
@@ -156,6 +158,12 @@ Data, etl program automatically retains the next use.
     SET PROPERTY FOR 'jack' 'exec_mem_limit' = '2147483648';
     ````
 
+13. Modify the user's query timeout limit, in second
+
+    ```sql
+    SET PROPERTY FOR 'jack' 'query_timeout' = '500';
+    ````
+
 ### Keywords
 
     SET, PROPERTY
diff --git a/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md b/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md
index b8d911ad62..7929edfd32 100644
--- a/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md
+++ b/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/SET-PROPERTY.md
@@ -60,6 +60,8 @@ key:
 
 ​        resource_tags:指定用户的资源标签权限。
 
+​        query_timeout:指定用户的查询超时权限。
+
     注:`cpu_resource_limit`, `exec_mem_limit` 两个属性如果未设置,则默认使用会话变量中值。
 
 普通用户权限:
@@ -155,6 +157,12 @@ key:
     ```sql
     SET PROPERTY FOR 'jack' 'exec_mem_limit' = '2147483648';
     ```
+
+13. 修改用户的查询超时限制,单位秒
+
+    ```sql
+    SET PROPERTY FOR 'jack' 'query_timeout' = '500';
+    ```
     
 ### Keywords
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/nio/AcceptListener.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/nio/AcceptListener.java
index b4f28be2c5..8744a272cd 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/nio/AcceptListener.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/nio/AcceptListener.java
@@ -78,6 +78,8 @@ public class AcceptListener implements ChannelListener<AcceptingChannel<StreamCo
                         throw new AfterConnectedException("Reach limit of connections");
                     }
                     context.setStartTime();
+                    context.setUserQueryTimeout(
+                            context.getEnv().getAuth().getQueryTimeout(context.getQualifiedUser()));
                     ConnectProcessor processor = new ConnectProcessor(context);
                     context.startAcceptQuery(processor);
                 } catch (AfterConnectedException e) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CommonUserProperties.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CommonUserProperties.java
index 0b83d12898..255388abf8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CommonUserProperties.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CommonUserProperties.java
@@ -51,6 +51,9 @@ public class CommonUserProperties implements Writable {
     @SerializedName("execMemLimit")
     private long execMemLimit = -1;
 
+    @SerializedName("queryTimeout")
+    private long queryTimeout = -1;
+
     private String[] sqlBlockRulesSplit = {};
 
     long getMaxConn() {
@@ -111,6 +114,14 @@ public class CommonUserProperties implements Writable {
         this.execMemLimit = execMemLimit;
     }
 
+    public long getQueryTimeout() {
+        return queryTimeout;
+    }
+
+    public void setQueryTimeout(long timeout) {
+        this.queryTimeout = timeout;
+    }
+
     public static CommonUserProperties read(DataInput in) throws IOException {
         String json = Text.readString(in);
         CommonUserProperties commonUserProperties = GsonUtils.GSON.fromJson(json, CommonUserProperties.class);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java
index 92ea8384ad..4729c4552a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java
@@ -1363,6 +1363,15 @@ public class PaloAuth implements Writable {
         }
     }
 
+    public long getQueryTimeout(String qualifiedUser) {
+        readLock();
+        try {
+            return propertyMgr.getQueryTimeout(qualifiedUser);
+        } finally {
+            readUnlock();
+        }
+    }
+
     public long getMaxQueryInstances(String qualifiedUser) {
         readLock();
         try {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserProperty.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserProperty.java
index a30f2d8d5c..741493a4c4 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserProperty.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserProperty.java
@@ -63,6 +63,7 @@ public class UserProperty implements Writable {
     private static final String PROP_SQL_BLOCK_RULES = "sql_block_rules";
     private static final String PROP_CPU_RESOURCE_LIMIT = "cpu_resource_limit";
     private static final String PROP_EXEC_MEM_LIMIT = "exec_mem_limit";
+    private static final String PROP_USER_QUERY_TIMEOUT = "query_timeout";
     // advanced properties end
 
     private static final String PROP_LOAD_CLUSTER = "load_cluster";
@@ -108,6 +109,7 @@ public class UserProperty implements Writable {
         ADVANCED_PROPERTIES.add(Pattern.compile("^" + PROP_CPU_RESOURCE_LIMIT + "$", Pattern.CASE_INSENSITIVE));
         ADVANCED_PROPERTIES.add(Pattern.compile("^" + PROP_RESOURCE_TAGS + "$", Pattern.CASE_INSENSITIVE));
         ADVANCED_PROPERTIES.add(Pattern.compile("^" + PROP_EXEC_MEM_LIMIT + "$", Pattern.CASE_INSENSITIVE));
+        ADVANCED_PROPERTIES.add(Pattern.compile("^" + PROP_USER_QUERY_TIMEOUT + "$", Pattern.CASE_INSENSITIVE));
 
         COMMON_PROPERTIES.add(Pattern.compile("^" + PROP_QUOTA + ".", Pattern.CASE_INSENSITIVE));
         COMMON_PROPERTIES.add(Pattern.compile("^" + PROP_DEFAULT_LOAD_CLUSTER + "$", Pattern.CASE_INSENSITIVE));
@@ -130,6 +132,10 @@ public class UserProperty implements Writable {
         return this.commonProperties.getMaxConn();
     }
 
+    public long getQueryTimeout() {
+        return this.commonProperties.getQueryTimeout();
+    }
+
     public long getMaxQueryInstances() {
         return commonProperties.getMaxQueryInstances(); // maxQueryInstances;
     }
@@ -176,6 +182,7 @@ public class UserProperty implements Writable {
         int cpuResourceLimit = this.commonProperties.getCpuResourceLimit();
         Set<Tag> resourceTags = this.commonProperties.getResourceTags();
         long execMemLimit = this.commonProperties.getExecMemLimit();
+        long queryTimeout = this.commonProperties.getQueryTimeout();
 
         UserResource newResource = resource.getCopiedUserResource();
         String newDefaultLoadCluster = defaultLoadCluster;
@@ -314,6 +321,15 @@ public class UserProperty implements Writable {
             } else if (keyArr[0].equalsIgnoreCase(PROP_EXEC_MEM_LIMIT)) {
                 // set property "exec_mem_limit" = "2147483648";
                 execMemLimit = getLongProperty(key, value, keyArr, PROP_EXEC_MEM_LIMIT);
+            } else if (keyArr[0].equalsIgnoreCase(PROP_USER_QUERY_TIMEOUT)) {
+                if (keyArr.length != 1) {
+                    throw new DdlException(PROP_MAX_USER_CONNECTIONS + " format error");
+                }
+                try {
+                    queryTimeout = Long.parseLong(value);
+                } catch (NumberFormatException e) {
+                    throw new DdlException(PROP_USER_QUERY_TIMEOUT + " is not number");
+                }
             } else {
                 throw new DdlException("Unknown user property(" + key + ")");
             }
@@ -326,6 +342,7 @@ public class UserProperty implements Writable {
         this.commonProperties.setCpuResourceLimit(cpuResourceLimit);
         this.commonProperties.setResourceTags(resourceTags);
         this.commonProperties.setExecMemLimit(execMemLimit);
+        this.commonProperties.setQueryTimeout(queryTimeout);
         resource = newResource;
         if (newDppConfigs.containsKey(newDefaultLoadCluster)) {
             defaultLoadCluster = newDefaultLoadCluster;
@@ -452,6 +469,9 @@ public class UserProperty implements Writable {
         // exec mem limit
         result.add(Lists.newArrayList(PROP_EXEC_MEM_LIMIT, String.valueOf(commonProperties.getExecMemLimit())));
 
+        // query timeout
+        result.add(Lists.newArrayList(PROP_USER_QUERY_TIMEOUT, String.valueOf(commonProperties.getQueryTimeout())));
+
         // resource tag
         result.add(Lists.newArrayList(PROP_RESOURCE_TAGS, Joiner.on(", ").join(commonProperties.getResourceTags())));
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
index 7d824971f7..df666e7ea5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/UserPropertyMgr.java
@@ -130,6 +130,15 @@ public class UserPropertyMgr implements Writable {
         property.update(properties);
     }
 
+    public long getQueryTimeout(String qualifiedUser) {
+        UserProperty existProperty = propertyMap.get(qualifiedUser);
+        existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
+        if (existProperty == null) {
+            return 0;
+        }
+        return existProperty.getQueryTimeout();
+    }
+
     public long getMaxConn(String qualifiedUser) {
         UserProperty existProperty = propertyMap.get(qualifiedUser);
         existProperty = getLdapPropertyIfNull(qualifiedUser, existProperty);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
index b6e7ac9d84..53b3c6cde7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
@@ -147,6 +147,12 @@ public class ConnectContext {
 
     private SessionContext sessionContext;
 
+    private long userQueryTimeout;
+
+    public void setUserQueryTimeout(long queryTimeout) {
+        this.userQueryTimeout = queryTimeout;
+    }
+
     private StatementContext statementContext;
 
     public SessionContext getSessionContext() {
@@ -562,12 +568,23 @@ public class ConnectContext {
                 killConnection = true;
             }
         } else {
-            if (delta > sessionVariable.getQueryTimeoutS() * 1000) {
-                LOG.warn("kill query timeout, remote: {}, query timeout: {}",
-                        getMysqlChannel().getRemoteHostPortString(), sessionVariable.getQueryTimeoutS());
+            if (userQueryTimeout > 0) {
+                // user set query_timeout property
+                if (delta > userQueryTimeout * 1000) {
+                    LOG.warn("kill query timeout, remote: {}, query timeout: {}",
+                            getMysqlChannel().getRemoteHostPortString(), userQueryTimeout);
 
-                // Only kill
-                killFlag = true;
+                    killFlag = true;
+                }
+            } else {
+                // default use session query_timeout
+                if (delta > sessionVariable.getQueryTimeoutS() * 1000) {
+                    LOG.warn("kill query timeout, remote: {}, query timeout: {}",
+                            getMysqlChannel().getRemoteHostPortString(), sessionVariable.getQueryTimeoutS());
+
+                    // Only kill
+                    killFlag = true;
+                }
             }
         }
         if (killFlag) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java
index 66702d438b..e31dfea298 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java
@@ -193,6 +193,7 @@ public class ConnectScheduler {
                     return;
                 }
 
+                context.setUserQueryTimeout(context.getEnv().getAuth().getQueryTimeout(context.getQualifiedUser()));
                 context.setStartTime();
                 ConnectProcessor processor = new ConnectProcessor(context);
                 processor.loop();
diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/UserPropertyTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/UserPropertyTest.java
index e7e8435871..c8c3613935 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/UserPropertyTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/UserPropertyTest.java
@@ -107,6 +107,7 @@ public class UserPropertyTest {
         properties.add(Pair.of("max_qUERY_instances", "3000"));
         properties.add(Pair.of("sql_block_rules", "rule1,rule2"));
         properties.add(Pair.of("cpu_resource_limit", "2"));
+        properties.add(Pair.of("query_timeout", "500"));
 
         UserProperty userProperty = new UserProperty();
         userProperty.update(properties);
@@ -118,6 +119,7 @@ public class UserPropertyTest {
         Assert.assertEquals(3000, userProperty.getMaxQueryInstances());
         Assert.assertEquals(new String[]{"rule1", "rule2"}, userProperty.getSqlBlockRules());
         Assert.assertEquals(2, userProperty.getCpuResourceLimit());
+        Assert.assertEquals(500, userProperty.getQueryTimeout());
 
         // fetch property
         List<List<String>> rows = userProperty.fetchProperty();
@@ -141,6 +143,8 @@ public class UserPropertyTest {
                 Assert.assertEquals("rule1,rule2", value);
             } else if (key.equalsIgnoreCase("cpu_resource_limit")) {
                 Assert.assertEquals("2", value);
+            } else if (key.equalsIgnoreCase("query_timeout")) {
+                Assert.assertEquals("500", value);
             }
         }
 
diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/ResourceTagQueryTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/ResourceTagQueryTest.java
index 391fb6c0d7..3d531a2024 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/planner/ResourceTagQueryTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/planner/ResourceTagQueryTest.java
@@ -279,7 +279,7 @@ public class ResourceTagQueryTest {
         Assert.assertEquals(1000000, execMemLimit);
 
         List<List<String>> userProps = Env.getCurrentEnv().getAuth().getUserProperties(PaloAuth.ROOT_USER);
-        Assert.assertEquals(16, userProps.size());
+        Assert.assertEquals(17, userProps.size());
     }
 
     private void checkTableReplicaAllocation(OlapTable tbl) throws InterruptedException {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java b/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java
index 2a984d9564..8fdcdadb1c 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/qe/ConnectContextTest.java
@@ -21,6 +21,7 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.mysql.MysqlCapability;
 import org.apache.doris.mysql.MysqlChannel;
 import org.apache.doris.mysql.MysqlCommand;
+import org.apache.doris.mysql.privilege.PaloAuth;
 import org.apache.doris.thrift.TUniqueId;
 
 import mockit.Expectations;
@@ -43,6 +44,10 @@ public class ConnectContextTest {
     private Env env;
     @Mocked
     private ConnectScheduler connectScheduler;
+    @Mocked
+    private PaloAuth paloAuth;
+    @Mocked
+    private String qualifiedUser;
 
     @Before
     public void setUp() throws Exception {
@@ -166,6 +171,14 @@ public class ConnectContextTest {
         ctx.checkTimeout(now);
         Assert.assertTrue(ctx.isKilled());
 
+        // user query timeout
+        ctx.setStartTime();
+        ctx.setUserQueryTimeout(1);
+        now = ctx.getStartTime() + paloAuth.getQueryTimeout(qualifiedUser) * 1000 + 1;
+        ctx.setExecutor(executor);
+        ctx.checkTimeout(now);
+        Assert.assertTrue(ctx.isKilled());
+
         // Kill
         ctx.kill(true);
         Assert.assertTrue(ctx.isKilled());


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