LCOV - lcov.info - ept/popcon/maint/popconindexer.cc

LTP GCOV extension - code coverage report
Current view: | directory - ept/popcon/maint - popconindexer.cc
Test: | lcov.info
Date: | 2008-08-14 |  | Instrumented lines: | 116
Code covered: | 79.3 % |  | Executed lines: | 92

           1                 : #include <ept/popcon/popcon.h>
           2                 : #include <ept/popcon/maint/popconindexer.h>
           3                 : #include <ept/popcon/maint/path.h>
           4                 :
           5                 : #include <wibble/exception.h>
           6                 : #include <wibble/sys/fs.h>
           7                 :
           8                 : #include <tagcoll/diskindex/mmap.h>
           9                 :
          10                 : #include <set>
          11                 : #include <string>
          12                 : #include <cstdio>
          13                 : #include <cstring>
          14                 :
          15                 : using namespace std;
          16                 :
          17                 : namespace ept {
          18                 : namespace popcon {
          19                 :
          20                 : template<typename STRUCT>
          21                 : struct StructIndexer : public tagcoll::diskindex::MMapIndexer
          22               1 : {
          23                 :         const STRUCT& data;
          24               1 :         StructIndexer(const STRUCT& data) : data(data) {}
          25                 :
          26               1 :         int encodedSize() const { return sizeof(STRUCT); }
          27               1 :         void encode(char* buf) const { *(STRUCT*)buf = data; }
          28                 : };
          29                 :
          30                 : /// MMapIndexer that indexes the package names
          31                 : struct PopconGenerator : public tagcoll::diskindex::MMapIndexer
          32               4 : {
          33                 :         // Sorted set of all available package names and data
          34                 :         std::map<std::string, Score> data;
          35                 :
          36               1 :         int encodedSize() const
          37                 :         {
          38               1 :                 int size = data.size() * sizeof(Score);
          39           69911 :                 for (std::map<std::string, Score>::const_iterator i = data.begin();
          40                 :                                 i != data.end(); ++i)
          41           69910 :                         size += i->first.size() + 1;
          42               1 :                 return tagcoll::diskindex::MMap::align(size);
          43                 :         }
          44                 :
          45               1 :         void encode(char* buf) const
          46                 :         {
          47               1 :                 int pos = data.size() * sizeof(Score);
          48               1 :                 int idx = 0;
          49           69911 :                 for (std::map<std::string, Score>::const_iterator i = data.begin();
          50                 :                                 i != data.end(); ++i)
          51                 :                 {
          52           69910 :                         ((Score*)buf)[idx] = i->second;
          53           69910 :                         ((Score*)buf)[idx].offset = pos;
          54           69910 :                         memcpy(buf + pos, i->first.c_str(), i->first.size() + 1);
          55           69910 :                         pos += i->first.size() + 1;
          56           69910 :                         ++idx;
          57                 :                 }
          58               1 :         }
          59                 : };
          60                 :
          61                 :
          62               7 : PopconIndexer::PopconIndexer()
          63                 :         : mainSource(Path::popconSourceDir()),
          64               7 :           userSource(Path::popconUserSourceDir())
          65                 : {
          66               7 :         rescan();
          67               7 : }
          68                 :
          69               7 : void PopconIndexer::rescan()
          70                 : {
          71               7 :         ts_main_src = mainSource.timestamp();
          72               7 :         ts_user_src = userSource.timestamp();
          73               7 :         ts_main_sco = Path::timestamp(Path::scores());
          74              14 :         ts_user_sco = Path::timestamp(Path::userScores());
          75              14 :         ts_main_idx = Path::timestamp(Path::scoresIndex());
          76              14 :         ts_user_idx = Path::timestamp(Path::userScoresIndex());
          77               7 : }
          78                 :
          79               7 : bool PopconIndexer::needsRebuild() const
          80                 : {
          81                 :         // If there are no indexes of any kind, then we need rebuilding
          82               7 :         if (ts_user_sco == 0 || ts_main_sco == 0 || ts_user_idx == 0 && ts_main_idx == 0)
          83               2 :                 return true;
          84                 :
          85                 :         // If the user index is ok, then we are fine
          86               5 :         if (ts_user_sco >= sourceTimestamp() && ts_user_idx >= sourceTimestamp())
          87               5 :                 return false;
          88                 :
          89                 :         // If there are user sources, then we cannot use the system index
          90               0 :         if (ts_user_src > 0)
          91               0 :                 return true;
          92                 :
          93                 :         // If there are no user sources, then we can fallback on the system
          94                 :         // indexes in case the user indexes are not up to date
          95               0 :         if (ts_main_sco >= sourceTimestamp() && ts_main_idx >= sourceTimestamp())
          96               0 :                 return false;
          97                 :
          98               0 :         return true;
          99                 : }
         100                 :
         101               7 : bool PopconIndexer::userIndexIsRedundant() const
         102                 : {
         103                 :         // If there is no user index, then it is not redundant
         104               7 :         if (ts_user_idx == 0)
         105               1 :                 return false;
         106                 :
         107                 :         // If the system index is not up to date, then the user index is not
         108                 :         // redundant
         109               6 :         if (ts_main_idx < sourceTimestamp())
         110               0 :                 return false;
         111                 :
         112               6 :         return true;
         113                 : }
         114                 :
         115               2 : bool PopconIndexer::rebuild(const std::string& scofname, const std::string& idxfname)
         116                 : {
         117               2 :         PopconGenerator gen;
         118                 :         InfoStruct is;
         119               2 :         is.submissions = 0;
         120               2 :         if (!mainSource.readScores(gen.data, is.submissions))
         121               1 :                 userSource.readScores(gen.data, is.submissions);
         122               2 :         if (gen.data.empty())
         123               1 :                 return false;
         124                 :
         125               1 :         StructIndexer<InfoStruct> infoStruct(is);
         126                 :
         127                 :         // Create the index
         128               1 :         tagcoll::diskindex::MasterMMapIndexer master(idxfname);
         129               1 :         master.append(gen);
         130               1 :         master.append(infoStruct);
         131               1 :         master.commit();
         132                 :
         133                 : //      for (map<string, Score>::const_iterator i = gen.data.begin(); i != gen.data.end(); ++i)
         134                 : //      {
         135                 : //              fprintf(stderr, "%s   %d   %f\n", i->first.c_str(), i->second.offset, i->second.score);
         136                 : //      }
         137                 :
         138                 :         // Create the score file
         139               1 :         FILE* out = fopen(scofname.c_str(), "wt");
         140               1 :         if (out == NULL)
         141               0 :                 throw wibble::exception::File(scofname, "opening and truncating file for writing");
         142           69911 :         for (map<string, Score>::const_iterator i = gen.data.begin();
         143                 :                         i != gen.data.end(); ++i)
         144                 :         {
         145           69910 :                 fprintf(out, "%s %f\n", i->first.c_str(), i->second.score);
         146                 :         }
         147               1 :         fclose(out);
         148               1 :         return true;
         149                 : }
         150                 :
         151               7 : bool PopconIndexer::rebuildIfNeeded()
         152                 : {
         153               7 :         if (needsRebuild())
         154                 :         {
         155                 :                 // Decide if we rebuild the user index or the system index
         156               2 :                 if (Path::access(Path::popconIndexDir(), W_OK) == 0)
         157                 :                 {
         158                 :                         // Since we can write on the system index directory, we rebuild
         159                 :                         // the system index
         160               2 :                         if (!rebuild(Path::scores(), Path::scoresIndex()))
         161               1 :                                 return false;
         162               1 :                         ts_main_sco = Path::timestamp(Path::scores());
         163               2 :                         ts_main_idx = Path::timestamp(Path::scoresIndex());
         164               2 :                         if (Path::scores() == Path::userScores())
         165               1 :                                 ts_user_sco = ts_main_sco;
         166               1 :                         if (Path::scoresIndex() == Path::userScoresIndex())
         167               1 :                                 ts_user_idx = ts_main_idx;
         168                 :                 } else {
         169               0 :                         wibble::sys::fs::mkFilePath(Path::userScores());
         170               0 :                         wibble::sys::fs::mkFilePath(Path::userScoresIndex());
         171               0 :                         if (!rebuild(Path::userScores(), Path::userScoresIndex()))
         172               0 :                                 return false;
         173               0 :                         ts_user_sco = Path::timestamp(Path::userScores());
         174               0 :                         ts_user_idx = Path::timestamp(Path::userScoresIndex());
         175                 :                 }
         176               1 :                 return true;
         177                 :         }
         178               5 :         return false;
         179                 : }
         180                 :
         181               7 : bool PopconIndexer::deleteRedundantUserIndex()
         182                 : {
         183               7 :         if (userIndexIsRedundant())
         184                 :         {
         185                 :                 // Delete the user indexes if they exist
         186               6 :                 if (Path::scores() != Path::userScores())
         187                 :                 {
         188               0 :                         unlink(Path::userScores().c_str());
         189               0 :                         ts_user_sco = 0;
         190                 :                 }
         191               6 :                 if (Path::scoresIndex() != Path::userScoresIndex())
         192                 :                 {
         193               0 :                         unlink(Path::userScoresIndex().c_str());
         194               0 :                         ts_user_idx = 0;
         195                 :                 }
         196               6 :                 return true;
         197                 :         }
         198               1 :         return false;
         199                 : }
         200                 :
         201               7 : bool PopconIndexer::getUpToDatePopcon(std::string& scofname, std::string& idxfname)
         202                 : {
         203                 :         // If there are no indexes of any kind, then we have nothing to return
         204               7 :         if (ts_user_sco == 0 && ts_main_sco == 0 && ts_user_idx == 0 && ts_main_idx == 0)
         205               1 :                 return false;
         206                 :
         207                 :         // If the user index is up to date, use it
         208               6 :         if (ts_user_sco >= sourceTimestamp() &&
         209                 :             ts_user_idx >= sourceTimestamp())
         210                 :         {
         211               6 :                 scofname = Path::userScores();
         212              12 :                 idxfname = Path::userScoresIndex();
         213               6 :                 return true;
         214                 :         }
         215                 :
         216                 :         // If the user index is not up to date and we have user sources, we cannot
         217                 :         // fall back to the system index
         218               0 :         if (ts_user_src != 0)
         219               0 :                 return false;
         220                 :
         221                 :         // Fallback to the system index
         222               0 :         if (ts_main_sco >= sourceTimestamp() &&
         223                 :             ts_main_idx >= sourceTimestamp())
         224                 :         {
         225               0 :                 scofname = Path::scores();
         226               0 :                 idxfname = Path::scoresIndex();
         227               0 :                 return true;
         228                 :         }
         229                 :
         230               0 :         return false;
         231                 : }
         232                 :
         233                 :
         234               7 : bool PopconIndexer::obtainWorkingPopcon(std::string& scofname, std::string& idxfname)
         235                 : {
         236               7 :         PopconIndexer indexer;
         237                 :
         238               7 :         indexer.rebuildIfNeeded();
         239               7 :         indexer.deleteRedundantUserIndex();
         240               7 :         return indexer.getUpToDatePopcon(scofname, idxfname);
         241                 : }
         242                 :
         243                 :
         244                 : }
         245               6 : }
         246                 :
         247                 : // vim:set ts=4 sw=4:

Generated by: LTP GCOV extension version 1.6