blob: 8ca0d503e74f5932998442dabe9e110efefb8aed [file]
// 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 "cloud/cloud_storage_engine.h"
#include "cloud/cloud_meta_mgr.h"
#include "cloud/cloud_tablet.h"
#include "cloud/cloud_tablet_mgr.h"
#include "cloud/config.h"
#include "io/fs/s3_file_system.h"
#include "olap/memtable_flush_executor.h"
#include "olap/storage_policy.h"
#include "runtime/memory/cache_manager.h"
namespace doris {
using namespace std::literals;
CloudStorageEngine::CloudStorageEngine(const UniqueId& backend_uid)
: BaseStorageEngine(Type::CLOUD, backend_uid),
_meta_mgr(std::make_unique<cloud::CloudMetaMgr>()),
_tablet_mgr(std::make_unique<CloudTabletMgr>(*this)) {}
CloudStorageEngine::~CloudStorageEngine() = default;
Status CloudStorageEngine::open() {
std::vector<std::tuple<std::string, S3Conf>> s3_infos;
do {
auto st = _meta_mgr->get_s3_info(&s3_infos);
if (st.ok()) {
break;
}
LOG(WARNING) << "failed to get s3 info, retry after 5s, err=" << st;
std::this_thread::sleep_for(5s);
} while (true);
CHECK(!s3_infos.empty()) << "no s3 infos";
for (auto& [id, s3_conf] : s3_infos) {
LOG(INFO) << "get s3 info: " << s3_conf.to_string() << " resource_id=" << id;
std::shared_ptr<io::S3FileSystem> s3_fs;
RETURN_IF_ERROR(io::S3FileSystem::create(std::move(s3_conf), id, &s3_fs));
RETURN_IF_ERROR(s3_fs->connect());
put_storage_resource(std::atol(id.c_str()), {s3_fs, 0});
}
set_latest_fs(get_filesystem(std::get<0>(s3_infos.back())));
// TODO(plat1ko): DeleteBitmapTxnManager
_memtable_flush_executor = std::make_unique<MemTableFlushExecutor>();
// TODO(plat1ko): Use file cache disks number?
_memtable_flush_executor->init(1);
_calc_delete_bitmap_executor = std::make_unique<CalcDeleteBitmapExecutor>();
_calc_delete_bitmap_executor->init();
return Status::OK();
}
void CloudStorageEngine::stop() {
if (_stopped) {
return;
}
_stopped = true;
_stop_background_threads_latch.count_down();
for (auto&& t : _bg_threads) {
if (t) {
t->join();
}
}
}
bool CloudStorageEngine::stopped() {
return _stopped;
}
Result<BaseTabletSPtr> CloudStorageEngine::get_tablet(int64_t tablet_id) {
return _tablet_mgr->get_tablet(tablet_id, false).transform([](auto&& t) {
return static_pointer_cast<BaseTablet>(std::move(t));
});
}
Status CloudStorageEngine::start_bg_threads() {
RETURN_IF_ERROR(Thread::create(
"CloudStorageEngine", "refresh_s3_info_thread",
[this]() { this->_refresh_s3_info_thread_callback(); }, &_bg_threads.emplace_back()));
LOG(INFO) << "refresh s3 info thread started";
RETURN_IF_ERROR(Thread::create(
"CloudStorageEngine", "vacuum_stale_rowsets_thread",
[this]() { this->_vacuum_stale_rowsets_thread_callback(); },
&_bg_threads.emplace_back()));
LOG(INFO) << "vacuum stale rowsets thread started";
RETURN_IF_ERROR(Thread::create(
"CloudStorageEngine", "sync_tablets_thread",
[this]() { this->_sync_tablets_thread_callback(); }, &_bg_threads.emplace_back()));
LOG(INFO) << "sync tablets thread started";
// TODO(plat1ko): lease_compaction_thread
// TODO(plat1ko): check_bucket_enable_versioning_thread
return Status::OK();
}
void CloudStorageEngine::_refresh_s3_info_thread_callback() {
while (!_stop_background_threads_latch.wait_for(
std::chrono::seconds(config::refresh_s3_info_interval_s))) {
std::vector<std::tuple<std::string, S3Conf>> s3_infos;
auto st = _meta_mgr->get_s3_info(&s3_infos);
if (!st.ok()) {
LOG(WARNING) << "failed to refresh object store info. err=" << st;
continue;
}
CHECK(!s3_infos.empty()) << "no s3 infos";
for (auto& [id, s3_conf] : s3_infos) {
auto fs = get_filesystem(id);
if (fs == nullptr) {
LOG(INFO) << "get new s3 info: " << s3_conf.to_string() << " resource_id=" << id;
std::shared_ptr<io::S3FileSystem> s3_fs;
auto st = io::S3FileSystem::create(std::move(s3_conf), id, &s3_fs);
if (!st.ok()) {
LOG(WARNING) << "failed to create s3 fs. id=" << id;
continue;
}
st = s3_fs->connect();
if (!st.ok()) {
LOG(WARNING) << "failed to connect s3 fs. id=" << id;
continue;
}
put_storage_resource(std::atol(id.c_str()), {s3_fs, 0});
} else {
auto s3_fs = std::reinterpret_pointer_cast<io::S3FileSystem>(fs);
if (s3_fs->s3_conf().ak != s3_conf.ak || s3_fs->s3_conf().sk != s3_conf.sk ||
s3_fs->s3_conf().sse_enabled != s3_conf.sse_enabled) {
auto cur_s3_conf = s3_fs->s3_conf();
LOG(INFO) << "update s3 info, old: " << cur_s3_conf.to_string()
<< " new: " << s3_conf.to_string() << " resource_id=" << id;
cur_s3_conf.ak = s3_conf.ak;
cur_s3_conf.sk = s3_conf.sk;
cur_s3_conf.sse_enabled = s3_conf.sse_enabled;
s3_fs->set_conf(std::move(cur_s3_conf));
st = s3_fs->connect();
if (!st.ok()) {
LOG(WARNING) << "failed to connect s3 fs. id=" << id;
}
}
}
}
if (auto& id = std::get<0>(s3_infos.back()); latest_fs()->id() != id) {
set_latest_fs(get_filesystem(id));
}
}
}
void CloudStorageEngine::_vacuum_stale_rowsets_thread_callback() {
while (!_stop_background_threads_latch.wait_for(
std::chrono::seconds(config::vacuum_stale_rowsets_interval_s))) {
_tablet_mgr->vacuum_stale_rowsets();
}
}
void CloudStorageEngine::_sync_tablets_thread_callback() {
while (!_stop_background_threads_latch.wait_for(
std::chrono::seconds(config::schedule_sync_tablets_interval_s))) {
_tablet_mgr->sync_tablets();
}
}
} // namespace doris