1 /* $Id: cdd_client.cpp 636069 2021-08-16 12:14:29Z 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: Aleksey Grichenko
27 *
28 * File Description:
29 * RPC client for CDD annotations
30 *
31 */
32
33 #include <ncbi_pch.hpp>
34 #include <serial/objostrjson.hpp>
35 #include <objects/seqloc/Seq_id.hpp>
36 #include <objects/seq/Seq_annot.hpp>
37 #include <objects/id2/ID2_Blob_Id.hpp>
38 #include <objtools/data_loaders/cdd/cdd_access/CDD_Request.hpp>
39 #include <objtools/data_loaders/cdd/cdd_access/cdd_client.hpp>
40 #include <objtools/data_loaders/cdd/cdd_access/cdd_access__.hpp>
41
42 BEGIN_NCBI_SCOPE
43
44 NCBI_PARAM_ENUM_DECL(objects::CCDDClient::EDataFormat, CDD, data_format);
NCBI_PARAM_ENUM_ARRAY(objects::CCDDClient::EDataFormat,CDD,data_format)45 NCBI_PARAM_ENUM_ARRAY(objects::CCDDClient::EDataFormat, CDD, data_format)
46 {
47 // Deliberately not covering eDefaultFormat!
48 { "JSON", objects::CCDDClient::eJSON },
49 { "semi-binary", objects::CCDDClient::eSemiBinary },
50 { "binary", objects::CCDDClient::eBinary }
51 };
52
53 NCBI_PARAM_ENUM_DEF(objects::CCDDClient::EDataFormat, CDD, data_format,
54 objects::CCDDClient::eBinary);
55
56 typedef NCBI_PARAM_TYPE(CDD, data_format) TDataFormatParam;
57
58 BEGIN_objects_SCOPE // namespace ncbi::objects::
59
60 static
s_GetSerialFormat(CCDDClient::EDataFormat & data_format)61 ESerialDataFormat s_GetSerialFormat(CCDDClient::EDataFormat& data_format)
62 {
63 if (data_format == CCDDClient::eDefaultFormat) {
64 data_format = TDataFormatParam::GetDefault();
65 }
66 return data_format == CCDDClient::eJSON ? eSerial_Json : eSerial_AsnBinary;
67 }
68
CCDDClient(const string & service_name,EDataFormat data_format)69 CCDDClient::CCDDClient(const string& service_name, EDataFormat data_format)
70 : Tparent(service_name.empty() ? DEFAULT_CDD_SERVICE_NAME : service_name,
71 s_GetSerialFormat(data_format)),
72 m_DataFormat(data_format)
73 {
74 if (data_format == eBinary) {
75 SetArgs("binary=1");
76 }
77 }
78
79
~CCDDClient(void)80 CCDDClient::~CCDDClient(void)
81 {
82 }
83
84
Ask(const CCDD_Request_Packet & request,CCDD_Reply & reply)85 void CCDDClient::Ask(const CCDD_Request_Packet& request, CCDD_Reply& reply)
86 {
87 m_Replies.clear();
88 Tparent::Ask(request, reply);
89 }
90
91
WriteRequest(CObjectOStream & out,const CCDD_Request_Packet & request)92 void CCDDClient::WriteRequest(CObjectOStream& out,
93 const CCDD_Request_Packet& request)
94 {
95 static const TSerial_Format_Flags kJSONFlags
96 = fSerial_Json_NoIndentation | fSerial_Json_NoEol;
97 if (m_DataFormat == eSemiBinary) {
98 CNcbiOstrstream oss;
99 CObjectOStreamJson joos(oss, eNoOwnership);
100 joos.SetFormattingFlags(kJSONFlags);
101 joos << request;
102 string s = CNcbiOstrstreamToString(oss);
103 SetArgs("binary=1&requestPacket="
104 + NStr::URLEncode(s, NStr::eUrlEnc_URIQueryValue));
105 x_Connect();
106 } else {
107 if (m_DataFormat == eJSON) {
108 out.SetFormattingFlags(kJSONFlags);
109 }
110 Tparent::WriteRequest(out, request);
111 }
112 }
113
114
ReadReply(CObjectIStream & in,CCDD_Reply & reply)115 void CCDDClient::ReadReply(CObjectIStream& in, CCDD_Reply& reply)
116 {
117 m_Replies.clear();
118 CRef<CCDD_Reply> next_reply;
119 do {
120 next_reply.Reset(new CCDD_Reply);
121 in >> *next_reply;
122 m_Replies.push_back(next_reply);
123 } while (!next_reply->IsSetEnd_of_reply());
124
125 if (!m_Replies.empty()) {
126 reply.Assign(*m_Replies.back());
127 }
128 }
129
130
AskBlobId(int serial_number,const CSeq_id & seq_id)131 CRef<CCDD_Reply> CCDDClient::AskBlobId(int serial_number, const CSeq_id& seq_id)
132 {
133 CCDD_Request_Packet cdd_packet;
134 CRef<CCDD_Request> cdd_request(new CCDD_Request);
135 cdd_request->SetSerial_number(serial_number);
136 cdd_request->SetRequest().SetGet_blob_id().Assign(seq_id);
137 cdd_packet.Set().push_back(cdd_request);
138 CRef<CCDD_Reply> cdd_reply(new CCDD_Reply);
139 try {
140 Ask(cdd_packet, *cdd_reply);
141 }
142 catch (exception& e) {
143 ERR_POST(e.what());
144 return null;
145 }
146 return cdd_reply;
147 }
148
149
AskBlob(int serial_number,const CID2_Blob_Id & blob_id)150 CRef<CCDD_Reply> CCDDClient::AskBlob(int serial_number, const CID2_Blob_Id& blob_id)
151 {
152 CCDD_Request_Packet cdd_packet;
153 CRef<CCDD_Request> cdd_request(new CCDD_Request);
154 cdd_request->SetSerial_number(serial_number);
155 cdd_request->SetRequest().SetGet_blob().Assign(blob_id);
156 cdd_packet.Set().push_back(cdd_request);
157 CRef<CCDD_Reply> cdd_reply(new CCDD_Reply);
158 try {
159 Ask(cdd_packet, *cdd_reply);
160 }
161 catch (exception& e) {
162 ERR_POST(e.what());
163 return null;
164 }
165 return cdd_reply;
166 }
167
168
JustAsk(const CCDD_Request_Packet & request)169 void CCDDClient::JustAsk(const CCDD_Request_Packet& request)
170 {
171 static const STimeout kZeroTimeout = { 0, 0 };
172 Connect();
173 WriteRequest(*m_Out, request);
174 dynamic_cast<CConn_ServiceStream&>(*m_Stream).Fetch(&kZeroTimeout);
175 }
176
177
178 /////////////////////////////////////////////////////////////////////////////
179 // CCDDBlobCache
180 /////////////////////////////////////////////////////////////////////////////
181
182
183 const int kMaxCacheLifespanSeconds = 300;
184 const size_t kMaxCacheSize = 1000;
185
186 struct SCDDCacheInfo
187 {
188 typedef CCDDClientPool::SCDDBlob TBlob;
189
SCDDCacheInfoSCDDCacheInfo190 SCDDCacheInfo(const CSeq_id_Handle idh, const TBlob& b)
191 : id(idh), blob(b), deadline(kMaxCacheLifespanSeconds) {}
192
193 CSeq_id_Handle id;
194 TBlob blob;
195 CDeadline deadline;
196
197 private:
198 SCDDCacheInfo(const SCDDCacheInfo&);
199 SCDDCacheInfo& operator=(const SCDDCacheInfo&);
200 };
201
202
203 class CCDDBlobCache
204 {
205 public:
CCDDBlobCache(void)206 CCDDBlobCache(void) {}
~CCDDBlobCache(void)207 ~CCDDBlobCache(void) {}
208
209 typedef CCDDClientPool::TBlobId TBlobId;
210 typedef CCDDClientPool::SCDDBlob TBlob;
211
212 TBlob Get(const CSeq_id_Handle& seq_id);
213 TBlob Get(const TBlobId& blob_id);
214 void Add(TBlob blob);
215
216 private:
217 void x_UpdateDeadline(shared_ptr<SCDDCacheInfo>& info);
218 typedef map<CSeq_id_Handle, shared_ptr<SCDDCacheInfo> > TSeqIdMap;
219 typedef map <string, shared_ptr<SCDDCacheInfo>> TBlobIdMap;
220 typedef list<shared_ptr<SCDDCacheInfo>> TInfoQueue;
221
222 mutable CFastMutex m_Mutex;
223 TSeqIdMap m_SeqIdMap;
224 TBlobIdMap m_BlobIdMap;
225 TInfoQueue m_Infos;
226 };
227
228
Get(const CSeq_id_Handle & seq_id)229 CCDDBlobCache::TBlob CCDDBlobCache::Get(const CSeq_id_Handle& seq_id)
230 {
231 CFastMutexGuard guard(m_Mutex);
232 auto found = m_SeqIdMap.find(seq_id);
233 if (found == m_SeqIdMap.end()) return TBlob();
234 shared_ptr<SCDDCacheInfo> info = found->second;
235 x_UpdateDeadline(info);
236 return info->blob;
237 }
238
239
Get(const TBlobId & blob_id)240 CCDDBlobCache::TBlob CCDDBlobCache::Get(const TBlobId& blob_id)
241 {
242 CFastMutexGuard guard(m_Mutex);
243 string sid = CCDDClientPool::BlobIdToString(blob_id);
244 auto found = m_BlobIdMap.find(sid);
245 if (found == m_BlobIdMap.end()) return TBlob();
246 shared_ptr<SCDDCacheInfo> info = found->second;
247 x_UpdateDeadline(info);
248 return info->blob;
249 }
250
251
Add(TBlob blob)252 void CCDDBlobCache::Add(TBlob blob)
253 {
254 CSeq_id_Handle idh = CSeq_id_Handle::GetHandle(blob.info->GetSeq_id());
255 CFastMutexGuard guard(m_Mutex);
256 auto found = m_SeqIdMap.find(idh);
257 if (found != m_SeqIdMap.end()) return;
258 // Create new entry.
259 shared_ptr<SCDDCacheInfo> info = make_shared<SCDDCacheInfo>(idh, blob);
260 while (!m_Infos.empty() && (m_Infos.size() > kMaxCacheSize || m_Infos.front()->deadline.IsExpired())) {
261 auto rm = m_Infos.front();
262 m_Infos.pop_front();
263 m_SeqIdMap.erase(rm->id);
264 m_BlobIdMap.erase(CCDDClientPool::BlobIdToString(rm->blob.info->GetBlob_id()));
265 }
266 m_Infos.push_back(info);
267 m_SeqIdMap[idh] = info;
268 m_BlobIdMap[CCDDClientPool::BlobIdToString(info->blob.info->GetBlob_id())] = info;
269 }
270
271
x_UpdateDeadline(shared_ptr<SCDDCacheInfo> & info)272 void CCDDBlobCache::x_UpdateDeadline(shared_ptr<SCDDCacheInfo>& info)
273 {
274 m_Infos.remove(info);
275 info->deadline = CDeadline(kMaxCacheLifespanSeconds);
276 m_Infos.push_back(info);
277 }
278
279
280 /////////////////////////////////////////////////////////////////////////////
281 // CCDDClientGuard
282 /////////////////////////////////////////////////////////////////////////////
283
284
285 class CCDDClientGuard
286 {
287 public:
CCDDClientGuard(CCDDClientPool & pool)288 CCDDClientGuard(CCDDClientPool& pool)
289 : m_Pool(pool)
290 {
291 m_Client = m_Pool.x_GetClient();
292 }
293
~CCDDClientGuard(void)294 ~CCDDClientGuard(void) {
295 m_Pool.x_ReleaseClient(m_Client);
296 }
297
Get(void)298 CCDDClient& Get(void) {
299 return *m_Client->second;
300 }
301
Discard(void)302 void Discard(void)
303 {
304 m_Pool.x_DiscardClient(m_Client);
305 }
306
307 private:
308 CCDDClientPool& m_Pool;
309 CCDDClientPool::TClient m_Client;
310 };
311
312
313 /////////////////////////////////////////////////////////////////////////////
314 // CCDDClientPool
315 /////////////////////////////////////////////////////////////////////////////
316
317
x_NextSerialNumber(void)318 int CCDDClientPool::x_NextSerialNumber(void)
319 {
320 static CAtomicCounter_WithAutoInit s_Counter;
321 return s_Counter.Add(1);
322 }
323
324
CCDDClientPool(const string & service_name,size_t pool_soft_limit,time_t pool_age_limit,bool exclude_nucleotides)325 CCDDClientPool::CCDDClientPool(const string& service_name,
326 size_t pool_soft_limit,
327 time_t pool_age_limit,
328 bool exclude_nucleotides)
329 {
330 m_ServiceName = service_name;
331 m_PoolSoftLimit = pool_soft_limit;
332 m_PoolAgeLimit = pool_age_limit;
333 m_ExcludeNucleotides = exclude_nucleotides;
334 m_Cache.reset(new CCDDBlobCache);
335 }
336
337
~CCDDClientPool(void)338 CCDDClientPool::~CCDDClientPool(void)
339 {
340 }
341
342
GetBlobBySeq_id(CSeq_id_Handle idh)343 CCDDClientPool::SCDDBlob CCDDClientPool::GetBlobBySeq_id(CSeq_id_Handle idh)
344 {
345 SCDDBlob ret = m_Cache->Get(idh);
346 if (ret.data) return ret;
347
348 if (ret.info) {
349 // Have blob info only, request blob data.
350 ret.data = x_RequestBlobData(ret.info->GetBlob_id());
351 if (ret.data) {
352 m_Cache->Add(ret);
353 }
354 return ret;
355 }
356
357 // Make a blob-by-seq-id request.
358 int serial = x_NextSerialNumber();
359 CCDD_Request_Packet cdd_packet;
360 CRef<CCDD_Request> cdd_request(new CCDD_Request);
361 cdd_request->SetSerial_number(serial);
362
363
364 CConstRef<CSeq_id> id(idh.GetSeqId());
365 if (!IsValidId(*id)) return ret;
366 CRef<CSeq_id> nc_id(new CSeq_id);
367 nc_id->Assign(*id);
368 cdd_request->SetRequest().SetGet_blob_by_seq_id(*nc_id);
369 cdd_packet.Set().push_back(cdd_request);
370
371 CCDDClientGuard client(*this);
372 CRef<CCDD_Reply> cdd_reply(new CCDD_Reply);
373 try {
374 client.Get().Ask(cdd_packet, *cdd_reply);
375 if (!x_CheckReply(cdd_reply, serial, CCDD_Reply::TReply::e_Get_blob_by_seq_id)) {
376 return ret;
377 }
378 auto& cdd_blob = cdd_reply->SetReply().SetGet_blob_by_seq_id();
379 ret.info.Reset(&cdd_blob.SetBlob_id());
380 ret.data.Reset(&cdd_blob.SetBlob());
381 m_Cache->Add(ret);
382 }
383 catch (exception& e) {
384 ERR_POST("CDD - get-blob-by-seq-id request failed: " << e.what());
385 client.Discard();
386 }
387 catch (...) {
388 client.Discard();
389 }
390 return ret;
391 }
392
393
GetBlobBySeq_ids(const TSeq_idSet & ids)394 CCDDClientPool::SCDDBlob CCDDClientPool::GetBlobBySeq_ids(const TSeq_idSet& ids)
395 {
396 SCDDBlob ret;
397 ITERATE(TSeq_idSet, id_it, ids) {
398 ret = m_Cache->Get(*id_it);
399 if (ret.info) break;
400 }
401
402 if (ret.data) return ret;
403
404 if (ret.info) {
405 // Have blob info only, request blob data.
406 ret.data = x_RequestBlobData(ret.info->GetBlob_id());
407 if (ret.data) {
408 m_Cache->Add(ret);
409 }
410 return ret;
411 }
412
413 // Make a blob-by-seq-id request.
414 int serial = x_NextSerialNumber();
415 CCDD_Request_Packet cdd_packet;
416 CRef<CCDD_Request> cdd_request(new CCDD_Request);
417 cdd_request->SetSerial_number(serial);
418
419 list<CRef<CSeq_id>>& req_ids = cdd_request->SetRequest().SetGet_blob_by_seq_ids();
420 ITERATE(TSeq_idSet, id_it, ids) {
421 CConstRef<CSeq_id> id(id_it->GetSeqId());
422 if (!IsValidId(*id)) continue;
423 CRef<CSeq_id> nc_id(new CSeq_id);
424 nc_id->Assign(*id);
425 req_ids.push_back(nc_id);
426 }
427 if (req_ids.empty()) return ret;
428 cdd_packet.Set().push_back(cdd_request);
429
430 CCDDClientGuard client(*this);
431 CRef<CCDD_Reply> cdd_reply(new CCDD_Reply);
432 try {
433 client.Get().Ask(cdd_packet, *cdd_reply);
434 if (!x_CheckReply(cdd_reply, serial, CCDD_Reply::TReply::e_Get_blob_by_seq_id)) {
435 return ret;
436 }
437 auto& cdd_blob = cdd_reply->SetReply().SetGet_blob_by_seq_id();
438 ret.info.Reset(&cdd_blob.SetBlob_id());
439 ret.data.Reset(&cdd_blob.SetBlob());
440 m_Cache->Add(ret);
441 }
442 catch (exception& e) {
443 ERR_POST("CDD - get-blob-by-seq-ids request failed: " << e.what());
444 client.Discard();
445 }
446 catch (...) {
447 client.Discard();
448 }
449 return ret;
450 }
451
452
GetBlobIdBySeq_id(CSeq_id_Handle idh)453 CCDDClientPool::TBlobInfo CCDDClientPool::GetBlobIdBySeq_id(CSeq_id_Handle idh)
454 {
455 SCDDBlob blob = m_Cache->Get(idh);
456 if (blob.info) return blob.info;
457
458 int serial = x_NextSerialNumber();
459 CCDD_Request_Packet cdd_packet;
460 CRef<CCDD_Request> cdd_request(new CCDD_Request);
461 cdd_request->SetSerial_number(serial);
462
463 CConstRef<CSeq_id> id(idh.GetSeqId());
464 if (!IsValidId(*id)) return blob.info;
465
466 cdd_request->SetRequest().SetGet_blob_id().Assign(*id);
467 cdd_packet.Set().push_back(cdd_request);
468
469 CCDDClientGuard client(*this);
470 CRef<CCDD_Reply> cdd_reply(new CCDD_Reply);
471 try {
472 client.Get().Ask(cdd_packet, *cdd_reply);
473 if (!x_CheckReply(cdd_reply, serial, CCDD_Reply::TReply::e_Get_blob_id)) {
474 return blob.info;
475 }
476 blob.info.Reset(&cdd_reply->SetReply().SetGet_blob_id());
477 m_Cache->Add(blob);
478 }
479 catch (exception& e) {
480 ERR_POST("CDD - get-blob-id request failed: " << e.what());
481 client.Discard();
482 }
483 catch (...) {
484 client.Discard();
485 }
486 return blob.info;
487 }
488
489
GetBlobByBlobId(const TBlobId & blob_id)490 CCDDClientPool::TBlobData CCDDClientPool::GetBlobByBlobId(const TBlobId& blob_id)
491 {
492 SCDDBlob blob = m_Cache->Get(blob_id);
493 if (blob.data) return blob.data;
494
495 blob.data = x_RequestBlobData(blob_id);
496 if (blob.info && blob.data) {
497 m_Cache->Add(blob);
498 }
499 return blob.data;
500 }
501
502
x_RequestBlobData(const TBlobId & blob_id)503 CCDDClientPool::TBlobData CCDDClientPool::x_RequestBlobData(const TBlobId& blob_id)
504 {
505 TBlobData ret;
506 int serial = x_NextSerialNumber();
507 CCDD_Request_Packet cdd_packet;
508 CRef<CCDD_Request> cdd_request(new CCDD_Request);
509 cdd_request->SetSerial_number(serial);
510
511 auto& req = cdd_request->SetRequest().SetGet_blob();
512 req.SetSat(blob_id.GetSat());
513 req.SetSub_sat(blob_id.GetSub_sat());
514 req.SetSat_key(blob_id.GetSat_key());
515 cdd_packet.Set().push_back(cdd_request);
516
517 CCDDClientGuard client(*this);
518 CRef<CCDD_Reply> cdd_reply(new CCDD_Reply);
519 try {
520 client.Get().Ask(cdd_packet, *cdd_reply);
521 if (!x_CheckReply(cdd_reply, serial, CCDD_Reply::TReply::e_Get_blob)) {
522 return ret;
523 }
524 ret.Reset(&cdd_reply->SetReply().SetGet_blob());
525 }
526 catch (exception& e) {
527 ERR_POST("CDD - get-blob request failed: " << e.what());
528 client.Discard();
529 }
530 catch (...) {
531 client.Discard();
532 }
533 return ret;
534 }
535
536
x_CheckReply(CRef<CCDD_Reply> & reply,int serial,CCDD_Reply::TReply::E_Choice choice)537 bool CCDDClientPool::x_CheckReply(CRef<CCDD_Reply>& reply, int serial, CCDD_Reply::TReply::E_Choice choice)
538 {
539 if (!reply) return false;
540 if (reply->GetReply().IsEmpty() && !reply->IsSetError()) return false;
541 if (reply->IsSetError()) {
542 const CCDD_Error& e = reply->GetError();
543 ERR_POST("CDD - reply error: " << e.GetMessage() << " (code " << e.GetCode() << ", severity " << (int)e.GetSeverity() << ").");
544 return false;
545 }
546 if (reply->GetSerial_number() != serial) {
547 ERR_POST("CDD - serial number mismatch: " << serial << " != " << reply->GetSerial_number());
548 return false;
549 }
550 if (reply->GetReply().Which() != choice) {
551 ERR_POST("CDD - wrong reply type: " << reply->GetReply().Which() << " != " << choice);
552 return false;
553 }
554 return true;
555 }
556
557
IsValidId(const CSeq_id & id)558 bool CCDDClientPool::IsValidId(const CSeq_id& id)
559 {
560 switch (id.Which()) {
561 case CSeq_id::e_not_set:
562 case CSeq_id::e_Local:
563 case CSeq_id::e_Gibbsq:
564 case CSeq_id::e_Gibbmt:
565 case CSeq_id::e_Giim:
566 case CSeq_id::e_Patent:
567 case CSeq_id::e_General:
568 case CSeq_id::e_Gpipe:
569 case CSeq_id::e_Named_annot_track:
570 // These seq-ids are not used in CDD.
571 return false;
572 case CSeq_id::e_Gi:
573 case CSeq_id::e_Pdb:
574 // Non-text seq-ids present in CDD.
575 return true;
576 default:
577 break;
578 }
579 // For text seq-ids check accession type.
580 if (m_ExcludeNucleotides && (id.IdentifyAccession() & CSeq_id::fAcc_nuc) != 0) return false;
581 return true;
582 }
583
584
x_GetClient()585 CCDDClientPool::TClient CCDDClientPool::x_GetClient()
586 {
587 TClientPool::iterator ret = m_InUse.end();
588 time_t now;
589 CTime::GetCurrentTimeT(&now);
590 time_t cutoff = now - m_PoolAgeLimit;
591 CFastMutexGuard guard(m_PoolLock);
592 TClientPool::iterator it = m_NotInUse.lower_bound(cutoff);
593 if (it == m_NotInUse.end()) {
594 CRef<CCDDClient> client(new CCDDClient(m_ServiceName));
595 ret = m_InUse.emplace(now, client);
596 }
597 else {
598 ret = m_InUse.insert(*it);
599 ++it;
600 }
601 m_NotInUse.erase(m_NotInUse.begin(), it);
602 return ret;
603 }
604
605
x_ReleaseClient(TClientPool::iterator & client)606 void CCDDClientPool::x_ReleaseClient(TClientPool::iterator& client)
607 {
608 time_t now;
609 CTime::GetCurrentTimeT(&now);
610 time_t cutoff = now - m_PoolAgeLimit;
611 CFastMutexGuard guard(m_PoolLock);
612 m_NotInUse.erase(m_NotInUse.begin(), m_NotInUse.lower_bound(cutoff));
613 if (client != m_InUse.end()) {
614 if (client->first >= cutoff
615 && m_InUse.size() + m_NotInUse.size() <= m_PoolSoftLimit) {
616 m_NotInUse.insert(*client);
617 }
618 m_InUse.erase(client);
619 client = m_InUse.end();
620 }
621 }
622
623
x_DiscardClient(TClient & client)624 void CCDDClientPool::x_DiscardClient(TClient& client)
625 {
626 CFastMutexGuard guard(m_PoolLock);
627 m_InUse.erase(client);
628 client = m_InUse.end();
629 }
630
631
BlobIdToString(const TBlobId & blob_id)632 string CCDDClientPool::BlobIdToString(const TBlobId& blob_id)
633 {
634 ostringstream s;
635 s << blob_id.GetSat() << '/' << blob_id.GetSub_sat() << '.' << blob_id.GetSat_key();
636 return s.str();
637 }
638
StringToBlobId(const string & s)639 CRef<CCDDClientPool::TBlobId> CCDDClientPool::StringToBlobId(const string& s)
640 {
641 CRef<TBlobId> ret;
642 try {
643 vector<string> parts;
644 NStr::Split(s, "/.", parts);
645 if (parts.size() != 3) return ret;
646 CRef<TBlobId> blob_id(new TBlobId);
647 blob_id->SetSat(NStr::StringToNumeric<TBlobId::TSat>(parts[0]));
648 blob_id->SetSub_sat(NStr::StringToNumeric<TBlobId::TSat>(parts[1]));
649 blob_id->SetSat_key(NStr::StringToNumeric<TBlobId::TSat>(parts[2]));
650 ret = blob_id;
651 }
652 catch (...) {}
653 return ret;
654 }
655
656
657 END_objects_SCOPE // namespace ncbi::objects::
658
659 END_NCBI_SCOPE
660
661 /* Original file checksum: lines: 57, chars: 1749, CRC32: ab618a22 */
662