1 #ifndef CORELIB___DB_SERVICE_MAPPER__HPP
2 #define CORELIB___DB_SERVICE_MAPPER__HPP
3 
4 /*  $Id: ncbi_dbsvcmapper.hpp 626335 2021-02-25 18:42:22Z ivanov $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author:  Sergey Sikorskiy
30  *
31  * File Description:
32  *   Database service name to server mapping policy.
33  *
34  */
35 
36 
37 #include <corelib/ncbimtx.hpp>
38 
39 #ifdef NCBI_OS_MSWIN
40 #  include <winsock2.h>
41 #endif
42 
43 BEGIN_NCBI_SCOPE
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 /// Forward declarations
47 ///
48 
49 class CDBServer;
50 class IDBServiceMapper;
51 class IRegistry;
52 
53 ///////////////////////////////////////////////////////////////////////////////
54 /// I_ConnectionExtra
55 ///
56 
57 class I_ConnectionExtra
58 {
59 public:
~I_ConnectionExtra(void)60     virtual ~I_ConnectionExtra(void) { }
61 
62 #ifdef NCBI_OS_MSWIN
63     typedef SOCKET  TSockHandle;
64 #else
65     typedef int     TSockHandle;
66 #endif
67 
68     /// Get OS handle of the socket represented by the connection
69     virtual TSockHandle GetLowLevelHandle(void) const = 0;
70 
71     virtual void SetUserData(CObject* data) = 0;
GetUserData(void)72     template<typename T> T* GetUserData(void)
73     { return dynamic_cast<T*>(x_GetUserData()); }
GetUserData(void) const74     template<typename T> const T* GetUserData(void) const
75     { return dynamic_cast<T*>(x_GetUserData()); }
76 
77 protected:
78     virtual CObject* x_GetUserData(void) const = 0;
x_RecordServer(const CDBServer &)79     virtual void     x_RecordServer(const CDBServer&) { }
80 
81 private:
82     friend class IDBServiceMapper;
83 };
84 
85 
86 /// Lightweight representation of just a host and a port.
87 class NCBI_XNCBI_EXPORT CEndpointKey
88 {
89 private:
90     typedef Uint8 TValue;
91 
92 public:
CEndpointKey(const CEndpointKey & that)93     CEndpointKey(const CEndpointKey& that)
94         : m_Value(that.m_Value)
95         { }
96 
CEndpointKey(Uint4 host,Uint2 port=0)97     CEndpointKey(Uint4 host, Uint2 port = 0)
98         : m_Value((static_cast<TValue>(host) << 16) | port)
99         { }
100 
101     CEndpointKey(const CTempString& name, NStr::TConvErrFlags flags = 0);
102 
GetHost(void) const103     Uint4 GetHost(void) const {
104         _ASSERT(m_Value >> 48 == 0);
105         return static_cast<Uint4>(m_Value >> 16);
106     }
107 
GetPort(void) const108     Uint2 GetPort(void) const {
109         return m_Value & 0xFFFF;
110     }
111 
operator ==(const CEndpointKey & that) const112     bool operator==(const CEndpointKey& that) const
113         { return m_Value == that.m_Value; }
114 
operator !=(const CEndpointKey & that) const115     bool operator!=(const CEndpointKey& that) const
116         { return m_Value != that.m_Value; }
117 
operator <(const CEndpointKey & that) const118     bool operator<(const CEndpointKey& that) const
119         { return m_Value < that.m_Value; }
120 
operator <=(const CEndpointKey & that) const121     bool operator<=(const CEndpointKey& that) const
122         { return m_Value <= that.m_Value; }
123 
operator >(const CEndpointKey & that) const124     bool operator>(const CEndpointKey& that) const
125         { return m_Value > that.m_Value; }
126 
operator >=(const CEndpointKey & that) const127     bool operator>=(const CEndpointKey& that) const
128         { return m_Value >= that.m_Value; }
129 
130 private:
131     TValue m_Value;
132 };
133 
134 
135 NCBI_XNCBI_EXPORT
136 ostream& operator<<(ostream& os, const CEndpointKey& key);
137 
138 
139 ///////////////////////////////////////////////////////////////////////////////
140 /// IDBServiceMapper
141 ///
142 
143 class CDBServer : public CObject
144 {
145 public:
146     CDBServer(void);
147     CDBServer(const string& name,
148               Uint4         host = 0,
149               Uint2         port = 0,
150               unsigned int  expire_time = 0);
151 
GetName(void) const152     const string& GetName      (void) const { return m_Name; }
GetHost(void) const153     Uint4         GetHost      (void) const { return m_Host; }
GetPort(void) const154     Uint2         GetPort      (void) const { return m_Port; }
GetExpireTime(void) const155     time_t        GetExpireTime(void) const { return time_t(m_ExpireTime); }
156 
IsValid(void) const157     bool IsValid(void) const
158     {
159         return !GetName().empty() || GetHost() != 0;
160     }
161 
162 private:
163     const string       m_Name;
164     const Uint4        m_Host;
165     const Uint2        m_Port;
166     const unsigned int m_ExpireTime;
167 };
168 typedef CRef<CDBServer> TSvrRef;
169 
170 bool operator== (const CDBServer& l, const CDBServer& r);
171 bool operator< (const CDBServer& l, const CDBServer& r);
172 
173 /// CDBServerOption -- CDBServer extended with additional information
174 /// that helps maintain a balanced pool of connections.  Rankings are
175 /// relative; what matters there is the ratios between rankings
176 /// obtained together.  Some rankings may be zero as long as the total
177 /// isn't.
178 class CDBServerOption : public CDBServer
179 {
180 public:
181     enum EState {
182         fState_Penalized = 1 << 0, ///< Penalized by the load balancer
183         fState_Excluded  = 1 << 1, ///< Excluded by DBAPI
184         fState_Normal    = 0       ///< Fully available
185     };
186     DECLARE_SAFE_FLAGS_TYPE(EState, TState);
187 
CDBServerOption(const string & name,Uint4 host,Uint2 port,double ranking,TState state=fState_Normal,unsigned int expire_time=0)188     CDBServerOption(const string& name,
189                     Uint4         host,
190                     Uint2         port,
191                     double        ranking,
192                     TState        state = fState_Normal,
193                     unsigned int  expire_time = 0)
194         : CDBServer(name, host, port, expire_time),
195           m_Ranking(ranking), m_State(state)
196         { }
197 
GetRanking(void) const198     double GetRanking (void) const { return m_Ranking;                  }
GetState(void) const199     TState GetState   (void) const { return m_State;                    }
IsPenalized(void) const200     bool   IsPenalized(void) const { return (m_State & fState_Penalized) != 0; }
IsExcluded(void) const201     bool   IsExcluded (void) const { return (m_State & fState_Excluded) != 0; }
IsNormal(void) const202     bool   IsNormal   (void) const { return m_State == fState_Normal;   }
203 
204 private:
205     friend class IDBServiceMapper;
206     friend class CDBUDRandomMapper;
207 
208     double m_Ranking;
209     TState m_State;
210 };
211 
212 DECLARE_SAFE_FLAGS(CDBServerOption::EState);
213 
214 ///////////////////////////////////////////////////////////////////////////////
215 /// IDBServiceMapper
216 ///
217 
218 class NCBI_XNCBI_EXPORT IDBServiceMapper : public CObject
219 {
220 public:
221     typedef IDBServiceMapper* (*TFactory)(const IRegistry* registry);
222     typedef list<CRef<CDBServerOption> > TOptions;
223 
224     struct SDereferenceLess
225     {
226         template <typename T>
operator ()IDBServiceMapper::SDereferenceLess227         bool operator()(T l, T r) const
228         {
229             _ASSERT(l.NotEmpty());
230             _ASSERT(r.NotEmpty());
231 
232             return *l < *r;
233         }
234     };
235 
~IDBServiceMapper(void)236     virtual ~IDBServiceMapper    (void) {}
237 
238     virtual string  GetName      (void) const;
239     virtual void    Configure    (const IRegistry* registry = NULL) = 0;
240     /// Map a service to a server
241     virtual TSvrRef GetServer    (const string&    service) = 0;
242 
243     /// Exclude a server from the mapping for a service.
244     /// @note Classes that override this method should either override
245     /// GetServerOptions too or chain to the base implementation (and
246     /// have CleanExcluded do the same!)
Exclude(const string & service,const TSvrRef & server)247     virtual void    Exclude      (const string&    service,
248                                   const TSvrRef&   server)
249     {
250         _TRACE("For " << service << ": excluding server '" << server->GetName()
251                << "' on "
252                << CEndpointKey(server->GetHost(), server->GetPort()));
253         CFastMutexGuard mg(m_Mtx);
254         m_ExcludeMap[service].insert(server);
255     }
256 
257     /// Clean the list of excluded servers for the given service
CleanExcluded(const string & service)258     virtual void    CleanExcluded(const string&    service)
259     {
260         CFastMutexGuard mg(m_Mtx);
261         _TRACE("For " << service << ": cleaning excluded list");
262         m_ExcludeMap.erase(service);
263     }
264 
HasExclusions(const string & service) const265     virtual bool    HasExclusions(const string& service) const
266     {
267         CFastMutexGuard mg(m_Mtx);
268         auto it = m_ExcludeMap.find(service);
269         return it != m_ExcludeMap.end()  &&  !it->second.empty();
270     }
271 
272     /// Get list of all servers for the given service disregarding any exclusions
GetServersList(const string &,list<string> * serv_list) const273     virtual void GetServersList(const string& /* service */,
274                                 list<string>* serv_list) const
275     {
276         serv_list->clear();
277     }
278 
279     /// Get an annotated list of all servers for the given service.
280     /// The default implementation just pads out the results of
281     /// calling GetServersList, which predates this method and as such
282     /// is likelier to be defined by derived classes.
283     virtual void GetServerOptions(const string& service, TOptions* options);
284 
285     /// Set up mapping preferences for a service
286     /// preference - value between 0 and 100
287     ///      (0 means *no particular preferances*, 100 means *do not choose,
288     ///      just use a given server*)
289     /// preferred_server - preferred server
290     virtual void    SetPreference(const string&    service,
291                                   const TSvrRef&   preferred_server,
292                                   double           preference = 100) = 0;
293 
294     /// Given a connection that succeeded even though this service
295     /// mapper was unable to identify a good server beforehand, try to
296     /// determine which server it actually reached on the basis of its
297     /// low-level handle (if available); on success, pass the result
298     /// to its x_RecordServer method to inform subsequent logging.
299     /// @return true if successful, false otherwise.
RecordServer(I_ConnectionExtra &) const300     virtual bool RecordServer(I_ConnectionExtra&) const { return false; }
301 
302 protected:
x_RecordServer(I_ConnectionExtra & extra,CDBServer & server)303     static void x_RecordServer(I_ConnectionExtra& extra, CDBServer& server)
304         { extra.x_RecordServer(server); }
305 
306     typedef set<TSvrRef, SDereferenceLess>  TSrvSet;
307     typedef map<string, TSrvSet>            TExcludeMap;
308     mutable CFastMutex  m_Mtx;
309     TExcludeMap         m_ExcludeMap;
310 };
311 
312 
313 ///////////////////////////////////////////////////////////////////////////////
314 /// DBServiceMapperTraits
315 /// IDBServiceMapper traits
316 ///
317 
318 template <class T>
319 class CDBServiceMapperTraits
320 {
321 public:
GetName(void)322     static string GetName(void)
323     {
324         _ASSERT(false);
325         return "none";
326     }
327 };
328 
329 inline
GetName(void) const330 string IDBServiceMapper::GetName(void) const
331 {
332     return CDBServiceMapperTraits<IDBServiceMapper>::GetName();
333 }
334 
335 ///////////////////////////////////////////////////////////////////////////////
336 
337 inline
operator ==(const CDBServer & l,const CDBServer & r)338 bool operator== (const CDBServer& l, const CDBServer& r)
339 {
340     return (l.GetName() == r.GetName() &&
341             l.GetHost() == r.GetHost() &&
342             l.GetPort() == r.GetPort());
343 }
344 
345 
346 inline
operator <(const CDBServer & l,const CDBServer & r)347 bool operator< (const CDBServer& l, const CDBServer& r)
348 {
349     int res = l.GetName().compare(r.GetName());
350     if (res != 0)
351         return res < 0;
352     if (l.GetHost() != r.GetHost())
353         return l.GetHost() < r.GetHost();
354     return l.GetPort() < r.GetPort();
355 }
356 
357 ///////////////////////////////////////////////////////////////////////////////
358 
359 inline
CDBServer(void)360 CDBServer::CDBServer(void) :
361     m_Host(0),
362     m_Port(0),
363     m_ExpireTime(0)
364 {
365 }
366 
367 inline
CDBServer(const string & name,Uint4 host,Uint2 port,unsigned int expire_time)368 CDBServer::CDBServer(const string& name,
369                      Uint4         host,
370                      Uint2         port,
371                      unsigned int  expire_time) :
372 m_Name(name),
373 m_Host(host),
374 m_Port(port),
375 m_ExpireTime(expire_time)
376 {
377 }
378 
379 
380 END_NCBI_SCOPE
381 
382 #endif  // CORELIB___DB_SERVICE_MAPPER__HPP
383