1 /* $Id: dbapi_pool_balancer.cpp 626337 2021-02-25 18:42:32Z ivanov $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Aaron Ucko
27 *
28 * File Description:
29 * Help distribute connections within a pool across servers.
30 *
31 * ===========================================================================
32 */
33
34 #include <ncbi_pch.hpp>
35
36 #include <dbapi/driver/impl/dbapi_pool_balancer.hpp>
37 #include <dbapi/driver/dbapi_conn_factory.hpp>
38 #include <dbapi/driver/impl/dbapi_impl_context.hpp>
39 #include <dbapi/error_codes.hpp>
40
41 #include <numeric>
42 #include <random>
43
44 #define NCBI_USE_ERRCODE_X Dbapi_PoolBalancer
45
46 BEGIN_NCBI_SCOPE
47
48 class CDBConnParams_DNC : public CDBConnParamsDelegate
49 {
50 public:
CDBConnParams_DNC(const CDBConnParams & other)51 CDBConnParams_DNC(const CDBConnParams& other)
52 : CDBConnParamsDelegate(other)
53 { }
54
GetParam(const string & key) const55 string GetParam(const string& key) const
56 {
57 if (key == "do_not_connect") {
58 return "true";
59 } else {
60 return CDBConnParamsDelegate::GetParam(key);
61 }
62 }
63 };
64
65
CDBPoolBalancer(const string & service_name,const string & pool_name,const IDBServiceMapper::TOptions & options,I_DriverContext * driver_ctx)66 CDBPoolBalancer::CDBPoolBalancer(const string& service_name,
67 const string& pool_name,
68 const IDBServiceMapper::TOptions& options,
69 I_DriverContext* driver_ctx)
70 : CPoolBalancer(service_name, options,
71 driver_ctx != nullptr
72 && !NStr::StartsWith(driver_ctx->GetDriverName(),
73 "ftds")),
74 m_DriverCtx(driver_ctx)
75 {
76 const impl::CDriverContext* ctx_impl
77 = dynamic_cast<const impl::CDriverContext*>(driver_ctx);
78 impl::CDriverContext::TCounts counts;
79 if (ctx_impl == NULL) {
80 if (driver_ctx != nullptr) {
81 ERR_POST_X(1, Warning <<
82 "Called with non-standard IDriverContext");
83 }
84 } else if (pool_name.empty()) {
85 ctx_impl->GetCountsForService(service_name, &counts);
86 } else {
87 ctx_impl->GetCountsForPool(pool_name, &counts);
88 }
89 x_InitFromCounts(counts);
90 }
91
92
x_TryPool(const void * params_in)93 IBalanceable* CDBPoolBalancer::x_TryPool(const void* params_in)
94 {
95 auto params = static_cast<const CDBConnParams*>(params_in);
96 _ASSERT(params != nullptr);
97 if (m_DriverCtx == nullptr) {
98 return nullptr;
99 } else {
100 CDBConnParams_DNC dnc_params(*params);
101 return IDBConnectionFactory::CtxMakeConnection(*m_DriverCtx,
102 dnc_params);
103 }
104 }
105
106
x_GetCount(const void * params_in,const string & name)107 unsigned int CDBPoolBalancer::x_GetCount(const void* params_in,
108 const string& name)
109 {
110 auto params = static_cast<const CDBConnParams*>(params_in);
111 _ASSERT(params != nullptr);
112 string pool_name = params->GetParam("pool_name");
113 return m_DriverCtx->NofConnections(name, pool_name);
114 }
115
116
x_GetPoolMax(const void * params_in)117 unsigned int CDBPoolBalancer::x_GetPoolMax(const void* params_in)
118 {
119 auto params = static_cast<const CDBConnParams*>(params_in);
120 _ASSERT(params != nullptr);
121 string pool_max_str = params->GetParam("pool_maxsize");
122 unsigned int pool_max = 0u;
123 if ( !pool_max_str.empty() && pool_max_str != "default") {
124 NStr::StringToNumeric(pool_max_str, &pool_max,
125 NStr::fConvErr_NoThrow);
126 }
127 return pool_max;
128 }
129
130
x_Discard(const void * params_in,IBalanceable * conn_in)131 void CDBPoolBalancer::x_Discard(const void* params_in, IBalanceable* conn_in)
132 {
133 auto params = static_cast<const CDBConnParams*>(params_in);
134 _ASSERT(params != nullptr);
135 auto conn = static_cast<const CDB_Connection*>(conn_in);
136 _ASSERT(conn != nullptr);
137 _TRACE("Proceeding to request turnover");
138 const string& server_name = conn->ServerName();
139 bool was_reusable = conn->IsReusable();
140 delete conn;
141 if (was_reusable) {
142 // This call might not close the exact connection we
143 // considered, but closing any connection to the
144 // relevant server is sufficient here.
145 m_DriverCtx->CloseUnusedConnections
146 (server_name, params->GetParam("pool_name"), 1u);
147 }
148 }
149
150
151 END_NCBI_SCOPE
152