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