1 /*  $Id: dbapi_svc_mapper.cpp 586267 2019-05-13 18:15:06Z ucko $
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:  Sergey Sikorskiy
27 *
28 */
29 
30 #include <ncbi_pch.hpp>
31 
32 #include <dbapi/driver/dbapi_svc_mapper.hpp>
33 #include <dbapi/driver/exception.hpp>
34 #include <corelib/ncbiapp.hpp>
35 // #include <connect/ncbi_socket.h>
36 #include <algorithm>
37 
38 
39 BEGIN_NCBI_SCOPE
40 
41 
42 //////////////////////////////////////////////////////////////////////////////
43 static
44 CRef<CDBServerOption>
make_server(const CTempString & specification,double & preference)45 make_server(const CTempString& specification, double& preference)
46 {
47     CTempString server;
48     // string host;
49     Uint4 host = 0;
50     Uint2 port = 0;
51     string::size_type pos = 0;
52 
53     pos = specification.find_first_of("@(", pos);
54     if (pos != string::npos) {
55         server = specification.substr(0, pos);
56 
57         if (specification[pos] == '@') {
58             // string::size_type old_pos = pos + 1;
59             pos = specification.find_first_of(":(", pos + 1);
60             if (pos != string::npos) {
61                 // string host_str = specification.substr(old_pos, pos - old_pos);
62                 // Ignore host in order to avoid dependebcy on libconnect.
63                 // SOCK_StringToHostPort(specification.c_str() + old_pos, &host, &port);
64                 if (specification[pos] == ':') {
65                     port = NStr::StringToUInt(specification.substr(pos + 1),
66                                               NStr::fAllowLeadingSpaces |
67                                               NStr::fAllowTrailingSymbols |
68                                               NStr::fConvErr_NoThrow);
69                     pos = specification.find("(", pos + 1);
70                     if (pos != string::npos) {
71                         // preference = NStr::StringToDouble(
72                         preference = NStr::StringToUInt(
73                             specification.substr(pos + 1),
74                             NStr::fAllowLeadingSpaces |
75                             NStr::fAllowTrailingSymbols |
76                             NStr::fConvErr_NoThrow);
77                     }
78                 } else {
79                     // preference = NStr::StringToDouble(
80                     preference = NStr::StringToUInt(
81                         specification.substr(pos + 1),
82                         NStr::fAllowLeadingSpaces |
83                         NStr::fAllowTrailingSymbols |
84                         NStr::fConvErr_NoThrow);
85                 }
86             } else {
87                 // host = specification.substr(old_pos);
88                 // Ignore host in order to avoid dependebcy on libconnect.
89                 // SOCK_StringToHostPort(specification.c_str() + old_pos, &host, &port);
90             }
91         } else {
92             // preference = NStr::StringToDouble(
93             preference = NStr::StringToUInt(
94                 specification.substr(pos + 1),
95                 NStr::fAllowLeadingSpaces |
96                 NStr::fAllowTrailingSymbols |
97                 NStr::fConvErr_NoThrow);
98         }
99     } else {
100         server = specification;
101     }
102 
103     if (server.empty() && host == 0) {
104         DATABASE_DRIVER_ERROR("Either server name or host name expected.",
105                               110100 );
106     }
107 
108     return CRef<CDBServerOption>
109         (new CDBServerOption(server, host, port, preference));
110 }
111 
112 
113 
114 //////////////////////////////////////////////////////////////////////////////
CDBDefaultServiceMapper(void)115 CDBDefaultServiceMapper::CDBDefaultServiceMapper(void)
116 {
117 }
118 
~CDBDefaultServiceMapper(void)119 CDBDefaultServiceMapper::~CDBDefaultServiceMapper(void)
120 {
121 }
122 
GetName(void) const123 string CDBDefaultServiceMapper::GetName(void) const
124 {
125     return CDBServiceMapperTraits<CDBDefaultServiceMapper>::GetName();
126 }
127 
128 void
Configure(const IRegistry *)129 CDBDefaultServiceMapper::Configure(const IRegistry*)
130 {
131     // Do nothing.
132 }
133 
134 TSvrRef
GetServer(const string & service)135 CDBDefaultServiceMapper::GetServer(const string& service)
136 {
137     if (m_ExcludeMap.find(service) != m_ExcludeMap.end()) {
138         return TSvrRef();
139     }
140 
141     return TSvrRef(new CDBServer(service));
142 }
143 
144 void
SetPreference(const string &,const TSvrRef &,double)145 CDBDefaultServiceMapper::SetPreference(const string&,
146                                        const TSvrRef&,
147                                        double)
148 {
149     // Do nothing.
150 }
151 
152 
153 //////////////////////////////////////////////////////////////////////////////
CDBServiceMapperCoR(void)154 CDBServiceMapperCoR::CDBServiceMapperCoR(void)
155 {
156 }
157 
~CDBServiceMapperCoR(void)158 CDBServiceMapperCoR::~CDBServiceMapperCoR(void)
159 {
160 }
161 
GetName(void) const162 string CDBServiceMapperCoR::GetName(void) const
163 {
164     if (Top().NotEmpty()) {
165         return Top()->GetName();
166     } else {
167         return CDBServiceMapperTraits<CDBServiceMapperCoR>::GetName();
168     }
169 }
170 
171 void
Configure(const IRegistry * registry)172 CDBServiceMapperCoR::Configure(const IRegistry* registry)
173 {
174     CFastMutexGuard mg(m_Mtx);
175 
176     ConfigureFromRegistry(registry);
177 }
178 
179 TSvrRef
GetServer(const string & service)180 CDBServiceMapperCoR::GetServer(const string& service)
181 {
182     CFastMutexGuard mg(m_Mtx);
183 
184     TSvrRef server;
185     TDelegates::reverse_iterator dg_it = m_Delegates.rbegin();
186     TDelegates::reverse_iterator dg_end = m_Delegates.rend();
187 
188     for (; server.Empty() && dg_it != dg_end; ++dg_it) {
189         server = (*dg_it)->GetServer(service);
190     }
191 
192     return server;
193 }
194 
195 void
Exclude(const string & service,const TSvrRef & server)196 CDBServiceMapperCoR::Exclude(const string&  service,
197                              const TSvrRef& server)
198 {
199     CFastMutexGuard mg(m_Mtx);
200 
201     NON_CONST_ITERATE(TDelegates, dg_it, m_Delegates) {
202         (*dg_it)->Exclude(service, server);
203     }
204 }
205 
206 void
CleanExcluded(const string & service)207 CDBServiceMapperCoR::CleanExcluded(const string&  service)
208 {
209     CFastMutexGuard mg(m_Mtx);
210 
211     NON_CONST_ITERATE(TDelegates, dg_it, m_Delegates) {
212         (*dg_it)->CleanExcluded(service);
213     }
214 }
215 
216 void
SetPreference(const string & service,const TSvrRef & preferred_server,double preference)217 CDBServiceMapperCoR::SetPreference(const string&  service,
218                                    const TSvrRef& preferred_server,
219                                    double preference)
220 {
221     CFastMutexGuard mg(m_Mtx);
222 
223     NON_CONST_ITERATE(TDelegates, dg_it, m_Delegates) {
224         (*dg_it)->SetPreference(service, preferred_server, preference);
225     }
226 }
227 
228 void
GetServersList(const string & service,list<string> * serv_list) const229 CDBServiceMapperCoR::GetServersList(const string& service, list<string>* serv_list) const
230 {
231     CFastMutexGuard mg(m_Mtx);
232 
233     TDelegates::const_reverse_iterator dg_it = m_Delegates.rbegin();
234     TDelegates::const_reverse_iterator dg_end = m_Delegates.rend();
235     for (; serv_list->empty() && dg_it != dg_end; ++dg_it) {
236         (*dg_it)->GetServersList(service, serv_list);
237     }
238 }
239 
240 void
GetServerOptions(const string & service,TOptions * options)241 CDBServiceMapperCoR::GetServerOptions(const string& service, TOptions* options)
242 {
243     CFastMutexGuard mg(m_Mtx);
244 
245     TDelegates::reverse_iterator dg_it = m_Delegates.rbegin();
246     TDelegates::reverse_iterator dg_end = m_Delegates.rend();
247     for (; options->empty() && dg_it != dg_end; ++dg_it) {
248         (*dg_it)->GetServerOptions(service, options);
249     }
250 }
251 
252 
253 bool
RecordServer(I_ConnectionExtra & extra) const254 CDBServiceMapperCoR::RecordServer(I_ConnectionExtra& extra) const
255 {
256     CFastMutexGuard mg(m_Mtx);
257     REVERSE_ITERATE (TDelegates, dg_it, m_Delegates) {
258         if ((*dg_it)->RecordServer(extra)) {
259             return true;
260         }
261     }
262     return false;
263 }
264 
265 
266 void
ConfigureFromRegistry(const IRegistry * registry)267 CDBServiceMapperCoR::ConfigureFromRegistry(const IRegistry* registry)
268 {
269     NON_CONST_ITERATE (TDelegates, dg_it, m_Delegates) {
270         (*dg_it)->Configure(registry);
271     }
272 }
273 
274 void
Push(const CRef<IDBServiceMapper> & mapper)275 CDBServiceMapperCoR::Push(const CRef<IDBServiceMapper>& mapper)
276 {
277     if (mapper.NotNull()) {
278         CFastMutexGuard mg(m_Mtx);
279 
280         m_Delegates.push_back(mapper);
281     }
282 }
283 
284 void
Pop(void)285 CDBServiceMapperCoR::Pop(void)
286 {
287     CFastMutexGuard mg(m_Mtx);
288 
289     m_Delegates.pop_back();
290 }
291 
292 CRef<IDBServiceMapper>
Top(void) const293 CDBServiceMapperCoR::Top(void) const
294 {
295     CFastMutexGuard mg(m_Mtx);
296 
297     return m_Delegates.back();
298 }
299 
300 bool
Empty(void) const301 CDBServiceMapperCoR::Empty(void) const
302 {
303     CFastMutexGuard mg(m_Mtx);
304 
305     return m_Delegates.empty();
306 }
307 
308 //////////////////////////////////////////////////////////////////////////////
CDBUDRandomMapper(const IRegistry * registry)309 CDBUDRandomMapper::CDBUDRandomMapper(const IRegistry* registry)
310 {
311     random_device rdev;
312     m_RandomEngine.seed(rdev());
313     ConfigureFromRegistry(registry);
314 }
315 
~CDBUDRandomMapper(void)316 CDBUDRandomMapper::~CDBUDRandomMapper(void)
317 {
318 }
319 
GetName(void) const320 string CDBUDRandomMapper::GetName(void) const
321 {
322     return CDBServiceMapperTraits<CDBUDRandomMapper>::GetName();
323 }
324 
325 void
Configure(const IRegistry * registry)326 CDBUDRandomMapper::Configure(const IRegistry* registry)
327 {
328     CFastMutexGuard mg(m_Mtx);
329 
330     ConfigureFromRegistry(registry);
331 }
332 
333 void
ConfigureFromRegistry(const IRegistry * registry)334 CDBUDRandomMapper::ConfigureFromRegistry(const IRegistry* registry)
335 {
336     const string section_name
337         (CDBServiceMapperTraits<CDBUDRandomMapper>::GetName());
338     list<string> entries;
339 
340     // Get current registry ...
341     if (!registry && CNcbiApplication::Instance()) {
342         registry = &CNcbiApplication::Instance()->GetConfig();
343     }
344 
345     if (registry) {
346         // Erase previous data ...
347         m_LBNameMap.clear();
348         m_ServerMap.clear();
349         m_FavoritesMap.clear();
350         m_PreferenceMap.clear();
351 
352         registry->EnumerateEntries(section_name, &entries);
353         ITERATE(list<string>, cit, entries) {
354             vector<string> server_name;
355             string service_name = *cit;
356 
357             NStr::Split(registry->GetString(section_name,
358                                             service_name,
359                                             service_name),
360                         " ,;",
361                         server_name,
362                         NStr::fSplit_MergeDelimiters);
363 
364             // Replace with new data ...
365             if (!server_name.empty()) {
366                 TOptions& server_list = m_ServerMap[service_name];
367 
368                 ITERATE(vector<string>, sn_it, server_name) {
369                     double tmp_preference = 0;
370 
371                     // Parse server preferences.
372                     auto cur_server = make_server(*sn_it, tmp_preference);
373                     if (tmp_preference < 0) {
374                         cur_server->m_Ranking = 0;
375                     } else if (tmp_preference >= 100) {
376                         cur_server->m_Ranking = 100;
377                         m_FavoritesMap[service_name].push_back(cur_server);
378                     }
379 
380                     server_list.push_back(cur_server);
381 
382                 }
383                 x_RecalculatePreferences(service_name);
384             }
385         }
386     }
387 }
388 
389 TSvrRef
GetServer(const string & service)390 CDBUDRandomMapper::GetServer(const string& service)
391 {
392     CFastMutexGuard mg(m_Mtx);
393 
394     if (m_LBNameMap.find(service) != m_LBNameMap.end() &&
395         m_LBNameMap[service] == false) {
396         // We've tried this service already. It is not served by load
397         // balancer. There is no reason to try it again.
398         return TSvrRef();
399     }
400 
401     const auto& it = m_PreferenceMap.find(service);
402     if (it != m_PreferenceMap.end()) {
403         m_LBNameMap[service] = true;
404         return it->second.servers[(*it->second.distribution)(m_RandomEngine)];
405     }
406 
407     m_LBNameMap[service] = false;
408     return TSvrRef();
409 }
410 
411 void
Add(const string & service,const TSvrRef & server,double preference)412 CDBUDRandomMapper::Add(const string&    service,
413                        const TSvrRef&   server,
414                        double           preference)
415 {
416     _ASSERT(false);
417 
418     if (service.empty() || server.Empty()) {
419         return;
420     }
421 
422     TOptions& server_list = m_ServerMap[service];
423     CRef<CDBServerOption> option
424         (new CDBServerOption(server->GetName(), server->GetHost(),
425                              server->GetPort(), preference));
426 
427     if (preference < 0) {
428         option->m_Ranking = 0;
429     } else if (preference >= 100) {
430         option->m_Ranking = 100;
431         m_FavoritesMap[service].push_back(option);
432     }
433 
434     server_list.push_back(option);
435 
436     x_RecalculatePreferences(service);
437 }
438 
439 void
Exclude(const string & service,const TSvrRef & server)440 CDBUDRandomMapper::Exclude(const string& service, const TSvrRef& server)
441 {
442     CFastMutexGuard mg(m_Mtx);
443     auto svc = m_ServerMap.find(service);
444     if (svc != m_ServerMap.end()) {
445         for (auto svr : svc->second) {
446             if (svr == server  ||  *svr == *server) {
447                 svr->m_State |= CDBServerOption::fState_Excluded;
448             }
449         }
450         x_RecalculatePreferences(service);
451     }
452 }
453 
454 void
CleanExcluded(const string & service)455 CDBUDRandomMapper::CleanExcluded(const string& service)
456 {
457     CFastMutexGuard mg(m_Mtx);
458     auto svc = m_ServerMap.find(service);
459     if (svc != m_ServerMap.end()) {
460         for (auto svr : svc->second) {
461             svr->m_State &= ~CDBServerOption::fState_Excluded;
462         }
463         x_RecalculatePreferences(service);
464     }
465 }
466 
467 bool
HasExclusions(const string & service) const468 CDBUDRandomMapper::HasExclusions(const string& service) const
469 {
470     CFastMutexGuard mg(m_Mtx);
471     auto svc   = m_ServerMap.find(service);
472     auto prefs = m_PreferenceMap.find(service);
473     if (svc == m_ServerMap.end()) {
474         return false;
475     } else if (prefs == m_PreferenceMap.end()) {
476         return true;
477     } else if (svc->second.size() == prefs->second.servers.size()) {
478         return false;
479     } else if (prefs->second.servers.size() != 1) {
480         return true;
481     } else {
482         return prefs->second.servers[0]->GetRanking() < 100.0;
483     }
484 }
485 
486 void
SetPreference(const string & service,const TSvrRef & preferred_server,double preference)487 CDBUDRandomMapper::SetPreference(const string&  service,
488                                  const TSvrRef& preferred_server,
489                                  double         preference)
490 {
491     CFastMutexGuard mg(m_Mtx);
492 
493     auto svc = m_ServerMap.find(service);
494     if (svc != m_ServerMap.end()) {
495         for (auto svr : svc->second) {
496             if (svr == preferred_server  ||  *svr == *preferred_server) {
497                 double old_preference = svr->GetRanking();
498                 svr->m_Ranking = max(0.0, min(100.0, preference));
499                 if (preference >= 100.0  &&  old_preference < 100.0) {
500                     m_FavoritesMap[service].push_back(svr);
501                 } else if (preference < 100.0  &&  old_preference >= 100.0) {
502                     auto& favorites = m_FavoritesMap[service];
503                     favorites.erase(find(favorites.begin(), favorites.end(),
504                                          svr));
505                     if (favorites.empty()) {
506                         m_FavoritesMap.erase(service);
507                     }
508                 }
509             }
510         }
511         x_RecalculatePreferences(service);
512     }
513 }
514 
515 void
GetServerOptions(const string & service,TOptions * options)516 CDBUDRandomMapper::GetServerOptions(const string& service, TOptions* options)
517 {
518     CFastMutexGuard mg(m_Mtx);
519     auto it = m_ServerMap.find(service);
520     if (it == m_ServerMap.end()) {
521         options->clear();
522     } else {
523         *options = it->second;
524     }
525 }
526 
527 IDBServiceMapper*
Factory(const IRegistry * registry)528 CDBUDRandomMapper::Factory(const IRegistry* registry)
529 {
530     return new CDBUDRandomMapper(registry);
531 }
532 
533 void
x_RecalculatePreferences(const string & service)534 CDBUDRandomMapper::x_RecalculatePreferences(const string& service)
535 {
536     SPreferences& service_preferences = m_PreferenceMap[service];
537     service_preferences.servers.clear();
538     {{
539         TServiceMap::const_iterator favs = m_FavoritesMap.find(service);
540         if (favs != m_FavoritesMap.end()) {
541             REVERSE_ITERATE(TOptions, it, favs->second) {
542                 if ( !(*it)->IsExcluded() ) {
543                     service_preferences.servers.push_back(*it);
544                     service_preferences.distribution.reset
545                         (new discrete_distribution<>({100.0}));
546                     return;
547                 }
548             }
549         }
550     }}
551     vector<double> weights;
552     bool all_zero = true;
553     for (const auto & it : m_ServerMap[service]) {
554         if ( !it->IsExcluded() ) {
555             double weight = it->GetRanking();
556             _ASSERT(weight < 100.0);
557             if (weight > 0.0) {
558                 all_zero = false;
559             }
560         }
561     }
562     if (all_zero) {
563         for (auto & w : weights) {
564             w = 1.0;
565         }
566     }
567     service_preferences.distribution.reset
568         (new discrete_distribution<>(weights.begin(), weights.end()));
569 }
570 
571 
572 //////////////////////////////////////////////////////////////////////////////
CDBUDPriorityMapper(const IRegistry * registry)573 CDBUDPriorityMapper::CDBUDPriorityMapper(const IRegistry* registry)
574 {
575     ConfigureFromRegistry(registry);
576 }
577 
~CDBUDPriorityMapper(void)578 CDBUDPriorityMapper::~CDBUDPriorityMapper(void)
579 {
580 }
581 
GetName(void) const582 string CDBUDPriorityMapper::GetName(void) const
583 {
584     return CDBServiceMapperTraits<CDBUDPriorityMapper>::GetName();
585 }
586 
587 void
Configure(const IRegistry * registry)588 CDBUDPriorityMapper::Configure(const IRegistry* registry)
589 {
590     CFastMutexGuard mg(m_Mtx);
591 
592     ConfigureFromRegistry(registry);
593 }
594 
595 void
ConfigureFromRegistry(const IRegistry * registry)596 CDBUDPriorityMapper::ConfigureFromRegistry(const IRegistry* registry)
597 {
598     const string section_name
599         (CDBServiceMapperTraits<CDBUDPriorityMapper>::GetName());
600     list<string> entries;
601 
602     // Get current registry ...
603     if (!registry && CNcbiApplication::Instance()) {
604         registry = &CNcbiApplication::Instance()->GetConfig();
605     }
606 
607     if (registry) {
608         // Erase previous data ...
609         m_ServerMap.clear();
610         m_ServiceUsageMap.clear();
611 
612         registry->EnumerateEntries(section_name, &entries);
613 
614         ITERATE(list<string>, cit, entries) {
615             vector<string> server_name;
616             string service_name = *cit;
617 
618             NStr::Split(registry->GetString(section_name,
619                                             service_name,
620                                             service_name),
621                         " ,;",
622                         server_name,
623                         NStr::fSplit_MergeDelimiters);
624 
625             // Replace with new data ...
626             if (!server_name.empty()) {
627 //                 TSvrMap& server_list = m_ServerMap[service_name];
628 //                 TServerUsageMap& usage_map = m_ServiceUsageMap[service_name];
629 
630                 ITERATE(vector<string>, sn_it, server_name) {
631                     double tmp_preference = 0;
632 
633                     // Parse server preferences.
634                     TSvrRef cur_server = make_server(*sn_it, tmp_preference);
635 
636                     // Replaced with Add()
637 //                     if (tmp_preference < 0) {
638 //                         tmp_preference = 0;
639 //                     } else if (tmp_preference > 100) {
640 //                         tmp_preference = 100;
641 //                     }
642 //
643 //                     server_list.insert(
644 //                         TSvrMap::value_type(cur_server, tmp_preference));
645 //                     usage_map.insert(TServerUsageMap::value_type(
646 //                         100 - tmp_preference,
647 //                         cur_server));
648 
649                     Add(service_name, cur_server, tmp_preference);
650                 }
651             }
652         }
653     }
654 }
655 
656 TSvrRef
GetServer(const string & service)657 CDBUDPriorityMapper::GetServer(const string& service)
658 {
659     CFastMutexGuard mg(m_Mtx);
660 
661     if (m_LBNameMap.find(service) != m_LBNameMap.end() &&
662         m_LBNameMap[service] == false) {
663         // We've tried this service already. It is not served by load
664         // balancer. There is no reason to try it again.
665         return TSvrRef();
666     }
667 
668     TServerUsageMap& usage_map = m_ServiceUsageMap[service];
669     TSvrMap& server_map = m_ServerMap[service];
670 
671     if (!server_map.empty() && !usage_map.empty()) {
672         TServerUsageMap::iterator su_it = usage_map.begin();
673         double new_preference = su_it->first;
674         TSvrRef cur_server = su_it->second;
675 
676         // Recalculate preferences ...
677         TSvrMap::const_iterator pr_it = server_map.find(cur_server);
678 
679         if (pr_it != server_map.end()) {
680             new_preference +=  100 - pr_it->second;
681         } else {
682             new_preference +=  100;
683         }
684 
685         // Reset usage map ...
686         usage_map.erase(su_it);
687         usage_map.insert(TServerUsageMap::value_type(new_preference,
688                                                      cur_server));
689 
690         m_LBNameMap[service] = true;
691         return cur_server;
692     }
693 
694     m_LBNameMap[service] = false;
695     return TSvrRef();
696 }
697 
698 void
Exclude(const string & service,const TSvrRef & server)699 CDBUDPriorityMapper::Exclude(const string& service,
700                              const TSvrRef& server)
701 {
702     IDBServiceMapper::Exclude(service, server);
703 
704     CFastMutexGuard mg(m_Mtx);
705 
706     TServerUsageMap& usage_map = m_ServiceUsageMap[service];
707 
708     // Remove elements ...
709     for (TServerUsageMap::iterator it = usage_map.begin();
710          it != usage_map.end();) {
711 
712         if (it->second == server) {
713             usage_map.erase(it++);
714         }
715         else {
716             ++it;
717         }
718     }
719 }
720 
721 void
CleanExcluded(const string & service)722 CDBUDPriorityMapper::CleanExcluded(const string& service)
723 {
724     IDBServiceMapper::CleanExcluded(service);
725 
726     CFastMutexGuard mg(m_Mtx);
727     m_ServiceUsageMap[service] = m_OrigServiceUsageMap[service];
728 }
729 
730 void
SetPreference(const string & service,const TSvrRef & preferred_server,double preference)731 CDBUDPriorityMapper::SetPreference(const string&  service,
732                                    const TSvrRef& preferred_server,
733                                    double         preference)
734 {
735     CFastMutexGuard mg(m_Mtx);
736 
737     TSvrMap& server_map = m_ServerMap[service];
738     TSvrMap::iterator pr_it = server_map.find(preferred_server);
739 
740     if (preference < 0) {
741         preference = 0;
742     } else if (preference > 100) {
743         preference = 100;
744     }
745 
746     if (pr_it != server_map.end()) {
747         pr_it->second = preference;
748     }
749 }
750 
751 
752 void
Add(const string & service,const TSvrRef & server,double preference)753 CDBUDPriorityMapper::Add(const string&    service,
754                          const TSvrRef&   server,
755                          double           preference)
756 {
757     TSvrMap& server_list = m_ServerMap[service];
758     TServerUsageMap& usage_map = m_ServiceUsageMap[service];
759     TServerUsageMap& usage_map2 = m_OrigServiceUsageMap[service];
760 
761     if (preference < 0) {
762         preference = 0;
763     } else if (preference > 100) {
764         preference = 100;
765     }
766 
767     server_list.insert(
768         TSvrMap::value_type(server, preference)
769         );
770     TServerUsageMap::value_type usage(100 - preference, server);
771     usage_map.insert(usage);
772     usage_map2.insert(usage);
773 }
774 
775 
776 IDBServiceMapper*
Factory(const IRegistry * registry)777 CDBUDPriorityMapper::Factory(const IRegistry* registry)
778 {
779     return new CDBUDPriorityMapper(registry);
780 }
781 
782 
783 //////////////////////////////////////////////////////////////////////////////
CDBUniversalMapper(const IRegistry * registry,const TMapperConf & ext_mapper)784 CDBUniversalMapper::CDBUniversalMapper(const IRegistry* registry,
785                                        const TMapperConf& ext_mapper)
786 {
787     if (!ext_mapper.first.empty() && ext_mapper.second != NULL) {
788         m_ExtMapperConf = ext_mapper;
789     }
790 
791     this->ConfigureFromRegistry(registry);
792     CDBServiceMapperCoR::ConfigureFromRegistry(registry);
793 }
794 
~CDBUniversalMapper(void)795 CDBUniversalMapper::~CDBUniversalMapper(void)
796 {
797 }
798 
GetName(void) const799 string CDBUniversalMapper::GetName(void) const
800 {
801     if (Top().NotEmpty()) {
802         return Top()->GetName();
803     } else {
804         return CDBServiceMapperTraits<CDBUniversalMapper>::GetName();
805     }
806 }
807 
808 void
Configure(const IRegistry * registry)809 CDBUniversalMapper::Configure(const IRegistry* registry)
810 {
811     CFastMutexGuard mg(m_Mtx);
812 
813     this->ConfigureFromRegistry(registry);
814     CDBServiceMapperCoR::ConfigureFromRegistry(registry);
815 }
816 
817 void
ConfigureFromRegistry(const IRegistry * registry)818 CDBUniversalMapper::ConfigureFromRegistry(const IRegistry* registry)
819 {
820     vector<string> service_name;
821     const string section_name
822         (CDBServiceMapperTraits<CDBUniversalMapper>::GetName());
823     const string def_mapper_name =
824         (m_ExtMapperConf.second ? m_ExtMapperConf.first :
825          CDBServiceMapperTraits<CDBUDRandomMapper>::GetName());
826 
827     // Get current registry ...
828     if (!registry && CNcbiApplication::Instance()) {
829         registry = &CNcbiApplication::Instance()->GetConfig();
830     }
831 
832     if (registry) {
833 
834         NStr::Split(registry->GetString
835                     (section_name, "MAPPERS",
836                         def_mapper_name),
837                     " ,;",
838                     service_name,
839                     NStr::fSplit_MergeDelimiters);
840 
841     } else {
842         service_name.push_back(def_mapper_name);
843     }
844 
845     ITERATE(vector<string>, it, service_name) {
846         IDBServiceMapper* mapper = NULL;
847         string mapper_name = *it;
848 
849         if (NStr::CompareNocase
850             (mapper_name,
851             CDBServiceMapperTraits<CDBDefaultServiceMapper>::GetName()) ==
852             0) {
853             mapper = new CDBDefaultServiceMapper();
854         } else if (NStr::CompareNocase
855                 (mapper_name,
856                     CDBServiceMapperTraits<CDBUDRandomMapper>::GetName())
857                 == 0) {
858             mapper = new CDBUDRandomMapper(registry);
859         } else if (NStr::CompareNocase
860                 (mapper_name,
861                     CDBServiceMapperTraits<CDBUDPriorityMapper>::GetName())
862                 == 0) {
863             mapper = new CDBUDPriorityMapper(registry);
864         } else if (m_ExtMapperConf.second && NStr::CompareNocase
865             (mapper_name, m_ExtMapperConf.first) == 0) {
866             mapper = (*m_ExtMapperConf.second)(registry);
867         }
868 
869         Push(CRef<IDBServiceMapper>(mapper));
870     }
871 }
872 
873 
874 //////////////////////////////////////////////////////////////////////////////
875 string
GetName(void)876 CDBServiceMapperTraits<CDBDefaultServiceMapper>::GetName(void)
877 {
878     return "DEFAULT_NAME_MAPPER";
879 }
880 
881 string
GetName(void)882 CDBServiceMapperTraits<CDBServiceMapperCoR>::GetName(void)
883 {
884     return "COR_NAME_MAPPER";
885 }
886 
887 string
GetName(void)888 CDBServiceMapperTraits<CDBUDRandomMapper>::GetName(void)
889 {
890     return "USER_DEFINED_RANDOM_DBNAME_MAPPER";
891 }
892 
893 string
GetName(void)894 CDBServiceMapperTraits<CDBUDPriorityMapper>::GetName(void)
895 {
896     return "USER_DEFINED_PRIORITY_DBNAME_MAPPER";
897 }
898 
899 string
GetName(void)900 CDBServiceMapperTraits<CDBUniversalMapper>::GetName(void)
901 {
902     return "UNIVERSAL_NAME_MAPPER";
903 }
904 
905 END_NCBI_SCOPE
906 
907