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