Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
206 changes: 181 additions & 25 deletions be/src/util/brpc_stub_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@

#include "util/brpc_stub_cache.h"

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
#include "common/config.h"
=======
#include "base/failpoint/fail_point.h"
#include "base/metrics.h"
#include "base/time/time.h"
#include "common/config_network_fwd.h"
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
#include "gen_cpp/internal_service.pb.h"
#ifndef __APPLE__
#include "gen_cpp/lake_service.pb.h"
Expand All @@ -25,7 +32,82 @@

namespace starrocks {

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
BrpcStubCache::BrpcStubCache(ExecEnv* exec_env) : _pipeline_timer(exec_env->pipeline_timer()) {
=======
namespace {

const char* const kBrpcEndpointStubCountMetric = "brpc_endpoint_stub_count";

template <typename Cache>
Cache*& singleton_cache() {
static Cache* cache = nullptr;
return cache;
}

template <typename Cache>
std::mutex& singleton_cache_mutex() {
static std::mutex mutex;
return mutex;
}

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;
BthreadTimer* timer = nullptr;
{
std::lock_guard<SpinLock> l(cache->_lock);
cache->_stopping = true;
timer = cache->_timer;
cache->_timer = nullptr;
for (auto& stub : cache->_stub_map) {
tasks.push_back(extract(stub.second));
}
cache->_stub_map.clear();
}
if (timer != nullptr) {
for (auto& task : tasks) {
task->unschedule_and_join(timer);
}
}
}

template <typename CacheT>
void reset_state_for_rebind(CacheT* cache, BthreadTimer* timer) {
DCHECK(timer != nullptr);
std::lock_guard<SpinLock> l(cache->_lock);
DCHECK(cache->_stub_map.empty() || cache->_timer == timer);
cache->_stopping = false;
cache->_timer = timer;
}

struct BrpcStubCache::Metrics {
Metrics(MetricRegistry* metric_registry, BrpcStubCache* cache) : registry(metric_registry), cache(cache) {
DCHECK(registry != nullptr);
registry->register_metric(kBrpcEndpointStubCountMetric, &brpc_endpoint_stub_count);
registry->register_hook(kBrpcEndpointStubCountMetric, [this] {
std::lock_guard<SpinLock> l(this->cache->_lock);
brpc_endpoint_stub_count.set_value(this->cache->_stub_map.size());
});
}

~Metrics() {
registry->deregister_hook(kBrpcEndpointStubCountMetric);
brpc_endpoint_stub_count.hide();
}

MetricRegistry* registry;
BrpcStubCache* cache;
UIntGauge brpc_endpoint_stub_count{MetricUnit::NOUNIT};
};

BrpcStubCache::BrpcStubCache(BthreadTimer* timer, MetricRegistry* metric_registry) : _timer(timer) {
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
_stub_map.init(239);
REGISTER_GAUGE_STARROCKS_METRIC(brpc_endpoint_stub_count, [this]() {
std::lock_guard<SpinLock> l(_lock);
Expand All @@ -34,6 +116,7 @@ BrpcStubCache::BrpcStubCache(ExecEnv* exec_env) : _pipeline_timer(exec_env->pipe
}

BrpcStubCache::~BrpcStubCache() {
<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
std::vector<std::shared_ptr<StubPool>> pools_to_cleanup;
{
std::lock_guard<SpinLock> l(_lock);
Expand All @@ -48,6 +131,20 @@ BrpcStubCache::~BrpcStubCache() {
}
std::lock_guard<SpinLock> l(_lock);
_stub_map.clear();
=======
_metrics.reset();
wait_clean_tasks_terminate(this, [](const std::shared_ptr<StubPool>& pool) { return pool->_cleanup_task; });
}

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;
}
return false;
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
}

std::shared_ptr<PInternalService_RecoverableStub> BrpcStubCache::get_stub(const butil::EndPoint& endpoint) {
Expand All @@ -56,17 +153,27 @@ 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);
}

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
if (_pipeline_timer->unschedule((*stub_pool)->_cleanup_task.get()) != TIMER_TASK_RUNNING) {
timespec tm = butil::seconds_from_now(config::brpc_stub_expire_s);
auto status = _pipeline_timer->schedule((*stub_pool)->_cleanup_task.get(), tm);
=======
timespec tm = butil::microseconds_to_timespec((*stub_pool)->_cleanup_task->deadline_locked());
auto status = _timer->schedule((*stub_pool)->_cleanup_task.get(), tm);
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
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,6 +203,7 @@ std::shared_ptr<PInternalService_RecoverableStub> BrpcStubCache::get_stub(const
return get_stub(endpoint);
}

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
void BrpcStubCache::cleanup_expired(const butil::EndPoint& endpoint) {
std::lock_guard<SpinLock> l(_lock);

Expand All @@ -104,6 +212,9 @@ void BrpcStubCache::cleanup_expired(const butil::EndPoint& endpoint) {
}

BrpcStubCache::StubPool::StubPool() : _idx(-1) {
=======
BrpcStubCache::StubPool::StubPool() {
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
_stubs.reserve(config::brpc_max_connections_per_server);
}

Expand Down Expand Up @@ -142,6 +253,7 @@ HttpBrpcStubCache::~HttpBrpcStubCache() {
shutdown();
}

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
void HttpBrpcStubCache::shutdown() {
std::vector<std::shared_ptr<EndpointCleanupTask<HttpBrpcStubCache>>> task_to_cleanup;

Expand All @@ -162,6 +274,24 @@ void HttpBrpcStubCache::shutdown() {
std::lock_guard<SpinLock> l(_lock);
_stub_map.clear();
}
=======
void HttpBrpcStubCache::bind_timer(BthreadTimer* timer) {
reset_state_for_rebind(this, timer);
}

void HttpBrpcStubCache::shutdown() {
wait_clean_tasks_terminate(this, [](const StubEntry& entry) { return entry.cleanup_task; });
}

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;
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
}

StatusOr<std::shared_ptr<PInternalService_RecoverableStub>> HttpBrpcStubCache::get_http_stub(
Expand All @@ -187,33 +317,36 @@ 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);
}

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
// 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 = _timer->schedule(stub_pair_ptr->cleanup_task.get(), tm);
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
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 @@ -232,6 +365,7 @@ LakeServiceBrpcStubCache::~LakeServiceBrpcStubCache() {
shutdown();
}

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
void LakeServiceBrpcStubCache::shutdown() {
std::vector<std::shared_ptr<EndpointCleanupTask<LakeServiceBrpcStubCache>>> task_to_cleanup;

Expand All @@ -252,6 +386,24 @@ void LakeServiceBrpcStubCache::shutdown() {
std::lock_guard<SpinLock> l(_lock);
_stub_map.clear();
}
=======
void LakeServiceBrpcStubCache::bind_timer(BthreadTimer* timer) {
reset_state_for_rebind(this, timer);
}

void LakeServiceBrpcStubCache::shutdown() {
wait_clean_tasks_terminate(this, [](const StubEntry& entry) { return entry.cleanup_task; });
}

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;
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
}

DEFINE_FAIL_POINT(get_stub_return_nullptr);
Expand All @@ -276,32 +428,36 @@ 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);
}

<<<<<<< HEAD:be/src/util/brpc_stub_cache.cpp
// 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 = _timer->schedule(stub_pair_ptr->cleanup_task.get(), tm);
>>>>>>> 2bbca67281 ([BugFix] Fix bRPC stub cache clean timer leak (#75973)):be/src/common/brpc/brpc_stub_cache.cpp
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
Loading
Loading