1 /* $Id: scope_info.cpp 630071 2021-04-26 17:10:15Z 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 * Authors:
27 * Eugene Vasilchenko
28 *
29 * File Description:
30 * Structures used by CScope
31 *
32 */
33
34 #include <ncbi_pch.hpp>
35 #include <objmgr/impl/scope_info.hpp>
36 #include <objmgr/impl/scope_impl.hpp>
37 #include <objmgr/scope.hpp>
38
39 #include <objmgr/impl/synonyms.hpp>
40 #include <objmgr/impl/data_source.hpp>
41
42 #include <objmgr/impl/tse_info.hpp>
43 #include <objmgr/tse_handle.hpp>
44 #include <objmgr/impl/seq_entry_info.hpp>
45 #include <objmgr/seq_entry_handle.hpp>
46 #include <objmgr/impl/seq_annot_info.hpp>
47 #include <objmgr/seq_annot_handle.hpp>
48 #include <objmgr/impl/bioseq_info.hpp>
49 #include <objmgr/bioseq_handle.hpp>
50 #include <objmgr/impl/bioseq_set_info.hpp>
51 #include <objmgr/bioseq_set_handle.hpp>
52
53 #include <corelib/ncbi_param.hpp>
54 #include <algorithm>
55
56 BEGIN_NCBI_SCOPE
57 BEGIN_SCOPE(objects)
58
59 #if 0
60 # define _TRACE_TSE_LOCK(x) _TRACE(x)
61 #else
62 # define _TRACE_TSE_LOCK(x) ((void)0)
63 #endif
64
65
66 NCBI_PARAM_DECL(bool, OBJMGR, SCOPE_AUTORELEASE);
67 NCBI_PARAM_DEF_EX(bool, OBJMGR, SCOPE_AUTORELEASE, true,
68 eParam_NoThread, OBJMGR_SCOPE_AUTORELEASE);
69
s_GetScopeAutoReleaseEnabled(void)70 static bool s_GetScopeAutoReleaseEnabled(void)
71 {
72 static CSafeStatic<NCBI_PARAM_TYPE(OBJMGR, SCOPE_AUTORELEASE)> sx_Value;
73 return sx_Value->Get();
74 }
75
76
77 NCBI_PARAM_DECL(unsigned, OBJMGR, SCOPE_AUTORELEASE_SIZE);
78 NCBI_PARAM_DEF_EX(unsigned, OBJMGR, SCOPE_AUTORELEASE_SIZE, 10,
79 eParam_NoThread, OBJMGR_SCOPE_AUTORELEASE_SIZE);
80
s_GetScopeAutoReleaseSize(void)81 static unsigned s_GetScopeAutoReleaseSize(void)
82 {
83 static CSafeStatic<NCBI_PARAM_TYPE(OBJMGR, SCOPE_AUTORELEASE_SIZE)> sx_Value;
84 return sx_Value->Get();
85 }
86
87
88 NCBI_PARAM_DECL(int, OBJMGR, SCOPE_POSTPONE_DELETE);
89 NCBI_PARAM_DEF_EX(int, OBJMGR, SCOPE_POSTPONE_DELETE, 1,
90 eParam_NoThread, OBJMGR_SCOPE_POSTPONE_DELETE);
91
s_GetScopePostponeDelete(void)92 static int s_GetScopePostponeDelete(void)
93 {
94 static CSafeStatic<NCBI_PARAM_TYPE(OBJMGR, SCOPE_POSTPONE_DELETE)> sx_Value;
95 return sx_Value->Get();
96 }
97
98
99 DEFINE_STATIC_FAST_MUTEX(sx_UsedTSEMutex);
100
101
102 /////////////////////////////////////////////////////////////////////////////
103 // CDataSource_ScopeInfo
104 /////////////////////////////////////////////////////////////////////////////
105
CDataSource_ScopeInfo(CScope_Impl & scope,CDataSource & ds)106 CDataSource_ScopeInfo::CDataSource_ScopeInfo(CScope_Impl& scope,
107 CDataSource& ds)
108 : m_Scope(&scope),
109 m_DataSource(&ds),
110 m_CanBeUnloaded(s_GetScopeAutoReleaseEnabled() &&
111 ds.GetDataLoader() &&
112 ds.GetDataLoader()->CanGetBlobById()),
113 m_CanBeEdited(ds.CanBeEdited()),
114 m_CanRemoveOnResetHistory(false),
115 m_NextTSEIndex(0),
116 m_TSE_UnlockQueue(s_GetScopeAutoReleaseSize())
117 {
118 }
119
120
~CDataSource_ScopeInfo(void)121 CDataSource_ScopeInfo::~CDataSource_ScopeInfo(void)
122 {
123 _ASSERT(!m_Scope);
124 _ASSERT(!m_DataSource);
125 }
126
127
GetScopeImpl(void) const128 CScope_Impl& CDataSource_ScopeInfo::GetScopeImpl(void) const
129 {
130 if ( !m_Scope ) {
131 NCBI_THROW(CCoreException, eNullPtr,
132 "CDataSource_ScopeInfo is not attached to CScope");
133 }
134 return *m_Scope;
135 }
136
137
GetDataLoader(void)138 CDataLoader* CDataSource_ScopeInfo::GetDataLoader(void)
139 {
140 return GetDataSource().GetDataLoader();
141 }
142
143
IsConst(void) const144 bool CDataSource_ScopeInfo::IsConst(void) const
145 {
146 return !CanBeEdited() && GetDataSource().CanBeEdited();
147 }
148
149
SetConst(void)150 void CDataSource_ScopeInfo::SetConst(void)
151 {
152 _ASSERT(CanBeEdited());
153 _ASSERT(GetDataSource().CanBeEdited());
154 m_CanBeEdited = false;
155 _ASSERT(IsConst());
156 }
157
158
SetCanRemoveOnResetHistory(void)159 void CDataSource_ScopeInfo::SetCanRemoveOnResetHistory(void)
160 {
161 _ASSERT(CanBeEdited());
162 _ASSERT(GetDataSource().CanBeEdited());
163 m_CanRemoveOnResetHistory = true;
164 _ASSERT(CanRemoveOnResetHistory());
165 }
166
167
DetachScope(void)168 void CDataSource_ScopeInfo::DetachScope(void)
169 {
170 if ( m_Scope ) {
171 _ASSERT(m_DataSource);
172 ResetDS();
173 GetScopeImpl().m_ObjMgr->ReleaseDataSource(m_DataSource);
174 _ASSERT(!m_DataSource);
175 m_Scope = 0;
176 }
177 }
178
179
180 const CDataSource_ScopeInfo::TTSE_InfoMap&
GetTSE_InfoMap(void) const181 CDataSource_ScopeInfo::GetTSE_InfoMap(void) const
182 {
183 return m_TSE_InfoMap;
184 }
185
186
187 const CDataSource_ScopeInfo::TTSE_LockSet&
GetTSE_LockSet(void) const188 CDataSource_ScopeInfo::GetTSE_LockSet(void) const
189 {
190 return m_TSE_LockSet;
191 }
192
193
194 static DECLARE_TLS_VAR(CUnlockedTSEsGuard*, st_Guard);
195
196
CUnlockedTSEsGuard(void)197 CUnlockedTSEsGuard::CUnlockedTSEsGuard(void)
198 {
199 if ( !st_Guard ) {
200 st_Guard = this;
201 }
202 }
203
204
~CUnlockedTSEsGuard(void)205 CUnlockedTSEsGuard::~CUnlockedTSEsGuard(void)
206 {
207 if ( st_Guard == this ) {
208 while ( !m_UnlockedTSEsInternal.empty() ) {
209 TUnlockedTSEsInternal locks;
210 swap(m_UnlockedTSEsInternal, locks);
211 }
212 while ( !m_UnlockedTSEsLock.empty() ) {
213 TUnlockedTSEsLock locks;
214 swap(m_UnlockedTSEsLock, locks);
215 }
216 st_Guard = 0;
217 }
218 }
219
220
SaveLock(const CTSE_Lock & lock)221 void CUnlockedTSEsGuard::SaveLock(const CTSE_Lock& lock)
222 {
223 if ( !s_GetScopePostponeDelete() ) {
224 return;
225 }
226 _ASSERT(st_Guard);
227 if ( CUnlockedTSEsGuard* guard = st_Guard ) {
228 guard->m_UnlockedTSEsLock.push_back(ConstRef(&*lock));
229 }
230 }
231
232
SaveInternal(const CTSE_ScopeInternalLock & lock)233 void CUnlockedTSEsGuard::SaveInternal(const CTSE_ScopeInternalLock& lock)
234 {
235 if ( !s_GetScopePostponeDelete() ) {
236 return;
237 }
238 _ASSERT(st_Guard);
239 if ( CUnlockedTSEsGuard* guard = st_Guard ) {
240 guard->m_UnlockedTSEsInternal.push_back(lock);
241 }
242 }
243
244
SaveInternal(const TUnlockedTSEsInternal & locks)245 void CUnlockedTSEsGuard::SaveInternal(const TUnlockedTSEsInternal& locks)
246 {
247 if ( !s_GetScopePostponeDelete() ) {
248 return;
249 }
250 _ASSERT(st_Guard);
251 if ( CUnlockedTSEsGuard* guard = st_Guard ) {
252 guard->m_UnlockedTSEsInternal.insert
253 (guard->m_UnlockedTSEsInternal.end(), locks.begin(), locks.end());
254 }
255 }
256
257
RemoveTSE_Lock(const CTSE_Lock & lock)258 void CDataSource_ScopeInfo::RemoveTSE_Lock(const CTSE_Lock& lock)
259 {
260 CUnlockedTSEsGuard::SaveLock(lock);
261 TTSE_LockSetMutex::TWriteLockGuard guard(m_TSE_LockSetMutex);
262 _VERIFY(m_TSE_LockSet.RemoveLock(lock));
263 }
264
265
AddTSE_Lock(const CTSE_Lock & lock)266 void CDataSource_ScopeInfo::AddTSE_Lock(const CTSE_Lock& lock)
267 {
268 TTSE_LockSetMutex::TWriteLockGuard guard(m_TSE_LockSetMutex);
269 _VERIFY(m_TSE_LockSet.AddLock(lock));
270 }
271
272 //
273 // CDataSource_ScopeInfo fields:
274 // m_TSE_InfoMap - history TSEs by their Blob-id, they may be unlocked with possibility to reload
275 // m_TSE_LockSet - all CTSE_Lock objects for lookup by CDataSource
276 // m_TSE_UnlockQueue - queue of CTSE_ScopeInternalLock ready to release their CTSE_Lock
277 // m_EditDS, m_ReplacedTSEs - edited entries support
278 //
279 // CTSE_ScopeInfo fields:
280 // m_ScopeInfoMap keeps track of sub-object ScopeInfo that's used in CSeq_entry_Handle and such.
281 // When new handle is created the ScopeInfo object is reused or created
282 // ScopeInfo objects are kept until m_TSE_Lock is being held
283 // Then m_TSE_Lock is released all ScopeInfo object are detached and released
284 // m_UsedTSE_Set rooted tree of dependent TSEs
285 // m_UsedByTSE parent pointer in the dependent TSEs tree
286 // The tree is cleared when internal lock is released,
287 // possibly causing release of internal locks of dependent TSEs.
288 //
289 // CScopeInfo<> fields:
290 // m_TSE_ScopeInfo - pointer to its TSE
291 // m_LockCounter - track count of corresponding handles
292 // m_TSE_Handle - holds TSE handle when m_LockCounter > 0
293 // m_ObjectInfo - pointer to CDataSource object
294 // m_DetachedInfo - mapping of sub-objects to CScopeInfo when object is removed from TSE (edit)
295 //
296 /////////////////////////////////////////////////////////////////////////////
297 // CScope TSE locking scheme.
298 //
299 // CTSE_ScopeUserLock is a link from user handles, it's also an internal lock.
300 //
301 // User lock maintains m_UserLockCounter, and when the last handle is deleted
302 // the TSE is put into m_TSE_UnlockQueue.
303 // The entries pushed out of m_TSE_UnlockQueue lose their internal lock.
304 //
305 // The TSE with user locks can be forcily released by explicit request:
306 // RemoveFromHistory(), RemoveDataLoader(), ResetHistory() etc.
307 // In this case all handles become invalidated - disconnected from scope.
308 // When a TSE is being forcily released the CTSE_ScopeInfo will remain
309 // as it may be referenced from other user-level handles, but the content
310 // of CTSE_ScopeInfo is cleared - info->IsAttached() == false.
311
312 // CTSE_ScopeInternalLock lock holds CTSE_Lock m_TSE_lock (in CDataSource).
313 //
314 // Internal locks are either links from user handles,
315 // links from another TSE (master to segments, sequence to external annots),
316 // or entries in m_TSE_UnlockQueue.
317 // Internal lock maintains m_TSE_LockCounter, and when the last internal lock
318 // is deleted the m_TSE_lock will be released if it's possible to reload
319 // the TSE later.
320 // When an internal lock is obtained it will be assigned with proper CTSE_Lock
321 // if necessary, which could involve reloading of entry from CDataLoader.
322
323 // So, possible states of CTSE_ScopeInfo are:
324 // 0 = Detached: detached from DS & Scope, can be only deleted
325 // m_DS_Info == null
326 // m_TSE_LockCounter >= 0
327 // m_UserLockCounter >= 0
328 // m_TSE_Lock == null
329 // m_UnloadedInfo == null
330 // m_UsedByTSE, m_UsedTSE_Set: empty
331 // m_ReplacedTSE == null
332 // m_BioseqById, m_ScopeInfoMap: empty
333 // not in m_TSE_UnlockQueue
334 // 1 = Unlocked: attached, unlocked, can be locked again
335 // m_DS_Info != null
336 // m_TSE_LockCounter == 0
337 // m_UserLockCounter == 0
338 // m_TSE_Lock, m_UnloadedInfo: exactly one of them is null
339 // m_UsedByTSE, m_UsedTSE_Set: empty
340 // m_ReplacedTSE
341 // m_BioseqById, m_ScopeInfoMap
342 // not in m_TSE_UnlockQueue
343 // 2 = InternalLocked: attached, locked, no user handle locks
344 // m_DS_Info != null
345 // m_TSE_LockCounter > 0
346 // m_UserLockCounter == 0
347 // m_TSE_Lock != null
348 // m_UnloadedInfo: any
349 // m_UsedByTSE, m_UsedTSE_Set: any
350 // m_ReplacedTSE: any
351 // m_BioseqById: any
352 // m_ScopeInfoMap: any
353 // may be m_TSE_UnlockQueue
354 // 3 = UserLocked: attached, locked, with user handle locks
355 // m_DS_Info != null
356 // m_TSE_LockCounter > 0
357 // m_UserLockCounter > 0
358 // m_TSE_Lock != null
359 // m_UnloadedInfo: any
360 // m_UsedByTSE, m_UsedTSE_Set: any
361 // m_ReplacedTSE: any
362 // m_BioseqById: any
363 // m_ScopeInfoMap: any
364 // not in m_TSE_UnlockQueue
365 //
366 // Notable conditions:
367 // (m_TSE_LockCounter == 0) => (not in m_TSE_UnlockQueue && not in UsedByTSE tree)
368 // (m_TSE_LockCounter > 0) => (m_TSE_Lock != null)
369 // (m_UserLockCounter > 0) => (not in m_TSE_UnlockQueue)
370 //
371 // TSE state changes:
372 // 3 -> 2 when last user handle is destroyed (m_UserLockCounter becomes zero).
373 // method - CTSE_ScopeUserLock -> CTSE_ScopeInternalLock
374 // : put it in unlock queue
375 // : possibly release TSE pushed out from unlock queue (via InternalLock mechanics)
376 // 2 -> 1 when last internal lock is released (e.g. pushed out of unlock queue).
377 // method - CTSE_ScopeInternalLock -> CRef<CTSE_ScopeInfo>(?)
378 // : release internal locks of used TSEs
379 // 1 -> 2 when internal lock is obtained (user handle or TSE dependency).
380 // method - CRef<CTSE_ScopeInfo> -> CTSE_ScopeInternalLock
381 // : aquire TSE lock if necessary
382 // 2 -> 3 when user handle is created
383 // method - CTSE_ScopeInternalLock -> CTSE_ScopeUserLock
384 // : remove from unlock queue
385 // 1,2,3 -> 0 when TSE is forcely released (RemoveFromHistory() or similar).
386 // method - CTSE_ScopeUserLock -> null
387 // 0 -> nothing
388 //
389 // CScopeObject states:
390 // 0 = Detached completely: detached from Scope, DS, and TSE
391 // m_TSE_ScopeInfo == null
392 // m_LockCounter: any (number of existing handles)
393 // m_TSE_Handle == null
394 // m_ObjectInfo == null
395 // m_DetachedInfo == null
396 // 1 = Detached: detached from Scope, DS, and TSE, can be reattached by user API
397 // m_TSE_ScopeInfo == null
398 // m_LockCounter: any (number of existing handles)
399 // m_TSE_Handle == null
400 // m_ObjectInfo != null
401 // m_DetachedInfo != null
402 // 2 = Unlocked: CScopeObject is allocated but not used in any handle
403 // m_TSE_ScopeInfo != null
404 // m_LockCounter == 0
405 // m_TSE_Handle == null
406 // m_ObjectInfo != null
407 // m_DetachedInfo == null
408 // 3 = UserLocked: there are handles to this object
409 // m_TSE_ScopeInfo != null
410 // m_LockCounter > 0
411 // m_TSE_Handle != null
412 // m_ObjectInfo != null
413 // m_DetachedInfo == null
414 //
415 // CScopeObject state changes:
416 // 3 -> 2 when last user handle is destroyed (m_LockCounter becomes zero).
417 // method - x_LastReferenceReleased()
418 // : clear m_TSE_Handle
419 // : release old TSE_Handle out of mutex lock
420 // 2 -> 3 when user handle is obtained
421 // methods - GetAnnotLock() etc
422 // : set m_TSE_Handle
423 // 3,2 -> 0 when TSE is removed from history
424 // method - RemoveFromHistory(tse)
425 // : clear m_TSE_Handle, m_TSE_ScopeInfo, m_ObjectInfo
426 // 3 -> 1 when the object is deleted from TSE (edit API)
427 // methods - RemoveAnnot() etc
428 // : information about all sub-objects is stored into m_DetachedInfo
429 // : clear m_TSE_Handle
430 // 1 -> 3 when the object is attached to a TSE (edit API)
431 // methods - AddAnnot() etc
432 // : set m_TSE_Handle
433 // : m_DetachedInfo is used to restore CScopeObject of sub-objects
434 // 0 -> nothing
435
436 // get user lock for a CTSE_Lock (in CDataSource)
437 // create CTSE_ScopeInfo if necessary
438 // preconditions:
439 // lock != null
440 // m_UserLockCounter >= 0 (any)
441
442
443 CTSE_ScopeUserLock
GetTSE_Lock(const CTSE_Lock & lock)444 CDataSource_ScopeInfo::GetTSE_Lock(const CTSE_Lock& lock)
445 {
446 CTSE_ScopeUserLock ret;
447 _ASSERT(lock);
448 if ( m_EditDS && TSEIsReplaced(lock->GetBlobId()) ) {
449 return ret;
450 }
451 TTSE_ScopeInfo info;
452 {{
453 TTSE_InfoMapMutex::TWriteLockGuard guard(m_TSE_InfoMapMutex);
454 TTSE_ScopeInfo& slot = m_TSE_InfoMap[lock->GetBlobId()];
455 if ( !slot ) {
456 slot = info = new CTSE_ScopeInfo(*this, lock,
457 m_NextTSEIndex++,
458 m_CanBeUnloaded);
459 if ( m_CanBeUnloaded ) {
460 // add this TSE into index by SeqId
461 x_IndexTSE(*info);
462 }
463 }
464 else {
465 info = slot;
466 }
467 _ASSERT(info->IsAttached() && &info->GetDSInfo() == this);
468 info->m_TSE_LockCounter.Add(1);
469 info->m_UserLockCounter.Add(1);
470 {{
471 // first remove the TSE from unlock queue
472 TTSE_LockSetMutex::TWriteLockGuard guard2(m_TSE_UnlockQueueMutex);
473 // TSE must be locked already by caller
474 _ASSERT(info->m_TSE_LockCounter.Get() > 0);
475 m_TSE_UnlockQueue.Erase(info);
476 // TSE must be still locked by caller even after removing it
477 // from unlock queue
478 _ASSERT(info->m_TSE_LockCounter.Get() > 0);
479 }}
480 info->SetTSE_Lock(lock);
481 ret.Reset(info);
482 _VERIFY(info->m_UserLockCounter.Add(-1) > 0);
483 _VERIFY(info->m_TSE_LockCounter.Add(-1) > 0);
484 _ASSERT(info->GetTSE_Lock() == lock);
485 }}
486 return ret;
487 }
488
489
AttachTSE(CTSE_ScopeInfo & info,const CTSE_Lock & lock)490 void CDataSource_ScopeInfo::AttachTSE(CTSE_ScopeInfo& info,
491 const CTSE_Lock& lock)
492 {
493 _ASSERT(m_CanBeUnloaded == info.CanBeUnloaded());
494 _ASSERT(!info.m_DS_Info);
495 _ASSERT(!info.m_TSE_Lock);
496 _ASSERT(lock && &lock->GetDataSource() == &GetDataSource());
497 TTSE_InfoMapMutex::TWriteLockGuard guard(m_TSE_InfoMapMutex);
498 _VERIFY(m_TSE_InfoMap.insert(TTSE_InfoMap::value_type
499 (lock->GetBlobId(),
500 //STSE_Key(*lock, m_CanBeUnloaded),
501 Ref(&info))).second);
502 if ( m_CanBeUnloaded ) {
503 // add this TSE into index by SeqId
504 x_IndexTSE(info);
505 }
506 info.m_DS_Info = this;
507 info.SetTSE_Lock(lock);
508 }
509
510
x_IndexTSE(CTSE_ScopeInfo & tse)511 void CDataSource_ScopeInfo::x_IndexTSE(CTSE_ScopeInfo& tse)
512 {
513 ITERATE ( CTSE_ScopeInfo::TSeqIds, it, tse.GetBioseqsIds() ) {
514 m_TSE_BySeqId.insert(TTSE_BySeqId::value_type(*it, Ref(&tse)));
515 }
516 }
517
518
x_UnindexTSE(const CTSE_ScopeInfo & tse)519 void CDataSource_ScopeInfo::x_UnindexTSE(const CTSE_ScopeInfo& tse)
520 {
521 ITERATE ( CTSE_ScopeInfo::TSeqIds, it, tse.GetBioseqsIds() ) {
522 TTSE_BySeqId::iterator tse_it = m_TSE_BySeqId.lower_bound(*it);
523 while ( tse_it != m_TSE_BySeqId.end() && tse_it->first == *it ) {
524 if ( tse_it->second == &tse ) {
525 m_TSE_BySeqId.erase(tse_it++);
526 }
527 else {
528 ++tse_it;
529 }
530 }
531 }
532 }
533
534
535 CDataSource_ScopeInfo::TTSE_ScopeInfo
x_FindBestTSEInIndex(const CSeq_id_Handle & idh) const536 CDataSource_ScopeInfo::x_FindBestTSEInIndex(const CSeq_id_Handle& idh) const
537 {
538 TTSE_ScopeInfo tse;
539 for ( TTSE_BySeqId::const_iterator it = m_TSE_BySeqId.lower_bound(idh);
540 it != m_TSE_BySeqId.end() && it->first == idh; ++it ) {
541 if ( !tse || x_IsBetter(idh, *it->second, *tse) ) {
542 tse = it->second;
543 }
544 }
545 return tse;
546 }
547
548
549 // Called by destructor of CTSE_ScopeUserLock when lock counter goes to 0
ReleaseTSEUserLock(CTSE_ScopeInfo & tse)550 void CDataSource_ScopeInfo::ReleaseTSEUserLock(CTSE_ScopeInfo& tse)
551 {
552 CUnlockedTSEsGuard guard;
553 {{
554 CTSE_ScopeInternalLock unlocked;
555 TTSE_LockSetMutex::TWriteLockGuard tse_guard(m_TSE_UnlockQueueMutex);
556 if ( tse.m_UserLockCounter.Get() > 0 ) {
557 // relocked already
558 return;
559 }
560 if ( !tse.GetTSE_Lock() ) {
561 // already unlocked
562 return;
563 }
564 m_TSE_UnlockQueue.Erase(&tse);
565 m_TSE_UnlockQueue.Put(&tse, CTSE_ScopeInternalLock(&tse), &unlocked);
566 if ( unlocked ) {
567 CUnlockedTSEsGuard::SaveInternal(unlocked);
568 }
569 }}
570 }
571
572
573 // Called when lock counter becomes non-zero
AcquireTSEUserLock(CTSE_ScopeInfo & tse)574 void CDataSource_ScopeInfo::AcquireTSEUserLock(CTSE_ScopeInfo& tse)
575 {
576 {{
577 // TODO: possible deadlock (1), m_TSE_UnlockQueueMutex is taken before m_TSE_LockMutex
578 TTSE_LockSetMutex::TWriteLockGuard tse_guard(m_TSE_UnlockQueueMutex);
579 m_TSE_UnlockQueue.Erase(&tse);
580 }}
581 if ( !tse.m_TSE_Lock ) {
582 CDataSource_ScopeInfo* ds = tse.m_DS_Info;
583 if ( !ds ) {
584 tse.m_UserLockCounter.Add(-1);
585 NCBI_THROW(CCoreException, eNullPtr,
586 "CTSE_ScopeInfo is not attached to CScope");
587 }
588 // obtain lock from CDataSource
589 CTSE_Lock lock = tse.m_UnloadedInfo->LockTSE();
590 _ASSERT(lock);
591 tse.SetTSE_Lock(lock);
592 _ASSERT(tse.GetTSE_Lock() == lock);
593 _ASSERT(tse.m_UserLockCounter.Get() > 0);
594 }
595 _ASSERT(tse.m_TSE_Lock);
596 }
597
598
599 // Called by destructor of CTSE_ScopeInternalLock when lock counter goes to 0
600 // CTSE_ScopeInternalLocks are stored in m_TSE_UnlockQueue
ForgetTSELock(CTSE_ScopeInfo & tse)601 void CDataSource_ScopeInfo::ForgetTSELock(CTSE_ScopeInfo& tse)
602 {
603 if ( tse.m_TSE_LockCounter.Get() > 0 ) {
604 // relocked already
605 return;
606 }
607 if ( !tse.GetTSE_Lock() ) {
608 // already unlocked
609 return;
610 }
611 CUnlockedTSEsGuard guard;
612 tse.ForgetTSE_Lock();
613 }
614
615
ResetDS(void)616 void CDataSource_ScopeInfo::ResetDS(void)
617 {
618 CUnlockedTSEsGuard guard;
619 TTSE_InfoMapMutex::TWriteLockGuard guard1(m_TSE_InfoMapMutex);
620 {{
621 TTSE_UnlockQueue::TUnlockSet unlocked;
622 {{
623 TTSE_LockSetMutex::TWriteLockGuard guard2(m_TSE_UnlockQueueMutex);
624 m_TSE_UnlockQueue.Clear(&unlocked);
625 }}
626 if ( !unlocked.empty() ) {
627 CUnlockedTSEsGuard::SaveInternal(unlocked);
628 }
629 }}
630 NON_CONST_ITERATE ( TTSE_InfoMap, it, m_TSE_InfoMap ) {
631 it->second->DropTSE_Lock();
632 it->second->x_DetachDS();
633 }
634 m_TSE_InfoMap.clear();
635 m_TSE_BySeqId.clear();
636 m_ReplacedTSEs.clear();
637 {{
638 TTSE_LockSetMutex::TWriteLockGuard guard2(m_TSE_LockSetMutex);
639 m_TSE_LockSet.clear();
640 }}
641 m_NextTSEIndex = 0;
642 }
643
644
ResetHistory(int action_if_locked)645 void CDataSource_ScopeInfo::ResetHistory(int action_if_locked)
646 {
647 if ( action_if_locked == CScope::eRemoveIfLocked ) {
648 // no checks -> fast reset
649 ResetDS();
650 return;
651 }
652 typedef vector< CRef<CTSE_ScopeInfo> > TTSEs;
653 TTSEs tses;
654 {{
655 TTSE_InfoMapMutex::TWriteLockGuard guard1(m_TSE_InfoMapMutex);
656 tses.reserve(m_TSE_InfoMap.size());
657 ITERATE ( TTSE_InfoMap, it, m_TSE_InfoMap ) {
658 if ( it->second->IsUserLocked() ) {
659 if ( action_if_locked == CScope::eKeepIfLocked ) {
660 // skip locked TSEs
661 continue;
662 }
663 if ( action_if_locked == CScope::eThrowIfLocked ) {
664 // there are locked TSEs
665 NCBI_THROW(CObjMgrException, eLockedData,
666 "Cannot reset scope's history "
667 "because TSE is locked");
668 }
669 }
670 tses.push_back(it->second);
671 }
672 }}
673 CUnlockedTSEsGuard guard;
674 ITERATE ( TTSEs, it, tses ) {
675 RemoveFromHistory(it->GetNCObject());
676 }
677 }
678
679
RemoveFromHistory(CTSE_ScopeInfo & tse,bool drop_from_ds)680 void CDataSource_ScopeInfo::RemoveFromHistory(CTSE_ScopeInfo& tse,
681 bool drop_from_ds)
682 {
683 tse.ReleaseUsedTSEs();
684 TTSE_InfoMapMutex::TWriteLockGuard guard1(m_TSE_InfoMapMutex);
685 if ( tse.CanBeUnloaded() ) {
686 x_UnindexTSE(tse);
687 }
688 tse.RestoreReplacedTSE();
689 _VERIFY(m_TSE_InfoMap.erase(tse.GetBlobId()));
690 // prevent storing into m_TSE_UnlockQueue
691 _VERIFY(tse.m_UserLockCounter.Add(1) > 0);
692 // remove TSE lock completely
693 {{
694 TTSE_LockSetMutex::TWriteLockGuard guard2(m_TSE_UnlockQueueMutex);
695 m_TSE_UnlockQueue.Erase(&tse);
696 }}
697 if ( CanRemoveOnResetHistory() ||
698 (drop_from_ds && GetDataSource().CanBeEdited()) ) {
699 // remove TSE from static blob set in DataSource
700 CConstRef<CTSE_Info> tse_info(&*tse.GetTSE_Lock());
701 tse.ResetTSE_Lock();
702 GetDataSource().DropStaticTSE(const_cast<CTSE_Info&>(*tse_info));
703 }
704 else {
705 tse.ResetTSE_Lock();
706 }
707 tse.x_DetachDS();
708 _VERIFY(tse.m_UserLockCounter.Add(-1) >= 0); // restore lock counter
709 _ASSERT(!tse.GetTSE_Lock());
710 _ASSERT(!tse.m_DS_Info);
711 }
712
713
714 CDataSource_ScopeInfo::TTSE_Lock
FindTSE_Lock(const CSeq_entry & tse)715 CDataSource_ScopeInfo::FindTSE_Lock(const CSeq_entry& tse)
716 {
717 CDataSource::TTSE_Lock lock;
718 {{
719 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
720 lock = GetDataSource().FindTSE_Lock(tse, m_TSE_LockSet);
721 }}
722 if ( lock ) {
723 return GetTSE_Lock(lock);
724 }
725 return TTSE_Lock();
726 }
727
728
729 CDataSource_ScopeInfo::TSeq_entry_Lock
GetSeq_entry_Lock(const CBlobIdKey & blob_id)730 CDataSource_ScopeInfo::GetSeq_entry_Lock(const CBlobIdKey& blob_id)
731 {
732 CDataSource::TSeq_entry_Lock lock;
733 {{
734 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
735 lock = GetDataSource().GetSeq_entry_Lock(blob_id);
736 }}
737 if ( lock.first ) {
738 return TSeq_entry_Lock(lock.first, GetTSE_Lock(lock.second));
739 }
740 return TSeq_entry_Lock();
741 }
742
743
744 CDataSource_ScopeInfo::TSeq_entry_Lock
FindSeq_entry_Lock(const CSeq_entry & entry)745 CDataSource_ScopeInfo::FindSeq_entry_Lock(const CSeq_entry& entry)
746 {
747 CDataSource::TSeq_entry_Lock lock;
748 {{
749 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
750 lock = GetDataSource().FindSeq_entry_Lock(entry, m_TSE_LockSet);
751 }}
752 if ( lock.first ) {
753 return TSeq_entry_Lock(lock.first, GetTSE_Lock(lock.second));
754 }
755 return TSeq_entry_Lock();
756 }
757
758
759 CDataSource_ScopeInfo::TSeq_annot_Lock
FindSeq_annot_Lock(const CSeq_annot & annot)760 CDataSource_ScopeInfo::FindSeq_annot_Lock(const CSeq_annot& annot)
761 {
762 CDataSource::TSeq_annot_Lock lock;
763 {{
764 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
765 lock = GetDataSource().FindSeq_annot_Lock(annot, m_TSE_LockSet);
766 }}
767 if ( lock.first ) {
768 return TSeq_annot_Lock(lock.first, GetTSE_Lock(lock.second));
769 }
770 return TSeq_annot_Lock();
771 }
772
773
774 CDataSource_ScopeInfo::TBioseq_set_Lock
FindBioseq_set_Lock(const CBioseq_set & seqset)775 CDataSource_ScopeInfo::FindBioseq_set_Lock(const CBioseq_set& seqset)
776 {
777 CDataSource::TBioseq_set_Lock lock;
778 {{
779 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
780 lock = GetDataSource().FindBioseq_set_Lock(seqset, m_TSE_LockSet);
781 }}
782 if ( lock.first ) {
783 return TBioseq_set_Lock(lock.first, GetTSE_Lock(lock.second));
784 }
785 return TBioseq_set_Lock();
786 }
787
788
789 CDataSource_ScopeInfo::TBioseq_Lock
FindBioseq_Lock(const CBioseq & bioseq)790 CDataSource_ScopeInfo::FindBioseq_Lock(const CBioseq& bioseq)
791 {
792 CDataSource::TBioseq_Lock lock;
793 {{
794 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
795 lock = GetDataSource().FindBioseq_Lock(bioseq, m_TSE_LockSet);
796 }}
797 if ( lock.first ) {
798 return GetTSE_Lock(lock.second)->GetBioseqLock(null, lock.first);
799 }
800 return TBioseq_Lock();
801 }
802
803
804 CDataSource_ScopeInfo::TSeq_feat_Lock
FindSeq_feat_Lock(const CSeq_id_Handle & loc_id,TSeqPos loc_pos,const CSeq_feat & feat)805 CDataSource_ScopeInfo::FindSeq_feat_Lock(const CSeq_id_Handle& loc_id,
806 TSeqPos loc_pos,
807 const CSeq_feat& feat)
808 {
809 TSeq_feat_Lock ret;
810 CDataSource::TSeq_feat_Lock lock;
811 {{
812 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
813 lock = GetDataSource().FindSeq_feat_Lock(loc_id, loc_pos, feat);
814 }}
815 if ( lock.first.first ) {
816 ret.first.first = lock.first.first;
817 ret.first.second = GetTSE_Lock(lock.first.second);
818 ret.second = lock.second;
819 }
820 return ret;
821 }
822
823
BestResolve(const CSeq_id_Handle & idh,int get_flag)824 SSeqMatch_Scope CDataSource_ScopeInfo::BestResolve(const CSeq_id_Handle& idh,
825 int get_flag)
826 {
827 SSeqMatch_Scope ret = x_GetSeqMatch(idh);
828 if ( !ret && get_flag == CScope::eGetBioseq_All ) {
829 // Try to load the sequence from the data source
830 SSeqMatch_DS ds_match = GetDataSource().BestResolve(idh);
831 if ( ds_match ) {
832 x_SetMatch(ret, ds_match);
833 }
834 }
835 #ifdef _DEBUG
836 if ( ret ) {
837 _ASSERT(ret.m_Seq_id);
838 _ASSERT(ret.m_Bioseq);
839 _ASSERT(ret.m_TSE_Lock);
840 _ASSERT(ret.m_Bioseq == ret.m_TSE_Lock->m_TSE_Lock->FindBioseq(ret.m_Seq_id));
841 }
842 #endif
843 return ret;
844 }
845
846
Resolve(const CSeq_id_Handle & idh,CTSE_ScopeInfo & tse)847 SSeqMatch_Scope CDataSource_ScopeInfo::Resolve(const CSeq_id_Handle& idh,
848 CTSE_ScopeInfo& tse)
849 {
850 SSeqMatch_Scope ret;
851 x_SetMatch(ret, tse, idh);
852 return ret;
853 }
854
855
x_GetSeqMatch(const CSeq_id_Handle & idh)856 SSeqMatch_Scope CDataSource_ScopeInfo::x_GetSeqMatch(const CSeq_id_Handle& idh)
857 {
858 SSeqMatch_Scope ret = x_FindBestTSE(idh);
859 if ( !ret && idh.HaveMatchingHandles() ) {
860 CSeq_id_Handle::TMatches ids;
861 idh.GetMatchingHandles(ids, eAllowWeakMatch);
862 ITERATE ( CSeq_id_Handle::TMatches, it, ids ) {
863 if ( *it == idh ) // already checked
864 continue;
865 if ( ret && ret.m_Seq_id.IsBetter(*it) ) // worse hit
866 continue;
867 if ( SSeqMatch_Scope match = x_FindBestTSE(*it) ) {
868 ret = match;
869 }
870 }
871 }
872 return ret;
873 }
874
875
x_FindBestTSE(const CSeq_id_Handle & idh)876 SSeqMatch_Scope CDataSource_ScopeInfo::x_FindBestTSE(const CSeq_id_Handle& idh)
877 {
878 SSeqMatch_Scope ret;
879 if ( m_CanBeUnloaded ) {
880 // We have full index of static TSEs.
881 TTSE_InfoMapMutex::TReadLockGuard guard(GetTSE_InfoMapMutex());
882 TTSE_ScopeInfo tse = x_FindBestTSEInIndex(idh);
883 if ( tse ) {
884 x_SetMatch(ret, *tse, idh);
885 }
886 }
887 else {
888 // We have to ask data source about it.
889 CDataSource::TSeqMatches matches;
890 {{
891 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_LockSetMutex);
892 CDataSource::TSeqMatches matches2 =
893 GetDataSource().GetMatches(idh, m_TSE_LockSet);
894 matches.swap(matches2);
895 }}
896 ITERATE ( CDataSource::TSeqMatches, it, matches ) {
897 SSeqMatch_Scope nxt;
898 x_SetMatch(nxt, *it);
899 if ( !nxt ) {
900 continue;
901 }
902 if ( !ret || x_IsBetter(idh, *nxt.m_TSE_Lock, *ret.m_TSE_Lock) ) {
903 ret = nxt;
904 }
905 }
906 }
907 return ret;
908 }
909
910
x_IsBetter(const CSeq_id_Handle & idh,const CTSE_ScopeInfo & tse1,const CTSE_ScopeInfo & tse2)911 bool CDataSource_ScopeInfo::x_IsBetter(const CSeq_id_Handle& idh,
912 const CTSE_ScopeInfo& tse1,
913 const CTSE_ScopeInfo& tse2)
914 {
915 // First of all we check if we already resolve bioseq with this id.
916 bool resolved1 = tse1.HasResolvedBioseq(idh);
917 bool resolved2 = tse2.HasResolvedBioseq(idh);
918 if ( resolved1 != resolved2 ) {
919 return resolved1;
920 }
921 // Now check TSEs' orders.
922 CTSE_ScopeInfo::TBlobOrder order1 = tse1.GetBlobOrder();
923 CTSE_ScopeInfo::TBlobOrder order2 = tse2.GetBlobOrder();
924 if ( order1 != order2 ) {
925 return order1 < order2;
926 }
927
928 // Now we have very similar TSE's so we'll prefer the first one added.
929 return tse1.GetLoadIndex() < tse2.GetLoadIndex();
930 }
931
932
x_SetMatch(SSeqMatch_Scope & match,CTSE_ScopeInfo & tse,const CSeq_id_Handle & idh) const933 void CDataSource_ScopeInfo::x_SetMatch(SSeqMatch_Scope& match,
934 CTSE_ScopeInfo& tse,
935 const CSeq_id_Handle& idh) const
936 {
937 match.m_Seq_id = idh;
938 match.m_TSE_Lock = CTSE_ScopeUserLock(&tse);
939 _ASSERT(match.m_Seq_id);
940 _ASSERT(match.m_TSE_Lock);
941 match.m_Bioseq = match.m_TSE_Lock->GetTSE_Lock()->FindBioseq(idh);
942 _ASSERT(match.m_Bioseq);
943 _ASSERT(match.m_Bioseq == match.m_TSE_Lock->m_TSE_Lock->FindBioseq(match.m_Seq_id));
944 }
945
946
x_SetMatch(SSeqMatch_Scope & match,const SSeqMatch_DS & ds_match)947 void CDataSource_ScopeInfo::x_SetMatch(SSeqMatch_Scope& match,
948 const SSeqMatch_DS& ds_match)
949 {
950 match.m_TSE_Lock = GetTSE_Lock(ds_match.m_TSE_Lock);
951 if ( !match.m_TSE_Lock ) {
952 match.m_Seq_id.Reset();
953 match.m_Bioseq.Reset();
954 return;
955 }
956 match.m_Seq_id = ds_match.m_Seq_id;
957 match.m_Bioseq = ds_match.m_Bioseq;
958 _ASSERT(match.m_Seq_id);
959 _ASSERT(match.m_Bioseq);
960 _ASSERT(match.m_TSE_Lock);
961 _ASSERT(match.m_Bioseq == match.m_TSE_Lock->GetTSE_Lock()->FindBioseq(match.m_Seq_id));
962 }
963
964
GetBlobs(TSeqMatchMap & match_map)965 void CDataSource_ScopeInfo::GetBlobs(TSeqMatchMap& match_map)
966 {
967 CDataSource::TSeqMatchMap ds_match_map;
968 ITERATE(TSeqMatchMap, it, match_map) {
969 if ( it->second ) {
970 continue;
971 }
972 ds_match_map.insert(CDataSource::TSeqMatchMap::value_type(
973 it->first, SSeqMatch_DS()));
974 }
975 if ( match_map.empty() ) {
976 return;
977 }
978 GetDataSource().GetBlobs(ds_match_map);
979 ITERATE(CDataSource::TSeqMatchMap, ds_match, ds_match_map) {
980 if ( !ds_match->second ) {
981 continue;
982 }
983 SSeqMatch_Scope& scope_match = match_map[ds_match->first];
984 scope_match = x_GetSeqMatch(ds_match->first);
985 x_SetMatch(scope_match, ds_match->second);
986 if ( !scope_match ) {
987 match_map.erase(ds_match->first);
988 }
989 }
990 }
991
992
TSEIsInQueue(const CTSE_ScopeInfo & tse) const993 bool CDataSource_ScopeInfo::TSEIsInQueue(const CTSE_ScopeInfo& tse) const
994 {
995 TTSE_LockSetMutex::TReadLockGuard guard(m_TSE_UnlockQueueMutex);
996 return m_TSE_UnlockQueue.Contains(&tse);
997 }
998
999
TSEIsReplaced(const TBlobId & blob_id) const1000 bool CDataSource_ScopeInfo::TSEIsReplaced(const TBlobId& blob_id) const
1001 {
1002 if ( m_EditDS ) {
1003 return m_EditDS->TSEIsReplaced(blob_id);
1004 }
1005 return m_ReplacedTSEs.find(blob_id) != m_ReplacedTSEs.end();
1006 }
1007
1008
1009 /////////////////////////////////////////////////////////////////////////////
1010 // CTSE_ScopeInfo
1011 /////////////////////////////////////////////////////////////////////////////
1012
1013
SUnloadedInfo(const CTSE_Lock & tse_lock)1014 CTSE_ScopeInfo::SUnloadedInfo::SUnloadedInfo(const CTSE_Lock& tse_lock)
1015 : m_Source(&tse_lock->GetDataSource()),
1016 m_BlobId(tse_lock->GetBlobId()),
1017 m_BlobOrder(tse_lock->GetBlobOrder())
1018 {
1019 _ASSERT(m_Source);
1020 _ASSERT(m_BlobId);
1021 // copy all bioseq ids
1022 tse_lock->GetBioseqsIds(m_BioseqsIds);
1023 }
1024
1025
LockTSE(void)1026 CTSE_Lock CTSE_ScopeInfo::SUnloadedInfo::LockTSE(void)
1027 {
1028 _ASSERT(m_Source);
1029 _ASSERT(m_BlobId);
1030 CTSE_Lock lock = m_Source->GetDataLoader()->GetBlobById(m_BlobId);
1031 if ( !lock ) {
1032 NCBI_THROW_FMT(CLoaderException, eConnectionFailed,
1033 "Data loader GetBlobById("<<m_BlobId.ToString()<<") returned null");
1034 }
1035 return lock;
1036 }
1037
1038
CTSE_ScopeInfo(CDataSource_ScopeInfo & ds_info,const CTSE_Lock & lock,int load_index,bool can_be_unloaded)1039 CTSE_ScopeInfo::CTSE_ScopeInfo(CDataSource_ScopeInfo& ds_info,
1040 const CTSE_Lock& lock,
1041 int load_index,
1042 bool can_be_unloaded)
1043 : m_DS_Info(&ds_info),
1044 m_LoadIndex(load_index),
1045 m_UsedByTSE(0)
1046 {
1047 _ASSERT(lock);
1048 if ( can_be_unloaded ) {
1049 _ASSERT(lock->GetBlobId());
1050 m_UnloadedInfo.reset(new SUnloadedInfo(lock));
1051 }
1052 else {
1053 // permanent lock
1054 _TRACE_TSE_LOCK("CTSE_ScopeInfo("<<this<<") perm lock");
1055 m_TSE_LockCounter.Add(1);
1056 x_SetTSE_Lock(lock);
1057 _ASSERT(m_TSE_Lock == lock);
1058 }
1059 }
1060
1061
~CTSE_ScopeInfo(void)1062 CTSE_ScopeInfo::~CTSE_ScopeInfo(void)
1063 {
1064 if ( !CanBeUnloaded() ) {
1065 // remove permanent lock
1066 _TRACE_TSE_LOCK("CTSE_ScopeInfo("<<this<<") perm unlock: "<<m_TSE_LockCounter.Get());
1067 _VERIFY(m_TSE_LockCounter.Add(-1) == 0);
1068 }
1069 x_DetachDS();
1070 _TRACE_TSE_LOCK("CTSE_ScopeInfo("<<this<<") final: "<<m_TSE_LockCounter.Get());
1071 _ASSERT(m_TSE_LockCounter.Get() == 0);
1072 _ASSERT(!m_TSE_Lock);
1073 _ASSERT(!m_UsedByTSE);
1074 _ASSERT(m_UsedTSE_Set.empty());
1075 }
1076
1077
GetBlobOrder(void) const1078 CTSE_ScopeInfo::TBlobOrder CTSE_ScopeInfo::GetBlobOrder(void) const
1079 {
1080 if ( !m_TSE_Lock ) {
1081 _ASSERT(m_UnloadedInfo.get());
1082 return m_UnloadedInfo->m_BlobOrder;
1083 }
1084 else {
1085 _ASSERT(m_TSE_Lock);
1086 TBlobOrder order = m_TSE_Lock->GetBlobOrder();
1087 if ( m_UnloadedInfo && m_UnloadedInfo->m_BlobOrder != order ) {
1088 m_UnloadedInfo->m_BlobOrder = order;
1089 }
1090 return order;
1091 }
1092 }
1093
1094
GetBlobId(void) const1095 CTSE_ScopeInfo::TBlobId CTSE_ScopeInfo::GetBlobId(void) const
1096 {
1097 if ( CanBeUnloaded() ) {
1098 _ASSERT(m_UnloadedInfo.get());
1099 return m_UnloadedInfo->m_BlobId;
1100 }
1101 else {
1102 _ASSERT(m_TSE_Lock);
1103 return m_TSE_Lock->GetBlobId();
1104 }
1105 }
1106
1107
GetBioseqsIds(void) const1108 const CTSE_ScopeInfo::TSeqIds& CTSE_ScopeInfo::GetBioseqsIds(void) const
1109 {
1110 _ASSERT(CanBeUnloaded());
1111 return m_UnloadedInfo->m_BioseqsIds;
1112 }
1113
1114
1115 /////////////////////////////////////////////////////////////////////////////
1116 // TSE locking support classes
1117
x_InternalLockTSE(void)1118 void CTSE_ScopeInfo::x_InternalLockTSE(void)
1119 {
1120 _VERIFY(m_TSE_LockCounter.Add(1) > 0);
1121 }
1122
1123
x_InternalUnlockTSE(void)1124 void CTSE_ScopeInfo::x_InternalUnlockTSE(void)
1125 {
1126 if ( m_TSE_LockCounter.Add(-1) == 0 ) {
1127 _ASSERT(CanBeUnloaded());
1128 if ( IsAttached() ) {
1129 GetDSInfo().ForgetTSELock(*this);
1130 }
1131 }
1132 }
1133
1134
x_UserLockTSE(void)1135 void CTSE_ScopeInfo::x_UserLockTSE(void)
1136 {
1137 if ( m_UserLockCounter.Add(1) == 1 || !GetTSE_Lock() ) {
1138 //_ASSERT(CanBeUnloaded());
1139 if ( IsAttached() ) {
1140 // TODO: possible race - if the TSE becomes detached after the above check
1141 // scenario - in several threads:
1142 // 1. get new TSE handle
1143 // 2. call RemoveFromHistory()
1144 try {
1145 GetDSInfo().AcquireTSEUserLock(*this);
1146 }
1147 catch ( ... ) {
1148 x_UserUnlockTSE();
1149 throw;
1150 }
1151 }
1152 }
1153 }
1154
1155
x_UserUnlockTSE(void)1156 void CTSE_ScopeInfo::x_UserUnlockTSE(void)
1157 {
1158 if ( m_UserLockCounter.Add(-1) == 0 ) {
1159 //_ASSERT(CanBeUnloaded());
1160 if ( IsAttached() ) {
1161 GetDSInfo().ReleaseTSEUserLock(*this);
1162 }
1163 }
1164 }
1165
1166
Lock(CTSE_ScopeInfo * tse) const1167 void CTSE_ScopeInternalLocker::Lock(CTSE_ScopeInfo* tse) const
1168 {
1169 CObjectCounterLocker::Lock(tse);
1170 tse->x_InternalLockTSE();
1171 }
1172
1173
Unlock(CTSE_ScopeInfo * tse) const1174 void CTSE_ScopeInternalLocker::Unlock(CTSE_ScopeInfo* tse) const
1175 {
1176 tse->x_InternalUnlockTSE();
1177 CObjectCounterLocker::Unlock(tse);
1178 }
1179
1180
Lock(CTSE_ScopeInfo * tse) const1181 void CTSE_ScopeUserLocker::Lock(CTSE_ScopeInfo* tse) const
1182 {
1183 CObjectCounterLocker::Lock(tse);
1184 tse->x_InternalLockTSE();
1185 try {
1186 tse->x_UserLockTSE();
1187 }
1188 catch ( ... ) {
1189 tse->x_InternalUnlockTSE();
1190 CObjectCounterLocker::Unlock(tse);
1191 throw;
1192 }
1193 }
1194
1195
Unlock(CTSE_ScopeInfo * tse) const1196 void CTSE_ScopeUserLocker::Unlock(CTSE_ScopeInfo* tse) const
1197 {
1198 tse->x_UserUnlockTSE();
1199 tse->x_InternalUnlockTSE();
1200 CObjectCounterLocker::Unlock(tse);
1201 }
1202
1203 // end of TSE locking support classes
1204 /////////////////////////////////////////////////////////////////////////////
1205
1206
x_SameTSE(const CTSE_Info & tse) const1207 bool CTSE_ScopeInfo::x_SameTSE(const CTSE_Info& tse) const
1208 {
1209 return m_TSE_LockCounter.Get() > 0 && m_TSE_Lock && &*m_TSE_Lock == &tse;
1210 }
1211
1212
ReleaseUsedTSEs(void)1213 void CTSE_ScopeInfo::ReleaseUsedTSEs(void)
1214 {
1215 // release all used TSEs
1216 TUsedTSE_LockSet used;
1217 CTSE_ScopeInternalLock self_lock;
1218 CFastMutexGuard guard(sx_UsedTSEMutex);
1219 NON_CONST_ITERATE ( TUsedTSE_LockSet, it, m_UsedTSE_Set ) {
1220 _ASSERT(it->second->m_UsedByTSE == this);
1221 it->second->m_UsedByTSE = 0;
1222 }
1223 m_UsedTSE_Set.swap(used);
1224 if ( m_UsedByTSE ) {
1225 self_lock.Reset(this); // prevent recursive deletion
1226 m_UsedByTSE->m_UsedTSE_Set.erase(ConstRef(this));
1227 m_UsedByTSE = 0;
1228 }
1229 }
1230
1231
AddUsedTSE(const CTSE_ScopeUserLock & used_tse) const1232 bool CTSE_ScopeInfo::AddUsedTSE(const CTSE_ScopeUserLock& used_tse) const
1233 {
1234 CTSE_ScopeInternalLock add_lock(used_tse.GetNCPointer());
1235 CTSE_ScopeInfo& add_info = const_cast<CTSE_ScopeInfo&>(*used_tse);
1236 if ( &add_info == this || // the same TSE
1237 !add_info.CanBeUnloaded() || // added is permanentrly locked
1238 m_TSE_LockCounter.Get() == 0 ) { // this one is unlocked
1239 return false;
1240 }
1241 CFastMutexGuard guard(sx_UsedTSEMutex);
1242 if ( add_info.m_UsedByTSE ) { // already used
1243 return false;
1244 }
1245 for ( const CTSE_ScopeInfo* p = m_UsedByTSE; p; p = p->m_UsedByTSE ) {
1246 if ( p == &add_info ) {
1247 return false;
1248 }
1249 }
1250 CTSE_ScopeInternalLock& add_slot = m_UsedTSE_Set[ConstRef(&*used_tse)];
1251 _ASSERT(!add_slot);
1252 add_info.m_UsedByTSE = this;
1253 swap(add_slot, add_lock);
1254 return true;
1255 }
1256
1257
x_SetTSE_Lock(const CTSE_Lock & lock)1258 void CTSE_ScopeInfo::x_SetTSE_Lock(const CTSE_Lock& lock)
1259 {
1260 _ASSERT(lock);
1261 if ( !m_TSE_Lock ) {
1262 m_TSE_Lock = lock;
1263 GetDSInfo().AddTSE_Lock(lock);
1264 }
1265 _ASSERT(m_TSE_Lock == lock);
1266 }
1267
1268
x_ResetTSE_Lock(void)1269 void CTSE_ScopeInfo::x_ResetTSE_Lock(void)
1270 {
1271 if ( m_TSE_Lock ) {
1272 CTSE_Lock lock;
1273 lock.Swap(m_TSE_Lock);
1274 GetDSInfo().RemoveTSE_Lock(lock);
1275 }
1276 _ASSERT(!m_TSE_Lock);
1277 }
1278
1279
SetTSE_Lock(const CTSE_Lock & lock)1280 void CTSE_ScopeInfo::SetTSE_Lock(const CTSE_Lock& lock)
1281 {
1282 _ASSERT(lock);
1283 if ( !m_TSE_Lock ) {
1284 CMutexGuard guard(m_TSE_LockMutex);
1285 x_SetTSE_Lock(lock);
1286 }
1287 _ASSERT(m_TSE_Lock == lock);
1288 }
1289
1290
ResetTSE_Lock(void)1291 void CTSE_ScopeInfo::ResetTSE_Lock(void)
1292 {
1293 if ( m_TSE_Lock ) {
1294 CMutexGuard guard(m_TSE_LockMutex);
1295 x_ResetTSE_Lock();
1296 }
1297 _ASSERT(!m_TSE_Lock);
1298 }
1299
1300
DropTSE_Lock(void)1301 void CTSE_ScopeInfo::DropTSE_Lock(void)
1302 {
1303 if ( m_TSE_Lock ) {
1304 CMutexGuard guard(m_TSE_LockMutex);
1305 m_TSE_Lock.Reset();
1306 }
1307 _ASSERT(!m_TSE_Lock);
1308 }
1309
1310
SetEditTSE(const CTSE_Lock & new_tse_lock,CDataSource_ScopeInfo & new_ds)1311 void CTSE_ScopeInfo::SetEditTSE(const CTSE_Lock& new_tse_lock,
1312 CDataSource_ScopeInfo& new_ds)
1313 {
1314 _ASSERT(!CanBeEdited());
1315 _ASSERT(new_ds.CanBeEdited());
1316 _ASSERT(&new_tse_lock->GetDataSource() == &new_ds.GetDataSource());
1317
1318 CUnlockedTSEsGuard unlocked_guard;
1319 CMutexGuard guard(m_TSE_LockMutex);
1320 _ASSERT(m_TSE_Lock);
1321 _ASSERT(&m_TSE_Lock->GetDataSource() == &GetDSInfo().GetDataSource());
1322 CTSE_Lock old_tse_lock = m_TSE_Lock;
1323
1324 TScopeInfoMap old_map; // save old scope info map
1325 CMutexGuard guard2(m_ScopeInfoMapMutex);
1326 old_map.swap(m_ScopeInfoMap);
1327 TBioseqById old_bioseq_map; // save old bioseq info map
1328 old_bioseq_map.swap(m_BioseqById);
1329
1330 GetDSInfo().RemoveFromHistory(*this); // remove tse from old ds
1331 _ASSERT(!m_TSE_Lock);
1332 _ASSERT(!m_DS_Info);
1333 if ( CanBeUnloaded() ) {
1334 m_UnloadedInfo.reset(); // edit tse cannot be unloaded
1335 m_TSE_LockCounter.Add(1);
1336 }
1337
1338 // convert scope info map
1339 const TEditInfoMap& edit_map = new_tse_lock->m_BaseTSE->m_ObjectCopyMap;
1340 NON_CONST_ITERATE ( TScopeInfoMap, it, old_map ) {
1341 CConstRef<CObject> old_obj(it->first);
1342 _ASSERT(old_obj);
1343 TEditInfoMap::const_iterator iter = edit_map.find(old_obj);
1344 TScopeInfoMapKey new_obj;
1345 if ( iter == edit_map.end() ) {
1346 _ASSERT(&*old_obj == &*old_tse_lock);
1347 new_obj.Reset(&*new_tse_lock);
1348 }
1349 else {
1350 new_obj.Reset(&dynamic_cast<const CTSE_Info_Object&>(*iter->second));
1351 }
1352 _ASSERT(new_obj);
1353 _ASSERT(&*new_obj != &*old_obj);
1354 TScopeInfoMapValue info = it->second;
1355 _ASSERT(info->m_ObjectInfo == old_obj);
1356 info->m_ObjectInfo = new_obj;
1357 _VERIFY(m_ScopeInfoMap.insert
1358 (TScopeInfoMap::value_type(new_obj, info)).second);
1359 }
1360 // restore bioseq info map
1361 m_BioseqById.swap(old_bioseq_map);
1362
1363 new_ds.AttachTSE(*this, new_tse_lock);
1364
1365 _ASSERT(&GetDSInfo() == &new_ds);
1366 _ASSERT(m_TSE_Lock == new_tse_lock);
1367
1368 const_cast<CTSE_Info&>(*new_tse_lock).m_BaseTSE->m_ObjectCopyMap.clear();
1369 }
1370
1371
RestoreReplacedTSE(void)1372 void CTSE_ScopeInfo::RestoreReplacedTSE(void)
1373 {
1374 if ( m_ReplacedTSE ) {
1375 _ASSERT(m_DS_Info);
1376 m_DS_Info->m_ReplacedTSEs.erase(m_ReplacedTSE);
1377 m_ReplacedTSE = TBlobId();
1378 }
1379 }
1380
1381
ReplaceTSE(const CTSE_Info & old_tse)1382 void CTSE_ScopeInfo::ReplaceTSE(const CTSE_Info& old_tse)
1383 {
1384 RestoreReplacedTSE();
1385 _ASSERT(m_DS_Info);
1386 m_ReplacedTSE = old_tse.GetBlobId();
1387 if ( !m_DS_Info->m_ReplacedTSEs.insert(m_ReplacedTSE).second ) {
1388 m_ReplacedTSE = TBlobId();
1389 ERR_POST("CTSE_ScopeInfo::ReplaceTSE("<<
1390 old_tse.GetDescription()<<"): already replaced");
1391 }
1392 }
1393
1394
1395 // Action A4.
ForgetTSE_Lock(void)1396 void CTSE_ScopeInfo::ForgetTSE_Lock(void)
1397 {
1398 if ( m_TSE_LockCounter.Get() > 0 ) {
1399 // relocked already
1400 return;
1401 }
1402 ReleaseUsedTSEs();
1403 if ( !m_TSE_Lock ) {
1404 return;
1405 }
1406 CMutexGuard guard(m_TSE_LockMutex);
1407 if ( m_TSE_LockCounter.Get() > 0 ) {
1408 // relocked already
1409 return;
1410 }
1411 if ( !m_TSE_Lock ) {
1412 return;
1413 }
1414 {{
1415 CMutexGuard guard2(m_ScopeInfoMapMutex);
1416 NON_CONST_ITERATE ( TScopeInfoMap, it, m_ScopeInfoMap ) {
1417 _ASSERT(!it->second->m_TSE_Handle.m_TSE);
1418 it->second->m_ObjectInfo.Reset();
1419 if ( it->second->IsTemporary() ) {
1420 it->second->x_DetachTSE(this);
1421 }
1422 }
1423 m_ScopeInfoMap.clear();
1424 }}
1425 x_ResetTSE_Lock();
1426 }
1427
1428
x_DetachDS(void)1429 void CTSE_ScopeInfo::x_DetachDS(void)
1430 {
1431 if ( !m_DS_Info ) {
1432 return;
1433 }
1434 ReleaseUsedTSEs();
1435 CMutexGuard guard(m_TSE_LockMutex);
1436 {{
1437 CMutexGuard guard2(m_ScopeInfoMapMutex);
1438 NON_CONST_ITERATE ( TScopeInfoMap, it, m_ScopeInfoMap ) {
1439 //_ASSERT(!it->second->m_TSE_Handle.m_TSE);
1440 it->second->m_TSE_Handle.Reset();
1441 it->second->m_ObjectInfo.Reset();
1442 it->second->x_DetachTSE(this);
1443 }
1444 m_ScopeInfoMap.clear();
1445 }}
1446 m_TSE_Lock.Reset();
1447 while ( !m_BioseqById.empty() ) {
1448 CRef<CBioseq_ScopeInfo> bioseq = m_BioseqById.begin()->second;
1449 bioseq->x_DetachTSE(this);
1450 _ASSERT(m_BioseqById.empty()||m_BioseqById.begin()->second != bioseq);
1451 }
1452 m_DS_Info = 0;
1453 }
1454
1455
x_GetDSLocksCount(void) const1456 int CTSE_ScopeInfo::x_GetDSLocksCount(void) const
1457 {
1458 int max_locks = CanBeUnloaded() ? 0 : 1;
1459 if ( GetDSInfo().TSEIsInQueue(*this) ) {
1460 // Extra-lock from delete queue allowed
1461 ++max_locks;
1462 }
1463 return max_locks;
1464 }
1465
1466
GetUserLockState(const CTSE_Handle * tseh) const1467 pair<bool, CScopeInfo_Base*> CTSE_ScopeInfo::GetUserLockState(const CTSE_Handle* tseh) const
1468 {
1469 pair<bool, CScopeInfo_Base*> ret;
1470 if ( !tseh ) {
1471 // no request handle, use simple handle lock count
1472 ret.first = IsUserLocked();
1473 return ret;
1474 }
1475 // now we have one handle already
1476 _ASSERT(&tseh->x_GetScopeInfo() == this);
1477 _ASSERT(m_UserLockCounter.Get() >= 1);
1478 if ( m_UserLockCounter.Get() > 1 ) {
1479 // there are more sub-object handles
1480 ret.first = true;
1481 return ret;
1482 }
1483 // now we may have several sub-object handles pointing to the same object
1484 // scan m_ScopeInfoMap for a possible handle having tseh inside
1485 CMutexGuard guard(m_ScopeInfoMapMutex);
1486 for ( auto& s : m_ScopeInfoMap ) {
1487 if ( &s.second->m_TSE_Handle == tseh ) {
1488 _ASSERT(s.second->m_LockCounter.Get() >= 1);
1489 ret.second = s.second.GetNCPointer();
1490 ret.first = s.second->m_LockCounter.Get() > 1;
1491 return ret;
1492 }
1493 }
1494 return ret;
1495 }
1496
1497
RemoveFromHistory(const CTSE_Handle * tseh,int action_if_locked,bool drop_from_ds)1498 void CTSE_ScopeInfo::RemoveFromHistory(const CTSE_Handle* tseh,
1499 int action_if_locked,
1500 bool drop_from_ds)
1501 {
1502 auto locked = GetUserLockState(tseh);
1503 if ( locked.first ) {
1504 switch ( action_if_locked ) {
1505 case CScope::eKeepIfLocked:
1506 return;
1507 case CScope::eThrowIfLocked:
1508 NCBI_THROW(CObjMgrException, eLockedData,
1509 "Cannot remove TSE from scope's history "
1510 "because it's locked");
1511 default: // forced removal
1512 break;
1513 }
1514 }
1515 CTSE_Handle tse;
1516 if ( locked.second ) {
1517 tse.Swap(locked.second->m_TSE_Handle);
1518 _ASSERT(&tse.x_GetScopeInfo() == this);
1519 }
1520 CUnlockedTSEsGuard guard;
1521 GetDSInfo().RemoveFromHistory(*this, drop_from_ds);
1522 }
1523
1524
RemoveFromHistory(const CTSE_Handle & tseh,int action_if_locked,bool drop_from_ds)1525 void CTSE_ScopeInfo::RemoveFromHistory(const CTSE_Handle& tseh,
1526 int action_if_locked,
1527 bool drop_from_ds)
1528 {
1529 tseh.x_GetScopeInfo().RemoveFromHistory(&tseh, action_if_locked, drop_from_ds);
1530 }
1531
1532
HasResolvedBioseq(const CSeq_id_Handle & id) const1533 bool CTSE_ScopeInfo::HasResolvedBioseq(const CSeq_id_Handle& id) const
1534 {
1535 return m_BioseqById.find(id) != m_BioseqById.end();
1536 }
1537
1538
ContainsBioseq(const CSeq_id_Handle & id) const1539 bool CTSE_ScopeInfo::ContainsBioseq(const CSeq_id_Handle& id) const
1540 {
1541 if ( CanBeUnloaded() ) {
1542 return binary_search(m_UnloadedInfo->m_BioseqsIds.begin(),
1543 m_UnloadedInfo->m_BioseqsIds.end(),
1544 id);
1545 }
1546 else {
1547 return m_TSE_Lock->ContainsBioseq(id);
1548 }
1549 }
1550
1551
1552 CSeq_id_Handle
ContainsMatchingBioseq(const CSeq_id_Handle & id) const1553 CTSE_ScopeInfo::ContainsMatchingBioseq(const CSeq_id_Handle& id) const
1554 {
1555 if ( CanBeUnloaded() ) {
1556 if ( ContainsBioseq(id) ) {
1557 return id;
1558 }
1559 if ( id.HaveMatchingHandles() ) {
1560 CSeq_id_Handle::TMatches ids;
1561 id.GetMatchingHandles(ids, eAllowWeakMatch);
1562 ITERATE ( CSeq_id_Handle::TMatches, it, ids ) {
1563 if ( *it != id ) {
1564 if ( ContainsBioseq(*it) ) {
1565 return *it;
1566 }
1567 }
1568 }
1569 }
1570 return null;
1571 }
1572 else {
1573 return m_TSE_Lock->ContainsMatchingBioseq(id);
1574 }
1575 }
1576
1577
1578 // Action A5.
1579 template<class TScopeInfo>
1580 CScopeInfo_Ref<TScopeInfo>
x_GetScopeLock(const CTSE_Handle & tse,const typename TScopeInfo::TObjectInfo & info)1581 CTSE_ScopeInfo::x_GetScopeLock(const CTSE_Handle& tse,
1582 const typename TScopeInfo::TObjectInfo& info)
1583 {
1584 CRef<TScopeInfo> scope_info;
1585 {{
1586 CMutexGuard guard2(m_ScopeInfoMapMutex);
1587 _ASSERT(x_SameTSE(tse.x_GetTSE_Info()));
1588 TScopeInfoMapKey key(&info);
1589 TScopeInfoMap::iterator iter = m_ScopeInfoMap.lower_bound(key);
1590 if ( iter == m_ScopeInfoMap.end() || iter->first != key ) {
1591 scope_info = new TScopeInfo(tse, info);
1592 TScopeInfoMapValue value(scope_info);
1593 m_ScopeInfoMap.insert(iter, TScopeInfoMap::value_type(key, value));
1594 value->m_ObjectInfo = &info;
1595 }
1596 else {
1597 _ASSERT(iter->second->HasObject());
1598 _ASSERT(&iter->second->GetObjectInfo_Base() == &info);
1599 scope_info = &dynamic_cast<TScopeInfo&>(*iter->second);
1600 }
1601 }}
1602 CScopeInfo_Ref<TScopeInfo> ret(*scope_info);
1603 ret->x_SetTSE_Handle(tse);
1604 return ret;
1605 }
1606
1607
1608 // Action A5.
1609 CTSE_ScopeInfo::TSeq_entry_Lock
GetScopeLock(const CTSE_Handle & tse,const CSeq_entry_Info & info)1610 CTSE_ScopeInfo::GetScopeLock(const CTSE_Handle& tse,
1611 const CSeq_entry_Info& info)
1612 {
1613 return x_GetScopeLock<CSeq_entry_ScopeInfo>(tse, info);
1614 }
1615
1616
1617 // Action A5.
1618 CTSE_ScopeInfo::TSeq_annot_Lock
GetScopeLock(const CTSE_Handle & tse,const CSeq_annot_Info & info)1619 CTSE_ScopeInfo::GetScopeLock(const CTSE_Handle& tse,
1620 const CSeq_annot_Info& info)
1621 {
1622 return x_GetScopeLock<CSeq_annot_ScopeInfo>(tse, info);
1623 }
1624
1625 // Action A5.
1626 CTSE_ScopeInfo::TBioseq_set_Lock
GetScopeLock(const CTSE_Handle & tse,const CBioseq_set_Info & info)1627 CTSE_ScopeInfo::GetScopeLock(const CTSE_Handle& tse,
1628 const CBioseq_set_Info& info)
1629 {
1630 return x_GetScopeLock<CBioseq_set_ScopeInfo>(tse, info);
1631 }
1632
1633 // Action A5.
1634 CTSE_ScopeInfo::TBioseq_Lock
GetBioseqLock(CRef<CBioseq_ScopeInfo> info,CConstRef<CBioseq_Info> bioseq)1635 CTSE_ScopeInfo::GetBioseqLock(CRef<CBioseq_ScopeInfo> info,
1636 CConstRef<CBioseq_Info> bioseq)
1637 {
1638 // TODO: possible deadlock (1), m_TSE_LockMutex is taken before m_TSE_UnlockQueueMutex
1639 // this thread calls GetBioseqHandle()
1640 CMutexGuard guard(m_TSE_LockMutex);
1641 CTSE_ScopeUserLock tse(this);
1642 _ASSERT(m_TSE_Lock);
1643 if ( !info ) {
1644 // find CBioseq_ScopeInfo
1645 _ASSERT(bioseq);
1646 _ASSERT(bioseq->BelongsToTSE_Info(*m_TSE_Lock));
1647 const CBioseq_Info::TId& ids = bioseq->GetId();
1648 if ( !ids.empty() ) {
1649 // named bioseq, look in Seq-id index only
1650 info = x_FindBioseqInfo(ids);
1651 if ( !info ) {
1652 info = x_CreateBioseqInfo(ids);
1653 }
1654 }
1655 else {
1656 // unnamed bioseq, look in object map, create if necessary
1657 {{
1658 CMutexGuard guard2(m_ScopeInfoMapMutex);
1659 TScopeInfoMapKey key(bioseq);
1660 TScopeInfoMap::iterator iter = m_ScopeInfoMap.lower_bound(key);
1661 if ( iter == m_ScopeInfoMap.end() || iter->first != key ) {
1662 info = new CBioseq_ScopeInfo(*this);
1663 TScopeInfoMapValue value(info);
1664 iter = m_ScopeInfoMap
1665 .insert(iter, TScopeInfoMap::value_type(key, value));
1666 value->m_ObjectInfo = &*bioseq;
1667 }
1668 else {
1669 _ASSERT(iter->second->HasObject());
1670 _ASSERT(&iter->second->GetObjectInfo_Base() == &*bioseq);
1671 info.Reset(&dynamic_cast<CBioseq_ScopeInfo&>(*iter->second));
1672 }
1673 }}
1674 TBioseq_Lock ret(*info);
1675 ret->x_SetTSE_Handle(tse);
1676 return ret;
1677 }
1678 }
1679 _ASSERT(info);
1680 _ASSERT(!info->IsDetached());
1681 // update CBioseq_ScopeInfo object
1682 if ( !info->HasObject() ) {
1683 if ( !bioseq ) {
1684 const CBioseq_ScopeInfo::TIds& ids = info->GetIds();
1685 if ( !ids.empty() ) {
1686 const CSeq_id_Handle& id = *ids.begin();
1687 bioseq = m_TSE_Lock->FindBioseq(id);
1688 _ASSERT(bioseq);
1689 }
1690 else {
1691 // unnamed bioseq without object - error,
1692 // this situation must be prevented by code.
1693 _ASSERT(0 && "CBioseq_ScopeInfo without ids and bioseq");
1694 }
1695 }
1696 _ASSERT(bioseq);
1697 _ASSERT(bioseq->GetId() == info->GetIds());
1698 CMutexGuard guard2(m_ScopeInfoMapMutex);
1699 TScopeInfoMapKey key(bioseq);
1700 TScopeInfoMapValue value(info);
1701 _VERIFY(m_ScopeInfoMap
1702 .insert(TScopeInfoMap::value_type(key, value)).second);
1703 }
1704 TBioseq_Lock ret(*info);
1705 if ( bioseq ) {
1706 ret->x_SetTSE_Lock(tse, *bioseq);
1707 }
1708 else {
1709 ret->x_SetTSE_Handle(tse);
1710 }
1711 return ret;
1712 }
1713
1714
1715 // Find scope bioseq info by match: CConstRef<CBioseq_Info> & CSeq_id_Handle
1716 // The problem is that CTSE_Info and CBioseq_Info may be unloaded and we
1717 // cannot store pointers to them.
1718 // However, we have to find the same CBioseq_ScopeInfo object.
1719 // It is stored in m_BioseqById map under one of Bioseq's ids.
1720 CRef<CBioseq_ScopeInfo>
GetBioseqInfo(const SSeqMatch_Scope & match)1721 CTSE_ScopeInfo::GetBioseqInfo(const SSeqMatch_Scope& match)
1722 {
1723 _ASSERT(&*match.m_TSE_Lock == this);
1724 _ASSERT(match.m_Seq_id);
1725 _ASSERT(match.m_Bioseq);
1726 CRef<CBioseq_ScopeInfo> info;
1727 const CBioseq_Info::TId& ids = match.m_Bioseq->GetId();
1728 _ASSERT(find(ids.begin(), ids.end(), match.m_Seq_id) != ids.end());
1729
1730 CMutexGuard guard(m_TSE_LockMutex);
1731
1732 info = x_FindBioseqInfo(ids);
1733 if ( !info ) {
1734 info = x_CreateBioseqInfo(ids);
1735 }
1736 return info;
1737 }
1738
1739
1740 CRef<CBioseq_ScopeInfo>
x_FindBioseqInfo(const TSeqIds & ids) const1741 CTSE_ScopeInfo::x_FindBioseqInfo(const TSeqIds& ids) const
1742 {
1743 if ( !ids.empty() ) {
1744 const CSeq_id_Handle& id = *ids.begin();
1745 for ( TBioseqById::const_iterator it(m_BioseqById.lower_bound(id));
1746 it != m_BioseqById.end() && it->first == id; ++it ) {
1747 if ( it->second->GetIds() == ids ) {
1748 return it->second;
1749 }
1750 }
1751 }
1752 return null;
1753 }
1754
1755
x_CreateBioseqInfo(const TSeqIds & ids)1756 CRef<CBioseq_ScopeInfo> CTSE_ScopeInfo::x_CreateBioseqInfo(const TSeqIds& ids)
1757 {
1758 return Ref(new CBioseq_ScopeInfo(*this, ids));
1759 }
1760
1761
x_IndexBioseq(const CSeq_id_Handle & id,CBioseq_ScopeInfo * info)1762 void CTSE_ScopeInfo::x_IndexBioseq(const CSeq_id_Handle& id,
1763 CBioseq_ScopeInfo* info)
1764 {
1765 m_BioseqById.insert(TBioseqById::value_type(id, Ref(info)));
1766 }
1767
1768
x_UnindexBioseq(const CSeq_id_Handle & id,const CBioseq_ScopeInfo * info)1769 void CTSE_ScopeInfo::x_UnindexBioseq(const CSeq_id_Handle& id,
1770 const CBioseq_ScopeInfo* info)
1771 {
1772 for ( TBioseqById::iterator it = m_BioseqById.lower_bound(id);
1773 it != m_BioseqById.end() && it->first == id; ++it ) {
1774 if ( it->second == info ) {
1775 m_BioseqById.erase(it);
1776 return;
1777 }
1778 }
1779 _ASSERT(0 && "UnindexBioseq: CBioseq_ScopeInfo is not in index");
1780 }
1781
1782 // Action A2.
ResetEntry(CSeq_entry_ScopeInfo & info)1783 void CTSE_ScopeInfo::ResetEntry(CSeq_entry_ScopeInfo& info)
1784 {
1785 CMutexGuard guard(m_TSE_LockMutex);
1786 _ASSERT(info.IsAttached());
1787 CScopeInfo_Ref<CScopeInfo_Base> child;
1788 if ( info.GetObjectInfo().Which() == CSeq_entry::e_Set ) {
1789 child.Reset(&*GetScopeLock(info.m_TSE_Handle,
1790 info.GetObjectInfo().GetSet()));
1791 }
1792 else if ( info.GetObjectInfo().Which() == CSeq_entry::e_Seq ) {
1793 CConstRef<CBioseq_Info> bioseq(&info.GetObjectInfo().GetSeq());
1794 child.Reset(&GetBioseqLock(null, bioseq).GetNCObject());
1795 }
1796 else {
1797 // nothing to do
1798 return;
1799 }
1800 info.GetNCObjectInfo().Reset();
1801 x_SaveRemoved(*child);
1802 _ASSERT(child->IsDetached());
1803 }
1804
1805 // Action A2.
RemoveEntry(CSeq_entry_ScopeInfo & info)1806 void CTSE_ScopeInfo::RemoveEntry(CSeq_entry_ScopeInfo& info)
1807 {
1808 CMutexGuard guard(m_TSE_LockMutex);
1809 _ASSERT(info.IsAttached());
1810 CSeq_entry_Info& entry = info.GetNCObjectInfo();
1811 entry.GetParentBioseq_set_Info().RemoveEntry(Ref(&entry));
1812 x_SaveRemoved(info);
1813 _ASSERT(info.IsDetached());
1814 }
1815
1816 // Action A2.
RemoveAnnot(CSeq_annot_ScopeInfo & info)1817 void CTSE_ScopeInfo::RemoveAnnot(CSeq_annot_ScopeInfo& info)
1818 {
1819 CMutexGuard guard(m_TSE_LockMutex);
1820 _ASSERT(info.IsAttached());
1821 _ASSERT(info.GetObjectInfo().BelongsToTSE_Info(*m_TSE_Lock));
1822 CSeq_annot_Info& annot = info.GetNCObjectInfo();
1823 annot.GetParentBioseq_Base_Info().RemoveAnnot(Ref(&annot));
1824 x_SaveRemoved(info);
1825 _ASSERT(info.IsDetached());
1826 _ASSERT(!info.GetObjectInfo().HasTSE_Info());
1827 }
1828
1829
1830 // Action A7.
1831 #ifdef _DEBUG
x_CheckAdded(CScopeInfo_Base & parent,CScopeInfo_Base & child)1832 void CTSE_ScopeInfo::x_CheckAdded(CScopeInfo_Base& parent,
1833 CScopeInfo_Base& child)
1834 {
1835 _ASSERT(parent.IsAttached());
1836 _ASSERT(parent.HasObject());
1837 _ASSERT(parent.m_LockCounter.Get() > 0);
1838 _ASSERT(child.IsDetached());
1839 _ASSERT(child.m_DetachedInfo);
1840 _ASSERT(child.HasObject());
1841 _ASSERT(!child.GetObjectInfo_Base().HasParent_Info());
1842 _ASSERT(child.m_LockCounter.Get() > 0);
1843 _ASSERT(x_SameTSE(parent.GetTSE_Handle().x_GetTSE_Info()));
1844 }
1845 #else /* _DEBUG */
x_CheckAdded(CScopeInfo_Base &,CScopeInfo_Base &)1846 void CTSE_ScopeInfo::x_CheckAdded(CScopeInfo_Base& /*parent*/,
1847 CScopeInfo_Base& /*child*/)
1848 {}
1849 #endif
1850
1851
1852 // Action A7.
AddEntry(CBioseq_set_ScopeInfo & parent,CSeq_entry_ScopeInfo & child,int index)1853 void CTSE_ScopeInfo::AddEntry(CBioseq_set_ScopeInfo& parent,
1854 CSeq_entry_ScopeInfo& child,
1855 int index)
1856 {
1857 CMutexGuard guard(m_TSE_LockMutex);
1858 x_CheckAdded(parent, child);
1859 parent.GetNCObjectInfo().AddEntry(Ref(&child.GetNCObjectInfo()), index, true);
1860 x_RestoreAdded(parent, child);
1861 _ASSERT(child.IsAttached());
1862 }
1863
1864
1865 // Action A7.
AddAnnot(CSeq_entry_ScopeInfo & parent,CSeq_annot_ScopeInfo & child)1866 void CTSE_ScopeInfo::AddAnnot(CSeq_entry_ScopeInfo& parent,
1867 CSeq_annot_ScopeInfo& child)
1868 {
1869 CMutexGuard guard(m_TSE_LockMutex);
1870 _ASSERT(!child.GetObjectInfo().HasTSE_Info());
1871 x_CheckAdded(parent, child);
1872 parent.GetNCObjectInfo().AddAnnot(Ref(&child.GetNCObjectInfo()));
1873 x_RestoreAdded(parent, child);
1874 _ASSERT(child.IsAttached());
1875 _ASSERT(child.GetObjectInfo().BelongsToTSE_Info(*m_TSE_Lock));
1876 }
1877
1878
1879 // Action A7.
SelectSet(CSeq_entry_ScopeInfo & parent,CBioseq_set_ScopeInfo & child)1880 void CTSE_ScopeInfo::SelectSet(CSeq_entry_ScopeInfo& parent,
1881 CBioseq_set_ScopeInfo& child)
1882 {
1883 CMutexGuard guard(m_TSE_LockMutex);
1884 x_CheckAdded(parent, child);
1885 _ASSERT(parent.GetObjectInfo().Which() == CSeq_entry::e_not_set);
1886 parent.GetNCObjectInfo().SelectSet(child.GetNCObjectInfo());
1887 x_RestoreAdded(parent, child);
1888 _ASSERT(child.IsAttached());
1889 }
1890
1891
1892 // Action A7.
SelectSeq(CSeq_entry_ScopeInfo & parent,CBioseq_ScopeInfo & child)1893 void CTSE_ScopeInfo::SelectSeq(CSeq_entry_ScopeInfo& parent,
1894 CBioseq_ScopeInfo& child)
1895 {
1896 CMutexGuard guard(m_TSE_LockMutex);
1897 x_CheckAdded(parent, child);
1898 _ASSERT(parent.GetObjectInfo().Which() == CSeq_entry::e_not_set);
1899 parent.GetNCObjectInfo().SelectSeq(child.GetNCObjectInfo());
1900 x_RestoreAdded(parent, child);
1901 _ASSERT(child.IsAttached());
1902 }
1903
1904
1905 // Save and restore scope info objects.
1906
1907 typedef pair<CConstRef<CTSE_Info_Object>,
1908 CRef<CScopeInfo_Base> > TDetachedInfoElement;
1909 typedef vector<TDetachedInfoElement> TDetachedInfo;
1910
1911 // Action A3.
x_SaveRemoved(CScopeInfo_Base & info)1912 void CTSE_ScopeInfo::x_SaveRemoved(CScopeInfo_Base& info)
1913 {
1914 _ASSERT(info.IsAttached()); // info is not yet detached
1915 _ASSERT(!info.m_DetachedInfo); // and doesn't contain m_DetachedInfo yet
1916 _ASSERT(info.HasObject()); // it contains pointer to removed object
1917 _ASSERT(!info.GetObjectInfo_Base().HasParent_Info()); //and is root of tree
1918 CRef<CObjectFor<TDetachedInfo> > save(new CObjectFor<TDetachedInfo>);
1919 _ASSERT(!m_UnloadedInfo); // this TSE cannot be unloaded
1920 _ASSERT(m_TSE_Lock); // and TSE is locked
1921 _TRACE("x_SaveRemoved("<<&info<<") TSE: "<<this);
1922 {{
1923 CMutexGuard guard2(m_ScopeInfoMapMutex);
1924 for ( TScopeInfoMap::iterator it = m_ScopeInfoMap.begin(); it != m_ScopeInfoMap.end(); ) {
1925 if ( !it->first->BelongsToTSE_Info(*m_TSE_Lock) ) {
1926 _TRACE(" "<<it->second<<" " << it->first);
1927 it->second->m_TSE_Handle.Reset();
1928 it->second->x_DetachTSE(this);
1929 if ( &*it->second != &info ) {
1930 _ASSERT(it->first->HasParent_Info());
1931 save->GetData().push_back(TDetachedInfoElement(it->first,
1932 it->second));
1933 }
1934 m_ScopeInfoMap.erase(it++);
1935 }
1936 else {
1937 ++it;
1938 }
1939 }
1940 }}
1941 _ASSERT(info.IsDetached()); // info is already detached
1942 _ASSERT(m_TSE_Lock);
1943 info.m_DetachedInfo.Reset(save); // save m_DetachedInfo
1944 #ifdef _DEBUG
1945 ITERATE ( TBioseqById, it, m_BioseqById ) {
1946 _ASSERT(!it->second->IsDetached());
1947 _ASSERT(&it->second->x_GetTSE_ScopeInfo() == this);
1948 _ASSERT(!it->second->HasObject() || it->second->GetObjectInfo_Base().BelongsToTSE_Info(*m_TSE_Lock));
1949 }
1950 #endif
1951 // post checks
1952 _ASSERT(info.IsDetached());
1953 _ASSERT(info.m_DetachedInfo);
1954 _ASSERT(info.HasObject()); // it contains pointer to removed object
1955 _ASSERT(!info.GetObjectInfo_Base().HasParent_Info());//and is root of tree
1956 }
1957
1958 // Action A7
x_RestoreAdded(CScopeInfo_Base & parent,CScopeInfo_Base & child)1959 void CTSE_ScopeInfo::x_RestoreAdded(CScopeInfo_Base& parent,
1960 CScopeInfo_Base& child)
1961 {
1962 _ASSERT(parent.IsAttached()); // parent is attached
1963 _ASSERT(parent.m_TSE_Handle); // and locked
1964 _ASSERT(parent.m_LockCounter.Get() > 0);
1965 _ASSERT(child.IsDetached()); // child is detached
1966 _ASSERT(child.m_DetachedInfo); // and contain m_DetachedInfo
1967 _ASSERT(child.HasObject()); // it contains pointer to removed object
1968 _ASSERT(child.GetObjectInfo_Base().HasParent_Info());//and is connected
1969 _ASSERT(child.m_LockCounter.Get() > 0);
1970
1971 _TRACE("x_RestoreAdded("<<&child<<") TSE: "<<this);
1972
1973 CRef<CObjectFor<TDetachedInfo> > infos
1974 (&dynamic_cast<CObjectFor<TDetachedInfo>&>(*child.m_DetachedInfo));
1975 child.m_DetachedInfo.Reset();
1976 infos->GetData().push_back
1977 (TDetachedInfoElement(ConstRef(&child.GetObjectInfo_Base()),
1978 Ref(&child)));
1979
1980 {{
1981 CMutexGuard guard2(m_ScopeInfoMapMutex);
1982 ITERATE ( TDetachedInfo, it, infos->GetData() ) {
1983 _TRACE(" "<<it->second<<" " << it->first);
1984 CScopeInfo_Base& info = it->second.GetNCObject();
1985 if ( info.m_LockCounter.Get() > 0 ) {
1986 info.x_AttachTSE(this);
1987 _VERIFY(m_ScopeInfoMap.insert
1988 (TScopeInfoMap::value_type(it->first, it->second)).second);
1989 info.x_SetTSE_Handle(parent.m_TSE_Handle);
1990 }
1991 }
1992 }}
1993 _ASSERT(child.IsAttached());
1994 _ASSERT(child.m_TSE_Handle.m_TSE);
1995 _ASSERT(child.HasObject());
1996 }
1997
1998
Resolve(const CSeq_id_Handle & id)1999 SSeqMatch_Scope CTSE_ScopeInfo::Resolve(const CSeq_id_Handle& id)
2000 {
2001 return GetDSInfo().Resolve(id, *this);
2002 }
2003
2004
2005 /////////////////////////////////////////////////////////////////////////////
2006 // CBioseq_ScopeInfo
2007 /////////////////////////////////////////////////////////////////////////////
2008
2009 // If this define will be uncomented then it must be changed to use ERR_POST_X
2010 //#define BIOSEQ_TRACE(x) ERR_POST(x)
2011 #ifndef BIOSEQ_TRACE
2012 # define BIOSEQ_TRACE(x)
2013 #endif
2014
CBioseq_ScopeInfo(TBlobStateFlags flags,int timestamp)2015 CBioseq_ScopeInfo::CBioseq_ScopeInfo(TBlobStateFlags flags, int timestamp)
2016 : m_BlobState(flags | CBioseq_Handle::fState_no_data),
2017 m_UnresolvedTimestamp(timestamp)
2018 {
2019 BIOSEQ_TRACE("CBioseq_ScopeInfo: "<<this);
2020 }
2021
2022
CBioseq_ScopeInfo(CTSE_ScopeInfo & tse)2023 CBioseq_ScopeInfo::CBioseq_ScopeInfo(CTSE_ScopeInfo& tse)
2024 : m_BlobState(CBioseq_Handle::fState_none),
2025 m_UnresolvedTimestamp(0)
2026 {
2027 BIOSEQ_TRACE("CBioseq_ScopeInfo: "<<this);
2028 x_AttachTSE(&tse);
2029 }
2030
2031
CBioseq_ScopeInfo(CTSE_ScopeInfo & tse,const TIds & ids)2032 CBioseq_ScopeInfo::CBioseq_ScopeInfo(CTSE_ScopeInfo& tse,
2033 const TIds& ids)
2034 : m_Ids(ids),
2035 m_BlobState(CBioseq_Handle::fState_none),
2036 m_UnresolvedTimestamp(0)
2037 {
2038 BIOSEQ_TRACE("CBioseq_ScopeInfo: "<<this);
2039 x_AttachTSE(&tse);
2040 }
2041
2042
~CBioseq_ScopeInfo(void)2043 CBioseq_ScopeInfo::~CBioseq_ScopeInfo(void)
2044 {
2045 if ( IsAttached() ) {
2046 BIOSEQ_TRACE("~CBioseq_ScopeInfo: "<<this<<
2047 " TSE "<<&x_GetTSE_ScopeInfo());
2048 }
2049 else {
2050 BIOSEQ_TRACE("~CBioseq_ScopeInfo: "<<this);
2051 }
2052 _ASSERT(!IsAttached());
2053 }
2054
2055
SetUnresolved(TBlobStateFlags flags,int timestamp)2056 void CBioseq_ScopeInfo::SetUnresolved(TBlobStateFlags flags, int timestamp)
2057 {
2058 _ASSERT(!HasBioseq());
2059 m_BlobState = flags | CBioseq_Handle::fState_no_data;
2060 m_UnresolvedTimestamp = timestamp;
2061 }
2062
2063
SetResolved(CTSE_ScopeInfo & tse,const TIds & ids)2064 void CBioseq_ScopeInfo::SetResolved(CTSE_ScopeInfo& tse,
2065 const TIds& ids)
2066 {
2067 _ASSERT(!HasBioseq());
2068 m_Ids = ids;
2069 m_BlobState = CBioseq_Handle::fState_none;
2070 m_UnresolvedTimestamp = 0;
2071 x_AttachTSE(&tse);
2072 }
2073
2074
GetIndexIds(void) const2075 const CBioseq_ScopeInfo::TIndexIds* CBioseq_ScopeInfo::GetIndexIds(void) const
2076 {
2077 const TIds& ids = GetIds();
2078 return ids.empty()? 0: &ids;
2079 }
2080
2081
HasBioseq(void) const2082 bool CBioseq_ScopeInfo::HasBioseq(void) const
2083 {
2084 return (GetBlobState() & CBioseq_Handle::fState_no_data) == 0;
2085 }
2086
2087
2088 CBioseq_ScopeInfo::TBioseq_Lock
GetLock(CConstRef<CBioseq_Info> bioseq)2089 CBioseq_ScopeInfo::GetLock(CConstRef<CBioseq_Info> bioseq)
2090 {
2091 return x_GetTSE_ScopeInfo().GetBioseqLock(Ref(this), bioseq);
2092 }
2093
2094
x_AttachTSE(CTSE_ScopeInfo * tse)2095 void CBioseq_ScopeInfo::x_AttachTSE(CTSE_ScopeInfo* tse)
2096 {
2097 BIOSEQ_TRACE("CBioseq_ScopeInfo: "<<this<<" x_AttachTSE "<<tse);
2098 m_BlobState = tse->GetTSE_Lock()->GetBlobState();
2099 CScopeInfo_Base::x_AttachTSE(tse);
2100 ITERATE ( TIds, it, GetIds() ) {
2101 tse->x_IndexBioseq(*it, this);
2102 }
2103 }
2104
x_DetachTSE(CTSE_ScopeInfo * tse)2105 void CBioseq_ScopeInfo::x_DetachTSE(CTSE_ScopeInfo* tse)
2106 {
2107 BIOSEQ_TRACE("CBioseq_ScopeInfo: "<<this<<" x_DetachTSE "<<tse);
2108 m_SynCache.Reset();
2109 x_ResetAnnotRef_Info();
2110 ITERATE ( TIds, it, GetIds() ) {
2111 tse->x_UnindexBioseq(*it, this);
2112 }
2113 CScopeInfo_Base::x_DetachTSE(tse);
2114 BIOSEQ_TRACE("CBioseq_ScopeInfo: "<<this<<" x_DetachTSE "<<tse<<" DONE");
2115 }
2116
2117
IdString(void) const2118 string CBioseq_ScopeInfo::IdString(void) const
2119 {
2120 CNcbiOstrstream os;
2121 const TIds& ids = GetIds();
2122 ITERATE ( TIds, it, ids ) {
2123 if ( it != ids.begin() )
2124 os << " | ";
2125 os << it->AsString();
2126 }
2127 return CNcbiOstrstreamToString(os);
2128 }
2129
2130
ResetId(void)2131 void CBioseq_ScopeInfo::ResetId(void)
2132 {
2133 _ASSERT(HasObject());
2134 const_cast<CBioseq_Info&>(GetObjectInfo()).ResetId();
2135 m_SynCache.Reset();
2136 x_GetScopeImpl().x_ClearCacheOnRemoveSeqId(CSeq_id_Handle(), *this);
2137 ITERATE ( TIds, it, GetIds() ) {
2138 x_GetTSE_ScopeInfo().x_UnindexBioseq(*it, this);
2139 }
2140 m_Ids.clear();
2141 }
2142
2143
AddId(const CSeq_id_Handle & id)2144 bool CBioseq_ScopeInfo::AddId(const CSeq_id_Handle& id)
2145 {
2146 _ASSERT(HasObject());
2147 CBioseq_Info& info = const_cast<CBioseq_Info&>(GetObjectInfo());
2148 if ( !info.AddId(id) ) {
2149 return false;
2150 }
2151 m_Ids.push_back(id);
2152 m_SynCache.Reset();
2153 x_GetTSE_ScopeInfo().x_IndexBioseq(id, this);
2154 x_GetScopeImpl().x_ClearCacheOnNewData(info.GetTSE_Info(), id);
2155 return true;
2156 }
2157
2158
RemoveId(const CSeq_id_Handle & id)2159 bool CBioseq_ScopeInfo::RemoveId(const CSeq_id_Handle& id)
2160 {
2161 _ASSERT(HasObject());
2162 if ( !const_cast<CBioseq_Info&>(GetObjectInfo()).RemoveId(id) ) {
2163 return false;
2164 }
2165 TIds::iterator it = find(m_Ids.begin(), m_Ids.end(), id);
2166 _ASSERT(it != m_Ids.end());
2167 x_GetScopeImpl().x_ClearCacheOnRemoveSeqId(id, *this);
2168 x_GetTSE_ScopeInfo().x_UnindexBioseq(id, this);
2169 m_Ids.erase(it);
2170 m_SynCache.Reset();
2171 return true;
2172 }
2173
2174
2175 /////////////////////////////////////////////////////////////////////////////
2176 // SSeq_id_ScopeInfo
2177 /////////////////////////////////////////////////////////////////////////////
2178
SSeq_id_ScopeInfo(void)2179 SSeq_id_ScopeInfo::SSeq_id_ScopeInfo(void)
2180 {
2181 }
2182
~SSeq_id_ScopeInfo(void)2183 SSeq_id_ScopeInfo::~SSeq_id_ScopeInfo(void)
2184 {
2185 }
2186
2187 /////////////////////////////////////////////////////////////////////////////
2188 // CSynonymsSet
2189 /////////////////////////////////////////////////////////////////////////////
2190
CSynonymsSet(void)2191 CSynonymsSet::CSynonymsSet(void)
2192 {
2193 }
2194
2195
~CSynonymsSet(void)2196 CSynonymsSet::~CSynonymsSet(void)
2197 {
2198 }
2199
2200
GetSeq_id_Handle(const const_iterator & iter)2201 CSeq_id_Handle CSynonymsSet::GetSeq_id_Handle(const const_iterator& iter)
2202 {
2203 return *iter;
2204 }
2205
2206
ContainsSynonym(const CSeq_id_Handle & id) const2207 bool CSynonymsSet::ContainsSynonym(const CSeq_id_Handle& id) const
2208 {
2209 ITERATE ( TIdSet, iter, m_IdSet ) {
2210 if ( *iter == id ) {
2211 return true;
2212 }
2213 }
2214 return false;
2215 }
2216
2217
AddSynonym(const CSeq_id_Handle & id)2218 void CSynonymsSet::AddSynonym(const CSeq_id_Handle& id)
2219 {
2220 _ASSERT(!ContainsSynonym(id));
2221 m_IdSet.push_back(id);
2222 }
2223
2224
2225 END_SCOPE(objects)
2226 END_NCBI_SCOPE
2227