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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: seqdbalias.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:46:33  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.13
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: seqdbalias.cpp,v 1000.1 2004/06/01 19:46:33 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 <corelib/ncbistr.hpp>
  39. #include <corelib/ncbifile.hpp>
  40. #include <algorithm>
  41. #include "seqdbalias.hpp"
  42. #include "seqdbfile.hpp"
  43. BEGIN_NCBI_SCOPE
  44. /// Index file.
  45. ///
  46. /// Index files (extension nin or pin) contain information on where to
  47. /// find information in other files.  The OID is the (implied) key.
  48. // Public Constructor
  49. //
  50. // This is the user-visible constructor, which builds the top level
  51. // node in the dbalias node tree.  This design effectively treats the
  52. // user-input database list as if it were an alias file containing
  53. // only the DBLIST specification.
  54. CSeqDBAliasNode::CSeqDBAliasNode(const string & dbname_list,
  55.                                  char           prot_nucl,
  56.                                  bool           use_mmap)
  57. {
  58.     string new_names(dbname_list);
  59.     x_ResolveNames(new_names, m_DBPath, prot_nucl);
  60.     
  61.     set<string> recurse;
  62.     
  63.     if (seqdb_debug_class & debug_alias) {
  64.         cout << "user list((" << dbname_list << "))<>";
  65.     }
  66.     
  67.     m_Values["DBLIST"] = new_names;
  68.     
  69.     x_ExpandAliases("-", prot_nucl, use_mmap, recurse);
  70. }
  71. // Private Constructor
  72. // 
  73. // This is the constructor for nodes other than the top-level node.
  74. // As such it is private and only called from this class.
  75. // 
  76. // This constructor constructs subnodes by calling x_ExpandAliases,
  77. // which calls this constructor again with the subnode's arguments.
  78. // But no node should be its own ancestor.  To prevent this kind of
  79. // recursive loop, each file adds its full path to a set of strings
  80. // and does not create a subnode for any path already in that set.
  81. // 
  82. // The set (recurse) is passed BY VALUE so that two branches of the
  83. // same file can contain equivalent nodes.  A more efficient method
  84. // for allowing this kind of sharing might be to pass by reference,
  85. // removing the current node path from the set after construction.
  86. CSeqDBAliasNode::CSeqDBAliasNode(const string & dbpath,
  87.                                  const string & dbname,
  88.                                  char           prot_nucl,
  89.                                  bool           use_mmap,
  90.                                  set<string>    recurse)
  91.     : m_DBPath(dbpath)
  92. {
  93.     if (seqdb_debug_class & debug_alias) {
  94.         bool comma = false;
  95.         
  96.         cout << dbname << "<";
  97.         for(set<string>::iterator i = recurse.begin(); i != recurse.end(); i++) {
  98.             if (comma) {
  99.                 cout << ",";
  100.             }
  101.             comma = true;
  102.             cout << SeqDB_GetFileName(*i);
  103.         }
  104.         cout << ">";
  105.     }
  106.     
  107.     string full_filename( x_MkPath(m_DBPath, dbname, prot_nucl) );
  108.     recurse.insert(full_filename);
  109.     
  110.     x_ReadValues(full_filename, use_mmap);
  111.     x_ExpandAliases(dbname, prot_nucl, use_mmap, recurse);
  112. }
  113. // This takes the names in dbname_list, finds the path for each name,
  114. // and recreates a space delimited version.  This is only done during
  115. // topmost node construction; names supplied by the end user get this
  116. // treatment, lower level nodes still need absolute or relative paths
  117. // to specify the database locations.
  118. // 
  119. // After each name is resolved, the largest prefix is found and moved
  120. // to the m_DBPath variable.
  121. // 
  122. // [I'm not sure if this is really worth while; it seemed like it
  123. // would be and it wasn't too bad to write.  It could probably be
  124. // omitted in the cliff notes version. -kmb]
  125. void CSeqDBAliasNode::x_ResolveNames(string & dbname_list,
  126.                                      string & dbname_path,
  127.                                      char     prot_nucl)
  128. {
  129.     dbname_path = ".";
  130.     
  131.     vector<string> namevec;
  132.     NStr::Tokenize(dbname_list, " ", namevec, NStr::eMergeDelims);
  133.     
  134.     Uint4 i = 0;
  135.     
  136.     for(i = 0; i < namevec.size(); i++) {
  137.         namevec[i] =
  138.             SeqDB_FindBlastDBPath(namevec[i], prot_nucl);
  139.         
  140.         if (namevec[i].empty()) {
  141.             NCBI_THROW(CSeqDBException,
  142.                        eFileErr,
  143.                        "No alias or index file found.");
  144.         }
  145.     }
  146.     
  147.     Uint4 common = namevec[0].size();
  148.     
  149.     // Reduce common length to length of min db path.
  150.     
  151.     for(i = 1; common && (i < namevec.size()); i++) {
  152.         if (namevec[i].size() < common) {
  153.             common = namevec.size();
  154.         }
  155.     }
  156.     
  157.     if (common) {
  158.         --common;
  159.     }
  160.     
  161.     // Reduce common length to largest universal prefix.
  162.     
  163.     string & first = namevec[0];
  164.     
  165.     for(i = 1; common && (i < namevec.size()); i++) {
  166.         // Reduce common prefix length until match is found.
  167.         
  168.         while(string(first, 0, common) != string(namevec[i], 0, common)) {
  169.             --common;
  170.         }
  171.     }
  172.     
  173.     // Adjust back to whole path component.
  174.     
  175.     while(common && (first[common] != CFile::GetPathSeparator())) {
  176.         --common;
  177.     }
  178.     
  179.     if (common) {
  180.         // Factor out common path components.
  181.         
  182.         dbname_path.assign(first, 0, common);
  183.         
  184.         for(i = 0; i < namevec.size(); i++) {
  185.             namevec[i].erase(0, common+1);
  186.         }
  187.     }
  188.     
  189.     dbname_list = namevec[0];
  190.     
  191.     for(i = 1; i < namevec.size(); i++) {
  192.         dbname_list += ' ';
  193.         dbname_list += namevec[i];
  194.     }
  195. }
  196. void CSeqDBAliasNode::x_ReadLine(const char * bp,
  197.                                  const char * ep)
  198. {
  199.     const char * p = bp;
  200.     
  201.     // If first nonspace char is '#', line is a comment, so skip.
  202.     if (*p == '#') {
  203.         return;
  204.     }
  205.     
  206.     // Find name
  207.     const char * spacep = p;
  208.     
  209.     while((spacep < ep) && (*spacep != ' '))
  210.         spacep ++;
  211.     
  212.     string name(p, spacep);
  213.     
  214.     // Find value
  215.     while((spacep < ep) && ((*spacep == ' ') || (*spacep == 't')))
  216.         spacep ++;
  217.     
  218.     string value(spacep, ep);
  219.     
  220.     // Store in this nodes' dictionary.
  221.     m_Values[name] = value;
  222. }
  223. void CSeqDBAliasNode::x_ReadValues(const string  & fn,
  224.                                    bool            use_mmap)
  225. {
  226.     CSeqDBMemPool mempool;
  227.     CSeqDBRawFile af(mempool, use_mmap);
  228.     af.Open(fn);
  229.     
  230.     Uint4 file_length = (Uint4) af.GetFileLength();
  231.     
  232.     const char * bp = af.GetRegion(0, file_length);
  233.     const char * ep = bp + file_length;
  234.     const char * p  = bp;
  235.     
  236.     while(p < ep) {
  237.         // Skip spaces
  238.         while((p < ep) && (*p == ' ')) {
  239.             p++;
  240.         }
  241.         
  242.         const char * eolp = p;
  243.         
  244.         while((eolp < ep) && (*eolp != 'n')) {
  245.             eolp++;
  246.         }
  247.         
  248.         // Non-empty line, so read it.
  249.         if (eolp != p) {
  250.             x_ReadLine(p, eolp);
  251.         }
  252.         
  253.         p = eolp + 1;
  254.     }
  255. }
  256. void CSeqDBAliasNode::x_ExpandAliases(const string & this_name,
  257.                                       char           prot_nucl,
  258.                                       bool           use_mmap,
  259.                                       set<string>  & recurse)
  260. {
  261.     vector<string> namevec;
  262.     string dblist( m_Values["DBLIST"] );
  263.     NStr::Tokenize(dblist, " ", namevec, NStr::eMergeDelims);
  264.     
  265.     bool parens = false;
  266.     
  267.     for(Uint4 i = 0; i<namevec.size(); i++) {
  268.         if (namevec[i] == SeqDB_GetBaseName(this_name)) {
  269.             // If the base name of the alias file is also listed in
  270.             // "dblist", it is assumed to refer to a volume instead of
  271.             // to itself.
  272.             
  273.             m_VolNames.push_back(this_name);
  274.             continue;
  275.         }
  276.         
  277.         string new_db_loc( x_MkPath(m_DBPath, namevec[i], prot_nucl) );
  278.         
  279.         if (recurse.find(new_db_loc) != recurse.end()) {
  280.             NCBI_THROW(CSeqDBException,
  281.                        eFileErr,
  282.                        "Illegal configuration: DB alias files are mutually recursive.");
  283.         }
  284.         
  285.         if ( CFile(new_db_loc).Exists() ) {
  286.             if (parens == false && seqdb_debug_class & debug_alias) {
  287.                 parens = true;
  288.                 cout << " {" << endl;
  289.             }
  290.             
  291.             string newpath = SeqDB_GetDirName(new_db_loc);
  292.             string newfile = SeqDB_GetBaseName(new_db_loc);
  293.             
  294.             CRef<CSeqDBAliasNode>
  295.                 subnode( new CSeqDBAliasNode(newpath,
  296.                                              newfile,
  297.                                              prot_nucl,
  298.                                              use_mmap,
  299.                                              recurse) );
  300.             
  301.             m_SubNodes.push_back(subnode);
  302.         } else {
  303.             // If the name is not found as an alias file, it is
  304.             // considered to be a volume.
  305.             
  306.             m_VolNames.push_back( SeqDB_GetBasePath(new_db_loc) );
  307.         }
  308.     }
  309.     
  310.     if (seqdb_debug_class & debug_alias) {
  311.         if (parens) {
  312.             cout << "}" << endl;
  313.         } else {
  314.             cout << ";" << endl;
  315.         }
  316.     }
  317. }
  318. void CSeqDBAliasNode::GetVolumeNames(vector<string> & vols) const
  319. {
  320.     set<string> volset;
  321.     x_GetVolumeNames(volset);
  322.     
  323.     vols.clear();
  324.     for(set<string>::iterator i = volset.begin(); i != volset.end(); i++) {
  325.         vols.push_back(*i);
  326.     }
  327.     
  328.     // Sort to insure deterministic order.
  329.     sort(vols.begin(), vols.end());
  330. }
  331. void CSeqDBAliasNode::x_GetVolumeNames(set<string> & vols) const
  332. {
  333.     Uint4 i = 0;
  334.     
  335.     for(i = 0; i < m_VolNames.size(); i++) {
  336.         vols.insert(m_VolNames[i]);
  337.     }
  338.     
  339.     for(i = 0; i < m_SubNodes.size(); i++) {
  340.         m_SubNodes[i]->x_GetVolumeNames(vols);
  341.     }
  342. }
  343. class CSeqDB_TitleWalker : public CSeqDB_AliasWalker {
  344. public:
  345.     virtual const char * GetFileKey(void) const
  346.     {
  347.         return "TITLE";
  348.     }
  349.     
  350.     virtual void Accumulate(const CSeqDBVol & vol)
  351.     {
  352.         AddString( vol.GetTitle() );
  353.     }
  354.     
  355.     virtual void AddString(const string & value)
  356.     {
  357.         if (! value.empty()) {
  358.             if (! m_Value.empty()) {
  359.                 m_Value += "; ";
  360.             }
  361.             m_Value += value;
  362.         }
  363.     }
  364.     
  365.     string GetTitle(void)
  366.     {
  367.         return m_Value;
  368.     }
  369.     
  370. private:
  371.     string m_Value;
  372. };
  373. // A slightly more clever approach (might) track the contributions
  374. // from each volume or alias file and trim the final total by the
  375. // amount of provable overcounting detected.
  376. // 
  377. // Since this is probably impossible in most cases, it is not done.
  378. // The working assumption then is that the specified databases are
  379. // disjoint.  This design should prevent undercounting but allows
  380. // overcounting in some cases.
  381. class CSeqDB_MaxLengthWalker : public CSeqDB_AliasWalker {
  382. public:
  383.     CSeqDB_MaxLengthWalker(void)
  384.     {
  385.         m_Value = 0;
  386.     }
  387.     
  388.     virtual const char * GetFileKey(void) const
  389.     {
  390.         // This field is not overrideable.
  391.         
  392.         return "MAX_SEQ_LENGTH";
  393.     }
  394.     
  395.     virtual void Accumulate(const CSeqDBVol & vol)
  396.     {
  397.         Uint4 new_max = vol.GetMaxLength();
  398.         
  399.         if (new_max > m_Value)
  400.             m_Value = new_max;
  401.     }
  402.     
  403.     virtual void AddString(const string & value)
  404.     {
  405.         m_Value = NStr::StringToUInt(value);
  406.     }
  407.     
  408.     Uint4 GetMaxLength(void)
  409.     {
  410.         return m_Value;
  411.     }
  412.     
  413. private:
  414.     Uint4 m_Value;
  415. };
  416. class CSeqDB_NSeqsWalker : public CSeqDB_AliasWalker {
  417. public:
  418.     CSeqDB_NSeqsWalker(void)
  419.     {
  420.         m_Value = 0;
  421.     }
  422.     
  423.     virtual const char * GetFileKey(void) const
  424.     {
  425.         return "NSEQ";
  426.     }
  427.     
  428.     virtual void Accumulate(const CSeqDBVol & vol)
  429.     {
  430.         m_Value += vol.GetNumSeqs();
  431.     }
  432.     
  433.     virtual void AddString(const string & value)
  434.     {
  435.         m_Value += NStr::StringToUInt(value);
  436.     }
  437.     
  438.     Uint4 GetNumSeqs(void) const
  439.     {
  440.         return m_Value;
  441.     }
  442.     
  443. private:
  444.     Uint4 m_Value;
  445. };
  446. class CSeqDB_TotalLengthWalker : public CSeqDB_AliasWalker {
  447. public:
  448.     CSeqDB_TotalLengthWalker(void)
  449.     {
  450.         m_Value = 0;
  451.     }
  452.     
  453.     virtual const char * GetFileKey(void) const
  454.     {
  455.         return "LENGTH";
  456.     }
  457.     
  458.     virtual void Accumulate(const CSeqDBVol & vol)
  459.     {
  460.         m_Value += vol.GetTotalLength();
  461.     }
  462.     
  463.     virtual void AddString(const string & value)
  464.     {
  465.         m_Value += NStr::StringToUInt8(value);
  466.     }
  467.     
  468.     Uint8 GetTotalLength(void) const
  469.     {
  470.         return m_Value;
  471.     }
  472.     
  473. private:
  474.     Uint8 m_Value;
  475. };
  476. void
  477. CSeqDBAliasNode::WalkNodes(CSeqDB_AliasWalker * walker,
  478.                            const CSeqDBVolSet & volset) const
  479. {
  480.     TVarList::const_iterator iter =
  481.         m_Values.find(walker->GetFileKey());
  482.     
  483.     if (iter != m_Values.end()) {
  484.         walker->AddString( (*iter).second );
  485.         return;
  486.     }
  487.     
  488.     Uint4 i;
  489.     
  490.     for(i = 0; i < m_SubNodes.size(); i++) {
  491.         m_SubNodes[i]->WalkNodes( walker, volset );
  492.     }
  493.     
  494.     // For each volume name, try to find the corresponding volume and
  495.     // call Accumulate.
  496.     
  497.     for(i = 0; i < m_VolNames.size(); i++) {
  498.         if (const CSeqDBVol * vptr = volset.GetVol(m_VolNames[i])) {
  499.             walker->Accumulate( *vptr );
  500.         }
  501.     }
  502. }
  503. void CSeqDBAliasNode::SetMasks(CSeqDBVolSet & volset)
  504. {
  505.     TVarList::iterator oid_iter = m_Values.find(string("OIDLIST"));
  506.     TVarList::iterator db_iter  = m_Values.find(string("DBLIST"));
  507.     
  508.     if ((oid_iter != m_Values.end()) &&
  509.         (db_iter  != m_Values.end())) {
  510.         
  511.         string vol_path (SeqDB_CombinePath(m_DBPath, (*db_iter).second));
  512.         string mask_path(SeqDB_CombinePath(m_DBPath, (*oid_iter).second));
  513.         
  514.         volset.AddMaskedVolume(vol_path, mask_path);
  515.         
  516.         return;
  517.     }
  518.     
  519.     Uint4 i;
  520.     
  521.     for(i = 0; i < m_SubNodes.size(); i++) {
  522.         m_SubNodes[i]->SetMasks( volset );
  523.     }
  524.     
  525.     for(i = 0; i < m_VolNames.size(); i++) {
  526.         if (CSeqDBVol * vptr = volset.GetVol(m_VolNames[i])) {
  527.             // We did NOT find an OIDLIST entry; therefore, any db
  528.             // volumes mentioned here are included unfiltered.
  529.             
  530.             volset.AddFullVolume(vptr->GetVolName());
  531.         }
  532.     }
  533. }
  534. string CSeqDBAliasNode::GetTitle(const CSeqDBVolSet & volset) const
  535. {
  536.     CSeqDB_TitleWalker walk;
  537.     WalkNodes(& walk, volset);
  538.     
  539.     return walk.GetTitle();
  540. }
  541. Uint4 CSeqDBAliasNode::GetNumSeqs(const CSeqDBVolSet & vols) const
  542. {
  543.     CSeqDB_NSeqsWalker walk;
  544.     WalkNodes(& walk, vols);
  545.     
  546.     return walk.GetNumSeqs();
  547. }
  548. Uint8 CSeqDBAliasNode::GetTotalLength(const CSeqDBVolSet & volset) const
  549. {
  550.     CSeqDB_TotalLengthWalker walk;
  551.     WalkNodes(& walk, volset);
  552.     
  553.     return walk.GetTotalLength();
  554. }
  555. END_NCBI_SCOPE