1 /*  $Id: data_source.cpp 610968 2020-06-26 12:55:17Z grichenk $
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, Eugene Vasilchenko
27 *
28 * File Description:
29 *   DataSource for object manager
30 *
31 */
32 
33 
34 #include <ncbi_pch.hpp>
35 #include <objmgr/impl/data_source.hpp>
36 
37 #include <objmgr/impl/annot_object.hpp>
38 #include <objmgr/impl/handle_range_map.hpp>
39 #include <objmgr/impl/seq_entry_info.hpp>
40 #include <objmgr/impl/seq_annot_info.hpp>
41 #include <objmgr/impl/bioseq_info.hpp>
42 #include <objmgr/impl/bioseq_set_info.hpp>
43 #include <objmgr/impl/tse_info.hpp>
44 #include <objmgr/impl/tse_loadlock.hpp>
45 #include <objmgr/impl/tse_split_info.hpp>
46 #include <objmgr/data_loader.hpp>
47 #include <objmgr/seq_map.hpp>
48 #include <objmgr/objmgr_exception.hpp>
49 #include <objmgr/bioseq_ci.hpp> // for CBioseq_CI_Base
50 
51 #include <objects/seqloc/Seq_loc.hpp>
52 #include <objects/seqloc/Seq_interval.hpp>
53 #include <objects/seqloc/Seq_point.hpp>
54 #include <objects/seqloc/Seq_loc_equiv.hpp>
55 
56 #include <objects/seq/Bioseq.hpp>
57 #include <objects/seq/seqport_util.hpp>
58 
59 #include <objects/seqset/Seq_entry.hpp>
60 #include <objects/seqset/Bioseq_set.hpp>
61 
62 #include <objects/seqalign/Seq_align.hpp>
63 #include <objects/seqfeat/Seq_feat.hpp>
64 #include <objects/seqres/Seq_graph.hpp>
65 
66 #include <objmgr/impl/prefetch_impl.hpp>
67 #include <objmgr/error_codes.hpp>
68 
69 #include <corelib/ncbimtx.hpp>
70 #include <corelib/ncbi_param.hpp>
71 #include <objmgr/scope.hpp>
72 
73 #include <algorithm>
74 
75 #if 0 && defined(_DEBUG)
76 # define TSE_LOCK_NO_SWAP
77 # define TSE_LOCK_TRACE(x) _TRACE(x)
78 #else
79 # define TSE_LOCK_TRACE(x)
80 #endif
81 
82 #define NCBI_USE_ERRCODE_X   ObjMgr_DataSource
83 
84 BEGIN_NCBI_SCOPE
85 
86 NCBI_DEFINE_ERR_SUBCODE_X(3);
87 
88 BEGIN_SCOPE(objects)
89 
90 class CSeq_entry;
91 
92 NCBI_PARAM_DECL(unsigned, OBJMGR, BLOB_CACHE);
93 NCBI_PARAM_DEF_EX(unsigned, OBJMGR, BLOB_CACHE, 10,
94                   eParam_NoThread, OBJMGR_BLOB_CACHE);
95 
GetDefaultBlobCacheSizeLimit(void)96 unsigned CDataSource::GetDefaultBlobCacheSizeLimit(void)
97 {
98     static CSafeStatic<NCBI_PARAM_TYPE(OBJMGR, BLOB_CACHE)> sx_Value;
99     return sx_Value->Get();
100 }
101 
102 
CDataSource(void)103 CDataSource::CDataSource(void)
104     : m_DefaultPriority(CObjectManager::kPriority_Entry),
105       m_Blob_Cache_Size(0),
106       m_Blob_Cache_Size_Limit(GetDefaultBlobCacheSizeLimit()),
107       m_StaticBlobCounter(0)
108 {
109 }
110 
111 
CDataSource(CDataLoader & loader)112 CDataSource::CDataSource(CDataLoader& loader)
113     : m_Loader(&loader),
114       m_DefaultPriority(loader.GetDefaultPriority()),
115       m_Blob_Cache_Size(0),
116       m_Blob_Cache_Size_Limit(min(GetDefaultBlobCacheSizeLimit(),
117                                   loader.GetDefaultBlobCacheSizeLimit())),
118       m_StaticBlobCounter(0)
119 {
120     m_Loader->SetTargetDataSource(*this);
121 }
122 
123 
CDataSource(const CObject & shared_object,const CSeq_entry & entry)124 CDataSource::CDataSource(const CObject& shared_object, const CSeq_entry& entry)
125     : m_SharedObject(&shared_object),
126       m_DefaultPriority(CObjectManager::kPriority_Entry),
127       m_Blob_Cache_Size(0),
128       m_Blob_Cache_Size_Limit(GetDefaultBlobCacheSizeLimit()),
129       m_StaticBlobCounter(0)
130 {
131     CTSE_Lock tse_lock = AddTSE(const_cast<CSeq_entry&>(entry));
132     m_StaticBlobs.PutLock(tse_lock);
133 }
134 
135 
~CDataSource(void)136 CDataSource::~CDataSource(void)
137 {
138     if (m_PrefetchThread) {
139         // Wait for the prefetch thread to stop
140         m_PrefetchThread->Terminate();
141         m_PrefetchThread->Join();
142     }
143     DropAllTSEs();
144     m_Loader.Reset();
145 }
146 
147 
RevokeDataLoader(void)148 void CDataSource::RevokeDataLoader(void)
149 {
150     if ( m_Loader ) {
151         TMainLock::TWriteLockGuard guard(m_DSMainLock);
152         m_Loader = null;
153     }
154 }
155 
156 
DropAllTSEs(void)157 void CDataSource::DropAllTSEs(void)
158 {
159     // Lock indexes
160     TMainLock::TWriteLockGuard guard(m_DSMainLock);
161 
162     // First clear all indices
163     m_InfoMap.clear();
164 
165     m_TSE_seq.clear();
166 
167     {{
168         TAnnotLock::TWriteLockGuard guard2(m_DSAnnotLock);
169         m_TSE_seq_annot.clear();
170         m_TSE_orphan_annot.clear();
171         m_DirtyAnnot_TSEs.clear();
172     }}
173 
174     // then drop all TSEs
175     {{
176         TCacheLock::TWriteLockGuard guard2(m_DSCacheLock);
177         // check if any TSE is locked by user
178         ITERATE ( TBlob_Map, it, m_Blob_Map ) {
179             CAtomicCounter::TValue lock_counter = it->second->m_LockCounter.Get();
180             CAtomicCounter::TValue used_counter = m_StaticBlobs.FindLock(it->second)? 1: 0;
181             if ( lock_counter != used_counter ) {
182                 ERR_POST_X(1, "CDataSource::DropAllTSEs: tse is locked");
183             }
184         }
185         NON_CONST_ITERATE( TBlob_Map, it, m_Blob_Map ) {
186             x_ForgetTSE(it->second);
187         }
188         m_StaticBlobs.Drop();
189         m_Blob_Map.clear();
190         m_Blob_Cache.clear();
191         m_Blob_Cache_Size = 0;
192         m_StaticBlobCounter = 0;
193     }}
194 }
195 
196 
GetSharedTSE(void) const197 CDataSource::TTSE_Lock CDataSource::GetSharedTSE(void) const
198 {
199     _ASSERT(GetSharedObject());
200     _ASSERT(m_StaticBlobs.size() == 1);
201     return m_StaticBlobs.begin()->second;
202 }
203 
204 
AddTSE(CSeq_entry & tse,CTSE_Info::TBlobState state)205 CDataSource::TTSE_Lock CDataSource::AddTSE(CSeq_entry& tse,
206                                            CTSE_Info::TBlobState state)
207 {
208     CRef<CTSE_Info> info(new CTSE_Info(tse, state));
209     return AddTSE(info);
210 }
211 
212 
AddTSE(CSeq_entry & tse,bool dead)213 CDataSource::TTSE_Lock CDataSource::AddTSE(CSeq_entry& tse,
214                                            bool dead)
215 {
216     return AddTSE(tse, dead ?
217         CBioseq_Handle::fState_dead : CBioseq_Handle::fState_none);
218 }
219 
220 
AddStaticTSE(CRef<CTSE_Info> info)221 CDataSource::TTSE_Lock CDataSource::AddStaticTSE(CRef<CTSE_Info> info)
222 {
223     TMainLock::TWriteLockGuard guard(m_DSMainLock);
224     if ( info->m_BlobVersion == -1 ) {
225         // assign fake version for conflict resolution
226         info->m_BlobVersion = -1-(++m_StaticBlobCounter);
227     }
228     TTSE_Lock lock = AddTSE(info);
229     m_StaticBlobs.AddLock(lock);
230     return lock;
231 }
232 
233 
AddStaticTSE(CSeq_entry & se)234 CDataSource::TTSE_Lock CDataSource::AddStaticTSE(CSeq_entry& se)
235 {
236     return AddStaticTSE(Ref(new CTSE_Info(se)));
237 }
238 
239 
240 namespace {
241     // local class for calling x_DSAttach()/x_DSDetach() without catch(...)
242     class CDSDetachGuard
243     {
244     public:
CDSDetachGuard(void)245         CDSDetachGuard(void)
246             : m_DataSource(0),
247               m_TSE_Info(0)
248             {
249             }
~CDSDetachGuard(void)250         ~CDSDetachGuard(void)
251             {
252                 if ( m_TSE_Info ) {
253                     m_TSE_Info->x_DSDetach(*m_DataSource);
254                 }
255             }
Attach(CDataSource * ds,CTSE_Info * tse)256         void Attach(CDataSource* ds, CTSE_Info* tse)
257             {
258                 m_DataSource = ds;
259                 m_TSE_Info = tse;
260                 m_TSE_Info->x_DSAttach(*m_DataSource);
261                 m_TSE_Info = 0;
262                 m_DataSource = 0;
263             }
264     private:
265         CDataSource* m_DataSource;
266         CTSE_Info* m_TSE_Info;
267 
268     private:
269         CDSDetachGuard(const CDSDetachGuard&);
270         void operator=(const CDSDetachGuard&);
271     };
272 }
273 
274 
AddTSE(CRef<CTSE_Info> info)275 CDataSource::TTSE_Lock CDataSource::AddTSE(CRef<CTSE_Info> info)
276 {
277     _ASSERT(!m_SharedObject || m_StaticBlobs.empty());
278     TTSE_Lock lock;
279     _ASSERT(IsLoaded(*info));
280     _ASSERT(!info->IsLocked());
281     _ASSERT(!info->HasDataSource());
282     TMainLock::TWriteLockGuard guard(m_DSMainLock);
283     TCacheLock::TWriteLockGuard guard2(m_DSCacheLock);
284     _ASSERT(!info->IsLocked());
285     _ASSERT(!info->HasDataSource());
286     TBlobId blob_id = info->GetBlobId();
287     if ( !blob_id ) {
288         // Set pointer to TSE itself as its BlobId.
289         info->m_BlobId = blob_id = new CBlobIdPtr(info.GetPointer());
290     }
291     if ( !m_Blob_Map.insert(TBlob_Map::value_type(blob_id, info)).second ) {
292         NCBI_THROW(CObjMgrException, eFindConflict,
293                    "Duplicated Blob-id");
294     }
295     {{
296         CDSDetachGuard detach_guard;
297         detach_guard.Attach(this, info);
298     }}
299     x_SetLock(lock, info);
300     _ASSERT(info->IsLocked());
301     return lock;
302 }
303 
304 
DropStaticTSE(CTSE_Info & info)305 bool CDataSource::DropStaticTSE(CTSE_Info& info)
306 {
307     TMainLock::TWriteLockGuard guard(m_DSMainLock);
308     m_StaticBlobs.RemoveLock(&info);
309     return DropTSE(info);
310 }
311 
312 
DropTSE(CTSE_Info & info)313 bool CDataSource::DropTSE(CTSE_Info& info)
314 {
315     TMainLock::TWriteLockGuard guard(m_DSMainLock);
316     CRef<CTSE_Info> ref(&info);
317 
318     if ( info.IsLocked() ) {
319         _TRACE("DropTSE: DS="<<this<<" TSE_Info="<<&info<<" locked");
320         return false; // Not really dropped, although found
321     }
322     if ( !info.HasDataSource() ) {
323         _TRACE("DropTSE: DS="<<this<<" TSE_Info="<<&info<<" already dropped");
324         return false; // Not really dropped, although found
325     }
326     _ASSERT(&info.GetDataSource() == this);
327     _ASSERT(!info.IsLocked());
328     x_DropTSE(ref);
329     _ASSERT(!info.IsLocked());
330     _ASSERT(!info.HasDataSource());
331     return true;
332 }
333 
334 
x_ForgetTSE(CRef<CTSE_Info> info)335 void CDataSource::x_ForgetTSE(CRef<CTSE_Info> info)
336 {
337     if ( m_Loader ) {
338         m_Loader->DropTSE(info);
339     }
340     info->m_CacheState = CTSE_Info::eNotInCache;
341     info->m_DataSource = 0;
342 }
343 
344 
x_DropTSE(CRef<CTSE_Info> info)345 void CDataSource::x_DropTSE(CRef<CTSE_Info> info)
346 {
347     _ASSERT(!info->IsLocked());
348     if ( m_Loader ) {
349         m_Loader->DropTSE(info);
350     }
351     _ASSERT(!info->IsLocked());
352     info->x_DSDetach(*this);
353     _ASSERT(!info->IsLocked());
354     {{
355         TCacheLock::TWriteLockGuard guard(m_DSCacheLock);
356         TBlobId blob_id = info->GetBlobId();
357         _ASSERT(blob_id);
358         _VERIFY(m_Blob_Map.erase(blob_id));
359     }}
360     _ASSERT(!info->IsLocked());
361     {{
362         TAnnotLock::TWriteLockGuard guard2(m_DSAnnotLock);
363         m_DirtyAnnot_TSEs.erase(info);
364     }}
365     _ASSERT(!info->IsLocked());
366 }
367 
368 
x_Map(const CObject * obj,const CTSE_Info_Object * info)369 void CDataSource::x_Map(const CObject* obj, const CTSE_Info_Object* info)
370 {
371     typedef TInfoMap::value_type value_type;
372     pair<TInfoMap::iterator, bool> ins =
373         m_InfoMap.insert(value_type(obj, info));
374     if ( !ins.second ) {
375         CNcbiOstrstream str;
376         str << "CDataSource::x_Map(): object already mapped:" <<
377             " " << typeid(*obj).name() <<
378             " obj: " << obj <<
379             " " << typeid(*info).name() <<
380             " info: " << info <<
381             " was: " << ins.first->second;
382         NCBI_THROW(CObjMgrException, eOtherError,
383                    CNcbiOstrstreamToString(str));
384     }
385 }
386 
387 
x_Unmap(const CObject * obj,const CTSE_Info_Object * info)388 void CDataSource::x_Unmap(const CObject* obj, const CTSE_Info_Object* info)
389 {
390     TInfoMap::iterator iter = m_InfoMap.find(obj);
391     if ( iter != m_InfoMap.end() && iter->second == info ) {
392         m_InfoMap.erase(iter);
393     }
394 }
395 
396 
397 /////////////////////////////////////////////////////////////////////////////
398 //   mapping of various XXX_Info
399 // CDataSource must be guarded by mutex
400 /////////////////////////////////////////////////////////////////////////////
401 
402 CDataSource::TTSE_Lock
FindTSE_Lock(const CSeq_entry & tse,const TTSE_LockSet &) const403 CDataSource::FindTSE_Lock(const CSeq_entry& tse,
404                           const TTSE_LockSet& /*history*/) const
405 {
406     TTSE_Lock ret;
407     {{
408         TMainLock::TReadLockGuard guard(m_DSMainLock);
409         CConstRef<CTSE_Info> info = x_FindTSE_Info(tse);
410         if ( info ) {
411             x_SetLock(ret, info);
412         }
413     }}
414     return ret;
415 }
416 
417 
418 CDataSource::TSeq_entry_Lock
GetSeq_entry_Lock(const CBlobIdKey & blob_id)419 CDataSource::GetSeq_entry_Lock(const CBlobIdKey& blob_id)
420 {
421     TSeq_entry_Lock ret;
422     {{
423         TMainLock::TWriteLockGuard guard(m_DSMainLock);
424         ret.first = m_Loader->GetBlobById(blob_id);
425         if ( ret.first ) {
426             x_SetLock(ret.second, ConstRef(&ret.first->GetTSE_Info()));
427         }
428     }}
429     return ret;
430 }
431 
432 
433 CDataSource::TSeq_entry_Lock
FindSeq_entry_Lock(const CSeq_entry & entry,const TTSE_LockSet &) const434 CDataSource::FindSeq_entry_Lock(const CSeq_entry& entry,
435                                 const TTSE_LockSet& /*history*/) const
436 {
437     TSeq_entry_Lock ret;
438     {{
439         TMainLock::TReadLockGuard guard(m_DSMainLock);
440         ret.first = x_FindSeq_entry_Info(entry);
441         if ( ret.first ) {
442             x_SetLock(ret.second, ConstRef(&ret.first->GetTSE_Info()));
443         }
444     }}
445     return ret;
446 }
447 
448 
449 CDataSource::TSeq_annot_Lock
FindSeq_annot_Lock(const CSeq_annot & annot,const TTSE_LockSet &) const450 CDataSource::FindSeq_annot_Lock(const CSeq_annot& annot,
451                                 const TTSE_LockSet& /*history*/) const
452 {
453     TSeq_annot_Lock ret;
454     {{
455         TMainLock::TReadLockGuard guard(m_DSMainLock);
456         ret.first = x_FindSeq_annot_Info(annot);
457         if ( ret.first ) {
458             x_SetLock(ret.second, ConstRef(&ret.first->GetTSE_Info()));
459         }
460     }}
461     return ret;
462 }
463 
464 
465 CDataSource::TBioseq_set_Lock
FindBioseq_set_Lock(const CBioseq_set & seqset,const TTSE_LockSet &) const466 CDataSource::FindBioseq_set_Lock(const CBioseq_set& seqset,
467                                  const TTSE_LockSet& /*history*/) const
468 {
469     TBioseq_set_Lock ret;
470     {{
471         TMainLock::TReadLockGuard guard(m_DSMainLock);
472         ret.first = x_FindBioseq_set_Info(seqset);
473         if ( ret.first ) {
474             x_SetLock(ret.second, ConstRef(&ret.first->GetTSE_Info()));
475         }
476     }}
477     return ret;
478 }
479 
480 
481 CDataSource::TBioseq_Lock
FindBioseq_Lock(const CBioseq & bioseq,const TTSE_LockSet &) const482 CDataSource::FindBioseq_Lock(const CBioseq& bioseq,
483                              const TTSE_LockSet& /*history*/) const
484 {
485     TBioseq_Lock ret;
486     {{
487         TMainLock::TReadLockGuard guard(m_DSMainLock);
488         ret.first = x_FindBioseq_Info(bioseq);
489         if ( ret.first ) {
490             x_SetLock(ret.second, ConstRef(&ret.first->GetTSE_Info()));
491         }
492     }}
493     return ret;
494 }
495 
496 
497 CDataSource::TSeq_feat_Lock
FindSeq_feat_Lock(const CSeq_id_Handle & loc_id,TSeqPos loc_pos,const CSeq_feat & feat) const498 CDataSource::FindSeq_feat_Lock(const CSeq_id_Handle& loc_id,
499                                TSeqPos loc_pos,
500                                const CSeq_feat& feat) const
501 {
502     const_cast<CDataSource*>(this)->UpdateAnnotIndex();
503     TSeq_feat_Lock ret;
504     TAnnotLock::TReadLockGuard guard(m_DSAnnotLock);
505     for ( int i = 0; i < 2; ++i ) {
506         const TSeq_id2TSE_Set& index = i? m_TSE_seq_annot: m_TSE_orphan_annot;
507         TSeq_id2TSE_Set::const_iterator it = index.find(loc_id);
508         if ( it != index.end() ) {
509             ITERATE ( TTSE_Set, it2, it->second ) {
510                 ret = (*it2)->x_FindSeq_feat(loc_id, loc_pos, feat);
511                 if ( ret.first.first ) {
512                     x_SetLock(ret.first.second,
513                               ConstRef(&ret.first.first->GetTSE_Info()));
514                     return ret;
515                 }
516             }
517         }
518     }
519     return ret;
520 }
521 
522 
x_GetLoadedBlob_ids(const CSeq_id_Handle & idh,TLoadedTypes types,TLoadedBlob_ids_Set & ids) const523 void CDataSource::x_GetLoadedBlob_ids(const CSeq_id_Handle& idh,
524                                       TLoadedTypes types,
525                                       TLoadedBlob_ids_Set& ids) const
526 {
527     if ( types & fLoaded_bioseqs ) {
528         TMainLock::TReadLockGuard guard(m_DSMainLock);
529         TSeq_id2TSE_Set::const_iterator tse_set = m_TSE_seq.find(idh);
530         if (tse_set != m_TSE_seq.end()) {
531             ITERATE(TTSE_Set, tse, tse_set->second) {
532                 ids.insert((*tse)->GetBlobId());
533             }
534         }
535     }
536     if ( types & fLoaded_annots ) {
537         TAnnotLock::TReadLockGuard guard(m_DSAnnotLock);
538         if ( types & fLoaded_bioseq_annots ) {
539             TSeq_id2TSE_Set::const_iterator tse_set =
540                 m_TSE_seq_annot.find(idh);
541             if (tse_set != m_TSE_seq_annot.end()) {
542                 ITERATE(TTSE_Set, tse, tse_set->second) {
543                     ids.insert((*tse)->GetBlobId());
544                 }
545             }
546         }
547         if ( types & fLoaded_orphan_annots ) {
548             TSeq_id2TSE_Set::const_iterator tse_set =
549                 m_TSE_orphan_annot.find(idh);
550             if (tse_set != m_TSE_orphan_annot.end()) {
551                 ITERATE(TTSE_Set, tse, tse_set->second) {
552                     ids.insert((*tse)->GetBlobId());
553                 }
554             }
555         }
556     }
557 }
558 
559 
GetLoadedBlob_ids(const CSeq_id_Handle & idh,TLoadedTypes types,TLoadedBlob_ids & blob_ids) const560 void CDataSource::GetLoadedBlob_ids(const CSeq_id_Handle& idh,
561                                     TLoadedTypes types,
562                                     TLoadedBlob_ids& blob_ids) const
563 {
564     TLoadedBlob_ids_Set ids;
565     if ( idh.HaveMatchingHandles() ) {
566         // Try to find the best matching id (not exactly equal)
567         CSeq_id_Handle::TMatches hset;
568         idh.GetMatchingHandles(hset, eAllowWeakMatch);
569         ITERATE ( CSeq_id_Handle::TMatches, hit, hset ) {
570             x_GetLoadedBlob_ids(*hit, types, ids);
571         }
572     }
573     else {
574         x_GetLoadedBlob_ids(idh, types, ids);
575     }
576     ITERATE(TLoadedBlob_ids_Set, it, ids) {
577         blob_ids.push_back(*it);
578     }
579 }
580 
581 
582 CConstRef<CTSE_Info>
x_FindTSE_Info(const CSeq_entry & obj) const583 CDataSource::x_FindTSE_Info(const CSeq_entry& obj) const
584 {
585     CConstRef<CTSE_Info> ret;
586     TInfoMap::const_iterator found = m_InfoMap.find(&obj);
587     if ( found != m_InfoMap.end() ) {
588         ret = dynamic_cast<const CTSE_Info*>(&*found->second);
589     }
590     return ret;
591 }
592 
593 
594 CConstRef<CSeq_entry_Info>
x_FindSeq_entry_Info(const CSeq_entry & obj) const595 CDataSource::x_FindSeq_entry_Info(const CSeq_entry& obj) const
596 {
597     CConstRef<CSeq_entry_Info> ret;
598     TInfoMap::const_iterator found = m_InfoMap.find(&obj);
599     if ( found != m_InfoMap.end() ) {
600         ret = dynamic_cast<const CSeq_entry_Info*>(&*found->second);
601     }
602     return ret;
603 }
604 
605 
606 CConstRef<CSeq_annot_Info>
x_FindSeq_annot_Info(const CSeq_annot & obj) const607 CDataSource::x_FindSeq_annot_Info(const CSeq_annot& obj) const
608 {
609     CConstRef<CSeq_annot_Info> ret;
610     TInfoMap::const_iterator found = m_InfoMap.find(&obj);
611     if ( found != m_InfoMap.end() ) {
612         ret = dynamic_cast<const CSeq_annot_Info*>(&*found->second);
613     }
614     return ret;
615 }
616 
617 
618 CConstRef<CBioseq_set_Info>
x_FindBioseq_set_Info(const CBioseq_set & obj) const619 CDataSource::x_FindBioseq_set_Info(const CBioseq_set& obj) const
620 {
621     CConstRef<CBioseq_set_Info> ret;
622     TInfoMap::const_iterator found = m_InfoMap.find(&obj);
623     if ( found != m_InfoMap.end() ) {
624         ret = dynamic_cast<const CBioseq_set_Info*>(&*found->second);
625     }
626     return ret;
627 }
628 
629 
630 CConstRef<CBioseq_Info>
x_FindBioseq_Info(const CBioseq & obj) const631 CDataSource::x_FindBioseq_Info(const CBioseq& obj) const
632 {
633     CConstRef<CBioseq_Info> ret;
634     TInfoMap::const_iterator found = m_InfoMap.find(&obj);
635     if ( found != m_InfoMap.end() ) {
636         ret = dynamic_cast<const CBioseq_Info*>(&*found->second);
637     }
638     return ret;
639 }
640 
641 /////////////////////////////////////////////////////////////////////////////
642 
643 
AttachEntry(CBioseq_set_Info & parent,CSeq_entry & entry,int index)644 CRef<CSeq_entry_Info> CDataSource::AttachEntry(CBioseq_set_Info& parent,
645                                                CSeq_entry& entry,
646                                                int index)
647 {
648     if ( m_Loader ) {
649         NCBI_THROW(CObjMgrException, eModifyDataError,
650                    "Can not remove a loaded entry");
651     }
652     TMainLock::TWriteLockGuard guard(m_DSMainLock);
653     return parent.AddEntry(entry, index);
654 }
655 
656 
RemoveEntry(CSeq_entry_Info & entry)657 void CDataSource::RemoveEntry(CSeq_entry_Info& entry)
658 {
659     if ( m_Loader ) {
660         NCBI_THROW(CObjMgrException, eModifyDataError,
661                    "Can not remove a loaded entry");
662     }
663     if ( !entry.HasParent_Info() ) {
664         // Top level entry
665         NCBI_THROW(CObjMgrException, eModifyDataError,
666                    "Can not remove top level seq-entry from a data source");
667     }
668 
669     TMainLock::TWriteLockGuard guard(m_DSMainLock);
670     CBioseq_set_Info& parent = entry.GetParentBioseq_set_Info();
671     parent.RemoveEntry(Ref(&entry));
672 }
673 
674 
AttachAnnot(CSeq_entry_Info & entry_info,CSeq_annot & annot)675 CRef<CSeq_annot_Info> CDataSource::AttachAnnot(CSeq_entry_Info& entry_info,
676                                                CSeq_annot& annot)
677 {
678     if ( m_Loader ) {
679         NCBI_THROW(CObjMgrException, eModifyDataError,
680                    "Can not modify a loaded entry");
681     }
682 
683     TMainLock::TWriteLockGuard guard(m_DSMainLock);
684     return entry_info.AddAnnot(annot);
685 }
686 
687 
AttachAnnot(CBioseq_Base_Info & parent,CSeq_annot & annot)688 CRef<CSeq_annot_Info> CDataSource::AttachAnnot(CBioseq_Base_Info& parent,
689                                                CSeq_annot& annot)
690 {
691     if ( m_Loader ) {
692         NCBI_THROW(CObjMgrException, eModifyDataError,
693                    "Can not modify a loaded entry");
694     }
695 
696     TMainLock::TWriteLockGuard guard(m_DSMainLock);
697     return parent.AddAnnot(annot);
698 }
699 
700 
RemoveAnnot(CSeq_annot_Info & annot)701 void CDataSource::RemoveAnnot(CSeq_annot_Info& annot)
702 {
703     if ( m_Loader ) {
704         NCBI_THROW(CObjMgrException, eModifyDataError,
705                    "Can not modify a loaded entry");
706     }
707 
708     TMainLock::TWriteLockGuard guard(m_DSMainLock);
709     CBioseq_Base_Info& parent = annot.GetParentBioseq_Base_Info();
710     parent.RemoveAnnot(Ref(&annot));
711 }
712 
713 
ReplaceAnnot(CSeq_annot_Info & old_annot,CSeq_annot & new_annot)714 CRef<CSeq_annot_Info> CDataSource::ReplaceAnnot(CSeq_annot_Info& old_annot,
715                                                 CSeq_annot& new_annot)
716 {
717     if ( m_Loader ) {
718         NCBI_THROW(CObjMgrException, eModifyDataError,
719                    "Can not modify a loaded entry");
720     }
721 
722     TMainLock::TWriteLockGuard guard(m_DSMainLock);
723     CBioseq_Base_Info& parent = old_annot.GetParentBioseq_Base_Info();
724     parent.RemoveAnnot(Ref(&old_annot));
725     return parent.AddAnnot(new_annot);
726 }
727 
728 
x_SetDirtyAnnotIndex(CTSE_Info & tse)729 void CDataSource::x_SetDirtyAnnotIndex(CTSE_Info& tse)
730 {
731     TAnnotLock::TWriteLockGuard guard(m_DSAnnotLock);
732     _ASSERT(tse.x_DirtyAnnotIndex());
733     _VERIFY(m_DirtyAnnot_TSEs.insert(Ref(&tse)).second);
734 }
735 
736 
x_ResetDirtyAnnotIndex(CTSE_Info & tse)737 void CDataSource::x_ResetDirtyAnnotIndex(CTSE_Info& tse)
738 {
739     _ASSERT(!tse.x_DirtyAnnotIndex());
740     _VERIFY(m_DirtyAnnot_TSEs.erase(Ref(&tse)));
741 }
742 
743 
CDSAnnotLockReadGuard(EEmptyGuard)744 CDSAnnotLockReadGuard::CDSAnnotLockReadGuard(EEmptyGuard)
745     : m_MainGuard(eEmptyGuard),
746       m_AnnotGuard(eEmptyGuard)
747 {
748 }
749 
CDSAnnotLockReadGuard(CDataSource & ds)750 CDSAnnotLockReadGuard::CDSAnnotLockReadGuard(CDataSource& ds)
751     : m_MainGuard(ds.m_DSMainLock),
752       m_AnnotGuard(ds.m_DSAnnotLock)
753 {
754 }
Guard(CDataSource & ds)755 void CDSAnnotLockReadGuard::Guard(CDataSource& ds)
756 {
757     m_MainGuard.Guard(ds.m_DSMainLock);
758     m_AnnotGuard.Guard(ds.m_DSAnnotLock);
759 }
760 
761 
CDSAnnotLockWriteGuard(EEmptyGuard)762 CDSAnnotLockWriteGuard::CDSAnnotLockWriteGuard(EEmptyGuard)
763     : m_MainGuard(eEmptyGuard),
764       m_AnnotGuard(eEmptyGuard)
765 {
766 }
CDSAnnotLockWriteGuard(CDataSource & ds)767 CDSAnnotLockWriteGuard::CDSAnnotLockWriteGuard(CDataSource& ds)
768     : m_MainGuard(ds.m_DSMainLock),
769       m_AnnotGuard(ds.m_DSAnnotLock)
770 {
771 }
Guard(CDataSource & ds)772 void CDSAnnotLockWriteGuard::Guard(CDataSource& ds)
773 {
774     m_MainGuard.Guard(ds.m_DSMainLock);
775     m_AnnotGuard.Guard(ds.m_DSAnnotLock);
776 }
777 
UpdateAnnotIndex(void)778 void CDataSource::UpdateAnnotIndex(void)
779 {
780     TAnnotLockWriteGuard guard(*this);
781     while ( !m_DirtyAnnot_TSEs.empty() ) {
782         CRef<CTSE_Info> tse_info = *m_DirtyAnnot_TSEs.begin();
783         tse_info->UpdateAnnotIndex();
784         _ASSERT(m_DirtyAnnot_TSEs.empty() ||
785                 *m_DirtyAnnot_TSEs.begin() != tse_info);
786 
787     }
788 }
789 
790 
UpdateAnnotIndex(const CSeq_entry_Info & entry_info)791 void CDataSource::UpdateAnnotIndex(const CSeq_entry_Info& entry_info)
792 {
793     TMainLock::TReadLockGuard guard(m_DSMainLock);
794     entry_info.UpdateAnnotIndex();
795 }
796 
797 
UpdateAnnotIndex(const CSeq_annot_Info & annot_info)798 void CDataSource::UpdateAnnotIndex(const CSeq_annot_Info& annot_info)
799 {
800     TMainLock::TReadLockGuard guard(m_DSMainLock);
801     annot_info.UpdateAnnotIndex();
802 }
803 
804 
805 CDataSource::TTSE_LockSet
x_GetRecords(const CSeq_id_Handle & idh,CDataLoader::EChoice choice)806 CDataSource::x_GetRecords(const CSeq_id_Handle& idh,
807                           CDataLoader::EChoice choice)
808 {
809     TTSE_LockSet tse_set;
810     if ( m_Loader ) {
811         CDataLoader::TTSE_LockSet tse_set2 = m_Loader->GetRecords(idh, choice);
812         ITERATE ( CDataLoader::TTSE_LockSet, it, tse_set2 ) {
813             tse_set.AddLock(*it);
814             (*it)->x_GetRecords(idh, choice == CDataLoader::eBioseqCore);
815         }
816     }
817     return tse_set;
818 }
819 
820 
sx_AddAnnotMatch(CDataSource::TTSE_LockMatchSet & ret,const CTSE_Lock & tse_lock,const CSeq_id_Handle & id)821 static inline void sx_AddAnnotMatch(CDataSource::TTSE_LockMatchSet& ret,
822                                     const CTSE_Lock& tse_lock,
823                                     const CSeq_id_Handle& id)
824 {
825     if ( ret.empty() ||
826          ret.back().second != id ||
827          ret.back().first != tse_lock ) {
828         ret.push_back(pair<CTSE_Lock, CSeq_id_Handle>(tse_lock, id));
829     }
830 }
831 
832 
x_AddTSEAnnots(TTSE_LockMatchSet & ret,const CSeq_id_Handle & id,const CTSE_Lock & tse_lock)833 void CDataSource::x_AddTSEAnnots(TTSE_LockMatchSet& ret,
834                                  const CSeq_id_Handle& id,
835                                  const CTSE_Lock& tse_lock)
836 {
837     //TSE annot index should be locked from modification by TAnnotLockReadGuard
838     const CTSE_Info& tse = *tse_lock;
839     if ( tse.HasMatchingAnnotIds() ) {
840         // full check
841         CSeq_id_Handle::TMatches ids;
842         id.GetReverseMatchingHandles(ids);
843         ITERATE ( CSeq_id_Handle::TMatches, id_it2, ids ) {
844             if ( tse.x_HasIdObjects(*id_it2) ) {
845                 sx_AddAnnotMatch(ret, tse_lock, *id_it2);
846             }
847         }
848     }
849     else if ( id.IsGi() || !tse.OnlyGiAnnotIds()  ) {
850         if ( tse.x_HasIdObjects(id) ) {
851             sx_AddAnnotMatch(ret, tse_lock, id);
852         }
853     }
854 }
855 
856 
x_AddTSEBioseqAnnots(TTSE_LockMatchSet & ret,const CBioseq_Info & bioseq,const CTSE_Lock & tse_lock)857 void CDataSource::x_AddTSEBioseqAnnots(TTSE_LockMatchSet& ret,
858                                        const CBioseq_Info& bioseq,
859                                        const CTSE_Lock& tse_lock)
860 {
861     const CTSE_Info& tse = *tse_lock;
862     ITERATE ( CBioseq_Info::TId, id_it, bioseq.GetId() ) {
863         tse.x_GetRecords(*id_it, false);
864     }
865     UpdateAnnotIndex(tse);
866     CTSE_Info::TAnnotLockReadGuard guard(tse.GetAnnotLock());
867     ITERATE ( CBioseq_Info::TId, id_it, bioseq.GetId() ) {
868         x_AddTSEAnnots(ret, *id_it, tse_lock);
869     }
870 }
871 
872 
x_AddTSEOrphanAnnots(TTSE_LockMatchSet & ret,const TSeq_idSet & ids,const CTSE_Lock & tse_lock)873 void CDataSource::x_AddTSEOrphanAnnots(TTSE_LockMatchSet& ret,
874                                        const TSeq_idSet& ids,
875                                        const CTSE_Lock& tse_lock)
876 {
877     const CTSE_Info& tse = *tse_lock;
878     ITERATE ( TSeq_idSet, id_it, ids ) {
879         if ( tse.ContainsMatchingBioseq(*id_it) ) {
880             // not orphan
881             return;
882         }
883         tse.x_GetRecords(*id_it, false);
884     }
885     UpdateAnnotIndex(tse);
886     CTSE_Info::TAnnotLockReadGuard guard(tse.GetAnnotLock());
887     ITERATE ( TSeq_idSet, id_it, ids ) {
888         x_AddTSEAnnots(ret, *id_it, tse_lock);
889     }
890 }
891 
892 
GetTSESetWithOrphanAnnots(const TSeq_idSet & ids,TTSE_LockMatchSet & ret,const SAnnotSelector * sel,CDataLoader::TProcessedNAs * processed_nas)893 void CDataSource::GetTSESetWithOrphanAnnots(const TSeq_idSet& ids,
894                                             TTSE_LockMatchSet& ret,
895                                             const SAnnotSelector* sel,
896                                             CDataLoader::TProcessedNAs* processed_nas)
897 {
898     if ( m_Loader ) {
899         // with loader installed we look only in TSEs reported by loader.
900 
901         // collect set of TSEs with orphan annotations
902         CDataLoader::TTSE_LockSet tse_set =
903             m_Loader->GetOrphanAnnotRecordsNA(ids, sel, processed_nas);
904 
905         ITERATE ( CDataLoader::TTSE_LockSet, tse_it, tse_set ) {
906             x_AddTSEOrphanAnnots(ret, ids, *tse_it);
907         }
908     }
909     else {
910         // without loader we look only in static TSE if any
911         if ( m_StaticBlobs.size() <= 10 ) {
912             ITERATE ( TTSE_LockSet, tse_it, m_StaticBlobs ) {
913                 x_AddTSEOrphanAnnots(ret, ids, tse_it->second);
914             }
915         }
916         else {
917             UpdateAnnotIndex();
918             TAnnotLock::TReadLockGuard guard(m_DSAnnotLock);
919             ITERATE ( TSeq_idSet, id_it, ids ) {
920                 TSeq_id2TSE_Set::const_iterator tse_set =
921                     m_TSE_orphan_annot.find(*id_it);
922                 if (tse_set != m_TSE_orphan_annot.end()) {
923                     ITERATE(TTSE_Set, tse_it, tse_set->second) {
924                         sx_AddAnnotMatch(ret,
925                                          m_StaticBlobs.FindLock(*tse_it),
926                                          *id_it);
927                     }
928                 }
929             }
930         }
931     }
932     sort(ret.begin(), ret.end());
933     ret.erase(unique(ret.begin(), ret.end()), ret.end());
934 }
935 
936 
GetTSESetWithBioseqAnnots(const CBioseq_Info & bioseq,const TTSE_Lock & tse,TTSE_LockMatchSet & ret,const SAnnotSelector * sel,CDataLoader::TProcessedNAs * processed_nas,bool external_only)937 void CDataSource::GetTSESetWithBioseqAnnots(const CBioseq_Info& bioseq,
938                                             const TTSE_Lock& tse,
939                                             TTSE_LockMatchSet& ret,
940                                             const SAnnotSelector* sel,
941                                             CDataLoader::TProcessedNAs* processed_nas,
942                                             bool external_only)
943 {
944     if ( !external_only ) {
945         // add bioseq annotations
946         x_AddTSEBioseqAnnots(ret, bioseq, tse);
947     }
948 
949     if ( m_Loader ) {
950         // with loader installed we look only in TSE with bioseq,
951         // and TSEs with external annotations reported by the loader.
952 
953         // external annotations
954         CDataLoader::TTSE_LockSet tse_set2 =
955             m_Loader->GetExternalAnnotRecordsNA(bioseq, sel, processed_nas);
956         ITERATE ( CDataLoader::TTSE_LockSet, tse_it, tse_set2 ) {
957             x_AddTSEBioseqAnnots(ret, bioseq, *tse_it);
958         }
959     }
960     else {
961         // without loader bioseq TSE is the same as manually added TSE
962         // and we already have added it
963         size_t blob_count = m_StaticBlobs.size();
964         if ( blob_count <= 1 ) {
965             _ASSERT(m_StaticBlobs.FindLock(tse));
966         }
967         else {
968             TSeq_idSet ids;
969             ITERATE ( CBioseq_Info::TId, it, bioseq.GetId() ) {
970                 if ( it->HaveReverseMatch() ) {
971                     CSeq_id_Handle::TMatches hset;
972                     it->GetReverseMatchingHandles(ids);
973                 }
974                 else {
975                     ids.insert(*it);
976                 }
977             }
978             if ( blob_count <= 10 ) {
979                 ITERATE ( TTSE_LockSet, it, m_StaticBlobs ) {
980                     if ( it->second == tse ) {
981                         continue;
982                     }
983                     x_AddTSEOrphanAnnots(ret, ids, it->second);
984                 }
985             }
986             else {
987                 UpdateAnnotIndex();
988                 TAnnotLock::TReadLockGuard guard(m_DSAnnotLock);
989                 ITERATE ( TSeq_idSet, id_it, ids ) {
990                     TSeq_id2TSE_Set::const_iterator annot_it =
991                         m_TSE_orphan_annot.find(*id_it);
992                     if ( annot_it == m_TSE_orphan_annot.end() ) {
993                         continue;
994                     }
995                     ITERATE ( TTSE_Set, tse_it, annot_it->second ) {
996                         if ( *tse_it == tse ) {
997                             continue;
998                         }
999                         sx_AddAnnotMatch(ret,
1000                                          m_StaticBlobs.FindLock(*tse_it),
1001                                          *id_it);
1002                     }
1003                 }
1004             }
1005         }
1006     }
1007     sort(ret.begin(), ret.end());
1008     ret.erase(unique(ret.begin(), ret.end()), ret.end());
1009 }
1010 
1011 
x_IndexTSE(TSeq_id2TSE_Set & tse_map,const CSeq_id_Handle & id,CTSE_Info * tse_info)1012 void CDataSource::x_IndexTSE(TSeq_id2TSE_Set& tse_map,
1013                              const CSeq_id_Handle& id,
1014                              CTSE_Info* tse_info)
1015 {
1016     TSeq_id2TSE_Set::iterator it = tse_map.lower_bound(id);
1017     if ( it == tse_map.end() || it->first != id ) {
1018         it = tse_map.insert(it, TSeq_id2TSE_Set::value_type(id, TTSE_Set()));
1019     }
1020     _ASSERT(it != tse_map.end() && it->first == id);
1021     it->second.insert(Ref(tse_info));
1022 }
1023 
1024 
x_UnindexTSE(TSeq_id2TSE_Set & tse_map,const CSeq_id_Handle & id,CTSE_Info * tse_info)1025 void CDataSource::x_UnindexTSE(TSeq_id2TSE_Set& tse_map,
1026                                const CSeq_id_Handle& id,
1027                                CTSE_Info* tse_info)
1028 {
1029     TSeq_id2TSE_Set::iterator it = tse_map.find(id);
1030     if ( it == tse_map.end() ) {
1031         return;
1032     }
1033     it->second.erase(Ref(tse_info));
1034     if ( it->second.empty() ) {
1035         tse_map.erase(it);
1036     }
1037 }
1038 
1039 
x_IndexSeqTSE(const CSeq_id_Handle & id,CTSE_Info * tse_info)1040 void CDataSource::x_IndexSeqTSE(const CSeq_id_Handle& id,
1041                                 CTSE_Info* tse_info)
1042 {
1043     // no need to lock as it's locked by callers
1044     TMainLock::TWriteLockGuard guard(m_DSMainLock);
1045     x_IndexTSE(m_TSE_seq, id, tse_info);
1046 }
1047 
1048 
x_IndexSeqTSE(const vector<CSeq_id_Handle> & ids,CTSE_Info * tse_info)1049 void CDataSource::x_IndexSeqTSE(const vector<CSeq_id_Handle>& ids,
1050                                 CTSE_Info* tse_info)
1051 {
1052     // no need to lock as it's locked by callers
1053     TMainLock::TWriteLockGuard guard(m_DSMainLock);
1054     ITERATE ( vector<CSeq_id_Handle>, it, ids ) {
1055         x_IndexTSE(m_TSE_seq, *it, tse_info);
1056     }
1057 }
1058 
1059 
x_UnindexSeqTSE(const CSeq_id_Handle & id,CTSE_Info * tse_info)1060 void CDataSource::x_UnindexSeqTSE(const CSeq_id_Handle& id,
1061                                   CTSE_Info* tse_info)
1062 {
1063     // no need to lock as it's locked by callers
1064     TMainLock::TWriteLockGuard guard(m_DSMainLock);
1065     x_UnindexTSE(m_TSE_seq, id, tse_info);
1066 }
1067 
1068 
x_IndexAnnotTSE(const CSeq_id_Handle & id,CTSE_Info * tse_info,bool orphan)1069 void CDataSource::x_IndexAnnotTSE(const CSeq_id_Handle& id,
1070                                   CTSE_Info* tse_info,
1071                                   bool orphan)
1072 {
1073     TAnnotLock::TWriteLockGuard guard(m_DSAnnotLock);
1074     x_IndexTSE(orphan? m_TSE_orphan_annot: m_TSE_seq_annot, id, tse_info);
1075 }
1076 
1077 
x_UnindexAnnotTSE(const CSeq_id_Handle & id,CTSE_Info * tse_info,bool orphan)1078 void CDataSource::x_UnindexAnnotTSE(const CSeq_id_Handle& id,
1079                                     CTSE_Info* tse_info,
1080                                     bool orphan)
1081 {
1082     TAnnotLock::TWriteLockGuard guard(m_DSAnnotLock);
1083     x_UnindexTSE(orphan? m_TSE_orphan_annot: m_TSE_seq_annot, id, tse_info);
1084 }
1085 
1086 
x_IndexAnnotTSEs(CTSE_Info * tse_info)1087 void CDataSource::x_IndexAnnotTSEs(CTSE_Info* tse_info)
1088 {
1089     TAnnotLock::TWriteLockGuard guard(m_DSAnnotLock);
1090     ITERATE ( CTSE_Info::TIdAnnotInfoMap, it, tse_info->m_IdAnnotInfoMap ) {
1091         x_IndexTSE(it->second.m_Orphan? m_TSE_orphan_annot: m_TSE_seq_annot,
1092                    it->first, tse_info);
1093     }
1094     if ( tse_info->x_DirtyAnnotIndex() ) {
1095         _VERIFY(m_DirtyAnnot_TSEs.insert(Ref(tse_info)).second);
1096     }
1097 }
1098 
1099 
x_UnindexAnnotTSEs(CTSE_Info * tse_info)1100 void CDataSource::x_UnindexAnnotTSEs(CTSE_Info* tse_info)
1101 {
1102     TAnnotLock::TWriteLockGuard guard(m_DSAnnotLock);
1103     ITERATE ( CTSE_Info::TIdAnnotInfoMap, it, tse_info->m_IdAnnotInfoMap ) {
1104         x_UnindexTSE(it->second.m_Orphan? m_TSE_orphan_annot: m_TSE_seq_annot,
1105                      it->first, tse_info);
1106     }
1107 }
1108 
1109 
x_CleanupUnusedEntries(void)1110 void CDataSource::x_CleanupUnusedEntries(void)
1111 {
1112 }
1113 
1114 
1115 
1116 CDataSource::TTSE_Lock
x_FindBestTSE(const CSeq_id_Handle & handle,const TTSE_LockSet & load_locks)1117 CDataSource::x_FindBestTSE(const CSeq_id_Handle& handle,
1118                            const TTSE_LockSet& load_locks)
1119 {
1120     TTSE_LockSet all_tse;
1121     {{
1122         TMainLock::TReadLockGuard guard(m_DSMainLock);
1123 #ifdef DEBUG_MAPS
1124         debug::CReadGuard<TSeq_id2TSE_Set> g1(m_TSE_seq);
1125 #endif
1126         TSeq_id2TSE_Set::const_iterator tse_set = m_TSE_seq.find(handle);
1127         if ( tse_set == m_TSE_seq.end() ) {
1128             return TTSE_Lock();
1129         }
1130 #ifdef DEBUG_MAPS
1131         debug::CReadGuard<TTSE_Set> g2(tse_set->second);
1132 #endif
1133         ITERATE ( TTSE_Set, it, tse_set->second ) {
1134             TTSE_Lock tse = x_LockTSE(**it, load_locks, fLockNoThrow);
1135             if ( tse ) {
1136                 all_tse.PutLock(tse);
1137             }
1138         }
1139     }}
1140     CDataLoader::TTSE_LockSet best_set = all_tse.GetBestTSEs();
1141     if ( best_set.empty() ) {
1142         // No TSE matches
1143         return TTSE_Lock();
1144     }
1145     CDataLoader::TTSE_LockSet::const_iterator it = best_set.begin();
1146     _ASSERT(it != best_set.end());
1147     if ( ++it == best_set.end() ) {
1148         // Only one TSE matches
1149         return *best_set.begin();
1150     }
1151 
1152     // We have multiple best TSEs
1153     if ( m_Loader ) {
1154         TTSE_Lock best = GetDataLoader()->ResolveConflict(handle, best_set);
1155         if ( best ) {
1156             // conflict resolved by data loader
1157             return best;
1158         }
1159     }
1160     // Cannot resolve conflict
1161     NCBI_THROW_FMT(CObjMgrException, eFindConflict,
1162                    "Multiple seq-id matches found for "<<handle);
1163 }
1164 
1165 
x_GetSeqMatch(const CSeq_id_Handle & idh,const TTSE_LockSet & locks)1166 SSeqMatch_DS CDataSource::x_GetSeqMatch(const CSeq_id_Handle& idh,
1167                                         const TTSE_LockSet& locks)
1168 {
1169     SSeqMatch_DS ret;
1170     ret.m_TSE_Lock = x_FindBestTSE(idh, locks);
1171     if ( ret.m_TSE_Lock ) {
1172         ret.m_Seq_id = idh;
1173         ret.m_Bioseq = ret.m_TSE_Lock->FindBioseq(ret.m_Seq_id);
1174         _ASSERT(ret);
1175     }
1176     else if ( idh.HaveMatchingHandles() ) {
1177         // Try to find the best matching id (not exactly equal)
1178         CSeq_id_Handle::TMatches hset;
1179         idh.GetMatchingHandles(hset, eAllowWeakMatch);
1180         ITERATE ( CSeq_id_Handle::TMatches, hit, hset ) {
1181             if ( *hit == idh ) // already checked
1182                 continue;
1183             if ( ret && ret.m_Seq_id.IsBetter(*hit) ) // worse hit
1184                 continue;
1185             ITERATE ( TTSE_LockSet, it, locks ) {
1186                 it->second->x_GetRecords(*hit, true);
1187             }
1188             TTSE_Lock new_tse = x_FindBestTSE(*hit, locks);
1189             if ( new_tse ) {
1190                 ret.m_TSE_Lock = new_tse;
1191                 ret.m_Seq_id = *hit;
1192                 ret.m_Bioseq = ret.m_TSE_Lock->FindBioseq(ret.m_Seq_id);
1193                 _ASSERT(ret);
1194             }
1195         }
1196     }
1197     return ret;
1198 }
1199 
1200 
x_GetSeqMatch(const CSeq_id_Handle & idh)1201 SSeqMatch_DS CDataSource::x_GetSeqMatch(const CSeq_id_Handle& idh)
1202 {
1203     TTSE_LockSet locks;
1204     try {
1205         return x_GetSeqMatch(idh, locks);
1206     }
1207     catch ( CObjMgrException& exc ) {
1208         if ( !m_Loader || exc.GetErrCode() != exc.eFindConflict ) {
1209             throw;
1210         }
1211     }
1212     return SSeqMatch_DS();
1213 }
1214 
1215 
BestResolve(const CSeq_id_Handle & idh)1216 SSeqMatch_DS CDataSource::BestResolve(const CSeq_id_Handle& idh)
1217 {
1218     return x_GetSeqMatch(idh, x_GetRecords(idh, CDataLoader::eBioseqCore));
1219 }
1220 
1221 
GetMatches(const CSeq_id_Handle & idh,const TTSE_LockSet & history)1222 CDataSource::TSeqMatches CDataSource::GetMatches(const CSeq_id_Handle& idh,
1223                                                  const TTSE_LockSet& history)
1224 {
1225     TSeqMatches ret;
1226 
1227     if ( !history.empty() ) {
1228         TMainLock::TReadLockGuard guard(m_DSMainLock);
1229         TSeq_id2TSE_Set::const_iterator tse_set = m_TSE_seq.find(idh);
1230         if ( tse_set != m_TSE_seq.end() ) {
1231             ITERATE ( TTSE_Set, it, tse_set->second ) {
1232                 TTSE_Lock tse_lock = history.FindLock(*it);
1233                 if ( !tse_lock ) {
1234                     continue;
1235                 }
1236                 SSeqMatch_DS match(tse_lock, idh);
1237                 _ASSERT(match);
1238                 ret.push_back(match);
1239             }
1240         }
1241     }
1242 
1243     return ret;
1244 }
1245 
1246 
GetIds(const CSeq_id_Handle & idh,TIds & ids)1247 void CDataSource::GetIds(const CSeq_id_Handle& idh, TIds& ids)
1248 {
1249     SSeqMatch_DS match = x_GetSeqMatch(idh);
1250     if ( match ) {
1251         ids = match.m_Bioseq->GetId();
1252         return;
1253     }
1254     // Bioseq not found - try to request ids from loader if any.
1255     if ( m_Loader ) {
1256         m_Loader->GetIds(idh, ids);
1257     }
1258 }
1259 
1260 
GetAccVer(const CSeq_id_Handle & idh)1261 CDataSource::SAccVerFound CDataSource::GetAccVer(const CSeq_id_Handle& idh)
1262 {
1263     SAccVerFound ret;
1264     SSeqMatch_DS match = x_GetSeqMatch(idh);
1265     if ( match ) {
1266         ret.acc_ver = CScope::x_GetAccVer(match.m_Bioseq->GetId());
1267         ret.sequence_found = true;
1268     }
1269     else if ( m_Loader ) {
1270         ret = m_Loader->GetAccVerFound(idh);
1271     }
1272     return ret;
1273 }
1274 
1275 
GetGi(const CSeq_id_Handle & idh)1276 CDataSource::SGiFound CDataSource::GetGi(const CSeq_id_Handle& idh)
1277 {
1278     SGiFound ret;
1279     SSeqMatch_DS match = x_GetSeqMatch(idh);
1280     if ( match ) {
1281         ret.gi = CScope::x_GetGi(match.m_Bioseq->GetId());
1282         ret.sequence_found = true;
1283     }
1284     else if ( m_Loader ) {
1285         ret = m_Loader->GetGiFound(idh);
1286     }
1287     return ret;
1288 }
1289 
1290 
GetLabel(const CSeq_id_Handle & idh)1291 string CDataSource::GetLabel(const CSeq_id_Handle& idh)
1292 {
1293     string ret;
1294     try {
1295         TTSE_LockSet locks;
1296         if ( SSeqMatch_DS match = x_GetSeqMatch(idh, locks) ) {
1297             ret = objects::GetLabel(match.m_Bioseq->GetId());
1298         }
1299     }
1300     catch ( CObjMgrException& /*exc*/ ) {
1301         if ( !m_Loader ) {
1302             throw;
1303         }
1304     }
1305     if ( m_Loader ) {
1306         ret = m_Loader->GetLabel(idh);
1307     }
1308     return ret;
1309 }
1310 
1311 
GetTaxId(const CSeq_id_Handle & idh)1312 TTaxId CDataSource::GetTaxId(const CSeq_id_Handle& idh)
1313 {
1314     TTaxId ret = INVALID_TAX_ID;
1315     SSeqMatch_DS match = x_GetSeqMatch(idh);
1316     if ( match ) {
1317         ret = match.m_Bioseq->GetTaxId();
1318     }
1319     else if ( m_Loader ) {
1320         ret = m_Loader->GetTaxId(idh);
1321     }
1322     return ret;
1323 }
1324 
1325 
GetSequenceLength(const CSeq_id_Handle & idh)1326 TSeqPos CDataSource::GetSequenceLength(const CSeq_id_Handle& idh)
1327 {
1328     TSeqPos ret = kInvalidSeqPos;
1329     SSeqMatch_DS match = x_GetSeqMatch(idh);
1330     if ( match ) {
1331         ret = match.m_Bioseq->GetBioseqLength();
1332     }
1333     else if ( m_Loader ) {
1334         ret = m_Loader->GetSequenceLength(idh);
1335     }
1336     return ret;
1337 }
1338 
1339 
1340 CDataSource::STypeFound
GetSequenceType(const CSeq_id_Handle & idh)1341 CDataSource::GetSequenceType(const CSeq_id_Handle& idh)
1342 {
1343     STypeFound ret;
1344     SSeqMatch_DS match = x_GetSeqMatch(idh);
1345     if ( match ) {
1346         ret.type = match.m_Bioseq->GetInst_Mol();
1347         ret.sequence_found = true;
1348     }
1349     else if ( m_Loader ) {
1350         ret = m_Loader->GetSequenceTypeFound(idh);
1351     }
1352     return ret;
1353 }
1354 
1355 
GetSequenceState(const CSeq_id_Handle & idh)1356 int CDataSource::GetSequenceState(const CSeq_id_Handle& idh)
1357 {
1358     int ret = CBioseq_Handle::fState_not_found|CBioseq_Handle::fState_no_data;
1359     SSeqMatch_DS match = x_GetSeqMatch(idh);
1360     if ( match ) {
1361         ret = match.m_Bioseq->GetTSE_Info().GetBlobState();
1362     }
1363     else if ( m_Loader ) {
1364         ret = m_Loader->GetSequenceState(idh);
1365     }
1366     return ret;
1367 }
1368 
1369 
GetAccVers(const TIds & ids,TLoaded & loaded,TIds & ret)1370 void CDataSource::GetAccVers(const TIds& ids, TLoaded& loaded, TIds& ret)
1371 {
1372     size_t count = ids.size(), remaining = 0;
1373     _ASSERT(ids.size() == loaded.size());
1374     _ASSERT(ids.size() == ret.size());
1375     for ( size_t i = 0; i < count; ++i ) {
1376         if ( loaded[i] ) {
1377             continue;
1378         }
1379         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1380         if ( match ) {
1381             ret[i] = CScope::x_GetAccVer(match.m_Bioseq->GetId());
1382             loaded[i] = true;
1383         }
1384         else {
1385             ++remaining;
1386         }
1387     }
1388     if ( remaining && m_Loader ) {
1389         m_Loader->GetAccVers(ids, loaded, ret);
1390     }
1391 }
1392 
1393 
GetGis(const TIds & ids,TLoaded & loaded,TGis & ret)1394 void CDataSource::GetGis(const TIds& ids, TLoaded& loaded, TGis& ret)
1395 {
1396     size_t count = ids.size(), remaining = 0;
1397     _ASSERT(ids.size() == loaded.size());
1398     _ASSERT(ids.size() == ret.size());
1399     for ( size_t i = 0; i < count; ++i ) {
1400         if ( loaded[i] ) {
1401             continue;
1402         }
1403         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1404         if ( match ) {
1405             ret[i] = CScope::x_GetGi(match.m_Bioseq->GetId());
1406             loaded[i] = true;
1407         }
1408         else {
1409             ++remaining;
1410         }
1411     }
1412     if ( remaining && m_Loader ) {
1413         m_Loader->GetGis(ids, loaded, ret);
1414     }
1415 }
1416 
1417 
GetLabels(const TIds & ids,TLoaded & loaded,TLabels & ret)1418 void CDataSource::GetLabels(const TIds& ids, TLoaded& loaded, TLabels& ret)
1419 {
1420     size_t count = ids.size(), remaining = 0;
1421     _ASSERT(ids.size() == loaded.size());
1422     _ASSERT(ids.size() == ret.size());
1423     for ( size_t i = 0; i < count; ++i ) {
1424         if ( loaded[i] ) {
1425             continue;
1426         }
1427         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1428         if ( match ) {
1429             ret[i] = objects::GetLabel(match.m_Bioseq->GetId());
1430             loaded[i] = true;
1431         }
1432         else {
1433             ++remaining;
1434         }
1435     }
1436     if ( remaining && m_Loader ) {
1437         m_Loader->GetLabels(ids, loaded, ret);
1438     }
1439 }
1440 
1441 
GetTaxIds(const TIds & ids,TLoaded & loaded,TTaxIds & ret)1442 void CDataSource::GetTaxIds(const TIds& ids, TLoaded& loaded, TTaxIds& ret)
1443 {
1444     size_t count = ids.size(), remaining = 0;
1445     _ASSERT(ids.size() == loaded.size());
1446     _ASSERT(ids.size() == ret.size());
1447     for ( size_t i = 0; i < count; ++i ) {
1448         if ( loaded[i] ) {
1449             continue;
1450         }
1451         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1452         if ( match ) {
1453             ret[i] = match.m_Bioseq->GetTaxId();
1454             loaded[i] = true;
1455         }
1456         else {
1457             ++remaining;
1458         }
1459     }
1460     if ( remaining && m_Loader ) {
1461         m_Loader->GetTaxIds(ids, loaded, ret);
1462     }
1463 }
1464 
1465 
GetSequenceLengths(const TIds & ids,TLoaded & loaded,TSequenceLengths & ret)1466 void CDataSource::GetSequenceLengths(const TIds& ids, TLoaded& loaded,
1467                                      TSequenceLengths& ret)
1468 {
1469     size_t count = ids.size(), remaining = 0;
1470     _ASSERT(ids.size() == loaded.size());
1471     _ASSERT(ids.size() == ret.size());
1472     for ( size_t i = 0; i < count; ++i ) {
1473         if ( loaded[i] ) {
1474             continue;
1475         }
1476         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1477         if ( match ) {
1478             ret[i] = match.m_Bioseq->GetBioseqLength();
1479             loaded[i] = true;
1480         }
1481         else {
1482             ++remaining;
1483         }
1484     }
1485     if ( remaining && m_Loader ) {
1486         m_Loader->GetSequenceLengths(ids, loaded, ret);
1487     }
1488 }
1489 
1490 
GetSequenceTypes(const TIds & ids,TLoaded & loaded,TSequenceTypes & ret)1491 void CDataSource::GetSequenceTypes(const TIds& ids, TLoaded& loaded,
1492                                    TSequenceTypes& ret)
1493 {
1494     size_t count = ids.size(), remaining = 0;
1495     _ASSERT(ids.size() == loaded.size());
1496     _ASSERT(ids.size() == ret.size());
1497     for ( size_t i = 0; i < count; ++i ) {
1498         if ( loaded[i] ) {
1499             continue;
1500         }
1501         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1502         if ( match ) {
1503             ret[i] = match.m_Bioseq->GetInst_Mol();
1504             loaded[i] = true;
1505         }
1506         else {
1507             ++remaining;
1508         }
1509     }
1510     if ( remaining && m_Loader ) {
1511         m_Loader->GetSequenceTypes(ids, loaded, ret);
1512     }
1513 }
1514 
1515 
GetSequenceStates(const TIds & ids,TLoaded & loaded,TSequenceStates & ret)1516 void CDataSource::GetSequenceStates(const TIds& ids, TLoaded& loaded,
1517                                     TSequenceStates& ret)
1518 {
1519     size_t count = ids.size(), remaining = 0;
1520     _ASSERT(ids.size() == loaded.size());
1521     _ASSERT(ids.size() == ret.size());
1522     for ( size_t i = 0; i < count; ++i ) {
1523         if ( loaded[i] ) {
1524             continue;
1525         }
1526         SSeqMatch_DS match = x_GetSeqMatch(ids[i]);
1527         if ( match ) {
1528             ret[i] = match.m_Bioseq->GetTSE_Info().GetBlobState();
1529             loaded[i] = true;
1530         }
1531         else {
1532             ++remaining;
1533         }
1534     }
1535     if ( remaining && m_Loader ) {
1536         m_Loader->GetSequenceStates(ids, loaded, ret);
1537     }
1538 }
1539 
1540 
1541 CDataSource::SHashFound
GetSequenceHash(const CSeq_id_Handle & idh)1542 CDataSource::GetSequenceHash(const CSeq_id_Handle& idh)
1543 {
1544     SHashFound ret;
1545     if ( m_Loader ) {
1546         ret = m_Loader->GetSequenceHashFound(idh);
1547     }
1548     return ret;
1549 }
1550 
1551 
GetSequenceHashes(const TIds & ids,TLoaded & loaded,TSequenceHashes & ret,THashKnown & known)1552 void CDataSource::GetSequenceHashes(const TIds& ids, TLoaded& loaded,
1553                                     TSequenceHashes& ret, THashKnown& known)
1554 {
1555     if ( m_Loader ) {
1556         m_Loader->GetSequenceHashes(ids, loaded, ret, known);
1557     }
1558 }
1559 
1560 
GetBlobs(TSeqMatchMap & match_map)1561 void CDataSource::GetBlobs(TSeqMatchMap& match_map)
1562 {
1563     if ( match_map.empty() ) {
1564         return;
1565     }
1566     if ( m_Loader ) {
1567         CDataLoader::TTSE_LockSets tse_sets;
1568         ITERATE(TSeqMatchMap, match, match_map) {
1569             _ASSERT( !match->second );
1570             tse_sets.insert(tse_sets.end(),
1571                 CDataLoader::TTSE_LockSets::value_type(
1572                 match->first, CDataLoader::TTSE_LockSet()));
1573         }
1574         m_Loader->GetBlobs(tse_sets);
1575         ITERATE(CDataLoader::TTSE_LockSets, tse_set, tse_sets) {
1576             TTSE_LockSet locks;
1577             ITERATE(CDataLoader::TTSE_LockSet, it, tse_set->second) {
1578                 locks.AddLock(*it);
1579                 (*it)->x_GetRecords(tse_set->first, true);
1580             }
1581             TSeqMatchMap::iterator match = match_map.find(tse_set->first);
1582             _ASSERT(match != match_map.end()  &&  !match->second);
1583             match->second = x_GetSeqMatch(tse_set->first, locks);
1584         }
1585     }
1586     else {
1587         NON_CONST_ITERATE(TSeqMatchMap, it, match_map) {
1588             if ( !it->second ) {
1589                 it->second = BestResolve(it->first);
1590             }
1591         }
1592     }
1593 }
1594 
1595 
GetName(void) const1596 string CDataSource::GetName(void) const
1597 {
1598     if ( m_Loader )
1599         return m_Loader->GetName();
1600     else
1601         return kEmptyStr;
1602 }
1603 
1604 
GetBioseqs(const CSeq_entry_Info & entry,TBioseq_InfoSet & bioseqs,CSeq_inst::EMol filter,TBioseqLevelFlag level)1605 void CDataSource::GetBioseqs(const CSeq_entry_Info& entry,
1606                              TBioseq_InfoSet& bioseqs,
1607                              CSeq_inst::EMol filter,
1608                              TBioseqLevelFlag level)
1609 {
1610     // Find TSE_Info
1611     x_CollectBioseqs(entry, bioseqs, filter, level);
1612 }
1613 
1614 
x_CollectBioseqs(const CSeq_entry_Info & info,TBioseq_InfoSet & bioseqs,CSeq_inst::EMol filter,TBioseqLevelFlag level)1615 void CDataSource::x_CollectBioseqs(const CSeq_entry_Info& info,
1616                                    TBioseq_InfoSet& bioseqs,
1617                                    CSeq_inst::EMol filter,
1618                                    TBioseqLevelFlag level)
1619 {
1620     // parts should be changed to all before adding bioseqs to the list
1621     if ( info.IsSeq() ) {
1622         const CBioseq_Info& seq = info.GetSeq();
1623         if ( level != CBioseq_CI::eLevel_Parts &&
1624              (filter == CSeq_inst::eMol_not_set ||
1625               seq.GetInst_Mol() == filter) ) {
1626             bioseqs.push_back(ConstRef(&seq));
1627         }
1628     }
1629     else {
1630         const CBioseq_set_Info& set = info.GetSet();
1631         ITERATE( CBioseq_set_Info::TSeq_set, it, set.GetSeq_set() ) {
1632             const CSeq_entry_Info& sub_info = **it;
1633             TBioseqLevelFlag local_level = level;
1634             if ( sub_info.IsSet() &&
1635                  sub_info.GetSet().GetClass() == CBioseq_set::eClass_parts ) {
1636                 switch (level) {
1637                 case CBioseq_CI::eLevel_Mains:
1638                     // Skip parts
1639                     continue;
1640                 case CBioseq_CI::eLevel_Parts:
1641                     // Allow adding bioseqs from lower levels
1642                     local_level = CBioseq_CI::eLevel_All;
1643                     break;
1644                 default:
1645                     break;
1646                 }
1647             }
1648             x_CollectBioseqs(sub_info, bioseqs, filter, local_level);
1649         }
1650     }
1651 }
1652 
1653 
1654 #if !defined(NCBI_NO_THREADS)
Prefetch(CPrefetchTokenOld_Impl & token)1655 void CDataSource::Prefetch(CPrefetchTokenOld_Impl& token)
1656 {
1657     if (!m_PrefetchThread) {
1658         CFastMutexGuard guard(m_PrefetchLock);
1659         // Check againi
1660         if (!m_PrefetchThread) {
1661             m_PrefetchThread.Reset(new CPrefetchThreadOld(*this));
1662             m_PrefetchThread->Run();
1663         }
1664     }
1665     _ASSERT(m_PrefetchThread);
1666     m_PrefetchThread->AddRequest(token);
1667 }
1668 #else
Prefetch(CPrefetchTokenOld_Impl &)1669 void CDataSource::Prefetch(CPrefetchTokenOld_Impl& /* token */)
1670 {
1671 }
1672 #endif
1673 
1674 
x_LockTSE(const CTSE_Info & tse_info,const TTSE_LockSet & locks,TLockFlags flags)1675 CDataSource::TTSE_Lock CDataSource::x_LockTSE(const CTSE_Info& tse_info,
1676                                               const TTSE_LockSet& locks,
1677                                               TLockFlags flags)
1678 {
1679     TTSE_Lock ret;
1680     _ASSERT(tse_info.Referenced());
1681     if ( (flags & fLockNoHistory) == 0 ) {
1682         ret = locks.FindLock(&tse_info);
1683         if ( ret ) {
1684             return ret;
1685         }
1686     }
1687     if ( (flags & fLockNoManual) == 0 ) {
1688         ret = m_StaticBlobs.FindLock(&tse_info);
1689         if ( ret ) {
1690             return ret;
1691         }
1692     }
1693     if ( (flags & fLockNoThrow) == 0 ) {
1694         NCBI_THROW(CObjMgrException, eOtherError,
1695                    "CDataSource::x_LockTSE: cannot find in locks");
1696     }
1697     return ret;
1698 }
1699 
1700 
1701 class CTSE_LoadLockGuard : public CObject
1702 {
1703 public:
CTSE_LoadLockGuard(CDataSource * ds,CTSE_Info::CLoadMutex * mutex)1704     CTSE_LoadLockGuard(CDataSource* ds, CTSE_Info::CLoadMutex* mutex)
1705         : m_DataSource(ds), m_Mutex(mutex), m_Guard(*mutex), m_Waiting(false)
1706         {
1707         }
~CTSE_LoadLockGuard(void)1708     ~CTSE_LoadLockGuard(void)
1709         {
1710             Release();
1711         }
1712 
Release(void)1713     void Release(void)
1714         {
1715             if ( m_Mutex ) {
1716                 if ( !m_Waiting ) {
1717                     m_Mutex->m_LoadWait.SignalAll();
1718                 }
1719                 m_Guard.Release();
1720                 m_Mutex.Reset();
1721             }
1722         }
1723 
WaitForSignal(const CDeadline & deadline)1724     bool WaitForSignal(const CDeadline& deadline)
1725         {
1726             m_Waiting = true;
1727             return m_Mutex->m_LoadWait.WaitForSignal(*m_Mutex, deadline);
1728         }
1729 
GetDataSource(void) const1730     CRef<CDataSource> GetDataSource(void) const
1731         {
1732             return m_DataSource;
1733         }
1734 
1735 private:
1736     CRef<CDataSource>   m_DataSource;
1737     CRef<CTSE_Info::CLoadMutex>  m_Mutex;
1738     CMutexGuard     m_Guard;
1739     bool m_Waiting;
1740 
1741 private:
1742     CTSE_LoadLockGuard(const CTSE_LoadLockGuard&);
1743     CTSE_LoadLockGuard operator=(const CTSE_LoadLockGuard&);
1744 };
1745 
1746 
GetTSE_LoadLock(const TBlobId & blob_id)1747 CTSE_LoadLock CDataSource::GetTSE_LoadLock(const TBlobId& blob_id)
1748 {
1749     _ASSERT(blob_id);
1750     CTSE_LoadLock ret;
1751     {{
1752         CTSE_Lock lock;
1753         CRef<CTSE_Info::CLoadMutex> load_mutex;
1754         {{
1755             TCacheLock::TWriteLockGuard guard(m_DSCacheLock);
1756             TTSE_Ref& slot = m_Blob_Map[blob_id];
1757             if ( !slot ) {
1758                 slot.Reset(new CTSE_Info(blob_id));
1759                 _ASSERT(!IsLoaded(*slot));
1760                 _ASSERT(!slot->m_LoadMutex);
1761                 slot->m_LoadMutex.Reset(new CTSE_Info::CLoadMutex);
1762             }
1763             x_SetLock(lock, slot);
1764             load_mutex = lock->m_LoadMutex;
1765         }}
1766         x_SetLoadLock(ret, const_cast<CTSE_Info&>(*lock), load_mutex);
1767     }}
1768     return ret;
1769 }
1770 
1771 
GetTSE_LoadLockIfLoaded(const TBlobId & blob_id)1772 CTSE_LoadLock CDataSource::GetTSE_LoadLockIfLoaded(const TBlobId& blob_id)
1773 {
1774     _ASSERT(blob_id);
1775     CTSE_LoadLock ret;
1776     {{
1777         CTSE_Lock lock;
1778         {{
1779             TCacheLock::TWriteLockGuard guard(m_DSCacheLock);
1780             TBlob_Map::const_iterator iter = m_Blob_Map.find(blob_id);
1781             if ( iter == m_Blob_Map.end() || !iter->second ||
1782                  !IsLoaded(*iter->second) ) {
1783                 return ret;
1784             }
1785             x_SetLock(lock, iter->second);
1786         }}
1787         _ASSERT(lock);
1788         _ASSERT(IsLoaded(*lock));
1789         ret.m_DataSource.Reset(this);
1790         TSE_LOCK_TRACE("TSE_LoadLock("<<&*lock<<") "<<&lock<<" lock");
1791         _VERIFY(lock->m_LockCounter.Add(1) > 1);
1792         ret.m_Info = const_cast<CTSE_Info*>(lock.GetNonNullPointer());
1793     }}
1794     return ret;
1795 }
1796 
1797 
GetLoadedTSE_Lock(const TBlobId & blob_id,const CTimeout & timeout)1798 CTSE_LoadLock CDataSource::GetLoadedTSE_Lock(const TBlobId& blob_id, const CTimeout& timeout)
1799 {
1800     CTSE_LoadLock lock = GetTSE_LoadLock(blob_id);
1801     if ( IsLoaded(*lock) ) {
1802         return lock;
1803     }
1804     CDeadline deadline(timeout);
1805     while ( lock.x_GetGuard().WaitForSignal(deadline) ) {
1806         if ( IsLoaded(*lock) ) {
1807             return lock;
1808         }
1809     }
1810     if ( IsLoaded(*lock) ) {
1811         return lock;
1812     }
1813     return CTSE_LoadLock();
1814 }
1815 
1816 
IsLoaded(const CTSE_Info & tse) const1817 bool CDataSource::IsLoaded(const CTSE_Info& tse) const
1818 {
1819     return tse.m_LoadState != CTSE_Info::eNotLoaded;
1820 }
1821 
1822 
SetLoaded(CTSE_LoadLock & lock)1823 void CDataSource::SetLoaded(CTSE_LoadLock& lock)
1824 {
1825     {{
1826         TMainLock::TWriteLockGuard guard(m_DSMainLock);
1827         _ASSERT(lock);
1828         _ASSERT(lock.m_Info);
1829         _ASSERT(!IsLoaded(*lock));
1830         _ASSERT(lock.m_LoadLock);
1831         _ASSERT(!lock->HasDataSource());
1832         CDSDetachGuard detach_guard;
1833         detach_guard.Attach(this, &*lock);
1834     }}
1835     {{
1836         TCacheLock::TWriteLockGuard guard2(m_DSCacheLock);
1837         lock->m_LoadState = CTSE_Info::eLoaded;
1838         lock->m_LoadMutex.Reset();
1839     }}
1840     lock.ReleaseLoadLock();
1841 }
1842 
1843 
x_ReleaseLastTSELock(CRef<CTSE_Info> tse)1844 void CDataSource::x_ReleaseLastTSELock(CRef<CTSE_Info> tse)
1845 {
1846     if ( !m_Loader ) {
1847         // keep in cache only when loader is used
1848         return;
1849     }
1850     _ASSERT(tse);
1851     vector<TTSE_Ref> to_delete;
1852     {{
1853         TCacheLock::TWriteLockGuard guard(m_DSCacheLock);
1854         if ( tse->IsLocked() ) { // already locked again
1855             return;
1856         }
1857         if ( !IsLoaded(*tse) ) { // not loaded yet
1858             _ASSERT(!tse->HasDataSource());
1859             return;
1860         }
1861         if ( !tse->HasDataSource() ) { // already released
1862             return;
1863         }
1864         _ASSERT(&tse->GetDataSource() == this);
1865 
1866         if ( tse->m_CacheState != CTSE_Info::eInCache ) {
1867             _ASSERT(find(m_Blob_Cache.begin(), m_Blob_Cache.end(), tse) ==
1868                     m_Blob_Cache.end());
1869             tse->m_CachePosition = m_Blob_Cache.insert(m_Blob_Cache.end(),tse);
1870             m_Blob_Cache_Size += 1;
1871             _ASSERT(m_Blob_Cache_Size == m_Blob_Cache.size());
1872             tse->m_CacheState = CTSE_Info::eInCache;
1873         }
1874         _ASSERT(tse->m_CachePosition ==
1875                 find(m_Blob_Cache.begin(), m_Blob_Cache.end(), tse));
1876         _ASSERT(m_Blob_Cache_Size == m_Blob_Cache.size());
1877 
1878         unsigned cache_size = m_Blob_Cache_Size_Limit;
1879         while ( m_Blob_Cache_Size > cache_size ) {
1880             CRef<CTSE_Info> del_tse = m_Blob_Cache.front();
1881             m_Blob_Cache.pop_front();
1882             m_Blob_Cache_Size -= 1;
1883             _ASSERT(m_Blob_Cache_Size == m_Blob_Cache.size());
1884             del_tse->m_CacheState = CTSE_Info::eNotInCache;
1885             to_delete.push_back(del_tse);
1886             _VERIFY(DropTSE(*del_tse));
1887         }
1888     }}
1889 }
1890 
1891 
x_SetLock(CTSE_Lock & lock,CConstRef<CTSE_Info> tse) const1892 void CDataSource::x_SetLock(CTSE_Lock& lock, CConstRef<CTSE_Info> tse) const
1893 {
1894     _ASSERT(!lock);
1895     _ASSERT(tse);
1896     lock.m_Info.Reset(&*tse);
1897     TSE_LOCK_TRACE("TSE_Lock("<<&*tse<<") "<<&lock<<" lock");
1898     if ( tse->m_LockCounter.Add(1) != 1 ) {
1899         return;
1900     }
1901 
1902     TCacheLock::TWriteLockGuard guard(m_DSCacheLock);
1903     if ( tse->m_CacheState == CTSE_Info::eInCache ) {
1904         _ASSERT(tse->m_CachePosition ==
1905                 find(m_Blob_Cache.begin(), m_Blob_Cache.end(), tse));
1906         tse->m_CacheState = CTSE_Info::eNotInCache;
1907         m_Blob_Cache.erase(tse->m_CachePosition);
1908         m_Blob_Cache_Size -= 1;
1909         _ASSERT(m_Blob_Cache_Size == m_Blob_Cache.size());
1910     }
1911 
1912     _ASSERT(find(m_Blob_Cache.begin(), m_Blob_Cache.end(), tse) ==
1913             m_Blob_Cache.end());
1914 }
1915 
1916 
x_SetLoadLock(CTSE_LoadLock & load,CTSE_Lock & lock)1917 void CDataSource::x_SetLoadLock(CTSE_LoadLock& load, CTSE_Lock& lock)
1918 {
1919     _ASSERT(lock && !load);
1920     _ASSERT(lock->IsLocked());
1921     load.m_DataSource.Reset(this);
1922     load.m_Info.Reset(const_cast<CTSE_Info*>(lock.GetNonNullPointer()));
1923     TSE_LOCK_TRACE("TSE_LoadLock("<<&*load<<") "<<&load<<" lock");
1924     load.m_Info->m_LockCounter.Add(1);
1925     if ( !IsLoaded(*load) ) {
1926         _ASSERT(load->m_LoadMutex);
1927         load.m_LoadLock.Reset(new CTSE_LoadLockGuard(this, load->m_LoadMutex));
1928         if ( IsLoaded(*load) ) {
1929             load.ReleaseLoadLock();
1930         }
1931     }
1932 }
1933 
1934 
x_SetLoadLock(CTSE_LoadLock & load,CTSE_Info & tse,CRef<CTSE_Info::CLoadMutex> load_mutex)1935 void CDataSource::x_SetLoadLock(CTSE_LoadLock& load,
1936                                 CTSE_Info& tse,
1937                                 CRef<CTSE_Info::CLoadMutex> load_mutex)
1938 {
1939     _ASSERT(!load);
1940     _ASSERT(tse.IsLocked());
1941     load.m_DataSource.Reset(this);
1942     TSE_LOCK_TRACE("TSE_LoadLock("<<&tse<<") "<<&load<<" lock");
1943     _VERIFY(tse.m_LockCounter.Add(1) > 1);
1944     load.m_Info.Reset(&tse);
1945     if ( !IsLoaded(tse) ) {
1946         _ASSERT(load_mutex);
1947         load.m_LoadLock.Reset(new CTSE_LoadLockGuard(this, load_mutex));
1948         if ( IsLoaded(tse) ) {
1949             load.ReleaseLoadLock();
1950         }
1951     }
1952 }
1953 
1954 
x_ReleaseLastLock(CTSE_Lock & lock)1955 void CDataSource::x_ReleaseLastLock(CTSE_Lock& lock)
1956 {
1957     CRef<CTSE_Info> info(const_cast<CTSE_Info*>(lock.GetNonNullPointer()));
1958     lock.m_Info.Reset();
1959     x_ReleaseLastTSELock(info);
1960 }
1961 
1962 
x_ReleaseLastLoadLock(CTSE_LoadLock & lock)1963 void CDataSource::x_ReleaseLastLoadLock(CTSE_LoadLock& lock)
1964 {
1965     CRef<CTSE_Info> info = lock.m_Info;
1966     if ( info->m_LoadState == CTSE_Info::eNotLoaded ) {
1967         // reset TSE info into empty state
1968         info->x_Reset();
1969     }
1970     lock.m_Info.Reset();
1971     lock.m_DataSource.Reset();
1972     x_ReleaseLastTSELock(info);
1973 }
1974 
1975 
x_Assign(const CTSE_LoadLock & load_lock)1976 void CTSE_Lock::x_Assign(const CTSE_LoadLock& load_lock)
1977 {
1978     _ASSERT(load_lock);
1979     _ASSERT(load_lock.IsLoaded());
1980     x_Relock(&*load_lock);
1981 }
1982 
1983 
operator =(const CTSE_LoadLock & lock)1984 CTSE_LoadLock& CTSE_LoadLock::operator=(const CTSE_LoadLock& lock)
1985 {
1986     if ( this != &lock ) {
1987         Reset();
1988         m_Info = lock.m_Info;
1989         m_DataSource = lock.m_DataSource;
1990         m_LoadLock = lock.m_LoadLock;
1991         if ( *this ) {
1992             TSE_LOCK_TRACE("TSE_LoadLock("<<&*lock<<") "<<this<<" lock");
1993             m_Info->m_LockCounter.Add(1);
1994         }
1995     }
1996     return *this;
1997 }
1998 
1999 
IsLoaded(void) const2000 bool CTSE_LoadLock::IsLoaded(void) const
2001 {
2002     return m_DataSource->IsLoaded(**this);
2003 }
2004 
2005 
SetLoaded(void)2006 void CTSE_LoadLock::SetLoaded(void)
2007 {
2008     _ASSERT(m_LoadLock);
2009     _ASSERT(!IsLoaded());
2010     _ASSERT(m_Info->m_LoadMutex);
2011     m_DataSource->SetLoaded(*this);
2012 }
2013 
2014 
Reset(void)2015 void CTSE_LoadLock::Reset(void)
2016 {
2017     ReleaseLoadLock();
2018     if ( *this ) {
2019         TSE_LOCK_TRACE("TSE_LoadLock("<<&**this<<") "<<this<<" unlock");
2020         if ( m_Info->m_LockCounter.Add(-1) == 0 ) {
2021             m_DataSource->x_ReleaseLastLoadLock(*this);
2022             _ASSERT(!*this);
2023             _ASSERT(!m_DataSource);
2024         }
2025         else {
2026             m_Info.Reset();
2027             m_DataSource.Reset();
2028         }
2029     }
2030 }
2031 
2032 
ReleaseLoadLock(void)2033 void CTSE_LoadLock::ReleaseLoadLock(void)
2034 {
2035     if ( m_LoadLock ) {
2036         if ( IsLoaded() ) {
2037             x_GetGuard().Release();
2038         }
2039         m_LoadLock.Reset();
2040     }
2041 }
2042 
2043 
x_Drop(void)2044 void CTSE_Lock::x_Drop(void)
2045 {
2046     _ASSERT(*this);
2047     const CTSE_Info* info = GetNonNullPointer();
2048     TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" drop");
2049     _VERIFY(info->m_LockCounter.Add(-1) == 0);
2050     m_Info.Reset();
2051 }
2052 
2053 
Swap(CTSE_Lock & lock)2054 void CTSE_Lock::Swap(CTSE_Lock& lock)
2055 {
2056 #ifdef TSE_LOCK_NO_SWAP
2057     CTSE_Lock tmp(lock);
2058     lock = *this;
2059     *this = tmp;
2060 #else
2061     m_Info.Swap(lock.m_Info);
2062 #endif
2063 }
2064 
2065 
x_Unlock(void)2066 void CTSE_Lock::x_Unlock(void)
2067 {
2068     _ASSERT(*this);
2069     const CTSE_Info* info = GetNonNullPointer();
2070     TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" unlock");
2071     CDataSource* ds = info->HasDataSource() ? &info->GetDataSource() : 0;
2072     if ( info->m_LockCounter.Add(-1) == 0 ) {
2073         _ASSERT(ds);
2074         ds->x_ReleaseLastLock(*this);
2075         _ASSERT(!*this);
2076     }
2077     else {
2078         m_Info.Reset();
2079     }
2080 }
2081 
2082 
x_Lock(const CTSE_Info * info)2083 bool CTSE_Lock::x_Lock(const CTSE_Info* info)
2084 {
2085     _ASSERT(!*this && info);
2086     m_Info.Reset(info);
2087     TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" lock");
2088     return info->m_LockCounter.Add(1) == 1;
2089 }
2090 
2091 
x_Relock(const CTSE_Info * info)2092 void CTSE_Lock::x_Relock(const CTSE_Info* info)
2093 {
2094     _ASSERT(!*this && info);
2095     _ASSERT(info->m_LockCounter.Get() != 0);
2096     m_Info.Reset(info);
2097     TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" lock");
2098     info->m_LockCounter.Add(1);
2099 }
2100 
2101 
clear(void)2102 void CTSE_LockSet::clear(void)
2103 {
2104     m_TSE_LockSet.clear();
2105 }
2106 
2107 
Drop(void)2108 void CTSE_LockSet::Drop(void)
2109 {
2110     NON_CONST_ITERATE ( TTSE_LockSet, it, m_TSE_LockSet ) {
2111         it->second.Drop();
2112     }
2113     m_TSE_LockSet.clear();
2114 }
2115 
2116 
FindLock(const CTSE_Info * info) const2117 CTSE_Lock CTSE_LockSet::FindLock(const CTSE_Info* info) const
2118 {
2119     TTSE_LockSet::const_iterator it = m_TSE_LockSet.find(info);
2120     if ( it == m_TSE_LockSet.end() ) {
2121         return CTSE_Lock();
2122     }
2123     return it->second;
2124 }
2125 
2126 
AddLock(const CTSE_Lock & lock)2127 bool CTSE_LockSet::AddLock(const CTSE_Lock& lock)
2128 {
2129     m_TSE_LockSet[&*lock] = lock;
2130     return true;
2131 }
2132 
2133 
PutLock(CTSE_Lock & lock)2134 bool CTSE_LockSet::PutLock(CTSE_Lock& lock)
2135 {
2136     m_TSE_LockSet[&*lock].Swap(lock);
2137     return true;
2138 }
2139 
2140 
RemoveLock(const CTSE_Lock & lock)2141 bool CTSE_LockSet::RemoveLock(const CTSE_Lock& lock)
2142 {
2143     return m_TSE_LockSet.erase(&*lock) != 0;
2144 }
2145 
2146 
RemoveLock(const CTSE_Info * info)2147 bool CTSE_LockSet::RemoveLock(const CTSE_Info* info)
2148 {
2149     return m_TSE_LockSet.erase(info) != 0;
2150 }
2151 
2152 
GetBestTSEs(void) const2153 CDataLoader::TTSE_LockSet CTSE_LockSet::GetBestTSEs(void) const
2154 {
2155     CDataLoader::TTSE_LockSet ret;
2156     ITERATE ( TTSE_LockSet, it, m_TSE_LockSet ) {
2157         if ( !ret.empty() ) {
2158             if ( IsBetter(**ret.begin(), *it->first) ) {
2159                 continue;
2160             }
2161             else if ( IsBetter(*it->first, **ret.begin()) ) {
2162                 ret.clear();
2163             }
2164         }
2165         ret.insert(it->second);
2166     }
2167     return ret;
2168 }
2169 
2170 
IsBetter(const CTSE_Info & tse1,const CTSE_Info & tse2)2171 bool CTSE_LockSet::IsBetter(const CTSE_Info& tse1,
2172                             const CTSE_Info& tse2)
2173 {
2174     return tse1.GetBlobOrder() < tse2.GetBlobOrder();
2175 }
2176 
2177 
2178 
2179 END_SCOPE(objects)
2180 END_NCBI_SCOPE
2181