LTP GCOV extension - code coverage report
Current view: directory - ept/debtags/maint - debtagsindexer.cc
Test: lcov.info
Date: 2008-08-14 Instrumented lines: 119
Code covered: 74.8 % Executed lines: 89

       1                 : #include <ept/debtags/maint/debtagsindexer.h>
       2                 : #include <ept/debtags/maint/path.h>
       3                 : #include <ept/debtags/maint/pkgid.h>
       4                 : #include <ept/debtags/maint/serializer.h>
       5                 : #include <ept/debtags/vocabulary.h>
       6                 : 
       7                 : #include <tagcoll/coll/intdiskindex.h>
       8                 : #include <tagcoll/coll/simple.h>
       9                 : #include <tagcoll/TextFormat.h>
      10                 : #include <tagcoll/stream/filters.h>
      11                 : 
      12                 : #include <wibble/exception.h>
      13                 : 
      14                 : #include <cstring>
      15                 : 
      16                 : using namespace std;
      17                 : 
      18                 : namespace ept {
      19                 : namespace debtags {
      20                 : 
      21                 : /// MMapIndexer that indexes the package names
      22                 : struct PkgIdGenerator : public tagcoll::diskindex::MMapIndexer
      23               2 : {
      24                 :         // Sorted set of all available package names
      25                 :         std::set<std::string> pkgs;
      26                 : 
      27               3 :         int encodedSize() const
      28                 :         {
      29               3 :                 int size = pkgs.size() * sizeof(int);
      30           63438 :                 for (std::set<std::string>::const_iterator i = pkgs.begin();
      31                 :                                 i != pkgs.end(); ++i)
      32           63435 :                         size += i->size() + 1;
      33               3 :                 return tagcoll::diskindex::MMap::align(size);
      34                 :         }
      35                 : 
      36               2 :         void encode(char* buf) const
      37                 :         {
      38               2 :                 int pos = pkgs.size() * sizeof(int);
      39               2 :                 int idx = 0;
      40           42292 :                 for (std::set<std::string>::const_iterator i = pkgs.begin();
      41                 :                                 i != pkgs.end(); ++i)
      42                 :                 {
      43           42290 :                         ((int*)buf)[idx++] = pos;
      44           42290 :                         memcpy(buf + pos, i->c_str(), i->size() + 1);
      45           42290 :                         pos += i->size() + 1;
      46                 :                 }
      47               2 :         }
      48                 : };
      49                 : 
      50                 : 
      51              10 : DebtagsIndexer::DebtagsIndexer(Vocabulary& voc)
      52                 :         : voc(voc),
      53                 :           mainSource(Path::debtagsSourceDir()),
      54              10 :           userSource(Path::debtagsUserSourceDir())
      55                 : {
      56              10 :         rescan();
      57              10 : }
      58                 : 
      59              10 : void DebtagsIndexer::rescan()
      60                 : {
      61              10 :         ts_main_src = mainSource.timestamp();
      62              10 :         ts_user_src = userSource.timestamp();
      63              10 :         ts_main_tag = Path::timestamp(Path::tagdb());
      64              20 :         ts_main_idx = Path::timestamp(Path::tagdbIndex());
      65              20 :         ts_user_tag = Path::timestamp(Path::userTagdb());
      66              20 :         ts_user_idx = Path::timestamp(Path::userTagdbIndex());
      67              10 : }
      68                 : 
      69              10 : bool DebtagsIndexer::needsRebuild() const
      70                 : {
      71                 :         // If there are no indexes of any kind, then we need rebuilding
      72              10 :         if (ts_user_tag == 0 && ts_user_idx == 0 && ts_main_tag == 0 && ts_main_idx == 0)
      73               2 :                 return true;
      74                 : 
      75                 :         // If the user index is ok, then we are fine
      76               8 :         if (ts_user_tag >= sourceTimestamp() && ts_user_idx >= sourceTimestamp())
      77               8 :                 return false;
      78                 : 
      79                 :         // If there are user sources, then we cannot use the system index
      80               0 :         if (ts_user_src > 0)
      81               0 :                 return true;
      82                 : 
      83                 :         // If there are no user sources, then we can fallback on the system
      84                 :         // indexes in case the user indexes are not up to date
      85               0 :         if (ts_main_tag >= sourceTimestamp() && ts_main_idx >= sourceTimestamp())
      86               0 :                 return false;
      87                 : 
      88               0 :         return true;
      89                 : }
      90                 : 
      91              10 : bool DebtagsIndexer::userIndexIsRedundant() const
      92                 : {
      93                 :         // If there is no user index, then it is not redundant
      94              10 :         if (ts_user_tag == 0 && ts_user_idx == 0)
      95               1 :                 return false;
      96                 : 
      97                 :         // If we have user sources, then the user index is never redundant
      98               9 :         if (ts_user_src > 0)
      99               9 :                 return false;
     100                 : 
     101                 :         // If the system index is not up to date, then the user index is not
     102                 :         // redundant
     103               0 :         if (ts_main_tag < sourceTimestamp() || ts_main_idx < sourceTimestamp())
     104               0 :                 return false;
     105                 : 
     106               0 :         return true;
     107                 : }
     108                 : 
     109               2 : bool DebtagsIndexer::rebuild(const std::string& tagfname, const std::string& idxfname)
     110                 : {
     111                 :         using namespace tagcoll;
     112                 : 
     113               2 :         diskindex::MasterMMapIndexer master(idxfname);
     114                 : 
     115                 :         // Read and merge tag data
     116               2 :         coll::Simple<string, string> merged;
     117               2 :         mainSource.readTags(inserter(merged));
     118               2 :         userSource.readTags(inserter(merged));
     119                 : 
     120               2 :         if (merged.empty())
     121                 :                 //throw wibble::exception::Consistency("Reading debtags sources from " + Path::debtagsSourceDir() + " and " + Path::debtagsUserSourceDir(), "Unable to find any tag data");
     122               1 :                 return false;
     123                 : 
     124                 :         // Create the pkgid index
     125               1 :         PkgIdGenerator pkgidGen;
     126           21146 :         for (coll::Simple<string, string>::const_iterator i = merged.begin();
     127                 :                         i != merged.end(); ++i)
     128           21145 :                 pkgidGen.pkgs.insert(i->first);
     129                 : 
     130                 :         // Temporary in-memory index to use for converting packages to ints while
     131                 :         // creating the debtags index
     132               1 :         char buf[pkgidGen.encodedSize()];
     133               1 :         pkgidGen.encode(buf);
     134               1 :         PkgId pkgid(buf, pkgidGen.encodedSize());
     135                 : 
     136                 :         // Create the Debtags index
     137               1 :         coll::IntDiskIndexer tagindexer;
     138               1 :         merged.output(stringToInt(pkgid, voc, inserter(tagindexer)));
     139                 : 
     140                 :         // MMap 0: pkgid
     141               1 :         master.append(pkgidGen);
     142                 :         // MMap 1: pkg->tag
     143               1 :         master.append(tagindexer.pkgIndexer());
     144                 :         // MMap 2: tag->pkg
     145               1 :         master.append(tagindexer.tagIndexer());
     146                 : 
     147                 :         // Write the tag database in text format
     148               1 :         std::string tmpdb = tagfname + ".tmp";
     149               1 :         FILE* out = fopen(tmpdb.c_str(), "wt");
     150               1 :         if (!out) throw wibble::exception::File(tmpdb, "creating temporary copy of tag index");
     151               1 :         merged.output(textformat::StdioWriter(out));
     152               1 :         fclose(out);
     153                 : 
     154                 :         // Perform "atomic" update of the tag database
     155                 :         // FIXME: cannot be atomic because race conditions happening between file
     156                 :         // renames
     157               1 :         if (rename(tmpdb.c_str(), tagfname.c_str()) == -1)
     158               0 :                 throw wibble::exception::System("Renaming " + tmpdb + " to " + tagfname);
     159                 : 
     160               1 :         master.commit();
     161               1 :         return true;
     162                 : }
     163                 : 
     164              10 : bool DebtagsIndexer::rebuildIfNeeded()
     165                 : {
     166              10 :         if (needsRebuild())
     167                 :         {
     168                 :                 // Decide if we rebuild the user index or the system index
     169                 : 
     170               2 :                 if (ts_user_src == 0 && Path::access(Path::debtagsIndexDir(), W_OK) == 0)
     171                 :                 {
     172                 :                         // There are no user sources and we can write to the system index
     173                 :                         // directory: rebuild the system index
     174               1 :                         if (!rebuild(Path::tagdb(), Path::tagdbIndex()))
     175               1 :                                 return false;
     176               0 :                         ts_main_tag = Path::timestamp(Path::tagdb());
     177               0 :                         ts_main_idx = Path::timestamp(Path::tagdbIndex());
     178               0 :                         if (Path::tagdb() == Path::userTagdb())
     179               0 :                                 ts_user_tag = ts_main_tag;
     180               0 :                         if (Path::tagdbIndex() == Path::userTagdbIndex())
     181               0 :                                 ts_user_idx = ts_main_idx;
     182                 :                 } else {
     183               1 :                         wibble::sys::fs::mkFilePath(Path::userTagdb());
     184               2 :                         wibble::sys::fs::mkFilePath(Path::userTagdbIndex());
     185               2 :                         if (!rebuild(Path::userTagdb(), Path::userTagdbIndex()))
     186               0 :                                 return false;
     187               1 :                         ts_user_tag = Path::timestamp(Path::userTagdb());
     188               2 :                         ts_user_idx = Path::timestamp(Path::userTagdbIndex());
     189                 :                 }
     190               1 :                 return true;
     191                 :         }
     192               8 :         return false;
     193                 : }
     194                 : 
     195              10 : bool DebtagsIndexer::deleteRedundantUserIndex()
     196                 : {
     197              10 :         if (userIndexIsRedundant())
     198                 :         {
     199                 :                 // Delete the user indexes if they exist
     200               0 :                 if (Path::tagdb() != Path::userTagdb())
     201                 :                 {
     202               0 :                         unlink(Path::userTagdb().c_str());
     203               0 :                         ts_user_tag = 0;
     204                 :                 }
     205               0 :                 if (Path::tagdbIndex() != Path::userTagdbIndex())
     206                 :                 {
     207               0 :                         unlink(Path::userTagdbIndex().c_str());
     208               0 :                         ts_user_idx = 0;
     209                 :                 }
     210               0 :                 return true;
     211                 :         }
     212              10 :         return false;
     213                 : }
     214                 : 
     215              10 : bool DebtagsIndexer::getUpToDateTagdb(std::string& tagfname, std::string& idxfname)
     216                 : {
     217                 :         // If there are no indexes of any kind, then we have nothing to return
     218              10 :         if (ts_user_tag == 0 && ts_user_idx == 0 && ts_main_tag == 0 && ts_main_idx == 0)
     219               1 :                 return false;
     220                 : 
     221                 :         // If the user index is up to date, use it
     222               9 :         if (ts_user_tag >= sourceTimestamp() &&
     223                 :                 ts_user_idx >= sourceTimestamp())
     224                 :         {
     225               9 :                 tagfname = Path::userTagdb();
     226              18 :                 idxfname = Path::userTagdbIndex();
     227               9 :                 return true;
     228                 :         }
     229                 : 
     230                 :         // If the user index is not up to date and we have user sources, we cannot
     231                 :         // fall back to the system index
     232               0 :         if (ts_user_src != 0)
     233               0 :                 return false;
     234                 :         
     235                 :         // Fallback to the system index
     236               0 :         if (ts_main_tag >= sourceTimestamp() &&
     237                 :                 ts_main_idx >= sourceTimestamp())
     238                 :         {
     239               0 :                 tagfname = Path::tagdb();
     240               0 :                 idxfname = Path::tagdbIndex();
     241               0 :                 return true;
     242                 :         }
     243                 :         
     244               0 :         return false;
     245                 : }
     246                 : 
     247                 : 
     248                 : 
     249              10 : bool DebtagsIndexer::obtainWorkingDebtags(Vocabulary& voc, std::string& tagfname, std::string& idxfname)
     250                 : {
     251              10 :         DebtagsIndexer t(voc);
     252                 : 
     253              10 :         t.rebuildIfNeeded();
     254              10 :         t.deleteRedundantUserIndex();
     255              10 :         return t.getUpToDateTagdb(tagfname, idxfname);
     256                 : }
     257                 : 
     258                 : }
     259                 : }
     260                 : 
     261                 : #include <ept/debtags/maint/sourcedir.tcc>
     262                 : #include <tagcoll/coll/simple.tcc>
     263                 : 
     264                 : // vim:set ts=4 sw=4:
     265                 : // -*- C++ -*-

Generated by: LTP GCOV extension version 1.6