//------------------------------------------------------------------------------ // File: XrdConnPool.cc // Author: Elvin-Alin Sindrilaru - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2019 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "common/XrdConnPool.hh" #include #include EOSCOMMONNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ XrdConnPool::XrdConnPool(bool is_enabled, uint32_t max_size): mIsEnabled(is_enabled), mMaxSize(max_size) { if (!mIsEnabled && getenv("EOS_XRD_USE_CONNECTION_POOL")) { mIsEnabled = true; if (getenv("EOS_XRD_CONNECTION_POOL_SIZE")) { max_size = strtoul(getenv("EOS_XRD_CONNECTION_POOL_SIZE"), 0, 10); } if (max_size < 1) { eos_warning("%s", "msg=\"wrong EOS_XRD_CONNECTION_POOL_SIZE, forcing " "max size to 1\""); max_size = 1; } if (max_size > 1024) { eos_warning("%s", "msg=\"too big EOS_XRD_CONNECTION_POOL_SIZE, forcing " "max size to 1024\""); max_size = 1024; } mMaxSize = max_size; } } //------------------------------------------------------------------------------ // Assign new connection from the pool to the given URL. What this actually // means is updating the username used in the URL when connecting to the // XRootD server. //------------------------------------------------------------------------------ uint32_t XrdConnPool::AssignConnection(XrdCl::URL& url) { uint32_t conn_id {0ull}; if (!mIsEnabled) { return conn_id; } bool found {false}; uint32_t best_conn_id {1}; uint32_t best_conn_val {std::numeric_limits::max()}; std::string target_host = url.GetHostName(); std::unique_lock scope_lock(mPoolMutex); // Map of connection id and score for current host auto& map_id_score = mConnPool[target_host]; for (auto& elem : map_id_score) { if (elem.second < best_conn_val) { best_conn_id = elem.first; best_conn_val = elem.second; } if (elem.second == 0) { ++elem.second; conn_id = elem.first; found = true; break; } } if (!found) { if (map_id_score.size() >= mMaxSize) { // Share the least busy connection ++map_id_score[best_conn_id]; conn_id = best_conn_id; eos_static_debug("msg=\"connection pool limit reached - using %u/%u " "connections\"", map_id_score.size(), mMaxSize); } else { conn_id = map_id_score.size() + 1; map_id_score[conn_id] = 1; } } if (conn_id) { url.SetUserName(std::to_string(conn_id)); } return conn_id; } //------------------------------------------------------------------------------ // Release a connection and update the status of the pool //------------------------------------------------------------------------------ void XrdConnPool::ReleaseConnection(const XrdCl::URL& url) { if (!mIsEnabled) { return; } uint32_t conn_id {0ull}; try { conn_id = std::stoul(url.GetUserName()); } catch (const std::exception& e) { // ignore } if (conn_id) { std::unique_lock scope_lock(mPoolMutex); auto it = mConnPool.find(url.GetHostName()); if (it != mConnPool.end()) { auto& map_id_score = it->second; if (map_id_score[conn_id] >= 1) { --map_id_score[conn_id]; } } } } //------------------------------------------------------------------------------ // Dump the status of the connection pool to the given string //------------------------------------------------------------------------------ void XrdConnPool::Dump(std::string& out) const { std::ostringstream oss; oss << "[connection-pool-dump]" << std::endl; for (auto it = mConnPool.begin(); it != mConnPool.end(); ++it) { for (auto fit = it->second.begin(); fit != it->second.end(); ++fit) { oss << "[connection-pool] host=" << it->first << " id=" << fit->first << " usage=" << fit->second << std::endl; } } out = oss.str(); } EOSCOMMONNAMESPACE_END