You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2022/06/08 00:50:39 UTC
[incubator-doris] branch dev-1.0.1 updated: [feature] detect alpha rowset and convert alpha rowset to beta rowset automatically (#9996)
This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch dev-1.0.1
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
The following commit(s) were added to refs/heads/dev-1.0.1 by this push:
new 7863e2ee20 [feature] detect alpha rowset and convert alpha rowset to beta rowset automatically (#9996)
7863e2ee20 is described below
commit 7863e2ee203b800316383c7cefda7a87a4ecb4a2
Author: jacktengg <18...@users.noreply.github.com>
AuthorDate: Wed Jun 8 08:50:32 2022 +0800
[feature] detect alpha rowset and convert alpha rowset to beta rowset automatically (#9996)
Add alpha rowset to beta rowset convert to convert rowset automatically. We will remove alpha rowset's code after 1.1.
---
be/src/common/config.h | 6 ++
be/src/olap/CMakeLists.txt | 1 +
be/src/olap/convert_rowset.cpp | 168 +++++++++++++++++++++++++++++++++++++++++
be/src/olap/convert_rowset.h | 60 +++++++++++++++
be/src/olap/olap_server.cpp | 53 +++++++++++++
be/src/olap/storage_engine.cpp | 8 ++
be/src/olap/storage_engine.h | 6 ++
be/src/olap/tablet.cpp | 9 +++
be/src/olap/tablet.h | 1 +
be/src/olap/tablet_manager.cpp | 15 ++++
be/src/olap/tablet_manager.h | 2 +
11 files changed, 329 insertions(+)
diff --git a/be/src/common/config.h b/be/src/common/config.h
index 48582beabe..3e4c31eb58 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -289,6 +289,12 @@ CONF_mInt64(min_compaction_failure_interval_sec, "5"); // 5 seconds
// This config can be set to limit thread number in compaction thread pool.
CONF_mInt32(max_compaction_threads, "10");
+// This config can be set to limit thread number in convert rowset thread pool.
+CONF_mInt32(convert_rowset_thread_num, "0");
+
+// initial sleep interval in seconds of scan alpha rowset
+CONF_mInt32(scan_alpha_rowset_min_interval_sec, "3");
+
// Thread count to do tablet meta checkpoint, -1 means use the data directories count.
CONF_Int32(max_meta_checkpoint_threads, "-1");
diff --git a/be/src/olap/CMakeLists.txt b/be/src/olap/CMakeLists.txt
index ced9307ee8..a16bf389b4 100644
--- a/be/src/olap/CMakeLists.txt
+++ b/be/src/olap/CMakeLists.txt
@@ -39,6 +39,7 @@ add_library(Olap STATIC
compaction_permit_limiter.cpp
comparison_predicate.cpp
compress.cpp
+ convert_rowset.cpp
cumulative_compaction.cpp
cumulative_compaction_policy.cpp
delete_handler.cpp
diff --git a/be/src/olap/convert_rowset.cpp b/be/src/olap/convert_rowset.cpp
new file mode 100644
index 0000000000..30d739f99f
--- /dev/null
+++ b/be/src/olap/convert_rowset.cpp
@@ -0,0 +1,168 @@
+// 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.
+
+#include "olap/convert_rowset.h"
+#include "olap/rowset/rowset_factory.h"
+
+namespace doris {
+
+OLAPStatus ConvertRowset::do_convert() {
+ if (!_tablet->init_succeeded()) {
+ return OLAP_ERR_CUMULATIVE_INVALID_PARAMETERS;
+ }
+ MutexLock base_compaction_lock(_tablet->get_base_lock(), TRY_LOCK);
+ MutexLock cumulative_compaction_lock(_tablet->get_cumulative_lock(), TRY_LOCK);
+ if (!base_compaction_lock.own_lock() || !cumulative_compaction_lock.own_lock()) {
+ LOG(INFO) << "The tablet is under compaction. tablet=" << _tablet->full_name();
+ return OLAP_ERR_CE_TRY_CE_LOCK_ERROR;
+ }
+
+ std::vector<RowsetSharedPtr> alpah_rowsets;
+ _tablet->find_alpha_rowsets(&alpah_rowsets);
+
+ Merger::Statistics stats;
+ OLAPStatus res = OLAP_SUCCESS;
+ const size_t max_convert_row_count = 20000000;
+ size_t row_count = 0;
+ for (size_t i = 0; i < alpah_rowsets.size(); ++i) {
+ Version output_version =
+ Version(alpah_rowsets[i]->start_version(), alpah_rowsets[i]->end_version());
+
+ RowsetReaderSharedPtr input_rs_reader;
+ RETURN_NOT_OK(alpah_rowsets[i]->create_reader(
+ MemTracker::CreateTracker(
+ -1, "ConvertRowset:RowsetReader:" + alpah_rowsets[i]->rowset_id().to_string(),
+ _reader_tracker, true, true),
+ &input_rs_reader));
+
+ std::unique_ptr<RowsetWriter> output_rs_writer;
+ RETURN_NOT_OK(construct_output_rowset_writer(output_version, &output_rs_writer));
+
+ res = Merger::merge_rowsets(_tablet, ReaderType::READER_BASE_COMPACTION, {input_rs_reader},
+ output_rs_writer.get(), &stats);
+
+ if (res != OLAP_SUCCESS) {
+ LOG(WARNING) << "fail to convert rowset. res=" << res
+ << ", tablet=" << _tablet->full_name();
+ return res;
+ } else {
+ auto output_rowset = output_rs_writer->build();
+ if (output_rowset == nullptr) {
+ LOG(WARNING) << "rowset writer build failed"
+ << ", tablet=" << _tablet->full_name();
+ return OLAP_ERR_MALLOC_ERROR;
+ }
+
+ RETURN_NOT_OK(check_correctness(alpah_rowsets[i], output_rowset, stats));
+
+ row_count += alpah_rowsets[i]->num_rows();
+
+ RETURN_NOT_OK(_modify_rowsets(alpah_rowsets[i], output_rowset));
+
+ LOG(INFO) << "succeed to convert rowset"
+ << ". tablet=" << _tablet->full_name()
+ << ", output_version=" << output_version
+ << ", disk=" << _tablet->data_dir()->path();
+
+ if (row_count >= max_convert_row_count) {
+ break;
+ }
+ }
+ }
+ return OLAP_SUCCESS;
+}
+
+OLAPStatus ConvertRowset::construct_output_rowset_writer(const Version& version, std::unique_ptr<RowsetWriter>* output) {
+ RowsetWriterContext context;
+ context.rowset_id = StorageEngine::instance()->next_rowset_id();
+ context.tablet_uid = _tablet->tablet_uid();
+ context.tablet_id = _tablet->tablet_id();
+ context.partition_id = _tablet->partition_id();
+ context.tablet_schema_hash = _tablet->schema_hash();
+ context.data_dir = _tablet->data_dir();
+ context.rowset_type = _tablet->tablet_meta()->preferred_rowset_type();
+ // Alpha Rowset will be removed in the future, so that if the tablet's default rowset type is
+ // alpah rowset, then set the newly created rowset to storage engine's default rowset.
+ if (context.rowset_type == ALPHA_ROWSET) {
+ context.rowset_type = StorageEngine::instance()->default_rowset_type();
+ }
+ context.path_desc = _tablet->tablet_path_desc();
+ context.tablet_schema = &(_tablet->tablet_schema());
+ context.rowset_state = VISIBLE;
+ context.version = version;
+ context.segments_overlap = NONOVERLAPPING;
+ context.parent_mem_tracker = _writer_tracker;
+ // The test results show that one rs writer is low-memory-footprint, there is no need to tracker its mem pool
+ RETURN_NOT_OK(RowsetFactory::create_rowset_writer(context, output));
+ return OLAP_SUCCESS;
+}
+
+OLAPStatus ConvertRowset::check_correctness(RowsetSharedPtr input_rowset, RowsetSharedPtr output_rowset,
+ const Merger::Statistics& stats) {
+ // 1. check row number
+ if (input_rowset->num_rows() !=
+ output_rowset->num_rows() + stats.merged_rows + stats.filtered_rows) {
+ LOG(WARNING) << "row_num does not match between input and output! "
+ << "input_row_num=" << input_rowset->num_rows()
+ << ", merged_row_num=" << stats.merged_rows
+ << ", filtered_row_num=" << stats.filtered_rows
+ << ", output_row_num=" << output_rowset->num_rows();
+
+ // ATTN(cmy): We found that the num_rows in some rowset meta may be set to the wrong value,
+ // but it is not known which version of the code has the problem. So when the convert
+ // result is inconsistent, we then try to verify by num_rows recorded in segment_groups.
+ // If the check passes, ignore the error and set the correct value in the output rowset meta
+ // to fix this problem.
+ // Only handle alpha rowset because we only find this bug in alpha rowset
+ int64_t num_rows = _get_input_num_rows_from_seg_grps(input_rowset);
+ if (num_rows == -1) {
+ return OLAP_ERR_CHECK_LINES_ERROR;
+ }
+ if (num_rows != output_rowset->num_rows() + stats.merged_rows + stats.filtered_rows) {
+ // If it is still incorrect, it may be another problem
+ LOG(WARNING) << "row_num got from seg groups does not match between cumulative input "
+ "and output! "
+ << "input_row_num=" << num_rows << ", merged_row_num=" << stats.merged_rows
+ << ", filtered_row_num=" << stats.filtered_rows
+ << ", output_row_num=" << output_rowset->num_rows();
+
+ return OLAP_ERR_CHECK_LINES_ERROR;
+ }
+ }
+ return OLAP_SUCCESS;
+}
+
+int64_t ConvertRowset::_get_input_num_rows_from_seg_grps(RowsetSharedPtr rowset) {
+ int64_t num_rows = 0;
+ for (auto& seg_grp : rowset->rowset_meta()->alpha_rowset_extra_meta_pb().segment_groups()) {
+ num_rows += seg_grp.num_rows();
+ }
+ return num_rows;
+}
+OLAPStatus ConvertRowset::_modify_rowsets(RowsetSharedPtr input_rowset, RowsetSharedPtr output_rowset) {
+ std::vector<RowsetSharedPtr> input_rowsets;
+ input_rowsets.push_back(input_rowset);
+
+ std::vector<RowsetSharedPtr> output_rowsets;
+ output_rowsets.push_back(output_rowset);
+
+ WriteLock wrlock(_tablet->get_header_lock());
+ RETURN_NOT_OK(_tablet->modify_rowsets(output_rowsets, input_rowsets, true));
+ _tablet->save_meta();
+ return OLAP_SUCCESS;
+}
+} // namespace doris
\ No newline at end of file
diff --git a/be/src/olap/convert_rowset.h b/be/src/olap/convert_rowset.h
new file mode 100644
index 0000000000..8319d5cb14
--- /dev/null
+++ b/be/src/olap/convert_rowset.h
@@ -0,0 +1,60 @@
+// 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.
+
+#pragma once
+
+#include "olap/merger.h"
+#include "olap/storage_engine.h"
+#include "olap/tablet.h"
+
+namespace doris {
+class DataDir;
+class ConvertRowset {
+public:
+ ConvertRowset(TabletSharedPtr tablet, const std::string& label,
+ const std::shared_ptr<MemTracker>& parent_tracker)
+ : _tablet(tablet),
+ _mem_tracker(MemTracker::CreateTracker(-1, label, parent_tracker, true, false, MemTrackerLevel::TASK)),
+ _reader_tracker(MemTracker::CreateTracker(-1, "ConvertRowsetReaderTracker:" + std::to_string(tablet->tablet_id()), _mem_tracker,
+ true, false)),
+ _writer_tracker(MemTracker::CreateTracker(-1, "ConvertRowsetWriterTracker:" + std::to_string(tablet->tablet_id()), _mem_tracker,
+ true, false)) {}
+
+ OLAPStatus do_convert();
+
+private:
+ OLAPStatus construct_output_rowset_writer(const Version& version, std::unique_ptr<RowsetWriter>* output);
+ OLAPStatus check_correctness(RowsetSharedPtr input_rowset, RowsetSharedPtr output_rowset,
+ const Merger::Statistics& stats);
+ int64_t _get_input_num_rows_from_seg_grps(RowsetSharedPtr rowset);
+ OLAPStatus _modify_rowsets(RowsetSharedPtr input_rowset, RowsetSharedPtr output_rowset);
+
+private:
+ TabletSharedPtr _tablet;
+
+ // the root tracker for this rowset converter
+ std::shared_ptr<MemTracker> _mem_tracker;
+
+ // the child of root, only track rowset reader mem
+ std::shared_ptr<MemTracker> _reader_tracker;
+
+ // the child of root, only track rowset writer mem
+ std::shared_ptr<MemTracker> _writer_tracker;
+
+ DISALLOW_COPY_AND_ASSIGN(ConvertRowset);
+};
+} // namespace doris
\ No newline at end of file
diff --git a/be/src/olap/olap_server.cpp b/be/src/olap/olap_server.cpp
index 196580ed72..550879ebfa 100644
--- a/be/src/olap/olap_server.cpp
+++ b/be/src/olap/olap_server.cpp
@@ -28,6 +28,7 @@
#include "agent/cgroups_mgr.h"
#include "common/status.h"
#include "gutil/strings/substitute.h"
+#include "olap/convert_rowset.h"
#include "olap/cumulative_compaction.h"
#include "olap/olap_common.h"
#include "olap/olap_define.h"
@@ -72,6 +73,21 @@ Status StorageEngine::start_bg_threads() {
.set_max_threads(max_thread_num)
.build(&_compaction_thread_pool);
+ int32_t convert_rowset_thread_num = config::convert_rowset_thread_num;
+ if (convert_rowset_thread_num > 0) {
+ ThreadPoolBuilder("ConvertRowsetTaskThreadPool")
+ .set_min_threads(convert_rowset_thread_num)
+ .set_max_threads(convert_rowset_thread_num)
+ .build(&_convert_rowset_thread_pool);
+
+ // alpha rowset scan thread
+ RETURN_IF_ERROR(Thread::create(
+ "StorageEngine", "alpha_rowset_scan_thread",
+ [this]() { this->_alpha_rowset_scan_thread_callback(); },
+ &_alpha_rowset_scan_thread));
+ LOG(INFO) << "alpha rowset scan thread started";
+ }
+
// compaction tasks producer thread
RETURN_IF_ERROR(Thread::create(
"StorageEngine", "compaction_tasks_producer_thread",
@@ -308,6 +324,43 @@ void StorageEngine::_tablet_checkpoint_callback(const std::vector<DataDir*>& dat
} while (!_stop_background_threads_latch.wait_for(MonoDelta::FromSeconds(interval)));
}
+void StorageEngine::_alpha_rowset_scan_thread_callback() {
+ LOG(INFO) << "try to start alpha rowset scan thread!";
+
+ auto scan_interval_sec = config::scan_alpha_rowset_min_interval_sec;
+ auto max_convert_task = config::convert_rowset_thread_num * 2;
+ do {
+ std::vector<TabletSharedPtr> tablet_have_alpha_rowset;
+ _tablet_manager->find_tablet_have_alpha_rowset(tablet_have_alpha_rowset);
+
+ std::random_device rd;
+ std::mt19937 g(rd());
+ std::shuffle(tablet_have_alpha_rowset.begin(), tablet_have_alpha_rowset.end(), g);
+
+ for (int i = 0; i < max_convert_task && i < tablet_have_alpha_rowset.size(); ++i) {
+ auto tablet = tablet_have_alpha_rowset[i];
+ auto st = _convert_rowset_thread_pool->submit_func([=]() {
+ CgroupsMgr::apply_system_cgroup();
+ std::string tracker_label =
+ "StorageEngine:ConvertRowset:" + std::to_string(tablet->tablet_id());
+ auto convert_rowset = std::make_shared<ConvertRowset>(
+ tablet, tracker_label, _convert_rowset_mem_tracker);
+ convert_rowset->do_convert();
+ });
+ if (!st.ok()) {
+ LOG(WARNING) << "submit convert tablet tasks failed.";
+ }
+ }
+
+ if (tablet_have_alpha_rowset.size() == 0) {
+ scan_interval_sec = std::min(3600, scan_interval_sec * 2);
+ } else {
+ _convert_rowset_thread_pool->wait();
+ scan_interval_sec = config::scan_alpha_rowset_min_interval_sec;
+ }
+ } while (!_stop_background_threads_latch.wait_for(MonoDelta::FromSeconds(scan_interval_sec)));
+}
+
void StorageEngine::_compaction_tasks_producer_callback() {
#ifdef GOOGLE_PROFILER
ProfilerRegisterThread();
diff --git a/be/src/olap/storage_engine.cpp b/be/src/olap/storage_engine.cpp
index 1e28d05562..7513765931 100644
--- a/be/src/olap/storage_engine.cpp
+++ b/be/src/olap/storage_engine.cpp
@@ -116,6 +116,8 @@ StorageEngine::StorageEngine(const EngineOptions& options)
false, MemTrackerLevel::OVERVIEW)),
_tablet_mem_tracker(MemTracker::CreateTracker(-1, "TabletHeader", nullptr, false, false,
MemTrackerLevel::OVERVIEW)),
+ _convert_rowset_mem_tracker(MemTracker::CreateTracker(-1, "ConvertRowset", nullptr, false,
+ false, MemTrackerLevel::OVERVIEW)),
_stop_background_threads_latch(1),
_tablet_manager(new TabletManager(config::tablet_map_shard_size)),
_txn_manager(new TxnManager(config::txn_map_shard_size, config::txn_shard_size)),
@@ -146,6 +148,9 @@ StorageEngine::~StorageEngine() {
if (_compaction_thread_pool) {
_compaction_thread_pool->shutdown();
}
+ if (_convert_rowset_thread_pool) {
+ _convert_rowset_thread_pool->shutdown();
+ }
if (_tablet_meta_checkpoint_thread_pool) {
_tablet_meta_checkpoint_thread_pool->shutdown();
}
@@ -562,6 +567,9 @@ void StorageEngine::stop() {
}
THREAD_JOIN(_compaction_tasks_producer_thread);
+ if (_alpha_rowset_scan_thread) {
+ THREAD_JOIN(_alpha_rowset_scan_thread);
+ }
THREAD_JOIN(_unused_rowset_monitor_thread);
THREAD_JOIN(_garbage_sweeper_thread);
THREAD_JOIN(_disk_stat_monitor_thread);
diff --git a/be/src/olap/storage_engine.h b/be/src/olap/storage_engine.h
index 6102242bf2..03ee581d59 100644
--- a/be/src/olap/storage_engine.h
+++ b/be/src/olap/storage_engine.h
@@ -251,6 +251,8 @@ private:
void _compaction_tasks_producer_callback();
+ void _alpha_rowset_scan_thread_callback();
+
std::vector<TabletSharedPtr> _generate_compaction_tasks(CompactionType compaction_type,
std::vector<DataDir*>& data_dirs,
bool check_score);
@@ -325,6 +327,7 @@ private:
std::shared_ptr<MemTracker> _compaction_mem_tracker;
std::shared_ptr<MemTracker> _tablet_mem_tracker;
std::shared_ptr<MemTracker> _schema_change_mem_tracker;
+ std::shared_ptr<MemTracker> _convert_rowset_mem_tracker;
CountDownLatch _stop_background_threads_latch;
scoped_refptr<Thread> _unused_rowset_monitor_thread;
@@ -363,6 +366,9 @@ private:
std::unique_ptr<ThreadPool> _compaction_thread_pool;
+ scoped_refptr<Thread> _alpha_rowset_scan_thread;
+ std::unique_ptr<ThreadPool> _convert_rowset_thread_pool;
+
std::unique_ptr<ThreadPool> _tablet_meta_checkpoint_thread_pool;
CompactionPermitLimiter _permit_limiter;
diff --git a/be/src/olap/tablet.cpp b/be/src/olap/tablet.cpp
index 27c436c253..8214c44494 100644
--- a/be/src/olap/tablet.cpp
+++ b/be/src/olap/tablet.cpp
@@ -1061,6 +1061,15 @@ void Tablet::pick_candidate_rowsets_to_cumulative_compaction(
_cumulative_point, candidate_rowsets);
}
+void Tablet::find_alpha_rowsets(std::vector<RowsetSharedPtr>* rowsets) const {
+ ReadLock rdlock(_meta_lock);
+ for (auto& it : _rs_version_map) {
+ if (it.second->rowset_meta()->rowset_type() == RowsetTypePB::ALPHA_ROWSET) {
+ rowsets->push_back(it.second);
+ }
+ }
+}
+
void Tablet::pick_candidate_rowsets_to_base_compaction(vector<RowsetSharedPtr>* candidate_rowsets) {
ReadLock rdlock(_meta_lock);
for (auto& it : _rs_version_map) {
diff --git a/be/src/olap/tablet.h b/be/src/olap/tablet.h
index 09a31ae459..5d0ad5ad05 100644
--- a/be/src/olap/tablet.h
+++ b/be/src/olap/tablet.h
@@ -267,6 +267,7 @@ public:
return _tablet_meta->all_beta();
}
+ void find_alpha_rowsets(std::vector<RowsetSharedPtr>* rowsets) const;
private:
OLAPStatus _init_once_action();
void _print_missed_versions(const std::vector<Version>& missed_versions) const;
diff --git a/be/src/olap/tablet_manager.cpp b/be/src/olap/tablet_manager.cpp
index cf75b8209c..88efecfe99 100644
--- a/be/src/olap/tablet_manager.cpp
+++ b/be/src/olap/tablet_manager.cpp
@@ -621,6 +621,21 @@ void TabletManager::get_tablet_stat(TTabletStatResult* result) {
result->__set_tablet_stat_list(*local_cache);
}
+void TabletManager::find_tablet_have_alpha_rowset(std::vector<TabletSharedPtr>& tablets) {
+ for (const auto& tablets_shard : _tablets_shards) {
+ ReadLock rdlock(tablets_shard.lock);
+ for (const auto& tablet_map : tablets_shard.tablet_map) {
+ for (const TabletSharedPtr& tablet_ptr : tablet_map.second.table_arr) {
+ if (!tablet_ptr->all_beta() &&
+ tablet_ptr->can_do_compaction(tablet_ptr->data_dir()->path_hash(),
+ BASE_COMPACTION)) {
+ tablets.push_back(tablet_ptr);
+ }
+ }
+ }
+ }
+}
+
TabletSharedPtr TabletManager::find_best_tablet_to_compaction(
CompactionType compaction_type, DataDir* data_dir,
const std::unordered_set<TTabletId>& tablet_submitted_compaction, uint32_t* score,
diff --git a/be/src/olap/tablet_manager.h b/be/src/olap/tablet_manager.h
index 90f03fa680..a52322d8e5 100644
--- a/be/src/olap/tablet_manager.h
+++ b/be/src/olap/tablet_manager.h
@@ -146,6 +146,8 @@ public:
void get_all_tablets_storage_format(TCheckStorageFormatResult* result);
+ void find_tablet_have_alpha_rowset(std::vector<TabletSharedPtr>& tablets);
+
private:
// Add a tablet pointer to StorageEngine
// If force, drop the existing tablet add this new one
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org