This is an automated email from the ASF dual-hosted git repository. lide pushed a commit to branch branch-2.0 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.0 by this push: new dc04778c290 [Improvement](coldhot) add statement to show objects which use storage policy (#35836) dc04778c290 is described below commit dc04778c290b0fbda86a5776008c1bc9f167094e Author: Yulei-Yang <yulei.yang0...@gmail.com> AuthorDate: Tue Jun 4 19:24:43 2024 +0800 [Improvement](coldhot) add statement to show objects which use storage policy (#35836) --- fe/fe-core/src/main/cup/sql_parser.cup | 8 + .../doris/analysis/ShowStoragePolicyUsingStmt.java | 78 ++++++++++ .../java/org/apache/doris/policy/PolicyMgr.java | 110 ++++++++++++++ .../java/org/apache/doris/qe/ShowExecutor.java | 8 + .../test_show_storage_policy_using.groovy | 164 +++++++++++++++++++++ 5 files changed, 368 insertions(+) diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index 5da2e9dc8cc..a9c33472534 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -3769,6 +3769,14 @@ show_stmt ::= {: RESULT = new ShowPolicyStmt(PolicyTypeEnum.STORAGE, null, null); :} + | KW_SHOW KW_STORAGE KW_POLICY KW_USING + {: + RESULT = new ShowStoragePolicyUsingStmt(null); + :} + | KW_SHOW KW_STORAGE KW_POLICY KW_USING KW_FOR ident:policy + {: + RESULT = new ShowStoragePolicyUsingStmt(policy); + :} ; show_param ::= diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowStoragePolicyUsingStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowStoragePolicyUsingStmt.java new file mode 100644 index 00000000000..56598a194ee --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowStoragePolicyUsingStmt.java @@ -0,0 +1,78 @@ +// 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.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.UserException; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ShowResultSetMetaData; + +import lombok.Getter; + +/** + * Show objects where storage policy is used + * syntax: + * SHOW STORAGE POLICY USING [for policy_name] + **/ +public class ShowStoragePolicyUsingStmt extends ShowStmt { + + public static final ShowResultSetMetaData RESULT_META_DATA = + ShowResultSetMetaData.builder() + .addColumn(new Column("PolicyName", ScalarType.createVarchar(100))) + .addColumn(new Column("Database", ScalarType.createVarchar(20))) + .addColumn(new Column("Table", ScalarType.createVarchar(20))) + .addColumn(new Column("Partitions", ScalarType.createVarchar(60))) + .build(); + @Getter + private final String policyName; + + public ShowStoragePolicyUsingStmt(String policyName) { + this.policyName = policyName; + } + + @Override + public void analyze(Analyzer analyzer) throws UserException { + super.analyze(analyzer); + + // check auth + if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN"); + } + } + + @Override + public String toSql() { + StringBuilder sb = new StringBuilder(); + sb.append("SHOW STORAGE POLICY USING"); + if (policyName != null) { + sb.append(" FOR ").append(policyName); + } + + return sb.toString(); + } + + @Override + public ShowResultSetMetaData getMetaData() { + return RESULT_META_DATA; + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java b/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java index 3527b77c1df..7ca5d4fcbea 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java @@ -22,6 +22,7 @@ import org.apache.doris.analysis.CompoundPredicate; import org.apache.doris.analysis.CreatePolicyStmt; import org.apache.doris.analysis.DropPolicyStmt; import org.apache.doris.analysis.ShowPolicyStmt; +import org.apache.doris.analysis.ShowStoragePolicyUsingStmt; import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.Database; import org.apache.doris.catalog.Env; @@ -55,7 +56,9 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -424,6 +427,113 @@ public class PolicyMgr implements Writable { } } + /** + * Show objects which is using the storage policy + **/ + public ShowResultSet showStoragePolicyUsing(ShowStoragePolicyUsingStmt showStmt) throws AnalysisException { + List<List<String>> rows = Lists.newArrayList(); + String targetPolicyName = showStmt.getPolicyName(); + + readLock(); + try { + List<Database> databases = Env.getCurrentEnv().getInternalCatalog().getDbs(); + // show for all storage policies + if (Strings.isNullOrEmpty(targetPolicyName)) { + for (Database db : databases) { + List<Table> tables = db.getTables(); + for (Table table : tables) { + if (!(table instanceof OlapTable)) { + continue; + } + + Map<String, List<String>> policyToPartitionsMap = new HashMap<>(); + OlapTable olapTable = (OlapTable) table; + PartitionInfo partitionInfo = olapTable.getPartitionInfo(); + // classify a table's all partitions by storage policy + for (Long partitionId : olapTable.getPartitionIds()) { + String policyName = partitionInfo.getDataProperty(partitionId).getStoragePolicy(); + if (StringUtils.isEmpty(policyName)) { + continue; + } + if (policyToPartitionsMap.containsKey(policyName)) { + policyToPartitionsMap.get(policyName) + .add(olapTable.getPartition(partitionId).getName()); + } else { + List<String> partitionList = new ArrayList<>(); + partitionList.add(olapTable.getPartition(partitionId).getName()); + policyToPartitionsMap.put(policyName, partitionList); + } + } + + //output, all partitions with same storage policy in a table will be shown in one line + if (policyToPartitionsMap.size() == 1) { + String[] policyArray = policyToPartitionsMap.keySet().toArray(new String[0]); + List<String> partitionsList = new ArrayList<>(policyToPartitionsMap.values()).get(0); + if (partitionsList.size() == olapTable.getPartitionNum()) { + List<String> row = Arrays.asList(policyArray[0], + ClusterNamespace.getNameFromFullName(db.getFullName()), olapTable.getName(), + "ALL"); + rows.add(row); + } else { + List<String> row = Arrays.asList(policyArray[0], + ClusterNamespace.getNameFromFullName(db.getFullName()), olapTable.getName(), + String.join(",", partitionsList)); + rows.add(row); + } + } else { + for (Map.Entry<String, List<String>> entry : policyToPartitionsMap.entrySet()) { + List<String> row = Arrays.asList(entry.getKey(), + ClusterNamespace.getNameFromFullName(db.getFullName()), olapTable.getName(), + String.join(",", entry.getValue())); + rows.add(row); + } + } + } + } + } else { + // show for specific storage policy + for (Database db : databases) { + List<Table> tables = db.getTables(); + for (Table table : tables) { + if (!(table instanceof OlapTable)) { + continue; + } + + OlapTable olapTable = (OlapTable) table; + int partitionMatchNum = 0; + StringBuilder matchPartitionsSB = new StringBuilder(); + PartitionInfo partitionInfo = olapTable.getPartitionInfo(); + for (Long partitionId : olapTable.getPartitionIds()) { + String policyName = partitionInfo.getDataProperty(partitionId).getStoragePolicy(); + if (policyName.equals(targetPolicyName)) { + partitionMatchNum++; + matchPartitionsSB.append(olapTable.getPartition(partitionId).getName()).append(","); + } + } + + if (partitionMatchNum == 0) { + continue; + } + + String matchPartitionsStr = "ALL"; + if (partitionMatchNum < olapTable.getPartitionNum()) { + matchPartitionsStr = matchPartitionsSB.toString(); + matchPartitionsStr = matchPartitionsStr.substring(0, matchPartitionsStr.length() - 1); + } + + List<String> row = Arrays.asList(targetPolicyName, + ClusterNamespace.getNameFromFullName(db.getFullName()), olapTable.getName(), + matchPartitionsStr); + rows.add(row); + } + } + } + return new ShowResultSet(showStmt.getMetaData(), rows); + } finally { + readUnlock(); + } + } + private void addTablePolicies(RowPolicy policy) { if (policy.getUser() != null) { policy.getUser().setIsAnalyzed(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java index 7a2e9f854cc..e7350a1c30a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java @@ -88,6 +88,7 @@ import org.apache.doris.analysis.ShowSmallFilesStmt; import org.apache.doris.analysis.ShowSnapshotStmt; import org.apache.doris.analysis.ShowSqlBlockRuleStmt; import org.apache.doris.analysis.ShowStmt; +import org.apache.doris.analysis.ShowStoragePolicyUsingStmt; import org.apache.doris.analysis.ShowStreamLoadStmt; import org.apache.doris.analysis.ShowSyncJobStmt; import org.apache.doris.analysis.ShowTableCreationStmt; @@ -423,6 +424,8 @@ public class ShowExecutor { handleShowCreateMaterializedView(); } else if (stmt instanceof ShowPolicyStmt) { handleShowPolicy(); + } else if (stmt instanceof ShowStoragePolicyUsingStmt) { + handleShowStoragePolicyUsing(); } else if (stmt instanceof ShowCatalogStmt) { handleShowCatalogs(); } else if (stmt instanceof ShowCreateCatalogStmt) { @@ -2690,6 +2693,11 @@ public class ShowExecutor { resultSet = Env.getCurrentEnv().getPolicyMgr().showPolicy(showStmt); } + public void handleShowStoragePolicyUsing() throws AnalysisException { + ShowStoragePolicyUsingStmt showStmt = (ShowStoragePolicyUsingStmt) stmt; + resultSet = Env.getCurrentEnv().getPolicyMgr().showStoragePolicyUsing(showStmt); + } + public void handleShowCatalogs() throws AnalysisException { ShowCatalogStmt showStmt = (ShowCatalogStmt) stmt; resultSet = Env.getCurrentEnv().getCatalogMgr().showCatalogs(showStmt, ctx.getCurrentCatalog() != null diff --git a/regression-test/suites/cold_heat_separation_p2/test_show_storage_policy_using.groovy b/regression-test/suites/cold_heat_separation_p2/test_show_storage_policy_using.groovy new file mode 100644 index 00000000000..ca94b09077e --- /dev/null +++ b/regression-test/suites/cold_heat_separation_p2/test_show_storage_policy_using.groovy @@ -0,0 +1,164 @@ +// 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. + +suite("test_show_storage_policy_using") { + + def resource_name = "test_remote_s3_resource" + def policy_name= "test_storage_policy" + def policy_name_2= "test_storage_policy_2" + def policy_name_not_exist = "policy_name_not_exist" + + sql """ + CREATE RESOURCE IF NOT EXISTS "${resource_name}" + PROPERTIES( + "type"="s3", + "AWS_ENDPOINT" = "${getS3Endpoint()}", + "AWS_REGION" = "${getS3Region()}", + "AWS_ROOT_PATH" = "regression/cooldown", + "AWS_ACCESS_KEY" = "${getS3AK()}", + "AWS_SECRET_KEY" = "${getS3SK()}", + "AWS_MAX_CONNECTIONS" = "50", + "AWS_REQUEST_TIMEOUT_MS" = "3000", + "AWS_CONNECTION_TIMEOUT_MS" = "1000", + "AWS_BUCKET" = "${getS3BucketName()}", + "s3_validity_check" = "true" + ); + """ + + sql """ + CREATE STORAGE POLICY IF NOT EXISTS ${policy_name} + PROPERTIES( + "storage_resource" = "${resource_name}", + "cooldown_ttl" = "300" + ) + """ + + sql """ + CREATE STORAGE POLICY IF NOT EXISTS ${policy_name_2} + PROPERTIES( + "storage_resource" = "${resource_name}", + "cooldown_ttl" = "600" + ) + """ + + sql """ DROP TABLE IF EXISTS table_with_storage_policy_1 """ + sql """ + CREATE TABLE IF NOT EXISTS table_with_storage_policy_1 + ( + k1 BIGINT, + v1 VARCHAR(48) + ) + DUPLICATE KEY(k1) + DISTRIBUTED BY HASH (k1) BUCKETS 3 + PROPERTIES( + "storage_policy" = "${policy_name}", + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """ DROP TABLE IF EXISTS table_no_storage_policy_1 """ + sql """ + CREATE TABLE IF NOT EXISTS table_no_storage_policy_1 + ( + k1 BIGINT, + v1 VARCHAR(32) + ) + DUPLICATE KEY(k1) + DISTRIBUTED BY HASH (k1) BUCKETS 3 + PROPERTIES( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """ DROP TABLE IF EXISTS partition_with_multiple_storage_policy """ + sql """ + CREATE TABLE `partition_with_multiple_storage_policy` ( + `id` int(11) NOT NULL COMMENT '', + `name` int(11) NOT NULL COMMENT '', + `event_date` date NOT NULL + ) ENGINE=OLAP + DUPLICATE KEY(`id`) + COMMENT "OLAP" + PARTITION BY RANGE(`event_date`) + ( + PARTITION p201701 VALUES [('0000-01-01'), ('2017-02-01')) ("storage_policy" = "${policy_name}"), + PARTITION `p201702` VALUES LESS THAN ("2017-03-01")("storage_policy" = "${policy_name_2}"), + PARTITION `p2018` VALUES [("2018-01-01"), ("2019-01-01")) + ) + DISTRIBUTED BY HASH(`id`) BUCKETS 8 + PROPERTIES( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """ DROP TABLE IF EXISTS table_with_storage_policy_2""" + sql """ + CREATE TABLE IF NOT EXISTS table_with_storage_policy_2 + ( + k1 BIGINT, + v1 VARCHAR(48) + ) + DUPLICATE KEY(k1) + DISTRIBUTED BY HASH (k1) BUCKETS 3 + PROPERTIES( + "storage_policy" = "${policy_name_2}", + "replication_allocation" = "tag.location.default: 1" + ); + """ + + show_result = sql """ + show storage policy using for ${policy_name} + """ + assertEquals(show_result.size(), 2) + assertTrue(show_result[0][2].equals("table_with_storage_policy_1") || show_result[1][2].equals("table_with_storage_policy_1")) + assertTrue(show_result[0][2].equals("partition_with_multiple_storage_policy") || show_result[1][2].equals("partition_with_multiple_storage_policy")) + if (show_result[0][2].equals("partition_with_multiple_storage_policy")) { + show_result[0][3].equals("p201701") + } + if (show_result[1][2].equals("partition_with_multiple_storage_policy")) { + show_result[1][3].equals("p201701") + } + + show_result = sql """ + show storage policy using for ${policy_name_2} + """ + assertTrue(show_result[0][2].equals("table_with_storage_policy_2") || show_result[1][2].equals("table_with_storage_policy_2")) + assertTrue(show_result[0][2].equals("partition_with_multiple_storage_policy") || show_result[1][2].equals("partition_with_multiple_storage_policy")) + if (show_result[0][2].equals("partition_with_multiple_storage_policy")) { + show_result[0][3].equals("p201702") + } + if (show_result[1][2].equals("partition_with_multiple_storage_policy")) { + show_result[1][3].equals("p201702") + } + + + show_result = sql """ + show storage policy using for ${policy_name_not_exist} + """ + assertTrue(show_result.size() == 0) + + show_result = sql """ + show storage policy using + """ + assertTrue(show_result.size() >= 4) + + // cleanup + sql """ DROP TABLE IF EXISTS table_with_storage_policy_1 """ + sql """ DROP TABLE IF EXISTS table_no_storage_policy_1 """ + sql """ DROP TABLE IF EXISTS partition_with_multiple_storage_policy """ + sql """ DROP TABLE IF EXISTS table_with_storage_policy_2""" +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org