seqdbfile.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:13k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: seqdbfile.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:46:39  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.10
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: seqdbfile.cpp,v 1000.1 2004/06/01 19:46:39 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Kevin Bealer
  35.  *
  36.  */
  37. #include <ncbi_pch.hpp>
  38. #include "seqdbfile.hpp"
  39. BEGIN_NCBI_SCOPE
  40. /// Index file.
  41. ///
  42. /// Index files (extension nin or pin) contain information on where to
  43. /// find information in other files.  The OID is the (implied) key.
  44. // A Word About Mutexes and Mutability in the File Classes
  45. //
  46. // The stream object in CSeqDBRawFile is mutable: this is because the
  47. // stream access methods modify the file.  Specifically, they modify
  48. // the file offset.  This means that two users of a stream object will
  49. // step on each other if they try to read from different offsets
  50. // concurrently.  Memory mapping does not have this problem of course.
  51. //
  52. // To fix this, the file object is mutable, but to access it, the user
  53. // needs to hold the m_FileLock mutex.
  54. //
  55. // One goal I have for these classes is to eliminate all locking for
  56. // the mmap case.  Locking is not needed to call a const method, so
  57. // methods are marked const whenever possible.  After construction of
  58. // CSeqDB, ONLY const methods are called.
  59. //
  60. // Some of the const methods need to modify fields; to do this, I mark
  61. // the fields 'mutable' and hold a mutex whenever accessing them.
  62. //
  63. // Each method falls into one of these categories:
  64. //
  65. // 1. Non-const: called only during CSeqDB construction.
  66. // 2. Const: no changes to any fields.
  67. // 3. Const: modifies mutable fields while holding m_FileLock.
  68. Uint8 BytesToUint8(char * bytes_sc)
  69. {
  70.     unsigned char * bytes = (unsigned char *) bytes_sc;
  71.     Uint8 value;
  72.     Int4 i;
  73.     value = 0;
  74.     for(i = 7; i >= 0; i--) {
  75.         value += bytes[i];
  76.         if(i) value <<= 8;
  77.     }
  78.     
  79.     return value;
  80. }
  81. bool CSeqDBRawFile::Open(const string & name)
  82. {
  83.     Clear();
  84.     
  85.     if (m_UseMMap) {
  86.         try {
  87.             m_Mapped = new CMemoryFile(name);
  88.             x_SetLength(false);
  89.         }
  90.         catch(...) {
  91.         }
  92.     }
  93.     
  94.     if (! m_Mapped) {
  95.         try {
  96.             // For now, no file creation
  97.             CFastMutexGuard guard(m_FileLock);
  98.             
  99.             m_Stream.clear();
  100.             m_Stream.open(name.data());
  101.             
  102.             if (m_Stream) {
  103.                 m_Opened = true;
  104.                 x_SetLength(true);
  105.             }
  106.         }
  107.         catch(...) {
  108.         }
  109.     }
  110.     
  111.     return Valid();
  112. }
  113. void CSeqDBRawFile::Clear(void)
  114. {
  115.     if (m_Mapped) {
  116.         delete m_Mapped;
  117.         m_Mapped = 0;
  118.     }
  119.     
  120.     // It might be good to clear out the parts of the mempool that
  121.     // relate to this file, by range... but only if the design was
  122.     // changed so that volumes could expire, or be cleaned up in some
  123.     // way, before the destruction of CSeqDB.
  124. }
  125. const char * CSeqDBRawFile::GetRegion(Uint4 start, Uint4 end) const
  126. {
  127.     const char * retval = 0;
  128.         
  129.     if (m_Mapped) {
  130.         if (x_ValidGet(start, end, (Uint4)m_Mapped->GetSize())) {
  131.             retval = ((const char *)m_Mapped->GetPtr()) + start;
  132.         }
  133.     } else if (m_Opened && x_ValidGet(start, end, (Uint4) m_Length)) {
  134.         //  Note that a more 'realistic' approach would involve a
  135.         //  cache of blocks or sections that have been brought in;
  136.         //  and would either free these on a refcount basis, or
  137.         //  return pointers to the insides of existing blocks, or
  138.         //  both.  In an advanced design, you might expand all
  139.         //  requests to block boundaries or powers of two, and
  140.         //  cache lists of existing blocks at different sizes.
  141.         //
  142.         //  Many of these would be an improvement, but if the mmap
  143.         //  fails, it may be impossible to do a good job with the
  144.         //  "open file" size of the equation, because there may
  145.         //  simply not be enough memory to do everything we want,
  146.         //  regardless.
  147.         
  148.         char * region = (char*) m_MemPool.Alloc(end-start);
  149.         
  150.         if (region) {
  151.             if (! x_ReadFileRegion(region, start, end)) {
  152.                 m_MemPool.Free((void*)region);
  153.                 region = 0;
  154.             } else {
  155.                 retval = region;
  156.             }
  157.         }
  158.     }
  159.     
  160.     return retval;
  161. }
  162. void CSeqDBRawFile::x_SetLength(bool have_lock)
  163. {
  164.     if (m_Mapped) {
  165.         m_Length = m_Mapped->GetSize();
  166.     } else if (m_Opened) {
  167.         CFastMutexGuard guard;
  168.         
  169.         if (! have_lock) {
  170.             guard.Guard(m_FileLock);
  171.         }
  172.         
  173.         CT_POS_TYPE p = m_Stream.tellg();
  174.         
  175.         m_Stream.seekg(0, ios::end);
  176.         CT_POS_TYPE retval = m_Stream.tellg();
  177.         
  178.         m_Stream.seekg(p);
  179.         
  180.         m_Length = retval - CT_POS_TYPE(0);
  181.     }
  182. }
  183. void CSeqDBRawFile::ReadSwapped(Uint4 * z)
  184. {
  185.     if (m_Mapped) {
  186.         Uint4 offset = m_Offset;
  187.         m_Offset += 4;
  188.         *z = SeqDB_GetStdOrd( (const Uint4 *)(((char *)m_Mapped->GetPtr()) + offset) );
  189.     } else if (m_Opened) {
  190.         CFastMutexGuard guard(m_FileLock);
  191.         
  192.         char buf[4];
  193.         Uint4 offset = m_Offset;
  194.         m_Stream.seekg(offset, ios::beg);
  195.         m_Stream.read(buf, 4);
  196.         // Should throw if .bad()?
  197.             
  198.         m_Offset += 4;
  199.         *z = SeqDB_GetStdOrd( (const Uint4 *)(buf) );
  200.     } else {
  201.         NCBI_THROW(CSeqDBException, eFileErr, "Could not open [raw] file.");
  202.     }
  203. }
  204. void CSeqDBRawFile::ReadSwapped(Uint8 * z)
  205. {
  206.     if (m_Mapped) {
  207.         Uint4 offset = m_Offset;
  208.         m_Offset += 8;
  209. *z = SeqDB_GetBroken((Int8 *) (((char *)m_Mapped->GetPtr()) + offset));
  210.     } else if (m_Opened) {
  211.         CFastMutexGuard guard(m_FileLock);
  212.         
  213.         char buf[8];
  214.         Uint4 offset = m_Offset;
  215.         m_Stream.seekg(offset, ios::beg);
  216.         m_Stream.read(buf, 8);
  217.         // Should throw if .bad()?
  218.             
  219.         m_Offset += 8;
  220. *z = SeqDB_GetBroken((Int8 *) buf);
  221.     } else {
  222. NCBI_THROW(CSeqDBException, eFileErr, "Could not open [raw] file.");
  223.     }
  224. }
  225. void CSeqDBRawFile::ReadSwapped(string * z)
  226. {
  227.     // This reads a string from byte data, assuming that the
  228.     // string is represented as the four bytes length followed by
  229.     // the contents.
  230.     
  231.     if (m_Mapped) {
  232.         Uint4 offset = m_Offset;
  233.         m_Offset += sizeof(offset);
  234. Uint4 string_size = SeqDB_GetStdOrd((Uint4 *)(((char *)m_Mapped->GetPtr()) + offset));
  235.         const char * str = ((const char *)m_Mapped->GetPtr()) + m_Offset;
  236.         m_Offset += string_size;
  237.         z->assign(str, str + string_size);
  238.     } else if (m_Opened) {
  239.         CFastMutexGuard guard(m_FileLock);
  240.         
  241.         char sl_buf[4];
  242.         m_Stream.seekg(m_Offset, ios::beg);
  243.         m_Stream.read(sl_buf, 4);
  244.         Uint4 string_size = SeqDB_GetStdOrd((Uint4 *) sl_buf);
  245.         char * strbuf = new char[string_size+1];
  246.         strbuf[string_size] = 0;
  247.         m_Stream.read(strbuf, string_size);
  248.             
  249.         // Should throw something if read fails? i.e. if .gcount()!=string_size
  250.             
  251.         z->assign(strbuf, strbuf + string_size);
  252.         m_Offset += string_size + 4;
  253.             
  254.         delete [] strbuf;
  255.     } else { 
  256.         NCBI_THROW(CSeqDBException, eFileErr, "Could not open [raw] file.");
  257.     }
  258. }
  259. // Does not modify (or use) internal file offset
  260. bool CSeqDBRawFile::ReadBytes(char * z, Uint4 start, Uint4 end) const
  261. {
  262.     // Read bytes from memory, no handling or adjustments.
  263.     if (m_Mapped) {
  264.         if (! x_ValidGet(start, end, (Uint4) m_Mapped->GetSize())) {
  265.             NCBI_THROW(CSeqDBException, eFileErr,
  266.                        "Invalid file offset: possible file corruption.");
  267.         }
  268.         
  269.         memcpy(z, ((char *) m_Mapped->GetPtr()) + start, end - start);
  270.         
  271.         return true;
  272.     } else if (m_Opened) {
  273.         if (! x_ValidGet(start, end, (Uint4) m_Length)) {
  274.             NCBI_THROW(CSeqDBException, eFileErr,
  275.                        "Invalid file offset: possible file corruption.");
  276.         }
  277.         
  278.         CFastMutexGuard guard(m_FileLock);
  279.         
  280.         m_Stream.seekg(start, ios::beg);
  281.         m_Stream.read((char *) z, end - start);
  282.         
  283.         return true;
  284.     }
  285.     
  286.     return false;
  287. }
  288. bool CSeqDBRawFile::x_ReadFileRegion(char * region, Uint4 start, Uint4 end) const
  289. {
  290.     CFastMutexGuard guard(m_FileLock);
  291.     
  292.     bool retval = false;
  293.     _ASSERT(m_Opened);
  294.     
  295.     m_Stream.seekg(start, ios::beg);
  296.     
  297.     Int4 size_left = end - start;
  298.     
  299.     while ((size_left > 0) && m_Stream) {
  300.         m_Stream.read(region, size_left);
  301.         Int4 gcnt = m_Stream.gcount();
  302.         
  303.         if (gcnt <= 0) {
  304.             NCBI_THROW(CSeqDBException, eFileErr,
  305.                        "Failed file read: possible file corruption.");
  306.         }
  307.         
  308.         if (gcnt > size_left) {
  309.             break;
  310.         } else if (gcnt <= size_left) {
  311.             size_left -= gcnt;
  312.             region    += gcnt;
  313.         }
  314.     }
  315.     
  316.     if (size_left == 0) {
  317.         retval = true;
  318.         //m_Offset += end - start;
  319.     }
  320.         
  321.     return retval;
  322. }
  323. CSeqDBExtFile::CSeqDBExtFile(CSeqDBMemPool & mempool,
  324.                              const string  & dbfilename,
  325.                              char            prot_nucl,
  326.                              bool            use_mmap)
  327.     : m_FileName(dbfilename),
  328.       m_File    (mempool, use_mmap)
  329. {
  330.     if ((prot_nucl != kSeqTypeProt) && (prot_nucl != kSeqTypeNucl)) {
  331.         NCBI_THROW(CSeqDBException,
  332.                    eArgErr,
  333.                    "Error: Invalid sequence type requested.");
  334.     }
  335.     
  336.     x_SetFileType(prot_nucl);
  337.     
  338.     if (! m_File.Open(m_FileName)) {
  339.         NCBI_THROW(CSeqDBException,
  340.                    eFileErr,
  341.                    "Error: File could not be found.");
  342.     }
  343. }
  344. CSeqDBIdxFile::CSeqDBIdxFile(CSeqDBMemPool & mempool,
  345.                              const string  & dbname,
  346.                              char            prot_nucl,
  347.                              bool            use_mmap)
  348.     : CSeqDBExtFile(mempool, dbname + ".-in", prot_nucl, use_mmap),
  349.       m_NumSeqs       (0),
  350.       m_TotLen        (0),
  351.       m_MaxLen        (0),
  352.       m_HdrHandle     (0),
  353.       m_SeqHandle     (0),
  354.       m_AmbCharHandle (0)
  355. {
  356.     // Input validation
  357.     
  358.     _ASSERT(! dbname.empty());
  359.     
  360.     if ((prot_nucl != kSeqTypeProt) && (prot_nucl != kSeqTypeNucl)) {
  361.         NCBI_THROW(CSeqDBException,
  362.                    eArgErr,
  363.                    "Error: Invalid sequence type requested.");
  364.     }
  365.     
  366.     Uint4 f_format_version = 0; // L3064
  367.     Uint4 f_db_seqtype = 0;     // L3077
  368.     
  369.     x_ReadSwapped(& f_format_version);
  370.     
  371.     if (f_format_version != 4) {
  372.         NCBI_THROW(CSeqDBException,
  373.                    eFileErr,
  374.                    "Error: Not a valid version 4 database.");
  375.     }
  376.     
  377.     x_ReadSwapped(& f_db_seqtype);
  378.     x_ReadSwapped(& m_Title);
  379.     x_ReadSwapped(& m_Date);
  380.     x_ReadSwapped(& m_NumSeqs);
  381.     x_ReadSwapped(& m_TotLen);
  382.     x_ReadSwapped(& m_MaxLen);
  383.         
  384.     Uint4 file_offset = x_GetFileOffset();
  385.         
  386.     Uint4 region_bytes = 4 * (m_NumSeqs + 1);
  387.         
  388.     Uint4 off1, off2, off3, offend;
  389.         
  390.     off1   = file_offset;
  391.     off2   = off1 + region_bytes;
  392.     off3   = off2 + region_bytes;
  393.     offend = off3 + region_bytes;
  394.         
  395.     m_HdrHandle     = x_GetRegion(off1, off2);
  396.     m_SeqHandle     = x_GetRegion(off2, off3);
  397.     m_AmbCharHandle = x_GetRegion(off3, offend);
  398.     
  399.     x_SetFileOffset(offend);
  400.     
  401.     char db_seqtype = ((f_db_seqtype == 1)
  402.                        ? kSeqTypeProt
  403.                        : kSeqTypeNucl);
  404.     
  405.     if (db_seqtype != x_GetSeqType()) {
  406.         NCBI_THROW(CSeqDBException,
  407.                    eFileErr,
  408.                    "Error: requested sequence type does not match DB.");
  409.     }
  410. }
  411. END_NCBI_SCOPE