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 236e0f1 [Feature] Support for querying the trash used capacity (#6247)
236e0f1 is described below
commit 236e0f1edaa5d561d964a7d9f1b5bbfd7630d603
Author: Pxl <[email protected]>
AuthorDate: Tue Aug 10 10:10:47 2021 +0800
[Feature] Support for querying the trash used capacity (#6247)
Support for querying the trash used capacity.
```
SHOW TRASH [ON ...]
```
Now user can proactively scan trash directory.
---
be/src/olap/storage_engine.cpp | 16 ++-
be/src/olap/storage_engine.h | 2 +
be/src/service/backend_service.cpp | 34 +++++
be/src/service/backend_service.h | 8 +-
docs/.vuepress/sidebar/en.js | 1 +
docs/.vuepress/sidebar/zh-CN.js | 1 +
.../sql-statements/Administration/SHOW TRASH.md | 53 ++++++++
.../sql-statements/Administration/SHOW TRASH.md | 49 ++++++++
fe/fe-core/src/main/cup/sql_parser.cup | 10 +-
.../apache/doris/analysis/ShowTrashDiskStmt.java | 75 +++++++++++
.../org/apache/doris/analysis/ShowTrashStmt.java | 73 +++++++++++
.../org/apache/doris/common/proc/ProcService.java | 1 +
.../org/apache/doris/common/proc/TrashProcDir.java | 138 +++++++++++++++++++++
.../apache/doris/common/proc/TrashProcNode.java | 107 ++++++++++++++++
.../org/apache/doris/common/util/DebugUtil.java | 2 +-
.../java/org/apache/doris/qe/ShowExecutor.java | 22 ++++
fe/fe-core/src/main/jflex/sql_scanner.flex | 1 +
.../org/apache/doris/common/GenericPoolTest.java | 13 ++
.../apache/doris/utframe/MockedBackendFactory.java | 11 ++
gensrc/thrift/BackendService.thrift | 10 ++
20 files changed, 623 insertions(+), 4 deletions(-)
diff --git a/be/src/olap/storage_engine.cpp b/be/src/olap/storage_engine.cpp
index 1f5efbf..2cbb387 100644
--- a/be/src/olap/storage_engine.cpp
+++ b/be/src/olap/storage_engine.cpp
@@ -331,7 +331,7 @@ std::vector<DataDir*> StorageEngine::get_stores() {
template std::vector<DataDir*> StorageEngine::get_stores<false>();
template std::vector<DataDir*> StorageEngine::get_stores<true>();
-OLAPStatus StorageEngine::get_all_data_dir_info(vector<DataDirInfo>*
data_dir_infos,
+OLAPStatus StorageEngine::get_all_data_dir_info(std::vector<DataDirInfo>*
data_dir_infos,
bool need_update) {
OLAPStatus res = OLAP_SUCCESS;
data_dir_infos->clear();
@@ -377,6 +377,20 @@ OLAPStatus
StorageEngine::get_all_data_dir_info(vector<DataDirInfo>* data_dir_in
return res;
}
+int64_t StorageEngine::get_file_or_directory_size(std::filesystem::path
file_path) {
+ if (!std::filesystem::exists(file_path)) {
+ return 0;
+ }
+ if (!std::filesystem::is_directory(file_path)) {
+ return std::filesystem::file_size(file_path);
+ }
+ int64_t sum_size = 0;
+ for (const auto& it : std::filesystem::directory_iterator(file_path)) {
+ sum_size += get_file_or_directory_size(it.path());
+ }
+ return sum_size;
+}
+
void StorageEngine::_start_disk_stat_monitor() {
for (auto& it : _store_map) {
it.second->health_check();
diff --git a/be/src/olap/storage_engine.h b/be/src/olap/storage_engine.h
index 1162260..feb2b1f 100644
--- a/be/src/olap/storage_engine.h
+++ b/be/src/olap/storage_engine.h
@@ -100,6 +100,8 @@ public:
// @brief 获取所有root_path信息
OLAPStatus get_all_data_dir_info(std::vector<DataDirInfo>* data_dir_infos,
bool need_update);
+ int64_t get_file_or_directory_size(std::filesystem::path file_path);
+
// get root path for creating tablet. The returned vector of root path
should be random,
// for avoiding that all the tablet would be deployed one disk.
std::vector<DataDir*> get_stores_for_create_tablet(TStorageMedium::type
storage_medium);
diff --git a/be/src/service/backend_service.cpp
b/be/src/service/backend_service.cpp
index f4e4fd0..87ad432 100644
--- a/be/src/service/backend_service.cpp
+++ b/be/src/service/backend_service.cpp
@@ -210,6 +210,40 @@ void BackendService::get_tablet_stat(TTabletStatResult&
result) {
StorageEngine::instance()->tablet_manager()->get_tablet_stat(&result);
}
+int64_t BackendService::get_trash_used_capacity() {
+ int64_t result = 0;
+
+ std::vector<DataDirInfo> data_dir_infos;
+ StorageEngine::instance()->get_all_data_dir_info(&data_dir_infos, false
/*do not update */);
+
+ for (const auto& root_path_info : data_dir_infos) {
+ std::string lhs_trash_path = root_path_info.path + TRASH_PREFIX;
+ std::filesystem::path trash_path(lhs_trash_path);
+ result +=
StorageEngine::instance()->get_file_or_directory_size(trash_path);
+ }
+ return result;
+}
+
+void BackendService::get_disk_trash_used_capacity(std::vector<TDiskTrashInfo>&
diskTrashInfos) {
+ std::vector<DataDirInfo> data_dir_infos;
+ StorageEngine::instance()->get_all_data_dir_info(&data_dir_infos, false
/*do not update */);
+
+ for (const auto& root_path_info : data_dir_infos) {
+ TDiskTrashInfo diskTrashInfo;
+
+ diskTrashInfo.__set_root_path(root_path_info.path);
+
+ diskTrashInfo.__set_state(root_path_info.is_used ? "ONLINE" :
"OFFLINE");
+
+ std::string lhs_trash_path = root_path_info.path + TRASH_PREFIX;
+ std::filesystem::path trash_path(lhs_trash_path);
+ diskTrashInfo.__set_trash_used_capacity(
+
StorageEngine::instance()->get_file_or_directory_size(trash_path));
+
+ diskTrashInfos.push_back(diskTrashInfo);
+ }
+}
+
void BackendService::submit_routine_load_task(TStatus& t_status,
const
std::vector<TRoutineLoadTask>& tasks) {
for (auto& task : tasks) {
diff --git a/be/src/service/backend_service.h b/be/src/service/backend_service.h
index 166a136..1464fe4 100644
--- a/be/src/service/backend_service.h
+++ b/be/src/service/backend_service.h
@@ -61,6 +61,7 @@ class TQueryOptions;
class TExportTaskRequest;
class TExportStatusResult;
class TStreamLoadRecordResult;
+class TDiskTrashInfo;
// This class just forward rpc for actual handler
// make this class because we can bind multiple service on single point
@@ -129,6 +130,10 @@ public:
virtual void get_tablet_stat(TTabletStatResult& result) override;
+ virtual int64_t get_trash_used_capacity() override;
+
+ virtual void get_disk_trash_used_capacity(std::vector<TDiskTrashInfo>&
diskTrashInfos) override;
+
virtual void submit_routine_load_task(TStatus& t_status,
const std::vector<TRoutineLoadTask>&
tasks) override;
@@ -141,7 +146,8 @@ public:
// used for external service, close some context and release resource
related with this context
virtual void close_scanner(TScanCloseResult& result_, const
TScanCloseParams& params);
- virtual void get_stream_load_record(TStreamLoadRecordResult& result, const
int64_t last_stream_record_time) override;
+ virtual void get_stream_load_record(TStreamLoadRecordResult& result,
+ const int64_t last_stream_record_time)
override;
private:
Status start_plan_fragment_execution(const TExecPlanFragmentParams&
exec_params);
diff --git a/docs/.vuepress/sidebar/en.js b/docs/.vuepress/sidebar/en.js
index 34bca23..b5f23fc 100644
--- a/docs/.vuepress/sidebar/en.js
+++ b/docs/.vuepress/sidebar/en.js
@@ -456,6 +456,7 @@ module.exports = [
"SHOW MIGRATIONS",
"SHOW PLUGINS",
"SHOW TABLE STATUS",
+ "SHOW TRASH",
"UNINSTALL PLUGIN",
],
},
diff --git a/docs/.vuepress/sidebar/zh-CN.js b/docs/.vuepress/sidebar/zh-CN.js
index 86ac1a1..ba1ac66 100644
--- a/docs/.vuepress/sidebar/zh-CN.js
+++ b/docs/.vuepress/sidebar/zh-CN.js
@@ -461,6 +461,7 @@ module.exports = [
"SHOW MIGRATIONS",
"SHOW PLUGINS",
"SHOW TABLE STATUS",
+ "SHOW TRASH",
"UNINSTALL PLUGIN",
],
},
diff --git a/docs/en/sql-reference/sql-statements/Administration/SHOW TRASH.md
b/docs/en/sql-reference/sql-statements/Administration/SHOW TRASH.md
new file mode 100644
index 0000000..b1081d5
--- /dev/null
+++ b/docs/en/sql-reference/sql-statements/Administration/SHOW TRASH.md
@@ -0,0 +1,53 @@
+---
+{
+ "title": "SHOW TRASH",
+ "language": "en"
+}
+---
+
+<!--
+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.
+-->
+
+# SHOW TRASH
+## description
+
+This statement is used to view trash used capacity on some backends.
+
+ Syntax:
+
+ SHOW TRASH [ON "BackendHost:BackendHeartBeatPort"];
+
+ Explain:
+
+ 1. Backend The format is BackendHost:BackendHeartBeatPort of the node.
+ 2. TrashUsedCapacity Indicates that the trash data of the node
occupies space.
+
+## example
+
+ 1. View the space occupied by trash data of all be nodes.
+
+ SHOW TRASH;
+
+ 2. Check the space occupied by trash data of '192.168.0.1:9050'(The
specific disk information will be displayed).
+
+ SHOW TRASH ON "192.168.0.1:9050";
+
+## keyword
+ SHOW, TRASH
+
diff --git a/docs/zh-CN/sql-reference/sql-statements/Administration/SHOW
TRASH.md b/docs/zh-CN/sql-reference/sql-statements/Administration/SHOW TRASH.md
new file mode 100644
index 0000000..5f2d3df
--- /dev/null
+++ b/docs/zh-CN/sql-reference/sql-statements/Administration/SHOW TRASH.md
@@ -0,0 +1,49 @@
+---
+{
+ "title": "SHOW TRASH",
+ "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+# SHOW TRASH
+## description
+ 该语句用于查看 backend 内的垃圾数据占用空间。
+ 语法:
+ SHOW TRASH [ON BackendHost:BackendHeartBeatPort];
+
+ 说明:
+ 1. Backend 格式为该节点的BackendHost:BackendHeartBeatPort。
+ 2. TrashUsedCapacity 表示该节点垃圾数据占用空间。
+
+## example
+
+ 1. 查看所有be节点的垃圾数据占用空间。
+
+ SHOW TRASH;
+
+ 2. 查看'192.168.0.1:9050'的垃圾数据占用空间(会显示具体磁盘信息)。
+
+ SHOW TRASH ON "192.168.0.1:9050";
+
+## keyword
+ SHOW, TRASH
+
diff --git a/fe/fe-core/src/main/cup/sql_parser.cup
b/fe/fe-core/src/main/cup/sql_parser.cup
index d6c4333..a433cf4 100644
--- a/fe/fe-core/src/main/cup/sql_parser.cup
+++ b/fe/fe-core/src/main/cup/sql_parser.cup
@@ -265,7 +265,7 @@ terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE,
KW_ALIAS, KW_ALL, KW_A
KW_SKEW,
KW_SMALLINT, KW_SNAPSHOT, KW_SONAME, KW_SPLIT, KW_START, KW_STATUS,
KW_STOP, KW_STORAGE, KW_STREAM, KW_STRING, KW_STRUCT,
KW_SUM, KW_SUPERUSER, KW_SYNC, KW_SYSTEM,
- KW_TABLE, KW_TABLES, KW_TABLET, KW_TASK, KW_TEMPORARY, KW_TERMINATED,
KW_THAN, KW_TIME, KW_THEN, KW_TIMESTAMP, KW_TINYINT,
+ KW_TABLE, KW_TABLES, KW_TABLET, KW_TASK, KW_TEMPORARY, KW_TERMINATED,
KW_THAN, KW_TIME, KW_THEN, KW_TIMESTAMP, KW_TINYINT,KW_TRASH,
KW_TO, KW_TRANSACTION, KW_TRIGGERS, KW_TRIM, KW_TRUE, KW_TRUNCATE,
KW_TYPE, KW_TYPES,
KW_UNCOMMITTED, KW_UNBOUNDED, KW_UNION, KW_UNIQUE, KW_UNSIGNED, KW_USE,
KW_USER, KW_USING, KW_UNINSTALL,
KW_VALUE, KW_VALUES, KW_VARCHAR, KW_VARIABLES, KW_VERBOSE, KW_VIEW,
@@ -2654,6 +2654,14 @@ show_param ::=
{:
RESULT = new ShowBackendsStmt();
:}
+ | KW_TRASH KW_ON STRING_LITERAL:backend
+ {:
+ RESULT = new ShowTrashDiskStmt(backend);
+ :}
+ | KW_TRASH
+ {:
+ RESULT = new ShowTrashStmt();
+ :}
| KW_FRONTENDS
{:
RESULT = new ShowFrontendsStmt();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTrashDiskStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTrashDiskStmt.java
new file mode 100644
index 0000000..3cca857
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTrashDiskStmt.java
@@ -0,0 +1,75 @@
+// 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.Catalog;
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.proc.TrashProcNode;
+import org.apache.doris.qe.ShowResultSetMetaData;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.system.Backend;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+
+import com.google.common.collect.ImmutableMap;
+
+public class ShowTrashDiskStmt extends ShowStmt {
+
+ private Backend backend;
+
+ public ShowTrashDiskStmt(String backendQuery) {
+ ImmutableMap<Long, Backend> backendsInfo =
Catalog.getCurrentSystemInfo().getIdToBackend();
+ for (Backend backend : backendsInfo.values()) {
+ String backendStr = String.valueOf(backend.getHost()) + ":" +
String.valueOf(backend.getHeartbeatPort());
+ if (backendQuery.equals(backendStr)) {
+ this.backend = backend;
+ break;
+ }
+ }
+ }
+
+ public Backend getBackend() {
+ return backend;
+ }
+
+ @Override
+ public void analyze(Analyzer analyzer) throws AnalysisException {
+ if
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
PrivPredicate.ADMIN)
+ &&
!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
+ PrivPredicate.OPERATOR)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"ADMIN/OPERATOR");
+ }
+ }
+
+ @Override
+ public ShowResultSetMetaData getMetaData() {
+ ShowResultSetMetaData.Builder builder =
ShowResultSetMetaData.builder();
+ for (String title : TrashProcNode.TITLE_NAMES) {
+ builder.addColumn(new Column(title, ScalarType.createVarchar(30)));
+ }
+ return builder.build();
+ }
+
+ @Override
+ public RedirectStatus getRedirectStatus() {
+ return RedirectStatus.NO_FORWARD;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTrashStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTrashStmt.java
new file mode 100644
index 0000000..a2c7444
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTrashStmt.java
@@ -0,0 +1,73 @@
+// 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.Catalog;
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.proc.TrashProcNode;
+import org.apache.doris.qe.ShowResultSetMetaData;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.system.Backend;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+public class ShowTrashStmt extends ShowStmt {
+ private List<Backend> backends = Lists.newArrayList();
+
+ public ShowTrashStmt() {
+ ImmutableMap<Long, Backend> backendsInfo =
Catalog.getCurrentSystemInfo().getIdToBackend();
+ for (Backend backend : backendsInfo.values()) {
+ this.backends.add(backend);
+ }
+ }
+
+ public List<Backend> getBackends() {
+ return backends;
+ }
+
+ @Override
+ public void analyze(Analyzer analyzer) throws AnalysisException {
+ if
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
PrivPredicate.ADMIN)
+ &&
!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
+ PrivPredicate.OPERATOR)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"ADMIN/OPERATOR");
+ }
+ }
+
+ @Override
+ public ShowResultSetMetaData getMetaData() {
+ ShowResultSetMetaData.Builder builder =
ShowResultSetMetaData.builder();
+ for (String title : TrashProcNode.TITLE_NAMES) {
+ builder.addColumn(new Column(title, ScalarType.createVarchar(30)));
+ }
+ return builder.build();
+ }
+
+ @Override
+ public RedirectStatus getRedirectStatus() {
+ return RedirectStatus.NO_FORWARD;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/common/proc/ProcService.java
b/fe/fe-core/src/main/java/org/apache/doris/common/proc/ProcService.java
index 1e23b0e..2558226 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/proc/ProcService.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/proc/ProcService.java
@@ -45,6 +45,7 @@ public final class ProcService {
root.register("resources",
Catalog.getCurrentCatalog().getResourceMgr().getProcNode());
root.register("load_error_hub", new
LoadErrorHubProcNode(Catalog.getCurrentCatalog()));
root.register("transactions", new TransDbProcDir());
+ root.register("trash", new TrashProcDir());
root.register("monitor", new MonitorProcDir());
root.register("current_queries", new CurrentQueryStatisticsProcDir());
root.register("current_backend_instances", new
CurrentQueryBackendInstanceProcDir());
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/common/proc/TrashProcDir.java
b/fe/fe-core/src/main/java/org/apache/doris/common/proc/TrashProcDir.java
new file mode 100644
index 0000000..e1b0b85
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/proc/TrashProcDir.java
@@ -0,0 +1,138 @@
+// 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.common.proc;
+
+import org.apache.doris.thrift.BackendService;
+import org.apache.doris.thrift.TNetworkAddress;
+import org.apache.doris.system.Backend;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Pair;
+import org.apache.doris.common.ClientPool;
+import org.apache.doris.common.util.DebugUtil;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * Show trash
+ * SHOW PROC '/trash'
+ * SHOW PROC '/trash/backendId'
+ */
+public class TrashProcDir implements ProcDirInterface {
+ private static final Logger LOG =
LogManager.getLogger(TrashProcNode.class);
+
+ public static final ImmutableList<String> TITLE_NAMES = new
ImmutableList.Builder<String>().add("BackendId")
+ .add("Backend").add("TrashUsedCapacity").build();
+
+ private List<Backend> backends = Lists.newArrayList();
+
+ public TrashProcDir() {
+ ImmutableMap<Long, Backend> backendsInfo =
Catalog.getCurrentSystemInfo().getIdToBackend();
+ for (Backend backend : backendsInfo.values()) {
+ this.backends.add(backend);
+ }
+ }
+
+ @Override
+ public ProcResult fetchResult() {
+ BaseProcResult result = new BaseProcResult();
+ result.setNames(TITLE_NAMES);
+
+ List<List<String>> infos = Lists.newArrayList();
+
+ getTrashInfo(backends, infos);
+
+ for (List<String> info : infos) {
+ result.addRow(info);
+ }
+
+ return result;
+ }
+
+ public static void getTrashInfo(List<Backend> backends, List<List<String>>
infos) {
+
+ for (Backend backend : backends) {
+ BackendService.Client client = null;
+ TNetworkAddress address = null;
+ Long trashUsedCapacityB = null;
+ boolean ok = false;
+ try {
+ long start = System.currentTimeMillis();
+ address = new TNetworkAddress(backend.getHost(),
backend.getBePort());
+ client = ClientPool.backendPool.borrowObject(address);
+ trashUsedCapacityB = client.getTrashUsedCapacity();
+ ok = true;
+ } catch (Exception e) {
+ LOG.warn("task exec error. backend[{}]", backend.getId(), e);
+ } finally {
+ if (ok) {
+ ClientPool.backendPool.returnObject(address, client);
+ } else {
+ ClientPool.backendPool.invalidateObject(address, client);
+ }
+ }
+
+ List<String> backendInfo = new ArrayList<String>();
+ backendInfo.add(String.valueOf(backend.getId()));
+ backendInfo.add(backend.getHost() + ":" +
String.valueOf(backend.getHeartbeatPort()));
+ if (trashUsedCapacityB != null) {
+ Pair<Double, String> trashUsedCapacity =
DebugUtil.getByteUint(trashUsedCapacityB);
+
backendInfo.add(DebugUtil.DECIMAL_FORMAT_SCALE_3.format(trashUsedCapacity.first)
+ " "
+ + trashUsedCapacity.second);
+ } else {
+ backendInfo.add("");
+ }
+ infos.add(backendInfo);
+ }
+ }
+
+ @Override
+ public boolean register(String name, ProcNodeInterface node) {
+ return false;
+ }
+
+ @Override
+ public ProcNodeInterface lookup(String backendHostAndPort) throws
AnalysisException {
+ if (Strings.isNullOrEmpty(backendHostAndPort)) {
+ throw new AnalysisException("BackendHost:HeartBeatPort is null");
+ }
+ String backendHost;
+ int backendHeartBeatPort;
+ try {
+ backendHost = backendHostAndPort.split(":")[0];
+ backendHeartBeatPort =
Integer.parseInt(backendHostAndPort.split(":")[1]);
+ } catch (NumberFormatException e) {
+ throw new AnalysisException("Invalid backend format: " +
backendHostAndPort);
+ }
+ Backend backend =
Catalog.getCurrentSystemInfo().getBackendWithHeartbeatPort(backendHost,
backendHeartBeatPort);
+ if (backend == null) {
+ throw new AnalysisException("Backend[" + backendHostAndPort + "]
does not exist.");
+ }
+
+ return new TrashProcNode(backend);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/common/proc/TrashProcNode.java
b/fe/fe-core/src/main/java/org/apache/doris/common/proc/TrashProcNode.java
new file mode 100644
index 0000000..d01e3cc
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/proc/TrashProcNode.java
@@ -0,0 +1,107 @@
+// 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.common.proc;
+
+import org.apache.doris.thrift.BackendService;
+import org.apache.doris.thrift.TDiskTrashInfo;
+import org.apache.doris.thrift.TNetworkAddress;
+import org.apache.doris.system.Backend;
+import org.apache.doris.common.Pair;
+import org.apache.doris.common.ClientPool;
+import org.apache.doris.common.util.DebugUtil;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TrashProcNode implements ProcNodeInterface {
+ private static final Logger LOG =
LogManager.getLogger(TrashProcNode.class);
+
+ public static final ImmutableList<String> TITLE_NAMES = new
ImmutableList.Builder<String>().add("RootPath")
+ .add("State").add("TrashUsedCapacity").build();
+
+ private Backend backend;
+
+ public TrashProcNode(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Override
+ public ProcResult fetchResult() {
+ Preconditions.checkNotNull(backend);
+
+ BaseProcResult result = new BaseProcResult();
+ result.setNames(TITLE_NAMES);
+
+ List<List<String>> infos = Lists.newArrayList();
+
+ getTrashDiskInfo(backend, infos);
+
+ for (List<String> info : infos) {
+ result.addRow(info);
+ }
+
+ return result;
+ }
+
+ public static void getTrashDiskInfo(Backend backend, List<List<String>>
infos) {
+
+ BackendService.Client client = null;
+ TNetworkAddress address = null;
+ boolean ok = false;
+ List<TDiskTrashInfo> diskTrashInfos = null;
+ try {
+ address = new TNetworkAddress(backend.getHost(),
backend.getBePort());
+ client = ClientPool.backendPool.borrowObject(address);
+ diskTrashInfos = client.getDiskTrashUsedCapacity();
+ ok = true;
+ } catch (Exception e) {
+ LOG.warn("task exec error. backend[{}]", backend.getId(), e);
+ } finally {
+ if (ok) {
+ ClientPool.backendPool.returnObject(address, client);
+ } else {
+ ClientPool.backendPool.invalidateObject(address, client);
+ }
+ }
+
+ if (diskTrashInfos == null) {
+ return;
+ }
+ for (TDiskTrashInfo diskTrashInfo : diskTrashInfos) {
+ List<String> diskInfo = new ArrayList<String>();
+
+ diskInfo.add(diskTrashInfo.getRootPath());
+
+ diskInfo.add(diskTrashInfo.getState());
+
+ long trashUsedCapacityB = diskTrashInfo.getTrashUsedCapacity();
+ Pair<Double, String> trashUsedCapacity =
DebugUtil.getByteUint(trashUsedCapacityB);
+ diskInfo.add(
+
DebugUtil.DECIMAL_FORMAT_SCALE_3.format(trashUsedCapacity.first) + " " +
trashUsedCapacity.second);
+
+ infos.add(diskInfo);
+ }
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java
b/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java
index 8d4b960..41d9118 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java
@@ -27,7 +27,7 @@ import java.text.DecimalFormat;
import java.util.UUID;
public class DebugUtil {
- public static final DecimalFormat DECIMAL_FORMAT_SCALE_3 = new
DecimalFormat("#.000");
+ public static final DecimalFormat DECIMAL_FORMAT_SCALE_3 = new
DecimalFormat("0.000");
public static int THOUSAND = 1000;
public static int MILLION = 1000 * THOUSAND;
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 54ca69f..83b0073 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
@@ -76,6 +76,8 @@ import org.apache.doris.analysis.ShowTableStatusStmt;
import org.apache.doris.analysis.ShowTableStmt;
import org.apache.doris.analysis.ShowTabletStmt;
import org.apache.doris.analysis.ShowTransactionStmt;
+import org.apache.doris.analysis.ShowTrashStmt;
+import org.apache.doris.analysis.ShowTrashDiskStmt;
import org.apache.doris.analysis.ShowUserPropertyStmt;
import org.apache.doris.analysis.ShowVariablesStmt;
import org.apache.doris.analysis.ShowViewStmt;
@@ -123,6 +125,8 @@ import org.apache.doris.common.proc.ProcNodeInterface;
import org.apache.doris.common.proc.RollupProcDir;
import org.apache.doris.common.proc.SchemaChangeProcDir;
import org.apache.doris.common.proc.TabletsProcDir;
+import org.apache.doris.common.proc.TrashProcDir;
+import org.apache.doris.common.proc.TrashProcNode;
import org.apache.doris.common.profile.ProfileTreeNode;
import org.apache.doris.common.profile.ProfileTreePrinter;
import org.apache.doris.common.util.ListComparator;
@@ -279,6 +283,10 @@ public class ShowExecutor {
handleShowGrants();
} else if (stmt instanceof ShowRolesStmt) {
handleShowRoles();
+ } else if (stmt instanceof ShowTrashStmt) {
+ handleShowTrash();
+ } else if (stmt instanceof ShowTrashDiskStmt) {
+ handleShowTrashDisk();
} else if (stmt instanceof AdminShowReplicaStatusStmt) {
handleAdminShowTabletStatus();
} else if (stmt instanceof AdminShowReplicaDistributionStmt) {
@@ -1766,6 +1774,20 @@ public class ShowExecutor {
List<List<String>> infos =
Catalog.getCurrentCatalog().getAuth().getRoleInfo();
resultSet = new ShowResultSet(showStmt.getMetaData(), infos);
}
+
+ private void handleShowTrash() {
+ ShowTrashStmt showStmt = (ShowTrashStmt) stmt;
+ List<List<String>> infos = Lists.newArrayList();
+ TrashProcDir.getTrashInfo(showStmt.getBackends(), infos);
+ resultSet = new ShowResultSet(showStmt.getMetaData(), infos);
+ }
+
+ private void handleShowTrashDisk() {
+ ShowTrashDiskStmt showStmt = (ShowTrashDiskStmt) stmt;
+ List<List<String>> infos = Lists.newArrayList();
+ TrashProcNode.getTrashDiskInfo(showStmt.getBackend(), infos);
+ resultSet = new ShowResultSet(showStmt.getMetaData(), infos);
+ }
private void handleAdminShowTabletStatus() throws AnalysisException {
AdminShowReplicaStatusStmt showStmt = (AdminShowReplicaStatusStmt)
stmt;
diff --git a/fe/fe-core/src/main/jflex/sql_scanner.flex
b/fe/fe-core/src/main/jflex/sql_scanner.flex
index f419622..589f57f 100644
--- a/fe/fe-core/src/main/jflex/sql_scanner.flex
+++ b/fe/fe-core/src/main/jflex/sql_scanner.flex
@@ -373,6 +373,7 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("tinyint", new Integer(SqlParserSymbols.KW_TINYINT));
keywordMap.put("to", new Integer(SqlParserSymbols.KW_TO));
keywordMap.put("transaction", new
Integer(SqlParserSymbols.KW_TRANSACTION));
+ keywordMap.put("trash", new Integer(SqlParserSymbols.KW_TRASH));
keywordMap.put("triggers", new Integer(SqlParserSymbols.KW_TRIGGERS));
keywordMap.put("trim", new Integer(SqlParserSymbols.KW_TRIM));
keywordMap.put("true", new Integer(SqlParserSymbols.KW_TRUE));
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/common/GenericPoolTest.java
b/fe/fe-core/src/test/java/org/apache/doris/common/GenericPoolTest.java
index b8a6152..e134e81 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/common/GenericPoolTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/common/GenericPoolTest.java
@@ -25,6 +25,7 @@ import org.apache.doris.thrift.TAgentTaskRequest;
import org.apache.doris.thrift.TCancelPlanFragmentParams;
import org.apache.doris.thrift.TCancelPlanFragmentResult;
import org.apache.doris.thrift.TDeleteEtlFilesRequest;
+import org.apache.doris.thrift.TDiskTrashInfo;
import org.apache.doris.thrift.TExecPlanFragmentParams;
import org.apache.doris.thrift.TExecPlanFragmentResult;
import org.apache.doris.thrift.TExportStatusResult;
@@ -194,6 +195,18 @@ public class GenericPoolTest {
}
@Override
+ public long getTrashUsedCapacity() throws TException {
+ // TODO Auto-generated method stub
+ return 0l;
+ }
+
+ @Override
+ public List<TDiskTrashInfo> getDiskTrashUsedCapacity() throws
TException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
public TTabletStatResult getTabletStat() throws TException {
// TODO Auto-generated method stub
return null;
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/utframe/MockedBackendFactory.java
b/fe/fe-core/src/test/java/org/apache/doris/utframe/MockedBackendFactory.java
index a65461d..f14d59b 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/utframe/MockedBackendFactory.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/utframe/MockedBackendFactory.java
@@ -33,6 +33,7 @@ import org.apache.doris.thrift.TBackendInfo;
import org.apache.doris.thrift.TCancelPlanFragmentParams;
import org.apache.doris.thrift.TCancelPlanFragmentResult;
import org.apache.doris.thrift.TDeleteEtlFilesRequest;
+import org.apache.doris.thrift.TDiskTrashInfo;
import org.apache.doris.thrift.TEtlState;
import org.apache.doris.thrift.TExecPlanFragmentParams;
import org.apache.doris.thrift.TExecPlanFragmentResult;
@@ -245,6 +246,16 @@ public class MockedBackendFactory {
}
@Override
+ public long getTrashUsedCapacity() throws TException {
+ return 0l;
+ }
+
+ @Override
+ public List<TDiskTrashInfo> getDiskTrashUsedCapacity() throws
TException {
+ return null;
+ }
+
+ @Override
public TTabletStatResult getTabletStat() throws TException {
return new TTabletStatResult(Maps.newHashMap());
}
diff --git a/gensrc/thrift/BackendService.thrift
b/gensrc/thrift/BackendService.thrift
index 200a8ea..1288a2b 100644
--- a/gensrc/thrift/BackendService.thrift
+++ b/gensrc/thrift/BackendService.thrift
@@ -105,6 +105,12 @@ struct TStreamLoadRecordResult {
1: required map<string, TStreamLoadRecord> stream_load_record
}
+struct TDiskTrashInfo {
+ 1: required string root_path
+ 2: required string state
+ 3: required i64 trash_used_capacity
+}
+
service BackendService {
// Called by coord to start asynchronous execution of plan fragment in
backend.
// Returns as soon as all incoming data streams have been set up.
@@ -147,6 +153,10 @@ service BackendService {
Status.TStatus erase_export_task(1:Types.TUniqueId task_id);
TTabletStatResult get_tablet_stat();
+
+ i64 get_trash_used_capacity();
+
+ list<TDiskTrashInfo> get_disk_trash_used_capacity();
Status.TStatus submit_routine_load_task(1:list<TRoutineLoadTask> tasks);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]