1 /* $Id: data_source.cpp 634759 2021-07-19 12:30:16Z 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, 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 ret.first = m_Loader->GetBlobById(blob_id);
424 TMainLock::TWriteLockGuard guard(m_DSMainLock);
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 CThread::GetSystemID(&load.m_LoadLockOwner);
1928 load.m_LoadLock.Reset(new CTSE_LoadLockGuard(this, load->m_LoadMutex));
1929 if ( IsLoaded(*load) ) {
1930 load.ReleaseLoadLock();
1931 }
1932 }
1933 }
1934
1935
x_SetLoadLock(CTSE_LoadLock & load,CTSE_Info & tse,CRef<CTSE_Info::CLoadMutex> load_mutex)1936 void CDataSource::x_SetLoadLock(CTSE_LoadLock& load,
1937 CTSE_Info& tse,
1938 CRef<CTSE_Info::CLoadMutex> load_mutex)
1939 {
1940 _ASSERT(!load);
1941 _ASSERT(tse.IsLocked());
1942 load.m_DataSource.Reset(this);
1943 TSE_LOCK_TRACE("TSE_LoadLock("<<&tse<<") "<<&load<<" lock");
1944 _VERIFY(tse.m_LockCounter.Add(1) > 1);
1945 load.m_Info.Reset(&tse);
1946 if ( !IsLoaded(tse) ) {
1947 _ASSERT(load_mutex);
1948 CThread::GetSystemID(&load.m_LoadLockOwner);
1949 load.m_LoadLock.Reset(new CTSE_LoadLockGuard(this, load_mutex));
1950 if ( IsLoaded(tse) ) {
1951 load.ReleaseLoadLock();
1952 }
1953 }
1954 }
1955
1956
x_ReleaseLastLock(CTSE_Lock & lock)1957 void CDataSource::x_ReleaseLastLock(CTSE_Lock& lock)
1958 {
1959 CRef<CTSE_Info> info(const_cast<CTSE_Info*>(lock.GetNonNullPointer()));
1960 lock.m_Info.Reset();
1961 x_ReleaseLastTSELock(info);
1962 }
1963
1964
x_ReleaseLastLoadLock(CTSE_LoadLock & lock)1965 void CDataSource::x_ReleaseLastLoadLock(CTSE_LoadLock& lock)
1966 {
1967 CRef<CTSE_Info> info = lock.m_Info;
1968 if ( info->m_LoadState == CTSE_Info::eNotLoaded ) {
1969 // reset TSE info into empty state
1970 info->x_Reset();
1971 }
1972 lock.m_Info.Reset();
1973 lock.m_DataSource.Reset();
1974 x_ReleaseLastTSELock(info);
1975 }
1976
1977
x_Assign(const CTSE_LoadLock & load_lock)1978 void CTSE_Lock::x_Assign(const CTSE_LoadLock& load_lock)
1979 {
1980 _ASSERT(load_lock);
1981 _ASSERT(load_lock.IsLoaded());
1982 x_Relock(&*load_lock);
1983 }
1984
1985
operator =(const CTSE_LoadLock & lock)1986 CTSE_LoadLock& CTSE_LoadLock::operator=(const CTSE_LoadLock& lock)
1987 {
1988 if ( this != &lock ) {
1989 Reset();
1990 m_Info = lock.m_Info;
1991 m_DataSource = lock.m_DataSource;
1992 m_LoadLockOwner = lock.m_LoadLockOwner;
1993 m_LoadLock = lock.m_LoadLock;
1994 if ( *this ) {
1995 TSE_LOCK_TRACE("TSE_LoadLock("<<&*lock<<") "<<this<<" lock");
1996 m_Info->m_LockCounter.Add(1);
1997 }
1998 }
1999 return *this;
2000 }
2001
2002
IsLoaded(void) const2003 bool CTSE_LoadLock::IsLoaded(void) const
2004 {
2005 return m_DataSource->IsLoaded(**this);
2006 }
2007
2008
SetLoaded(void)2009 void CTSE_LoadLock::SetLoaded(void)
2010 {
2011 _ASSERT(m_LoadLock);
2012 _ASSERT(!IsLoaded());
2013 _ASSERT(m_Info->m_LoadMutex);
2014 m_DataSource->SetLoaded(*this);
2015 }
2016
2017
Reset(void)2018 void CTSE_LoadLock::Reset(void)
2019 {
2020 ReleaseLoadLock();
2021 if ( *this ) {
2022 TSE_LOCK_TRACE("TSE_LoadLock("<<&**this<<") "<<this<<" unlock");
2023 if ( m_Info->m_LockCounter.Add(-1) == 0 ) {
2024 m_DataSource->x_ReleaseLastLoadLock(*this);
2025 _ASSERT(!*this);
2026 _ASSERT(!m_DataSource);
2027 }
2028 else {
2029 m_Info.Reset();
2030 m_DataSource.Reset();
2031 }
2032 }
2033 }
2034
2035
ReleaseLoadLock(void)2036 void CTSE_LoadLock::ReleaseLoadLock(void)
2037 {
2038 if ( m_LoadLock ) {
2039 if ( IsLoaded() ) {
2040 TThreadSystemID current;
2041 CThread::GetSystemID(¤t);
2042 if ( m_LoadLockOwner == current ) {
2043 x_GetGuard().Release();
2044 }
2045 }
2046 m_LoadLock.Reset();
2047 }
2048 }
2049
2050
x_Drop(void)2051 void CTSE_Lock::x_Drop(void)
2052 {
2053 _ASSERT(*this);
2054 const CTSE_Info* info = GetNonNullPointer();
2055 TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" drop");
2056 _VERIFY(info->m_LockCounter.Add(-1) == 0);
2057 m_Info.Reset();
2058 }
2059
2060
Swap(CTSE_Lock & lock)2061 void CTSE_Lock::Swap(CTSE_Lock& lock)
2062 {
2063 #ifdef TSE_LOCK_NO_SWAP
2064 CTSE_Lock tmp(lock);
2065 lock = *this;
2066 *this = tmp;
2067 #else
2068 m_Info.Swap(lock.m_Info);
2069 #endif
2070 }
2071
2072
x_Unlock(void)2073 void CTSE_Lock::x_Unlock(void)
2074 {
2075 _ASSERT(*this);
2076 const CTSE_Info* info = GetNonNullPointer();
2077 TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" unlock");
2078 CDataSource* ds = info->HasDataSource() ? &info->GetDataSource() : 0;
2079 if ( info->m_LockCounter.Add(-1) == 0 ) {
2080 _ASSERT(ds);
2081 ds->x_ReleaseLastLock(*this);
2082 _ASSERT(!*this);
2083 }
2084 else {
2085 m_Info.Reset();
2086 }
2087 }
2088
2089
x_Lock(const CTSE_Info * info)2090 bool CTSE_Lock::x_Lock(const CTSE_Info* info)
2091 {
2092 _ASSERT(!*this && info);
2093 m_Info.Reset(info);
2094 TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" lock");
2095 return info->m_LockCounter.Add(1) == 1;
2096 }
2097
2098
x_Relock(const CTSE_Info * info)2099 void CTSE_Lock::x_Relock(const CTSE_Info* info)
2100 {
2101 _ASSERT(!*this && info);
2102 _ASSERT(info->m_LockCounter.Get() != 0);
2103 m_Info.Reset(info);
2104 TSE_LOCK_TRACE("TSE_Lock("<<info<<") "<<this<<" lock");
2105 info->m_LockCounter.Add(1);
2106 }
2107
2108
clear(void)2109 void CTSE_LockSet::clear(void)
2110 {
2111 m_TSE_LockSet.clear();
2112 }
2113
2114
Drop(void)2115 void CTSE_LockSet::Drop(void)
2116 {
2117 NON_CONST_ITERATE ( TTSE_LockSet, it, m_TSE_LockSet ) {
2118 it->second.Drop();
2119 }
2120 m_TSE_LockSet.clear();
2121 }
2122
2123
FindLock(const CTSE_Info * info) const2124 CTSE_Lock CTSE_LockSet::FindLock(const CTSE_Info* info) const
2125 {
2126 TTSE_LockSet::const_iterator it = m_TSE_LockSet.find(info);
2127 if ( it == m_TSE_LockSet.end() ) {
2128 return CTSE_Lock();
2129 }
2130 return it->second;
2131 }
2132
2133
AddLock(const CTSE_Lock & lock)2134 bool CTSE_LockSet::AddLock(const CTSE_Lock& lock)
2135 {
2136 m_TSE_LockSet[&*lock] = lock;
2137 return true;
2138 }
2139
2140
PutLock(CTSE_Lock & lock)2141 bool CTSE_LockSet::PutLock(CTSE_Lock& lock)
2142 {
2143 m_TSE_LockSet[&*lock].Swap(lock);
2144 return true;
2145 }
2146
2147
RemoveLock(const CTSE_Lock & lock)2148 bool CTSE_LockSet::RemoveLock(const CTSE_Lock& lock)
2149 {
2150 return m_TSE_LockSet.erase(&*lock) != 0;
2151 }
2152
2153
RemoveLock(const CTSE_Info * info)2154 bool CTSE_LockSet::RemoveLock(const CTSE_Info* info)
2155 {
2156 return m_TSE_LockSet.erase(info) != 0;
2157 }
2158
2159
GetBestTSEs(void) const2160 CDataLoader::TTSE_LockSet CTSE_LockSet::GetBestTSEs(void) const
2161 {
2162 CDataLoader::TTSE_LockSet ret;
2163 ITERATE ( TTSE_LockSet, it, m_TSE_LockSet ) {
2164 if ( !ret.empty() ) {
2165 if ( IsBetter(**ret.begin(), *it->first) ) {
2166 continue;
2167 }
2168 else if ( IsBetter(*it->first, **ret.begin()) ) {
2169 ret.clear();
2170 }
2171 }
2172 ret.insert(it->second);
2173 }
2174 return ret;
2175 }
2176
2177
IsBetter(const CTSE_Info & tse1,const CTSE_Info & tse2)2178 bool CTSE_LockSet::IsBetter(const CTSE_Info& tse1,
2179 const CTSE_Info& tse2)
2180 {
2181 return tse1.GetBlobOrder() < tse2.GetBlobOrder();
2182 }
2183
2184
2185
2186 END_SCOPE(objects)
2187 END_NCBI_SCOPE
2188