1 #ifndef OBJTOOLS_READERS_SEQDB__SEQDBATLAS_HPP
2 #define OBJTOOLS_READERS_SEQDB__SEQDBATLAS_HPP
3
4 /* $Id: seqdbatlas.hpp 631567 2021-05-19 13:53:46Z ivanov $
5 * ===========================================================================
6 *
7 * PUBLIC DOMAIN NOTICE
8 * National Center for Biotechnology Information
9 *
10 * This software/database is a "United States Government Work" under the
11 * terms of the United States Copyright Act. It was written as part of
12 * the author's official duties as a United States Government employee and
13 * thus cannot be copyrighted. This software/database is freely available
14 * to the public for use. The National Library of Medicine and the U.S.
15 * Government have not placed any restriction on its use or reproduction.
16 *
17 * Although all reasonable efforts have been taken to ensure the accuracy
18 * and reliability of the software and data, the NLM and the U.S.
19 * Government do not and cannot warrant the performance or results that
20 * may be obtained by using this software or data. The NLM and the U.S.
21 * Government disclaim all warranties, express or implied, including
22 * warranties of performance, merchantability or fitness for any particular
23 * purpose.
24 *
25 * Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author: Kevin Bealer
30 *
31 */
32
33 /// @file seqdbatlas.hpp
34 /// The SeqDB memory management layer.
35 ///
36 /// Defines classes:
37 /// CSeqDBLockHold
38 /// CSeqDBMemReg
39 /// CSeqDB_AtlasRegionHolder
40 /// CSeqDBAtlas
41 /// CSeqDBAtlasHolder
42 ///
43 /// Implemented for: UNIX, MS-Windows
44
45
46 #include <corelib/ncbimtx.hpp>
47 #include <corelib/ncbiatomic.hpp>
48 #include <corelib/ncbifile.hpp>
49 #include <corelib/ncbi_system.hpp>
50 #include <corelib/ncbiapp_api.hpp>
51
52 #include <objtools/blast/seqdb_reader/impl/seqdbgeneral.hpp>
53
54 #include <vector>
55 #include <map>
56 #include <set>
57 #include <mutex>
58
59 BEGIN_NCBI_SCOPE
60
61 #ifdef SEQDB_TRACE_LOGFILE
62
63 #define SEQDB_LOGCLASS_DEFAULT 1
64 #define SEQDB_LOGCLASS_MMAP 2
65 #define SEQDB_LOGCLASS_MFILE 4
66 #define SEQDB_LOGCLASS_GET 8
67
68 extern ofstream * seqdb_logfile;
69 extern int seqdb_logclass;
70
71 void seqdb_log(const char * s);
72 void seqdb_log(const char * s1, const string & s2);
73
74 void seqdb_log(int cl, const char * s);
75 void seqdb_log(int cl, const char * s1, const string & s2);
76 void seqdb_log(int cl, const char * s1, int s2);
77 #endif // SEQDB_TRACE_LOGFILE
78
79 #ifdef _DEBUG
80
81 #include <iostream>
82
83 // These defines implement a system for testing memory corruption,
84 // especially overwritten pointers and clobbered objects. They are
85 // only enabled in debug mode.
86
87 // If this is required for release mode as well, be sure to replace
88 // _ASSERT() with something useful for release mode.
89
90 /// Define memory marker for class (4+ bytes of uppercase ascii).
91
92 // Note: this is now strictly 4 bytes and little-endian-centric (on
93 // big endian architectures the bytes will be in the other order than
94 // the string would imply. This should not matter to the code.
95
96 #define INT4IFY_STRING(a) \
97 (((a[3] & 0xFF) << 24) | \
98 ((a[2] & 0xFF) << 16) | \
99 ((a[1] & 0xFF) << 8) | \
100 ((a[0] & 0xFF)))
101
102 #define CLASS_MARKER_FIELD(a) \
103 static int x_GetClassMark() { return INT4IFY_STRING(a); } \
104 static string x_GetMarkString() { return string((a a), 4); } \
105 int m_ClassMark;
106
107 /// Marker initializer for constructor
108 #define INIT_CLASS_MARK() m_ClassMark = x_GetClassMark()
109
110 /// Assertion to verify the marker
111 #define CHECK_MARKER() \
112 if (m_ClassMark != x_GetClassMark()) { \
113 cout << "Marker=" << m_ClassMark << endl; \
114 cout << "GetMrk=" << x_GetClassMark() << endl; \
115 cout << "\n!! Broken [" << x_GetMarkString() << "] mark detected.\n" \
116 << "!! Mark is [" << hex << m_ClassMark << "], should be [" \
117 << hex << x_GetClassMark() << "]." << endl; \
118 _ASSERT(m_ClassMark == x_GetClassMark()); \
119 }
120
121 /// Make the marker of this class invalid.
122 #define BREAK_MARKER() m_ClassMark |= 0x20202020;
123
124 #else
125
126 /// Define memory marker for class (release mode code elision)
127 #define CLASS_MARKER_FIELD(a)
128
129 /// Initializer for constructor (release mode code elision)
130 #define INIT_CLASS_MARK()
131
132 /// Assertion to verify the marker (release mode code elision)
133 #define CHECK_MARKER()
134
135 /// Make the marker of this class invalid (release mode code elision)
136 #define BREAK_MARKER()
137
138 #endif
139
140 /// CSeqDBAtlas class - a collection of memory maps.
141 class CSeqDBAtlas; // WorkShop needs this forward declaration.
142 class CSeqDBFileMemMap;
143
144 /// Return path with delimiters changed to platform preferred kind.
145 ///
146 /// The path is modified and returned. The 'Make' interface is more
147 /// convenient for cases where the input path and output path are
148 /// different objects. Delimiter conversion should be called by SeqDB
149 /// at least once on any path received from the user, or via
150 /// filesystem sources such as alias files.
151 ///
152 /// @param dbs This is the input path.
153 /// @return The modified path is returned.
154 string SeqDB_MakeOSPath(const string & dbs);
155
156
157 /// CSeqDBLockHold
158 ///
159 /// This class is used to keep track of whether this thread holds the
160 /// atlas lock. The atlas code will skip subsequent Lock() operations
161 /// during the same transaction if the lock is already held. This
162 /// allows code that needs locking to get the lock without worrying
163 /// about whether the calling function has already done so. The
164 /// destructor of this object will call Unlock() on the atlas if this
165 /// thread has it locked.
166
167 class NCBI_XOBJREAD_EXPORT CSeqDBLockHold {
168 public:
169 /// Constructor
170 ///
171 /// This object constructs to an unlocked state, which means that
172 /// the thread owning the stack frame where this object is stored
173 /// does not hold the atlas lock. This object keeps a reference
174 /// to the atlas object so that it can release the lock on
175 /// destruction, making it easier to write exception safe code.
176 /// @param atlas
177 /// A reference to the atlas object.
CSeqDBLockHold(class CSeqDBAtlas & atlas)178 CSeqDBLockHold(class CSeqDBAtlas & atlas)
179 : m_Atlas(atlas),
180 m_Locked(false)
181 {
182 INIT_CLASS_MARK();
183 }
184
185
186 /// Destructor
187 ///
188 /// The class will unlock the atlas's lock on destruction (if it
189 /// is the owner of that lock).
190 ~CSeqDBLockHold();
191
192 private:
193 CLASS_MARKER_FIELD("LHLD")
194
195 /// Private method to prevent copy construction.
196 CSeqDBLockHold(CSeqDBLockHold & oth);
197 CSeqDBLockHold& operator=(CSeqDBLockHold & oth);
198
199 /// Only the atlas code is permitted to modify this object - it
200 /// does so simply by editing the m_Locked member as needed.
201 friend class CSeqDBAtlas;
202
203 /// This reference allows unlock on exit.
204 class CSeqDBAtlas & m_Atlas;
205
206 /// If this is true, this thread owns the atlas lock.
207 volatile bool m_Locked;
208 };
209
210
211 /// CSeqDBMemReg
212 ///
213 /// This class is used to keep track of bytes allocated externally to
214 /// the atlas, but included under its memory bound.
215
216 class CSeqDBMemReg {
217 public:
218 /// Constructor
219 ///
220 /// This object constructs to an empty state, which means that the
221 /// atlas does not consider this object to "own" any bytes.
222 ///
223 /// @param atlas
224 /// A reference to the atlas object.
CSeqDBMemReg(class CSeqDBAtlas & atlas)225 CSeqDBMemReg(class CSeqDBAtlas & atlas)
226 : m_Atlas(atlas),
227 m_Bytes(0)
228 {
229 }
230
231 /// Destructor
232 ///
233 /// The class will unlock the atlas's lock on destruction (if it
234 /// is the owner of that lock).
235 inline ~CSeqDBMemReg();
236
237 private:
238 /// Private method to prevent copy construction.
239 CSeqDBMemReg(CSeqDBMemReg & oth);
240
241 /// Only the atlas code is permitted to modify this object - it
242 /// does so simply by editing the m_Locked member as needed.
243 friend class CSeqDBAtlas;
244
245 /// This reference allows unlock on exit.
246 class CSeqDBAtlas & m_Atlas;
247
248 /// This object "owns" this many bytes of the atlas memory bound.
249 size_t m_Bytes;
250 };
251
252
253
254
255 /// Hold a memory region refcount, return to atlas when destroyed.
256 ///
257 /// This object `owns' a reference to a region of atlas owned memory,
258 /// releasing that reference when destructed. This can be used to
259 /// return a hold on a region of memory to the user. Care should be
260 /// taken when managing these objects. In particular there should
261 /// never be a case where a "live" object of this type could be
262 /// destroyed in a thread that already holds the atlas lock. A simple
263 /// technique is to keep an extra CRef<> to this object until the
264 /// thread releasees the lock.
265
266 class CSeqDB_AtlasRegionHolder : public CObject {
267 public:
268 /// Constructor.
269 CSeqDB_AtlasRegionHolder(CSeqDBAtlas & atlas, const char * ptr);
270
271 /// Destructor.
272 ~CSeqDB_AtlasRegionHolder();
273
274 private:
275 /// Reference to the memory management layer.
276 CSeqDBAtlas & m_Atlas;
277
278 /// Pointer to this object.
279 const char * m_Ptr;
280 };
281
282
283 /// CSeqDBAtlas class
284 ///
285 /// This object manages a collection of (memory) maps. It mmaps or
286 /// reads data from files on demand, to allow a set of files to be
287 /// accessed efficiently by SeqDB. The total size of the files used
288 /// by a multivolume database may exceed the usable address space of
289 /// the system by several times. SeqDB also registers certain large,
290 /// dynamically allocated (via new[]) memory blocks with this object,
291 /// in an effort to limit the total memory usage. This class also
292 /// contains the primary mutex used to sequentialize access to the
293 /// various SeqDB critical regions, some of which are outside of this
294 /// class. ["Atlas: n. 1. A book or bound collection of maps..."; The
295 /// American Heritage Dictionary of the English Language, 4th Edition.
296 /// Copyright (c) 2000 by Houghton Mifflin Company.]
297
298 class NCBI_XOBJREAD_EXPORT CSeqDBAtlas {
299 public:
300 /// The type used for file offsets.
301 //typedef CRegionMap::TIndx TIndx;
302 typedef CNcbiStreamoff TIndx;
303
304 /// Constructor
305 ///
306 /// Initializes the atlas object.
307 /// @param use_atlas_lock If true, the atlas lock will be used to protect
308 /// critical regions, otherwise the Lock() and Unlock() functions will be
309 /// noops. Setting the parameter to false improves CPU utilization when
310 /// each thread access a different database volume. It should be set to
311 /// true in other cases.
312 CSeqDBAtlas(bool use_atlas_lock);
313
314 /// The destructor unmaps and frees all associated memory.
315 ~CSeqDBAtlas();
316
317
318 enum {e_MaxFileDescritors = 950};
319
320 /// Check if file exists.
321 ///
322 /// If the file exists, this method will return true, otherwise
323 /// false. Also, if the file exists, the first slice of it will
324 /// be mapped. This method exists for efficiency reasons; it is
325 /// cheaper to ask the atlas whether it already knows about a file
326 /// than to search the filesystem for the file, particularly in
327 /// the case of network file systems. If a slice of the file has
328 /// already been mapped, this will return true without consulting
329 /// the file system, so this method will not detect files that
330 /// have been deleted since the mapping occurred.
331 ///
332 /// @param fname
333 /// The filename of the file to get.
334 /// @param locked
335 /// The lock hold object for this thread.
336 /// @return
337 /// True if the file exists.
338 bool DoesFileExist(const string & fname);
339
340 /// Check if file exists.
341 ///
342 /// This is like the previous but accepts CSeqDB_Path.
343 ///
344 /// @param fname
345 /// The filename of the file to get.
346 /// @param locked
347 /// The lock hold object for this thread.
348 /// @return
349 /// True if the file exists.
DoesFileExist(const CSeqDB_Path & fname)350 bool DoesFileExist(const CSeqDB_Path & fname)
351 {
352 return DoesFileExist(fname.GetPathS());
353 }
354
355 /// Get size of a file.
356 ///
357 /// Check whether a file exists and get the file's size.
358 ///
359 /// @param fname
360 /// The filename of the file to get the size of.
361 /// @param length
362 /// The length of the file is returned here.
363 /// @param locked
364 /// The lock hold object for this thread.
365 /// @return
366 /// true if the file exists.
367 bool GetFileSize(const string & fname,
368 TIndx & length);
369
370 /// Get size of a file.
371 ///
372 /// Check whether a file exists and get the file's size. This
373 /// version assumes the atlas lock is held.
374 ///
375 /// @param fname
376 /// The filename of the file to get the size of.
377 /// @param length
378 /// The length of the file is returned here.
379 /// @return
380 /// true if the file exists.
381 bool GetFileSizeL(const string & fname, TIndx & length);
382
383 /// Free allocated memory.
384 ///
385 /// This method releases the memory aquired
386 /// by the Alloc() method. With
387 /// data known to have originated in Alloc(), it is faster to call
388 /// the Free() method. This method assumes the lock is held.
389 ///
390 /// @param datap
391 /// Pointer to the data to release or deallocate.
392 static void RetRegion(const char * datap);
393
394 /// Allocate memory that atlas will keep track of.
395 ///
396 /// This method allocates memory for the calling code's use.
397 /// There are three reasons to do this. First, the allocated
398 /// memory is guaranteed to be deleted when the atlas destructor
399 /// runs, so using this method ties the lifetime of the allocated
400 /// memory to that of the atlas, which may prevent memory leaks.
401 /// Secondly, allocating memory in this way brings the allocated
402 /// memory under the total memory bound the atlas imposes on
403 /// itself. The amount of memory assumed to be available for
404 /// slice allocation will be reduced by the size of these
405 /// allocations during garbage collection. Thirdly, the memory
406 /// allocated this way can be freed by the RetRegion(char*)
407 /// method, so the RetSequence code in the volume layers (and
408 /// thereabouts) does not need to can return allocated memory to
409 /// the user as "sequence data", and does not have to track
410 /// whether the data was allocated or mapped.
411 ///
412 /// @param length
413 /// Amount of memory to allocate in bytes.
414 /// @param locked
415 /// The lock hold object for this thread.
416 /// @param clear
417 /// Specify true to zero out memory contents.
418 /// @return
419 /// A pointer to the allocation region of memory.
420 static char * Alloc(size_t length, bool clear = true);
421
422
423 /// Register externally allocated memory.
424 ///
425 /// This method tells the atlas code that memory was allocated
426 /// external to the atlas code, and should be included under the
427 /// memory bound enforced by the atlas. These areas of memory
428 /// will not be managed by the atlas, but may influence the atlas
429 /// by causing database volume files or auxiliary files to be
430 /// unmapped earlier or more often. This method may trigger atlas
431 /// garbage collection. RegisterFree() should be called when the
432 /// memory is freed.
433 ///
434 /// @param memreg
435 /// Memory registration tracking object.
436 /// @param bytes
437 /// Amount of memory externally allocated.
438 /// @param locked
439 /// The lock hold object for this thread.
440 void RegisterExternal(CSeqDBMemReg & memreg,
441 size_t bytes,
442 CSeqDBLockHold & locked);
443
444 /// Unregister externally allocated memory.
445 ///
446 /// This method tells the atlas that external memory registered
447 /// with RegisterExternal() has been freed. The atlas lock is
448 /// assumed to be held.
449 ///
450 /// @param memreg
451 /// Memory registration tracking object.
452 void UnregisterExternal(CSeqDBMemReg & memreg);
453
454 /// Lock the atlas.
455 ///
456 /// If the lock hold object passed to
457 /// this method is already in a "locked" state, this call is a
458 /// noop. Otherwise, the lock hold object is put in a locked
459 /// state and the lock is acquired.
460 ///
461 /// @param locked
462 /// This object tracks whether this thread owns the mutex.
Lock(CSeqDBLockHold & locked)463 void Lock(CSeqDBLockHold & locked)
464 {
465 if (m_UseLock && !locked.m_Locked) {
466 m_Lock.Lock();
467 locked.m_Locked = true;
468 }
469 }
470
471 /// Unlock the atlas.
472 ///
473 /// If the lock hold object passed to
474 /// this method is already in an "unlocked" state, this call is a
475 /// noop. Otherwise, the lock hold object is put in an unlocked
476 /// state and the lock is released.
477 ///
478 /// @param locked
479 /// This object tracks whether this thread owns the mutex.
Unlock(CSeqDBLockHold & locked)480 void Unlock(CSeqDBLockHold & locked)
481 {
482 if (m_UseLock && locked.m_Locked) {
483 locked.m_Locked = false;
484 m_Lock.Unlock();
485 }
486 }
487
488
489 /// Get the current slice size.
490 ///
491 /// This returns the current slice size used for mmap() style
492 /// memory allocations.
493 ///
494 /// @return
495 /// Atlas will try to map this much data at a time.
496
GetSliceSize()497 Uint8 GetSliceSize()
498 {
499 Uint8 max_slice = e_MaxSlice64;
500 Uint8 sliceSize = min(max_slice,m_MaxFileSize);
501 return sliceSize;
502 }
503
504 /// Get BlastDB search path.
GetSearchPath() const505 const string GetSearchPath() const
506 {
507 return m_SearchPath;
508 }
509
510 /// Generate search path
GenerateSearchPath()511 static const string GenerateSearchPath() {
512 string splitter;
513 string path;
514 #if defined(NCBI_OS_UNIX)
515 splitter = ":";
516 #else
517 splitter = ";";
518 #endif
519 // Local directory first;
520 path = CDirEntry::NormalizePath(CDir::GetCwd(),eFollowLinks);
521 path += splitter;
522 // Then, BLASTDB;
523 CNcbiEnvironment env;
524 path += CDirEntry::NormalizePath(env.Get("BLASTDB"),eFollowLinks);
525 path += splitter;
526 // Finally, the config file.
527 CNcbiApplicationAPI* app = CNcbiApplicationAPI::Instance();
528 if (app) {
529 const CNcbiRegistry& registry = app->GetConfig();
530 if (registry.HasEntry("BLAST", "BLASTDB")) {
531 path += CDirEntry::NormalizePath(registry.Get("BLAST", "BLASTDB"),eFollowLinks);
532 path += splitter;
533 }
534 }
535 return path;
536 }
537
538 CMemoryFile* GetMemoryFile(const string& fileName);
539
540 enum EFilesCount{
541 eFileCounterNoChange,
542 eFileCounterIncrement,
543 eFileCounterDecrement
544 };
545
546 CMemoryFile* ReturnMemoryFile(const string& fileName);
547
ChangeOpenedFilseCount(EFilesCount fc)548 int ChangeOpenedFilseCount(EFilesCount fc)
549 {
550 switch(fc) {
551 case eFileCounterIncrement:
552 m_OpenedFilesCount++;
553 break;
554
555 case eFileCounterDecrement:
556 m_OpenedFilesCount--;
557 break;
558
559 default:
560 break;
561 }
562 m_MaxOpenedFilesCount = max(m_MaxOpenedFilesCount,m_OpenedFilesCount);
563 return m_OpenedFilesCount;
564 }
565
GetOpenedFilseCount(void)566 int GetOpenedFilseCount(void) { return m_OpenedFilesCount;}
567
568 private:
569
570 class CAtlasMappedFile : public CMemoryFile {
571 public:
CAtlasMappedFile(const string & filename)572 CAtlasMappedFile(const string & filename): CMemoryFile(filename),m_Count(1){
573 const string exts="hd|hi|nd|ni|pd|pi|si|sd|ti|td";
574 string ext = filename.substr(filename.length()-2);
575 if (exts.find(ext) != NPOS) {
576 m_isIsam = true;
577 }
578 else {
579 m_isIsam = false;
580 }
581 }
~CAtlasMappedFile()582 ~CAtlasMappedFile() {
583 _ASSERT(m_Count == 0);
584 }
585 int m_Count;
586 bool m_isIsam;
587 };
588 /// Private method to prevent copy construction.
589 CSeqDBAtlas(const CSeqDBAtlas &);
590
591 /// Protects most of the critical regions of the SeqDB library.
592 CMutex m_Lock;
593
594 /// Use single atlas lock to protect critical regions. The single lock is
595 /// not needed if each thread access different database volume.
596 bool m_UseLock;
597
598 enum {e_MaxSlice64 = 1 << 30};
599
600 /// Cache of file existence and length.
601 std::mutex m_FileSizeMutex;
602 map< string, pair<bool, TIndx> > m_FileSize;
603 /// Maxium file size.
604 Uint8 m_MaxFileSize;
605
606 std::mutex m_FileMemMapMutex;
607 map<string, unique_ptr<CAtlasMappedFile> > m_FileMemMap;
608 int m_OpenedFilesCount;
609 int m_MaxOpenedFilesCount;
610
611 /// BlastDB search path.
612 const string m_SearchPath;
613 };
614
615
~CSeqDBMemReg()616 inline CSeqDBMemReg::~CSeqDBMemReg()
617 {
618 m_Atlas.UnregisterExternal(*this);
619 }
620
621
622 /// Guard object for the SeqDBAtlas singleton.
623 ///
624 /// The CSeqDBAtlas object is a singleton - only one exists at any
625 /// given time, and only if a CSeqDB object exists. This object
626 /// implements that policy. When no CSeqDBAtlas object exists, the
627 /// first CSeqDB object to be created will decide whether memory
628 /// mapping is enabled. One of these objects exists in every
629 /// CSeqDBImpl and CSeqDBColumn object, and in the frames of a few
630 /// static functions.
631
632 class CSeqDBAtlasHolder {
633 public:
634 /// Constructor.
635 /// @param locked The lock hold object for this thread (or NULL).
636 /// @param use_atlas_lock If true, the atlas lock will be used to protect
637 /// critical regions, otherwise the Lock() and Unlock() functions will be
638 /// noops. Setting the parameter to false improves CPU utilization when
639 /// each thread access a different database volume. It should be set to
640 /// true in other cases.
641 CSeqDBAtlasHolder(CSeqDBLockHold * lockedp, bool use_atlas_lock);
642
643 NCBI_DEPRECATED
644 CSeqDBAtlasHolder(bool user_atlas_lock, CSeqDBLockHold* lockdep);
645
646 /// Destructor.
647 ~CSeqDBAtlasHolder();
648
649 /// Get the CSeqDBAtlas object.
650 CSeqDBAtlas & Get();
651
652 private:
653
654 /// Lock protecting this object's fields
655 DECLARE_CLASS_STATIC_FAST_MUTEX(m_Lock);
656
657 /// Count of users of the CSeqDBAtlas object.
658 static int m_Count;
659
660 /// The CSeqDBAtlas object itself.
661 static CSeqDBAtlas * m_Atlas;
662 };
663
664
665 class CSeqDBFileMemMap {
666 public:
667
668 typedef CNcbiStreamoff TIndx;
669 /// Constructor
670 ///
671 /// Initializes a memory map object.
672 ///
673 /// @param filename
674 /// file to memory map
CSeqDBFileMemMap(class CSeqDBAtlas & atlas,const string filename)675 CSeqDBFileMemMap(class CSeqDBAtlas & atlas, const string filename)
676 : m_Atlas(atlas),
677 m_DataPtr (NULL),
678 m_MappedFile( NULL),
679 m_Mapped(false)
680 {
681 Init(filename);
682 }
683
CSeqDBFileMemMap(class CSeqDBAtlas & atlas)684 CSeqDBFileMemMap(class CSeqDBAtlas & atlas)
685 : m_Atlas(atlas),
686 m_DataPtr (NULL),
687 m_MappedFile( NULL),
688 m_Mapped(false)
689 {
690
691 }
692
693 /// Destructor
~CSeqDBFileMemMap()694 ~CSeqDBFileMemMap()
695 {
696 Clear();
697 }
698
699 /// Initializes a memory map object.
700 ///
701 /// @param filename
702 /// file to memory map
Init(const string filename)703 void Init(const string filename) {
704 CSeqDBLockHold locked(m_Atlas);
705 m_Atlas.Lock(locked);
706 if(!m_MappedFile || m_Filename != filename)
707 {
708 Clear();
709 m_Filename = filename;
710 Init();
711 }
712 m_Atlas.Unlock(locked);
713 }
714
715 //m_Filename is set
Init(void)716 void Init(void)
717 {
718 try {
719 m_MappedFile = m_Atlas.GetMemoryFile(m_Filename);
720 m_Mapped = true;
721 }
722 catch (const std::exception&) {
723 NCBI_THROW(CSeqDBException,
724 eFileErr,
725 "Cannot memory map " + m_Filename + ". Number of files opened: " + NStr::IntToString(m_Atlas.GetOpenedFilseCount()));
726 }
727
728 m_DataPtr = (char *)(m_MappedFile->GetPtr());
729 }
730
731
732 /// Clears the memory mapobject.
733 ///
Clear()734 void Clear()
735 {
736
737 if(m_MappedFile && m_Mapped ) {
738 m_MappedFile = m_Atlas.ReturnMemoryFile(m_Filename);
739 m_Mapped = false;
740 }
741 }
742
IsMapped()743 bool IsMapped(){return m_Mapped;}
744
745 /// Get a pointer to the specified offset.
746 ///
747 /// Given an offset (which is assumed to be available here), this
748 /// method returns a pointer to the data at that offset.
749 ///
750 /// @param offset
751 /// The required offset relative to the start of the file.
752 /// @return
753 /// A pointer to the data at the requested location.
GetFileDataPtr(const string & fname,TIndx offset)754 const char *GetFileDataPtr(const string & fname,TIndx offset)
755 {
756 if(!m_MappedFile || m_Filename != fname) {
757 Init(fname);
758 }
759
760 return(const char *)(m_DataPtr + offset);
761 }
762
GetFileDataPtr(TIndx offset)763 const char *GetFileDataPtr(TIndx offset)
764 {
765 return(const char *)(m_DataPtr + offset);
766 }
767
768 private:
769 CSeqDBAtlas & m_Atlas;
770 /// Points to the beginning of the data area.
771 const char * m_DataPtr;
772
773 string m_Filename;
774
775 CMemoryFile *m_MappedFile;
776
777 bool m_Mapped;
778 };
779
780
781
782 END_NCBI_SCOPE
783
784 #endif // OBJTOOLS_READERS_SEQDB__SEQDBATLAS_HPP
785
786