Currently, there are some useless includes in the codebase. We can use a tool named include-what-you-use to optimize these includes. By using a strict include-what-you-use policy, we can get lots of benefits from it.
211 lines
7.3 KiB
C++
211 lines
7.3 KiB
C++
// 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 "runtime/client_cache.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "common/logging.h"
|
|
#include "util/doris_metrics.h"
|
|
#include "util/network_util.h"
|
|
|
|
namespace doris {
|
|
|
|
DEFINE_GAUGE_METRIC_PROTOTYPE_3ARG(thrift_used_clients, MetricUnit::NOUNIT,
|
|
"Number of clients 'checked-out' from the cache");
|
|
DEFINE_GAUGE_METRIC_PROTOTYPE_3ARG(thrift_opened_clients, MetricUnit::NOUNIT,
|
|
"Total clients in the cache, including those in use");
|
|
|
|
ClientCacheHelper::~ClientCacheHelper() {
|
|
for (auto& it : _client_map) {
|
|
delete it.second;
|
|
}
|
|
}
|
|
|
|
void ClientCacheHelper::_get_client_from_cache(const TNetworkAddress& hostport, void** client_key) {
|
|
*client_key = nullptr;
|
|
std::lock_guard<std::mutex> lock(_lock);
|
|
//VLOG_RPC << "get_client(" << hostport << ")";
|
|
auto cache_entry = _client_cache.find(hostport);
|
|
|
|
if (cache_entry == _client_cache.end()) {
|
|
cache_entry = _client_cache.insert(std::make_pair(hostport, std::list<void*>())).first;
|
|
DCHECK(cache_entry != _client_cache.end());
|
|
}
|
|
|
|
std::list<void*>& info_list = cache_entry->second;
|
|
if (!info_list.empty()) {
|
|
*client_key = info_list.front();
|
|
VLOG_RPC << "get_client(): cached client for " << hostport;
|
|
info_list.pop_front();
|
|
}
|
|
}
|
|
|
|
Status ClientCacheHelper::get_client(const TNetworkAddress& hostport, ClientFactory& factory_method,
|
|
void** client_key, int timeout_ms) {
|
|
_get_client_from_cache(hostport, client_key);
|
|
if (*client_key == nullptr) {
|
|
RETURN_IF_ERROR(_create_client(hostport, factory_method, client_key, timeout_ms));
|
|
}
|
|
|
|
if (_metrics_enabled) {
|
|
thrift_used_clients->increment(1);
|
|
}
|
|
|
|
return Status::OK();
|
|
}
|
|
|
|
Status ClientCacheHelper::reopen_client(ClientFactory& factory_method, void** client_key,
|
|
int timeout_ms) {
|
|
DCHECK(*client_key != nullptr) << "Trying to reopen nullptr client";
|
|
ThriftClientImpl* client_to_close = nullptr;
|
|
{
|
|
std::lock_guard<std::mutex> lock(_lock);
|
|
auto client_map_entry = _client_map.find(*client_key);
|
|
DCHECK(client_map_entry != _client_map.end());
|
|
client_to_close = client_map_entry->second;
|
|
}
|
|
const std::string ipaddress = client_to_close->ipaddress();
|
|
int port = client_to_close->port();
|
|
|
|
client_to_close->close();
|
|
|
|
// TODO: Thrift TBufferedTransport cannot be re-opened after Close() because it does
|
|
// not clean up internal buffers it reopens. To work around this issue, create a new
|
|
// client instead.
|
|
{
|
|
std::lock_guard<std::mutex> lock(_lock);
|
|
_client_map.erase(*client_key);
|
|
}
|
|
delete client_to_close;
|
|
*client_key = nullptr;
|
|
|
|
if (_metrics_enabled) {
|
|
thrift_opened_clients->increment(-1);
|
|
}
|
|
|
|
RETURN_IF_ERROR(_create_client(make_network_address(ipaddress, port), factory_method,
|
|
client_key, timeout_ms));
|
|
|
|
return Status::OK();
|
|
}
|
|
|
|
Status ClientCacheHelper::_create_client(const TNetworkAddress& hostport,
|
|
ClientFactory& factory_method, void** client_key,
|
|
int timeout_ms) {
|
|
std::unique_ptr<ThriftClientImpl> client_impl(factory_method(hostport, client_key));
|
|
//VLOG_CONNECTION << "create_client(): adding new client for "
|
|
// << client_impl->ipaddress() << ":" << client_impl->port();
|
|
|
|
client_impl->set_conn_timeout(config::thrift_connect_timeout_seconds * 1000);
|
|
|
|
Status status = client_impl->open();
|
|
|
|
if (!status.ok()) {
|
|
*client_key = nullptr;
|
|
return status;
|
|
}
|
|
|
|
DCHECK(*client_key != nullptr);
|
|
client_impl->set_send_timeout(timeout_ms);
|
|
client_impl->set_recv_timeout(timeout_ms);
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(_lock);
|
|
// Because the client starts life 'checked out', we don't add it to the cache map
|
|
DCHECK(_client_map.count(*client_key) == 0);
|
|
_client_map[*client_key] = client_impl.release();
|
|
}
|
|
|
|
if (_metrics_enabled) {
|
|
thrift_opened_clients->increment(1);
|
|
}
|
|
|
|
return Status::OK();
|
|
}
|
|
|
|
void ClientCacheHelper::release_client(void** client_key) {
|
|
DCHECK(*client_key != nullptr) << "Trying to release nullptr client";
|
|
ThriftClientImpl* client_to_close = nullptr;
|
|
{
|
|
std::lock_guard<std::mutex> lock(_lock);
|
|
auto client_map_entry = _client_map.find(*client_key);
|
|
DCHECK(client_map_entry != _client_map.end());
|
|
client_to_close = client_map_entry->second;
|
|
|
|
auto cache_list = _client_cache.find(
|
|
make_network_address(client_to_close->ipaddress(), client_to_close->port()));
|
|
DCHECK(cache_list != _client_cache.end());
|
|
if (_max_cache_size_per_host >= 0 &&
|
|
cache_list->second.size() >= _max_cache_size_per_host) {
|
|
// cache of this host is full, close this client connection and remove if from _client_map
|
|
_client_map.erase(*client_key);
|
|
} else {
|
|
cache_list->second.push_back(*client_key);
|
|
// There is no need to close client if we put it to cache list.
|
|
client_to_close = nullptr;
|
|
}
|
|
}
|
|
|
|
if (client_to_close != nullptr) {
|
|
client_to_close->close();
|
|
delete client_to_close;
|
|
if (_metrics_enabled) {
|
|
thrift_opened_clients->increment(-1);
|
|
}
|
|
}
|
|
|
|
if (_metrics_enabled) {
|
|
thrift_used_clients->increment(-1);
|
|
}
|
|
|
|
*client_key = nullptr;
|
|
}
|
|
|
|
std::string ClientCacheHelper::debug_string() {
|
|
std::stringstream out;
|
|
out << "ClientCacheHelper(#hosts=" << _client_cache.size() << " [";
|
|
|
|
bool isfirst = true;
|
|
for (const auto& [endpoint, client_keys] : _client_cache) {
|
|
if (!isfirst) {
|
|
out << " ";
|
|
isfirst = false;
|
|
}
|
|
out << endpoint << ":" << client_keys.size();
|
|
}
|
|
|
|
out << "])";
|
|
return out.str();
|
|
}
|
|
|
|
void ClientCacheHelper::init_metrics(const std::string& name) {
|
|
// Not strictly needed if init_metrics is called before any cache
|
|
// usage, but ensures that _metrics_enabled is published.
|
|
std::lock_guard<std::mutex> lock(_lock);
|
|
|
|
_thrift_client_metric_entity = DorisMetrics::instance()->metric_registry()->register_entity(
|
|
std::string("thrift_client.") + name, {{"name", name}});
|
|
INT_GAUGE_METRIC_REGISTER(_thrift_client_metric_entity, thrift_used_clients);
|
|
INT_GAUGE_METRIC_REGISTER(_thrift_client_metric_entity, thrift_opened_clients);
|
|
|
|
_metrics_enabled = true;
|
|
}
|
|
|
|
} // namespace doris
|