NCBI C++ ToolKit
object_manager.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: object_manager.cpp 95839 2022-01-04 18:35:30Z fongah2 $
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 * Andrei Gourianov
28 * Aleksey Grichenko
29 * Michael Kimelman
30 * Denis Vakatov
31 *
32 * File Description:
33 * Object manager manages data objects,
34 * provides them to Scopes when needed
35 *
36 */
37 
38 #include <ncbi_pch.hpp>
40 #include <objmgr/data_loader.hpp>
44 #include <objmgr/error_codes.hpp>
45 
49 
50 
51 #define NCBI_USE_ERRCODE_X ObjMgr_Main
52 
54 
56 
58 
59 #ifdef _DEBUG
60 namespace {
61 
62 NCBI_PARAM_DECL(bool, OBJMGR, DEBUG_SCOPE);
63 NCBI_PARAM_DEF(bool, OBJMGR, DEBUG_SCOPE, false);
64 
65 static bool s_DebugScope(void)
66 {
67  static CSafeStatic<NCBI_PARAM_TYPE(OBJMGR, DEBUG_SCOPE)> sx_Value;
68  return sx_Value->Get();
69 }
70 
71 typedef map<const CScope_Impl*, AutoPtr<CStackTrace> > TScopeRegisterMap;
72 static CSafeStatic<TScopeRegisterMap> s_ScopeRegisterMap;
73 
74 void s_RegisterScope(const CScope_Impl& scope)
75 {
76  if ( s_DebugScope() ) {
78  s_ScopeRegisterMap.Get()[&scope] = st;
79  }
80 }
81 
82 void s_RevokeScope(const CScope_Impl& scope)
83 {
84  if ( s_DebugScope() ) {
85  s_ScopeRegisterMap.Get().erase(&scope);
86  }
87 }
88 
89 void s_DumpScopes(void)
90 {
91  if ( s_DebugScope() ) {
92  ITERATE ( TScopeRegisterMap, it, s_ScopeRegisterMap.Get() ) {
93  ERR_POST("Scope "<<it->first<<" registered at "<<*it->second);
94  }
95  }
96 }
97 
98 }
99 #endif
100 
101 
103 {
107  return Ref(&s_Instance.Get());
108 }
109 
110 
112  : m_Seq_id_Mapper(CSeq_id_Mapper::GetInstance())
113 {
114 }
115 
116 
118 {
119  // delete scopes
120  TWriteLockGuard guard(m_OM_Lock);
121 
122  if(!m_setScope.empty()) {
123  ERR_POST_X(1, "Attempt to delete Object Manager with open scopes");
124  while ( !m_setScope.empty() ) {
125  // this will cause calling RegisterScope and changing m_setScope
126  // be careful with data access synchronization
127  (*m_setScope.begin())->x_DetachFromOM();
128  }
129  }
130  // release data sources
131 
133 
134  while (!m_mapToSource.empty()) {
135  CDataSource* pSource = m_mapToSource.begin()->second.GetPointer();
136  _ASSERT(pSource);
137  if ( !pSource->ReferencedOnlyOnce() ) {
138  ERR_POST_X(2, "Attempt to delete Object Manager with used datasources");
139  }
141  }
142  // LOG_POST_X(3, "~CObjectManager - delete " << this << " done");
143 }
144 
145 /////////////////////////////////////////////////////////////////////////////
146 // configuration functions
147 
148 
150  EIsDefault is_default,
151  TPriority priority)
152 {
153  TWriteLockGuard guard(m_OM_Lock);
154  CDataLoader* loader = FindDataLoader(loader_maker.m_Name);
155  if (loader) {
156  loader_maker.m_RegisterInfo.Set(loader, false);
157  return;
158  }
159  try {
160  loader = loader_maker.CreateLoader();
161  x_RegisterLoader(*loader, priority, is_default);
162  }
163  catch (CObjMgrException& e) {
164  ERR_POST_X(4, Warning <<
165  "CObjectManager::RegisterDataLoader: " << e.GetMsg());
166  // This can happen only if something is wrong with the new loader.
167  // loader_maker.m_RegisterInfo.Set(0, false);
168  throw;
169  }
170  loader_maker.m_RegisterInfo.Set(loader, true);
171 }
172 
173 
175 {
176  if (!m_PluginManager.get()) {
177  TWriteLockGuard guard(m_OM_Lock);
178  if (!m_PluginManager.get()) {
179  m_PluginManager.reset(new TPluginManager);
180  }
181  }
182  _ASSERT(m_PluginManager.get());
183  return *m_PluginManager;
184 }
185 
186 
189  const string& driver_name)
190 {
191  // Check params, extract driver name, add pointer to self etc.
192  //
193  //
194  typedef CInterfaceVersion<CDataLoader> TDLVersion;
195  return x_GetPluginManager().CreateInstance(driver_name,
196  CVersionInfo(TDLVersion::eMajor,
197  TDLVersion::eMinor,
198  TDLVersion::ePatchLevel),
199  params);
200 }
201 
202 
204 {
205  string loader_name = loader.GetName();
206 
207  TWriteLockGuard guard(m_OM_Lock);
208  // make sure it is registered
209  CDataLoader* my_loader = x_GetLoaderByName(loader_name);
210  if ( my_loader != &loader ) {
211  NCBI_THROW(CObjMgrException, eRegisterError,
212  "Data loader " + loader_name + " not registered");
213  }
214  TDataSourceLock lock = x_RevokeDataLoader(&loader);
215  guard.Release();
216  return lock.NotEmpty();
217 }
218 
219 
220 bool CObjectManager::RevokeDataLoader(const string& loader_name)
221 {
222  TWriteLockGuard guard(m_OM_Lock);
223  CDataLoader* loader = x_GetLoaderByName(loader_name);
224  // if not registered
225  if ( !loader ) {
226  NCBI_THROW(CObjMgrException, eRegisterError,
227  "Data loader " + loader_name + " not registered");
228  }
229  TDataSourceLock lock = x_RevokeDataLoader(loader);
230  guard.Release();
231  return lock.NotEmpty();
232 }
233 
234 
236 {
237  TWriteLockGuard guard(m_OM_Lock);
239  iter->second->RevokeDataLoader();
240  }
244 }
245 
246 
248 {
249 }
250 
251 
253 {
254  TWriteLockGuard guard(m_OM_Lock);
256  TDataSourceLock source = iter->second;
257  CDataLoader* loader = source->GetDataLoader();
258  if ( loader && filter.IsDataLoaderMatches(*loader) ) {
259  m_mapNameToLoader.erase(loader->GetName());
260  m_mapToSource.erase(loader);
262  source->RevokeDataLoader();
263  }
264  }
265 }
266 
267 
270 {
272  _ASSERT(iter != m_mapToSource.end());
273  _ASSERT(iter->second->GetDataLoader() == loader);
274  bool is_default = m_setDefaultSource.erase(iter->second) != 0;
275  if ( !iter->second->ReferencedOnlyOnce() ) {
276  // this means it is in use
277  if ( is_default )
278  _VERIFY(m_setDefaultSource.insert(iter->second).second);
279  ERR_POST_X(5, "CObjectManager::RevokeDataLoader: "
280  "data loader is in use");
281 #ifdef _DEBUG
282  s_DumpScopes();
283 #endif
284  return TDataSourceLock();
285  }
286  // remove from the maps
287  TDataSourceLock lock(iter->second);
288  m_mapNameToLoader.erase(loader->GetName());
289  m_mapToSource.erase(loader);
290  return lock;
291 }
292 
293 
294 CDataLoader* CObjectManager::FindDataLoader(const string& loader_name) const
295 {
296  TReadLockGuard guard(m_OM_Lock);
297  return x_GetLoaderByName(loader_name);
298 }
299 
300 
302 {
303  TReadLockGuard guard(m_OM_Lock);
305  names.push_back(it->first);
306  }
307 }
308 
309 
310 // Update loader's options
311 void CObjectManager::SetLoaderOptions(const string& loader_name,
312  EIsDefault is_default,
313  TPriority priority)
314 {
315  TWriteLockGuard guard(m_OM_Lock);
316  CDataLoader* loader = x_GetLoaderByName(loader_name);
317  if ( !loader ) {
318  NCBI_THROW(CObjMgrException, eRegisterError,
319  "Data loader " + loader_name + " not registered");
320  }
321  TMapToSource::iterator data_source = m_mapToSource.find(loader);
322  _ASSERT(data_source != m_mapToSource.end());
324  m_setDefaultSource.find(data_source->second);
325  if (is_default == eDefault && def_it == m_setDefaultSource.end()) {
326  m_setDefaultSource.insert(data_source->second);
327  }
328  else if (is_default == eNonDefault && def_it != m_setDefaultSource.end()) {
329  m_setDefaultSource.erase(def_it);
330  }
331  if (priority != kPriority_Default &&
332  data_source->second->GetDefaultPriority() != priority) {
333  data_source->second->SetDefaultPriority(priority);
334  }
335 }
336 
337 
338 /////////////////////////////////////////////////////////////////////////////
339 // functions for scopes
340 
342 {
344  _VERIFY(m_setScope.insert(&scope).second);
345 #ifdef _DEBUG
346  s_RegisterScope(scope);
347 #endif
348 }
349 
350 
352 {
354  _VERIFY(m_setScope.erase(&scope));
355 #ifdef _DEBUG
356  s_RevokeScope(scope);
357 #endif
358 }
359 
360 
362 {
363  TReadLockGuard guard(m_OM_Lock);
364  sources = m_setDefaultSource;
365 }
366 
367 
370 {
371  TReadLockGuard guard(m_OM_Lock);
372  TDataSourceLock lock = x_FindDataSource(&loader);
373  if ( !lock ) {
374  guard.Release();
375  TWriteLockGuard wguard(m_OM_Lock);
376  lock = x_RegisterLoader(loader, kPriority_Default, eNonDefault, true);
377  }
378  return lock;
379 }
380 
381 
383 CObjectManager::AcquireDataLoader(const string& loader_name)
384 {
385  TReadLockGuard guard(m_OM_Lock);
386  CDataLoader* loader = x_GetLoaderByName(loader_name);
387  if ( !loader ) {
388  NCBI_THROW(CObjMgrException, eRegisterError,
389  "Data loader " + loader_name + " not found");
390  }
391  TDataSourceLock lock = x_FindDataSource(loader);
392  _ASSERT(lock);
393  return lock;
394 }
395 
396 
399 {
400  TReadLockGuard guard(m_OM_Lock);
401  TDataSourceLock lock = x_FindDataSource(&object);
402  if ( !lock ) {
403  guard.Release();
404 
405  TDataSourceLock source(new CDataSource(object, object));
406  source->DoDeleteThisObject();
407 
408  TWriteLockGuard wguard(m_OM_Lock);
409  lock = m_mapToSource.insert(
410  TMapToSource::value_type(&object, source)).first->second;
411  _ASSERT(lock);
412  }
413  return lock;
414 }
415 
416 
419 {
420  TReadLockGuard guard(m_OM_Lock);
421  TDataSourceLock lock = x_FindDataSource(&object);
422  if ( !lock ) {
423  guard.Release();
424 
425  CRef<CSeq_entry> entry(new CSeq_entry);
426  entry->SetSeq(const_cast<CBioseq&>(object));
427  TDataSourceLock source(new CDataSource(object, *entry));
428  source->DoDeleteThisObject();
429 
430  TWriteLockGuard wguard(m_OM_Lock);
431  lock = m_mapToSource.insert(
432  TMapToSource::value_type(&object, source)).first->second;
433  _ASSERT(lock);
434  }
435  return lock;
436 }
437 
438 
441 {
442  TReadLockGuard guard(m_OM_Lock);
443  TDataSourceLock lock = x_FindDataSource(&object);
444  if ( !lock ) {
445  guard.Release();
446 
447  CRef<CSeq_entry> entry(new CSeq_entry);
448  entry->SetSet().SetSeq_set(); // it's not optional
449  entry->SetSet().SetAnnot()
450  .push_back(Ref(&const_cast<CSeq_annot&>(object)));
451  TDataSourceLock source(new CDataSource(object, *entry));
452  source->DoDeleteThisObject();
453 
454  TWriteLockGuard wguard(m_OM_Lock);
455  lock = m_mapToSource.insert(
456  TMapToSource::value_type(&object, source)).first->second;
457  _ASSERT(lock);
458  }
459  return lock;
460 }
461 
462 
463 /////////////////////////////////////////////////////////////////////////////
464 // private functions
465 
466 
469 {
471  return iter == m_mapToSource.end()? TDataSourceLock(): iter->second;
472 }
473 
474 
477  CPriorityNode::TPriority priority,
478  EIsDefault is_default,
479  bool no_warning)
480 {
481  string loader_name = loader.GetName();
482  _ASSERT(!loader_name.empty());
483 
484  // if already registered
485  pair<TMapNameToLoader::iterator, bool> ins =
487  if ( !ins.second ) {
488  if ( ins.first->second != &loader ) {
489  NCBI_THROW(CObjMgrException, eRegisterError,
490  "Attempt to register different data loaders "
491  "with the same name");
492  }
493  if ( !no_warning ) {
494  ERR_POST_X(6, Warning <<
495  "CObjectManager::RegisterDataLoader() -- data loader " <<
496  loader_name << " already registered");
497  }
499  _ASSERT(it != m_mapToSource.end() && it->second);
500  return it->second;
501  }
502  ins.first->second = &loader;
503 
504  // create data source
505  TDataSourceLock source(new CDataSource(loader));
506  source->DoDeleteThisObject();
507  if (priority != kPriority_Default) {
508  source->SetDefaultPriority(priority);
509  }
511  source)).second);
512  if (is_default == eDefault) {
514  }
515  return source;
516 }
517 
518 
520 {
522  return itMap == m_mapNameToLoader.end()? 0: itMap->second;
523 }
524 
525 
527 {
528  CDataSource& ds = *pSource;
529  _ASSERT(pSource->Referenced());
530  CDataLoader* loader = ds.GetDataLoader();
531  if ( loader ) {
532  pSource.Reset();
533  return;
534  }
535 
537  if ( !key ) {
538  pSource.Reset();
539  return;
540  }
541 
542  TWriteLockGuard guard(m_OM_Lock);
544  if ( iter == m_mapToSource.end() ) {
545  guard.Release();
546  ERR_POST_X(7, "CObjectManager::ReleaseDataSource: "
547  "unknown data source");
548  pSource.Reset();
549  return;
550  }
551  _ASSERT(pSource == iter->second);
552  _ASSERT(ds.Referenced() && !ds.ReferencedOnlyOnce());
553  pSource.Reset();
554  if ( ds.ReferencedOnlyOnce() ) {
555  // Destroy data source if it's linked to an entry and is not
556  // referenced by any scope.
557  pSource = iter->second;
558  m_mapToSource.erase(iter);
560  guard.Release();
561  pSource.Reset();
562  return;
563  }
564  return;
565 }
566 
567 
CDataLoader * GetDataLoader(void) const
const CConstRef< CObject > & GetSharedObject(void) const
void Release()
Manually force the resource to be released.
Definition: guard.hpp:166
CInterfaceVersion<> –.
Base class for all object manager exceptions.
CObject –.
Definition: ncbiobj.hpp:180
CPluginManager<> –.
CSafeStaticLifeSpan::
@ eLifeLevel_AppMain
Destroyed in CNcbiApplication::AppMain, if possible.
CSafeStatic<>::
T & Get(void)
Create the variable if not created yet, return the reference.
Definition: Seq_entry.hpp:56
definition of a Culling tree
Definition: ncbi_tree.hpp:100
CVersionInfo –.
void erase(iterator pos)
Definition: map.hpp:167
const_iterator begin() const
Definition: map.hpp:151
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
bool empty() const
Definition: map.hpp:149
void clear()
Definition: map.hpp:169
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: map.hpp:338
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
const_iterator begin() const
Definition: set.hpp:135
void clear()
Definition: set.hpp:153
parent_type::iterator iterator
Definition: set.hpp:80
bool empty() const
Definition: set.hpp:133
const_iterator find(const key_type &key) const
Definition: set.hpp:137
void erase(iterator pos)
Definition: set.hpp:151
const_iterator end() const
Definition: set.hpp:136
static const struct name_t names[]
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define ERASE_ITERATE(Type, Var, Cont)
Non-constant version with ability to erase current element, if container permits.
Definition: ncbimisc.hpp:843
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define _VERIFY(expr)
Definition: ncbidbg.hpp:161
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
const string & GetMsg(void) const
Get message string.
Definition: ncbiexpt.cpp:461
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
void Set(CDataLoader *loader, bool created)
void AcquireDefaultDataSources(TDataSourcesLock &sources)
TMapNameToLoader m_mapNameToLoader
TDataSourceLock AcquireSharedSeq_entry(const CSeq_entry &object)
static CRef< CObjectManager > GetInstance(void)
Return the existing object manager or create one.
TDataSourceLock x_RevokeDataLoader(CDataLoader *loader)
virtual CDataLoader * CreateLoader(void) const =0
void RevokeDataLoaders(IDataLoaderFilter &filter)
Revoke data loaders by filter, even if they were still used.
void RevokeScope(CScope_Impl &scope)
TSetDefaultSource m_setDefaultSource
string GetName(void) const
void RevokeAllDataLoaders(void)
Revoke all registered data loaders, even if they were still used.
void SetLoaderOptions(const string &loader_name, EIsDefault is_default, TPriority priority=kPriority_Default)
Update loader's default-ness and priority.
CDataLoader * FindDataLoader(const string &loader_name) const
Try to find a registered data loader by name.
virtual ~CObjectManager(void)
TRegisterInfo_Base m_RegisterInfo
TMapToSource m_mapToSource
EIsDefault
Flag defining if the data loader is included in the "default" group.
CDataLoader * RegisterDataLoader(TPluginManagerParamTree *params=0, const string &driver_name=kEmptyStr)
Add data loader using plugin manager.
TDataSourceLock AcquireSharedBioseq(const CBioseq &object)
TSetScope m_setScope
TDataSourceLock AcquireSharedSeq_annot(const CSeq_annot &object)
void RegisterScope(CScope_Impl &scope)
virtual bool IsDataLoaderMatches(CDataLoader &loader) const =0
CRef< CDataSource > TDataSourceLock
unique_ptr< TPluginManager > m_PluginManager
TDataSourceLock AcquireDataLoader(CDataLoader &loader)
friend class CDataSource
void GetRegisteredNames(TRegisteredNames &names)
Get names of all registered data loaders.
vector< string > TRegisteredNames
TDataSourceLock x_RegisterLoader(CDataLoader &loader, TPriority priority, EIsDefault is_default=eNonDefault, bool no_warning=false)
TPluginManager & x_GetPluginManager(void)
TDataSourceLock x_FindDataSource(const CObject *key)
void ReleaseDataSource(TDataSourceLock &data_source)
bool RevokeDataLoader(CDataLoader &loader)
Revoke previously registered data loader.
CDataLoader * x_GetLoaderByName(const string &loader_name) const
@ kPriority_Default
Use default priority for added data.
CRef< C > Ref(C *object)
Helper functions to get CRef<> and CConstRef<> objects.
Definition: ncbiobj.hpp:2015
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
bool NotEmpty(void) const THROWS_NONE
Check if CRef is not empty – pointing to an object and has a non-null value.
Definition: ncbiobj.hpp:726
bool Referenced(void) const THROWS_NONE
Check if object is referenced.
Definition: ncbiobj.hpp:468
bool ReferencedOnlyOnce(void) const THROWS_NONE
Check if object is referenced only once.
Definition: ncbiobj.hpp:475
#define NCBI_PARAM_TYPE(section, name)
Generate typename for a parameter from its {section, name} attributes.
Definition: ncbi_param.hpp:149
#define NCBI_PARAM_DECL(type, section, name)
Parameter declaration.
Definition: ncbi_param.hpp:157
#define NCBI_PARAM_DEF(type, section, name, default_value)
Parameter definition.
Definition: ncbi_param.hpp:206
TClass * CreateInstance(const string &driver=kEmptyStr, const CVersionInfo &version=GetDefaultDrvVers(), const TPluginManagerParamTree *params=0)
Create class instance.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define END_SCOPE(ns)
End the previously defined scope.
Definition: ncbistl.hpp:75
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define BEGIN_SCOPE(ns)
Define a new scope.
Definition: ncbistl.hpp:72
TSet & SetSet(void)
Select the variant.
Definition: Seq_entry_.cpp:130
TAnnot & SetAnnot(void)
Assign a value to Annot data member.
TSeq & SetSeq(void)
Select the variant.
Definition: Seq_entry_.cpp:108
TSeq_set & SetSeq_set(void)
Assign a value to Seq_set data member.
Definition of all error codes used in objmgr libraries (xobjmgr.lib, xobjutil.lib and others).
static CSafeStatic< CMetaRegistry > s_Instance
Definition: metareg.cpp:59
const struct ncbi::grid::netcache::search::fields::KEY key
const CharType(& source)[N]
Definition: pointer.h:1149
Static variables safety - create on demand, destroy on application termination.
NCBI_DEFINE_ERR_SUBCODE_X(7)
The Object manager core.
#define _ASSERT
Modified on Fri Dec 01 04:47:51 2023 by modify_doxy.py rev. 669887