Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 86 additions & 89 deletions be/src/util/brpc_stub_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,32 @@

namespace starrocks {

namespace {

inline int64_t absolute_deadline_us(int64_t ttl_seconds) {
return butil::gettimeofday_us() + ttl_seconds * 1000 * 1000;
}

} // namespace

template <typename CacheT, typename ExtractFn>
void wait_clean_tasks_terminate(CacheT* cache, ExtractFn extract) {
std::vector<std::shared_ptr<EndpointCleanupTask<CacheT>>> tasks;
{
std::lock_guard<SpinLock> l(cache->_lock);
cache->_stopping = true;
for (auto& stub : cache->_stub_map) {
tasks.push_back(extract(stub.second));
}
cache->_stub_map.clear();
}
if (cache->_pipeline_timer != nullptr) {
for (auto& task : tasks) {
(void)cache->_pipeline_timer->unschedule(task.get());
}
}
}

BrpcStubCache::BrpcStubCache(ExecEnv* exec_env) : _pipeline_timer(exec_env->pipeline_timer()) {
_stub_map.init(239);
REGISTER_GAUGE_STARROCKS_METRIC(brpc_endpoint_stub_count, [this]() {
Expand All @@ -34,20 +60,17 @@ BrpcStubCache::BrpcStubCache(ExecEnv* exec_env) : _pipeline_timer(exec_env->pipe
}

BrpcStubCache::~BrpcStubCache() {
std::vector<std::shared_ptr<StubPool>> pools_to_cleanup;
{
std::lock_guard<SpinLock> l(_lock);

for (auto& stub : _stub_map) {
pools_to_cleanup.push_back(stub.second);
}
}
wait_clean_tasks_terminate(this, [](const std::shared_ptr<StubPool>& pool) { return pool->_cleanup_task; });
}

for (auto& pool : pools_to_cleanup) {
(void)_pipeline_timer->unschedule(pool->_cleanup_task.get());
bool BrpcStubCache::replace_cleanup_task_locked(const butil::EndPoint& endpoint,
std::shared_ptr<EndpointCleanupTask<BrpcStubCache>> task) {
auto pool = _stub_map.seek(endpoint);
if (pool != nullptr) {
(*pool)->_cleanup_task = std::move(task);
return true;
}
std::lock_guard<SpinLock> l(_lock);
_stub_map.clear();
return false;
}

std::shared_ptr<PInternalService_RecoverableStub> BrpcStubCache::get_stub(const butil::EndPoint& endpoint) {
Expand All @@ -56,17 +79,21 @@ std::shared_ptr<PInternalService_RecoverableStub> BrpcStubCache::get_stub(const
auto stub_pool = _stub_map.seek(endpoint);
if (stub_pool == nullptr) {
auto new_pool = std::make_shared<StubPool>();
new_pool->_cleanup_task = std::make_shared<EndpointCleanupTask<BrpcStubCache>>(this, endpoint);
new_pool->_cleanup_task =
std::make_shared<EndpointCleanupTask<BrpcStubCache>>(this, endpoint, config::brpc_stub_expire_s);
new_pool->_cleanup_task->renew_deadline_locked(absolute_deadline_us(config::brpc_stub_expire_s));
_stub_map.insert(endpoint, new_pool);
stub_pool = _stub_map.seek(endpoint);
}

if (_pipeline_timer->unschedule((*stub_pool)->_cleanup_task.get()) != TIMER_TASK_RUNNING) {
timespec tm = butil::seconds_from_now(config::brpc_stub_expire_s);
timespec tm = butil::microseconds_to_timespec((*stub_pool)->_cleanup_task->deadline_locked());
auto status = _pipeline_timer->schedule((*stub_pool)->_cleanup_task.get(), tm);
if (!status.ok()) {
LOG(WARNING) << "Failed to schedule brpc cleanup task: " << endpoint;
_stub_map.erase(endpoint);
return new_pool->get_or_create(endpoint);
}
} else {
(*stub_pool)->_cleanup_task->renew_deadline_locked(absolute_deadline_us(config::brpc_stub_expire_s));
}

return (*stub_pool)->get_or_create(endpoint);
Expand Down Expand Up @@ -96,13 +123,6 @@ std::shared_ptr<PInternalService_RecoverableStub> BrpcStubCache::get_stub(const
return get_stub(endpoint);
}

void BrpcStubCache::cleanup_expired(const butil::EndPoint& endpoint) {
std::lock_guard<SpinLock> l(_lock);

LOG(INFO) << "cleanup brpc stub, endpoint:" << endpoint;
_stub_map.erase(endpoint);
}

BrpcStubCache::StubPool::StubPool() : _idx(-1) {
_stubs.reserve(config::brpc_max_connections_per_server);
}
Expand Down Expand Up @@ -143,25 +163,17 @@ HttpBrpcStubCache::~HttpBrpcStubCache() {
}

void HttpBrpcStubCache::shutdown() {
std::vector<std::shared_ptr<EndpointCleanupTask<HttpBrpcStubCache>>> task_to_cleanup;

{
std::lock_guard<SpinLock> l(_lock);
for (auto& stub : _stub_map) {
task_to_cleanup.push_back(stub.second.second);
}
}
wait_clean_tasks_terminate(this, [](const StubEntry& entry) { return entry.cleanup_task; });
}

if (_pipeline_timer != nullptr) {
for (auto& task : task_to_cleanup) {
_pipeline_timer->unschedule(task.get());
}
}

{
std::lock_guard<SpinLock> l(_lock);
_stub_map.clear();
bool HttpBrpcStubCache::replace_cleanup_task_locked(const butil::EndPoint& endpoint,
std::shared_ptr<EndpointCleanupTask<HttpBrpcStubCache>> task) {
auto entry = _stub_map.seek(endpoint);
if (entry != nullptr) {
entry->cleanup_task = std::move(task);
return true;
}
return false;
}

StatusOr<std::shared_ptr<PInternalService_RecoverableStub>> HttpBrpcStubCache::get_http_stub(
Expand All @@ -187,33 +199,29 @@ StatusOr<std::shared_ptr<PInternalService_RecoverableStub>> HttpBrpcStubCache::g
auto stub_pair_ptr = _stub_map.seek(endpoint);
if (stub_pair_ptr == nullptr) {
// create
auto new_task = std::make_shared<EndpointCleanupTask<HttpBrpcStubCache>>(this, endpoint);
auto new_task =
std::make_shared<EndpointCleanupTask<HttpBrpcStubCache>>(this, endpoint, config::brpc_stub_expire_s);
auto stub = std::make_shared<PInternalService_RecoverableStub>(endpoint, "http");
if (!stub->reset_channel().ok()) {
return Status::RuntimeError("init http brpc channel error on " + taddr.hostname + ":" +
std::to_string(taddr.port));
}
_stub_map.insert(endpoint, std::make_pair(stub, new_task));
new_task->renew_deadline_locked(absolute_deadline_us(config::brpc_stub_expire_s));
_stub_map.insert(endpoint, StubEntry{stub, new_task});
stub_pair_ptr = _stub_map.seek(endpoint);
}

// schedule clean up task
if (_pipeline_timer->unschedule((*stub_pair_ptr).second.get()) != TIMER_TASK_RUNNING) {
timespec tm = butil::seconds_from_now(config::brpc_stub_expire_s);
auto status = _pipeline_timer->schedule((*stub_pair_ptr).second.get(), tm);
timespec tm = butil::microseconds_to_timespec(stub_pair_ptr->cleanup_task->deadline_locked());
auto status = _pipeline_timer->schedule(stub_pair_ptr->cleanup_task.get(), tm);
if (!status.ok()) {
LOG(WARNING) << "Failed to schedule http brpc cleanup task: " << endpoint;
LOG(WARNING) << "Failed to schedule brpc cleanup task: " << endpoint;
_stub_map.erase(endpoint);
return stub;
}
} else {
stub_pair_ptr->cleanup_task->renew_deadline_locked(absolute_deadline_us(config::brpc_stub_expire_s));
}

return (*stub_pair_ptr).first;
}

void HttpBrpcStubCache::cleanup_expired(const butil::EndPoint& endpoint) {
std::lock_guard<SpinLock> l(_lock);

LOG(INFO) << "cleanup http brpc stub, endpoint:" << endpoint;
_stub_map.erase(endpoint);
return stub_pair_ptr->stub;
}

#ifndef __APPLE__
Expand All @@ -233,25 +241,17 @@ LakeServiceBrpcStubCache::~LakeServiceBrpcStubCache() {
}

void LakeServiceBrpcStubCache::shutdown() {
std::vector<std::shared_ptr<EndpointCleanupTask<LakeServiceBrpcStubCache>>> task_to_cleanup;

{
std::lock_guard<SpinLock> l(_lock);
for (auto& stub : _stub_map) {
task_to_cleanup.push_back(stub.second.second);
}
}

if (_pipeline_timer != nullptr) {
for (auto& task : task_to_cleanup) {
_pipeline_timer->unschedule(task.get());
}
}
wait_clean_tasks_terminate(this, [](const StubEntry& entry) { return entry.cleanup_task; });
}

{
std::lock_guard<SpinLock> l(_lock);
_stub_map.clear();
bool LakeServiceBrpcStubCache::replace_cleanup_task_locked(
const butil::EndPoint& endpoint, std::shared_ptr<EndpointCleanupTask<LakeServiceBrpcStubCache>> task) {
auto entry = _stub_map.seek(endpoint);
if (entry != nullptr) {
entry->cleanup_task = std::move(task);
return true;
}
return false;
}

DEFINE_FAIL_POINT(get_stub_return_nullptr);
Expand All @@ -276,32 +276,29 @@ StatusOr<std::shared_ptr<starrocks::LakeService_RecoverableStub>> LakeServiceBrp
if (stub_pair_ptr == nullptr) {
// create
auto stub = std::make_shared<starrocks::LakeService_RecoverableStub>(endpoint, "");
auto new_task = std::make_shared<EndpointCleanupTask<LakeServiceBrpcStubCache>>(this, endpoint);
auto new_task = std::make_shared<EndpointCleanupTask<LakeServiceBrpcStubCache>>(this, endpoint,
config::brpc_stub_expire_s);
if (!stub->reset_channel().ok()) {
return Status::RuntimeError("init lakeService brpc channel error on " + host + ":" + std::to_string(port));
}
_stub_map.insert(endpoint, std::make_pair(stub, new_task));
new_task->renew_deadline_locked(absolute_deadline_us(config::brpc_stub_expire_s));
_stub_map.insert(endpoint, StubEntry{stub, new_task});
stub_pair_ptr = _stub_map.seek(endpoint);
}

// schedule clean up task
if (_pipeline_timer->unschedule((*stub_pair_ptr).second.get()) != TIMER_TASK_RUNNING) {
timespec tm = butil::seconds_from_now(config::brpc_stub_expire_s);
auto status = _pipeline_timer->schedule((*stub_pair_ptr).second.get(), tm);
timespec tm = butil::microseconds_to_timespec(stub_pair_ptr->cleanup_task->deadline_locked());
auto status = _pipeline_timer->schedule(stub_pair_ptr->cleanup_task.get(), tm);
if (!status.ok()) {
LOG(WARNING) << "Failed to schedule lake brpc cleanup task: " << endpoint;
LOG(WARNING) << "Failed to schedule brpc cleanup task: " << endpoint;
_stub_map.erase(endpoint);
return stub;
}
} else {
stub_pair_ptr->cleanup_task->renew_deadline_locked(absolute_deadline_us(config::brpc_stub_expire_s));
}

return (*stub_pair_ptr).first;
return stub_pair_ptr->stub;
}

void LakeServiceBrpcStubCache::cleanup_expired(const butil::EndPoint& endpoint) {
std::lock_guard<SpinLock> l(_lock);

LOG(INFO) << "cleanup lake service brpc stub, endpoint:" << endpoint;
_stub_map.erase(endpoint);
}
#endif

} // namespace starrocks
} // namespace starrocks
Loading
Loading