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