"Fossies" - the Fresh Open Source Software Archive

Member "worker-4.1.0/src/prefixdb.cc" (10 Sep 2019, 11720 Bytes) of package /linux/privat/worker-4.1.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "prefixdb.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.0.1_vs_4.1.0.

    1 /* prefixdb.cc
    2  * This file belongs to Worker, a file manager for UN*X/X11.
    3  * Copyright (C) 2010-2019 Ralf Hoffmann.
    4  * You can contact me at: ralf@boomerangsworld.de
    5  *   or http://www.boomerangsworld.de/worker
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
   10  * (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   20  */
   21 
   22 #include "prefixdb.hh"
   23 #include <algorithm>
   24 #include <iostream>
   25 #include <fstream>
   26 #include "nwc_fsentry.hh"
   27 #include "datei.h"
   28 #include "configtokens.h"
   29 #include "configheader.h"
   30 #include "configparser.hh"
   31 #include <aguix/util.h>
   32 #include "filelock.hh"
   33 
   34 PrefixDB::PrefixDB( const std::string &filename ) : m_next_aging( 0 ),
   35                             m_filename( filename ),
   36                             m_lastmod( 0 ),
   37                             m_lastsize( 0 )
   38 
   39 {
   40     time_t now = time( NULL );
   41 
   42     m_next_aging = now + 24 * 60 * 60;
   43 }
   44 
   45 PrefixDB::~PrefixDB()
   46 {
   47 }
   48 
   49 std::string PrefixDB::getBestHit( const std::string &prefix, time_t &return_last_use )
   50 {
   51     read();
   52 
   53     std::vector< PrefixDBEntry >::const_iterator it1;
   54 
   55     PrefixDBEntry pdb_test( prefix );
   56 
   57     // m_db needs to be sorted
   58 
   59     it1 = std::lower_bound( m_db.begin(),
   60                             m_db.end(),
   61                             pdb_test );
   62 
   63     // now it1 is the first entry which is not lower than pdb_test
   64 
   65     return_last_use = 0;
   66     if ( it1 == m_db.end() ) return "";
   67 
   68     std::string best_hit;
   69     float best_hit_count = -1.0;
   70     time_t best_last_use = 0;
   71 
   72     // for exact hit consider only this entry
   73     if ( it1->getPrefix() == prefix ) {
   74         return it1->getBestHit( best_hit_count,
   75                                 return_last_use );
   76     }
   77 
   78     // otherwise search all entries for which prefix is a prefix
   79 
   80     for ( ;
   81           it1 != m_db.end();
   82           it1++ ) {
   83         if ( it1->getPrefix().compare( 0, prefix.length(), prefix ) == 0 ) {
   84             if ( best_hit_count < 0 ) {
   85                 best_hit = it1->getBestHit( best_hit_count, best_last_use );
   86             } else {
   87                 float t1;
   88                 std::string s1;
   89                 time_t t2;
   90 
   91                 s1 = it1->getBestHit( t1, t2 );
   92         
   93                 if ( t1 > best_hit_count ) {
   94                     best_hit = s1;
   95                     best_hit_count = t1;
   96                     best_last_use = t2;
   97                 }
   98             }
   99         } else {
  100             // since m_db is sorted we can stop here
  101             break;
  102         }
  103     }
  104 
  105     return_last_use = best_last_use;
  106 
  107     return best_hit;
  108 }
  109 
  110 void PrefixDB::pushAccess( const std::string &prefix,
  111                            const std::string &value,
  112                            time_t last_use )
  113 {
  114     read();
  115 
  116     std::vector< PrefixDBEntry >::iterator it1;
  117 
  118     PrefixDBEntry pdb_test( prefix );
  119 
  120     // m_db needs to be sorted
  121 
  122     it1 = std::lower_bound( m_db.begin(),
  123                             m_db.end(),
  124                             pdb_test );
  125 
  126     // now it1 is the first entry which is not lower than pdb_test
  127 
  128     if ( it1 == m_db.end() ||
  129          it1->getPrefix() != prefix ) {
  130         PrefixDBEntry pe( prefix );
  131         pe.storeAccess( value, last_use );
  132         m_db.push_back( pe );
  133         std::sort( m_db.begin(), m_db.end() );
  134     } else {
  135         it1->storeAccess( value, last_use );
  136     }
  137 
  138     write();
  139 }
  140 
  141 void PrefixDB::read()
  142 {
  143     NWC::FSEntry fe( m_filename );
  144 
  145     if ( ! fe.entryExists() ) return;
  146 
  147     if ( fe.isLink() ) {
  148         if ( fe.stat_dest_lastmod() == m_lastmod &&
  149              fe.stat_dest_size() == m_lastsize ) return;
  150     } else {
  151         if ( fe.stat_lastmod() == m_lastmod &&
  152              fe.stat_size() == m_lastsize ) return;
  153     }
  154 
  155     m_db.clear();
  156     
  157     if ( fe.isLink() ) {
  158         m_lastmod = fe.stat_dest_lastmod();
  159         m_lastsize = fe.stat_dest_size();
  160     } else {
  161         m_lastmod = fe.stat_lastmod();
  162         m_lastsize = fe.stat_size();
  163     }
  164 
  165     std::string lockname = m_filename;
  166     lockname += ".lock";
  167 
  168     FileLock fl( lockname );
  169 
  170     if ( fl.lock_retry() ) {
  171 #if 0
  172         // this is a working version with plain key value pairs
  173         // it uses no scanner but is much stricter
  174         std::string myfilename = m_filename;
  175         myfilename += "-plain_kv";
  176         std::ifstream ifile( myfilename.c_str() );
  177         std::string line;
  178 
  179         if ( ifile.is_open() ) {
  180             bool failed = true;
  181             if ( std::getline( ifile, line ) ) {
  182                 if ( line.compare( 0, std::string( "next_aging=" ).length(), "next_aging=" ) == 0 ) {
  183                     m_next_aging = atoi( line.c_str() + std::string( "next_aging=" ).length() );
  184                     failed = false;
  185                 }
  186             }
  187 
  188             if ( ! failed ) {
  189                 while ( ! failed && std::getline( ifile, line ) ) {
  190                     if ( line == "begin_entry" ) {
  191                         PrefixDBEntry pe( "" );
  192                         failed = pe.read( ifile );
  193                         if ( ! failed ) {
  194                             m_db.push_back( pe );
  195                         }
  196                     }
  197                 }
  198             }
  199 
  200             if ( failed ) {
  201                 std::cout << "read failed" << std::endl;
  202             }
  203         }
  204 #else
  205         FILE *fp;
  206         int found_error = 0;
  207 
  208         fp = worker_fopen( m_filename.c_str(), "r" );
  209         if ( fp != NULL ) {
  210             yyrestart( fp );
  211             readtoken();
  212             for (;;) {
  213                 if ( worker_token == NEXTAGING_WCP ) {
  214                     readtoken();
  215 
  216                     if ( worker_token != '=' ) {
  217                         found_error = 1;
  218                         break;
  219                     }
  220                     readtoken();
  221 
  222                     if ( worker_token == STRING_WCP ) {
  223                         if ( ! AGUIXUtils::convertFromString( yylval.strptr,
  224                                                               m_next_aging ) ) {
  225                             fprintf( stderr, "Worker:unable to parse nextaging\n" );
  226                             m_next_aging = 0;
  227                             //TODO abort parsing?
  228                         }
  229                     } else {
  230                         found_error = 1;
  231                         break;
  232                     }
  233                     readtoken();
  234 
  235                     if ( worker_token != ';' ) {
  236                         found_error = 1;
  237                         break;
  238                     }
  239                     readtoken();
  240                 } else if ( worker_token == ENTRY_WCP ) {
  241                     readtoken();
  242 
  243                     if ( worker_token != LEFTBRACE_WCP ) {
  244                         found_error = 1;
  245                         break;
  246                     }
  247                     readtoken();
  248         
  249                     PrefixDBEntry pe( "" );
  250                     bool failed = pe.read( fp );
  251                     if ( ! failed ) {
  252                         m_db.push_back( pe );
  253                     } else {
  254                         found_error = 1;
  255                         break;
  256                     }
  257         
  258                     if ( worker_token != RIGHTBRACE_WCP ) {
  259                         found_error = 1;
  260                         break;
  261                     }
  262                     readtoken();
  263                 } else if ( worker_token != 0 ) {
  264                     // parse error
  265                     found_error = 1;
  266                     break;
  267                 } else break;  // end
  268             }
  269             if ( found_error != 0 ) {
  270                 //TODO: Requester zeigen?
  271                 //      Eigentlich kann der User eh nicht viel machen
  272                 //      denn beim Beenden wird neue Datei geschrieben
  273                 fprintf( stderr, "Worker:error in prefixdb\n" );
  274             }
  275             worker_fclose( fp );
  276         }
  277 #endif
  278 
  279         fl.unlock();
  280     } else {
  281         fprintf( stderr, "Worker:locking file %s failed\n", lockname.c_str() );
  282     }
  283 
  284     std::sort( m_db.begin(), m_db.end() );
  285 }
  286 
  287 void PrefixDB::write()
  288 {
  289     time_t now = time( NULL );
  290 
  291     if ( now >= m_next_aging ) {
  292         age();
  293         m_next_aging = now + 24 * 60 * 60;
  294     }
  295 
  296     std::string lockname = m_filename;
  297     lockname += ".lock";
  298 
  299     FileLock fl( lockname );
  300 
  301     if ( fl.lock_retry() ) {
  302 #if 0
  303         std::string myfilename = m_filename;
  304         myfilename += "-plain_kv";
  305         std::ofstream ofile( myfilename.c_str() );
  306         
  307         ofile << "next_aging=" << m_next_aging << std::endl;
  308         
  309         std::vector< PrefixDBEntry >::iterator it1;
  310         
  311         for ( it1 = m_db.begin();
  312               it1 != m_db.end();
  313               it1++ ) {
  314             ofile << "begin_entry" << std::endl;
  315             
  316             it1->write( ofile );
  317             
  318             ofile << "end_entry" << std::endl;
  319         }
  320 #else
  321         Datei fh;
  322 
  323         std::string temp_target_file = m_filename;
  324         temp_target_file += ".new";
  325 
  326         if ( fh.open( temp_target_file.c_str(), "w" ) == 0 ) {
  327             fh.configPutPairString( "nextaging", AGUIXUtils::convertToString( m_next_aging ).c_str() );
  328         
  329             std::vector< PrefixDBEntry >::iterator it1;
  330         
  331             for ( it1 = m_db.begin();
  332                   it1 != m_db.end();
  333                   it1++ ) {
  334                 fh.configOpenSection( "entry" );
  335             
  336                 it1->write( fh );
  337             
  338                 fh.configCloseSection();
  339             }
  340             fh.close();
  341 
  342             if ( fh.errors() ) {
  343                 worker_unlink( temp_target_file.c_str() );
  344             } else {
  345                 worker_rename( temp_target_file.c_str(), m_filename.c_str() );
  346             }
  347         }
  348 #endif
  349 
  350         fl.unlock();
  351     } else {
  352         fprintf( stderr, "Worker:locking file %s failed\n", lockname.c_str() );
  353     }
  354     //TODO set lastsize and lastmod to avoid next read?
  355 }
  356 
  357 void PrefixDB::age( float factor )
  358 {
  359     std::vector< PrefixDBEntry >::iterator it1;
  360 
  361     for ( it1 = m_db.begin();
  362       it1 != m_db.end();
  363       it1++ ) {
  364     it1->age( factor );
  365     }
  366 }
  367 
  368 std::set< std::string > PrefixDB::getAllStrings()
  369 {
  370     std::set< std::string > strings;
  371 
  372     read();
  373 
  374     for ( auto &dbe : m_db ) {
  375         for ( auto &s1 : dbe.getStrings() ) {
  376             strings.insert( std::get<0>( s1 ) );
  377         }
  378     }
  379 
  380     return strings;
  381 }
  382 
  383 std::map< std::string, std::tuple< std::string, float, time_t > > PrefixDB::getAllBestHits()
  384 {
  385     std::map< std::string, std::tuple< std::string, float, time_t > > res;
  386 
  387     read();
  388 
  389     for ( auto &dbe : m_db ) {
  390         float f = 1.234;
  391         time_t last_use = 0;
  392         std::string p = dbe.getBestHit( f, last_use );
  393 
  394         if ( ! p.empty() ) {
  395             res[ dbe.getPrefix() ] = std::make_tuple( p, f, last_use );
  396         }
  397     }
  398 
  399     return res;
  400 }
  401 
  402 void PrefixDB::removeEntry( const std::string &prefix )
  403 {
  404     read();
  405 
  406     auto it = std::find_if( m_db.begin(),
  407                             m_db.end(),
  408                             [prefix] ( const PrefixDBEntry &e ) {
  409                                 return e.getPrefix() == prefix;
  410                             } );
  411 
  412     if ( it == m_db.end() ) {
  413         return;
  414     }
  415 
  416     m_db.erase( it );
  417 
  418     write();
  419 }
  420 
  421 loff_t PrefixDB::getLastSize() const
  422 {
  423     return m_lastsize;
  424 }