libzypp  10.5.0
Locks.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00009 
00010 #include <set>
00011 #include <fstream>
00012 #include <boost/function.hpp>
00013 #include <boost/function_output_iterator.hpp>
00014 #include <algorithm>
00015 
00016 #include "zypp/base/Regex.h"
00017 #include "zypp/base/String.h"
00018 #include "zypp/base/Logger.h"
00019 #include "zypp/base/IOStream.h"
00020 #include "zypp/PoolItem.h"
00021 #include "zypp/PoolQueryUtil.tcc"
00022 #include "zypp/ZYppCallbacks.h"
00023 #include "zypp/sat/SolvAttr.h"
00024 #include "zypp/sat/Solvable.h"
00025 #include "zypp/PathInfo.h"
00026 
00027 #undef ZYPP_BASE_LOGGER_LOGGROUP
00028 #define ZYPP_BASE_LOGGER_LOGGROUP "locks"
00029 
00030 #include "zypp/Locks.h"
00031 
00032 using namespace std;
00033 using namespace zypp;
00034 using namespace zypp::str;
00035 
00036 namespace zypp
00037 {
00038 
00039 Locks& Locks::instance()
00040 {
00041   static Locks _instance;
00042   return _instance;
00043 }
00044 
00045 class Locks::Impl
00046 {
00047 public:
00048   LockList locks;
00049   LockList toAdd;
00050   LockList toRemove;
00051   bool     locksDirty;
00052 
00053   bool mergeList(callback::SendReport<SavingLocksReport>& report);
00054   
00055   Impl():locksDirty(false){}
00056 };
00057 
00058 Locks::Locks() : _pimpl(new Impl){}
00059 
00060 Locks::const_iterator Locks::begin() const
00061 { return _pimpl->locks.begin(); }
00062 
00063 Locks::const_iterator Locks::end() const
00064 { return _pimpl->locks.end(); }
00065 
00066 Locks::LockList::size_type Locks::size() const
00067 { return _pimpl->locks.size(); }
00068 
00069 bool Locks::empty() const
00070 { return _pimpl->locks.empty(); }
00071 
00072 struct ApplyLock
00073 {
00074   void operator()(const PoolQuery& query) const
00075   {
00076     for_( it,query.begin(),query.end() )
00077     {
00078       PoolItem item(*it);
00079       item.status().setLock(true,ResStatus::USER);
00080       DBG << "lock "<< item.resolvable()->name();
00081     }
00082   }
00083 };
00084 
00089 template <class OutputIterator>
00090 struct LockingOutputIterator
00091 {
00092   LockingOutputIterator(OutputIterator& out_)
00093     : out(out_)
00094     {}
00095 
00096   void operator()(const PoolQuery& query) const
00097   {
00098     ApplyLock a;a(query);
00099     *out++ = query;
00100   }
00101   
00102   private:
00103   OutputIterator& out;
00104 };
00105 
00106 void Locks::readAndApply( const Pathname& file )
00107 {
00108   MIL << "read and apply locks from "<<file << endl;
00109   PathInfo pinfo(file);
00110   if ( pinfo.isExist() )
00111   {
00112     insert_iterator<LockList> ii( _pimpl->locks,
00113         _pimpl->locks.end() );
00114     LockingOutputIterator<insert_iterator<LockList> > lout(ii);
00115     readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
00116   }
00117   else
00118     MIL << "file not exist(or cannot be stat), no lock added." << endl;
00119 
00120 }
00121 
00122 void Locks::read( const Pathname& file )
00123 {
00124   MIL << "read locks from "<<file << endl;
00125   PathInfo pinfo(file);
00126   if ( pinfo.isExist() )
00127     readPoolQueriesFromFile(
00128        file, insert_iterator<LockList>(_pimpl->locks, _pimpl->locks.end()) );
00129   else 
00130     MIL << "file not exist(or cannot be stat), no lock added." << endl;
00131 }
00132 
00133 
00134 void Locks::apply() const
00135 { 
00136   DBG << "apply locks" << endl;
00137   for_each(begin(), end(), ApplyLock());
00138 }
00139 
00140 
00141 void Locks::addLock( const PoolQuery& query )
00142 {
00143   MIL << "add new lock" << endl;
00144   for_( it,query.begin(),query.end() )
00145   {
00146     PoolItem item(*it);
00147     item.status().setLock(true,ResStatus::USER);
00148   }
00149   LockList::iterator i = find(_pimpl->toRemove.begin(),
00150     _pimpl->toRemove.end(), query);
00151   if ( i != _pimpl->toRemove.end() )
00152   {
00153     DBG << "query removed from toRemove" << endl;
00154     _pimpl->toRemove.erase(i);
00155   }
00156   else
00157   {
00158     DBG << "query added as new" << endl;
00159     _pimpl->toAdd.push_back( query );
00160   }
00161 }
00162 
00163 void Locks::addLock( const IdString& ident_r )
00164 {
00165   sat::Solvable::SplitIdent id(ident_r);
00166   addLock(id.kind(),id.name());
00167 }
00168 
00169 void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
00170 {
00171   addLock(kind_r,IdString(name_r));
00172 }
00173 
00174 void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
00175 {
00176   PoolQuery q;
00177   q.addAttribute( sat::SolvAttr::name,name_r.asString() );
00178   q.addKind( kind_r );
00179   q.setMatchExact();
00180   q.setCaseSensitive(true);
00181   DBG << "add lock by identifier" << endl;
00182   addLock( q );
00183 }
00184 
00185 void Locks::removeLock( const PoolQuery& query )
00186 {
00187   MIL << "remove lock" << endl;
00188   for_( it,query.begin(),query.end() )
00189   {
00190     PoolItem item(*it);
00191     item.status().setLock(false,ResStatus::USER);
00192   }
00193   
00194   LockList::iterator i = find(_pimpl->toAdd.begin(),
00195     _pimpl->toAdd.end(), query);
00196   if ( i != _pimpl->toAdd.end() )
00197   {
00198     DBG << "query removed from added" << endl;
00199     _pimpl->toAdd.erase(i);
00200   }
00201   else
00202   {
00203     DBG << "needed remove some old lock" << endl;
00204     _pimpl->toRemove.push_back( query );
00205   }
00206 }
00207 
00208 void Locks::removeLock( const IdString& ident_r )
00209 {
00210   sat::Solvable::SplitIdent id(ident_r);
00211   removeLock(id.kind(),id.name());
00212 }
00213 
00214 void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
00215 {
00216   removeLock(kind_r,IdString(name_r));
00217 }
00218 
00219 void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
00220 {
00221   PoolQuery q;
00222   q.addAttribute( sat::SolvAttr::name,name_r.asString() );
00223   q.addKind( kind_r );
00224   q.setMatchExact();
00225   q.setCaseSensitive(true);
00226   q.requireAll();
00227   DBG << "remove lock by selectactable" << endl;
00228   removeLock(q);
00229 }
00230 
00231 bool Locks::existEmpty() const
00232 {
00233   for_( it, _pimpl->locks.begin(), _pimpl->locks.end() )
00234   {
00235     if( it->empty() )
00236       return true;
00237   }
00238 
00239   return false;
00240 }
00241 
00242 //handle locks during removing
00243 class LocksCleanPredicate{
00244 private:
00245   bool skip_rest;
00246   size_t searched;
00247   size_t all;
00248   callback::SendReport<CleanEmptyLocksReport> &report;
00249 
00250 public:
00251   LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
00252 
00253   bool aborted(){ return skip_rest; }
00254 
00255   bool operator()(PoolQuery& q)
00256   {
00257     if( skip_rest )
00258       return false;
00259     searched++;
00260     if( !q.empty() )
00261       return false;
00262 
00263     if (!report->progress((100*searched)/all))
00264     {
00265       skip_rest = true;
00266       return false;
00267     }
00268 
00269     switch (report->execute(q))
00270     {
00271     case CleanEmptyLocksReport::ABORT:
00272       report->finish(CleanEmptyLocksReport::ABORTED);
00273       skip_rest = true;
00274       return false;
00275     case CleanEmptyLocksReport::DELETE:
00276       return true;
00277     case CleanEmptyLocksReport::IGNORE:
00278       return false;
00279     default:
00280       WAR << "Unknown returned value. Callback have more value then"
00281           << " this switch. Need correct handle all enum values." << std::endl;
00282     }
00283 
00284     return false;
00285   }
00286 
00287 };
00288 
00289 void Locks::removeEmpty()
00290 {
00291   MIL << "cleaning of locks" << endl;
00292   callback::SendReport<CleanEmptyLocksReport> report;
00293   report->start();
00294   size_t sum = _pimpl->locks.size();
00295   LocksCleanPredicate p(sum, report);
00296 
00297   _pimpl->locks.remove_if(p);
00298 
00299   if( p.aborted() )
00300   {
00301     MIL << "cleaning aborted" << endl;
00302     report->finish(CleanEmptyLocksReport::ABORTED);
00303   }
00304   else 
00305   {
00306     report->finish(CleanEmptyLocksReport::NO_ERROR);
00307 
00308   }
00309 
00310   if ( sum != _pimpl->locks.size() ) //some locks has been removed
00311     _pimpl->locksDirty = true;
00312 }
00313 
00314 class LocksRemovePredicate
00315 {
00316 private:
00317   std::set<sat::Solvable>& solvs;
00318   const PoolQuery& query;
00319   callback::SendReport<SavingLocksReport>& report;
00320   bool aborted_;
00321 
00322   //1 for subset of set, 2 only intersect, 0 for not intersect
00323   int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
00324   {
00325     bool intersect = false;
00326     for_( it,q.begin(),q.end() )
00327     {
00328       if ( s.find(*it)!=s.end() )
00329       {
00330         intersect = true;
00331       }
00332       else
00333       {
00334         if (intersect)
00335           return 2;
00336       }
00337     }
00338     return intersect ? 1 : 0;
00339   }
00340 
00341 public:
00342   LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
00343       callback::SendReport<SavingLocksReport>& r)
00344       : solvs(s), query(q),report(r),aborted_(false) {}
00345 
00346   bool operator()(const PoolQuery& q)
00347   {
00348     if (aborted())
00349       return false;
00350     if( q==query )
00351     {//identical
00352       DBG << "identical queries" << endl;
00353       return true;
00354     }
00355 
00356     SavingLocksReport::ConflictState cs;
00357     switch( contains(q,solvs) )
00358     {
00359     case 0:
00360       return false; //another lock
00361     case 1:
00362       cs = SavingLocksReport::SAME_RESULTS;
00363       break;
00364     case 2:
00365       cs = SavingLocksReport::INTERSECT;
00366       break;
00367     default:
00368       return true;
00369     }
00370     MIL << "find conflict: " << cs << endl;
00371     switch (report->conflict(q,cs))
00372     {
00373     case SavingLocksReport::ABORT:
00374       aborted_ = true;
00375       DBG << "abort merging" << endl;
00376       return false;
00377     case SavingLocksReport::DELETE:
00378       DBG << "force delete" << endl;
00379       return true;
00380     case SavingLocksReport::IGNORE:
00381       DBG << "skip lock" << endl;
00382       return false;
00383     }
00384     WAR << "should not reached, some state is missing" << endl;
00385     return false;
00386   }
00387 
00388   bool aborted(){ return aborted_; }
00389 };
00390 
00391 bool Locks::Impl::mergeList(callback::SendReport<SavingLocksReport>& report)
00392 {
00393   MIL << "merging list old: " << locks.size()
00394     << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
00395   for_(it,toRemove.begin(),toRemove.end())
00396   {
00397     std::set<sat::Solvable> s(it->begin(),it->end());
00398     locks.remove_if(LocksRemovePredicate(s,*it, report));
00399   }
00400 
00401   if (!report->progress())
00402     return false;
00403 
00404   for_( it, toAdd.begin(), toAdd.end() )
00405   {
00406     if( std::find( locks.begin(), locks.end(), *it ) == locks.end() )
00407       locks.push_back( *it );
00408   }
00409 
00410   toAdd.clear();
00411   toRemove.clear();
00412 
00413   return true;
00414 }
00415 
00416 void Locks::merge()
00417 {
00418   if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
00419   {
00420     return; //nothing to merge
00421   }
00422 
00423   callback::SendReport<SavingLocksReport> report;
00424   report->start();
00425   if (!_pimpl->mergeList(report))
00426   {
00427     report->finish(SavingLocksReport::ABORTED);
00428     return;
00429   }
00430   DBG << "locks merged" << endl;
00431   report->finish(SavingLocksReport::NO_ERROR);
00432   _pimpl->locksDirty = true;
00433 }
00434 
00435 void Locks::save( const Pathname& file )
00436 {
00437   if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
00438       && !_pimpl->locksDirty )
00439   {
00440     DBG << "nothing changed in locks - no write to file" << endl;
00441     return;
00442   }
00443 
00444   callback::SendReport<SavingLocksReport> report;
00445   report->start();
00446 
00447   if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
00448   {
00449     if (!_pimpl->mergeList(report))
00450     {
00451       report->finish(SavingLocksReport::ABORTED);
00452       return;
00453     }
00454   }
00455 
00456   DBG << "writed "<< _pimpl->locks.size() << "locks" << endl;
00457   writePoolQueriesToFile( file, _pimpl->locks.begin(), _pimpl->locks.end() );
00458   report->finish(SavingLocksReport::NO_ERROR);
00459 }
00460 
00461 void Locks::removeDuplicates()
00462 {
00463   size_type sum = size();
00464   for_(it,_pimpl->locks.begin(),_pimpl->locks.end())
00465   {
00466     if ( find(_pimpl->locks.begin(),it,*it) != it )
00467       _pimpl->locks.erase(it--); //-- to avoid using break iterator
00468   }
00469   
00470   if (sum!=size())
00471     _pimpl->locksDirty = true;
00472 }
00473 
00474 } // ns zypp