libzypp 9.41.1

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   DBG << "remove lock by Selectable" << endl;
00227   removeLock(q);
00228 }
00229 
00230 bool Locks::existEmpty() const
00231 {
00232   for_( it, _pimpl->locks.begin(), _pimpl->locks.end() )
00233   {
00234     if( it->empty() )
00235       return true;
00236   }
00237 
00238   return false;
00239 }
00240 
00241 //handle locks during removing
00242 class LocksCleanPredicate{
00243 private:
00244   bool skip_rest;
00245   size_t searched;
00246   size_t all;
00247   callback::SendReport<CleanEmptyLocksReport> &report;
00248 
00249 public:
00250   LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
00251 
00252   bool aborted(){ return skip_rest; }
00253 
00254   bool operator()(PoolQuery& q)
00255   {
00256     if( skip_rest )
00257       return false;
00258     searched++;
00259     if( !q.empty() )
00260       return false;
00261 
00262     if (!report->progress((100*searched)/all))
00263     {
00264       skip_rest = true;
00265       return false;
00266     }
00267 
00268     switch (report->execute(q))
00269     {
00270     case CleanEmptyLocksReport::ABORT:
00271       report->finish(CleanEmptyLocksReport::ABORTED);
00272       skip_rest = true;
00273       return false;
00274     case CleanEmptyLocksReport::DELETE:
00275       return true;
00276     case CleanEmptyLocksReport::IGNORE:
00277       return false;
00278     default:
00279       WAR << "Unknown returned value. Callback have more value then"
00280           << " this switch. Need correct handle all enum values." << std::endl;
00281     }
00282 
00283     return false;
00284   }
00285 
00286 };
00287 
00288 void Locks::removeEmpty()
00289 {
00290   MIL << "cleaning of locks" << endl;
00291   callback::SendReport<CleanEmptyLocksReport> report;
00292   report->start();
00293   size_t sum = _pimpl->locks.size();
00294   LocksCleanPredicate p(sum, report);
00295 
00296   _pimpl->locks.remove_if(p);
00297 
00298   if( p.aborted() )
00299   {
00300     MIL << "cleaning aborted" << endl;
00301     report->finish(CleanEmptyLocksReport::ABORTED);
00302   }
00303   else 
00304   {
00305     report->finish(CleanEmptyLocksReport::NO_ERROR);
00306 
00307   }
00308 
00309   if ( sum != _pimpl->locks.size() ) //some locks has been removed
00310     _pimpl->locksDirty = true;
00311 }
00312 
00313 class LocksRemovePredicate
00314 {
00315 private:
00316   std::set<sat::Solvable>& solvs;
00317   const PoolQuery& query;
00318   callback::SendReport<SavingLocksReport>& report;
00319   bool aborted_;
00320 
00321   //1 for subset of set, 2 only intersect, 0 for not intersect
00322   int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
00323   {
00324     bool intersect = false;
00325     for_( it,q.begin(),q.end() )
00326     {
00327       if ( s.find(*it)!=s.end() )
00328       {
00329         intersect = true;
00330       }
00331       else
00332       {
00333         if (intersect)
00334           return 2;
00335       }
00336     }
00337     return intersect ? 1 : 0;
00338   }
00339 
00340 public:
00341   LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
00342       callback::SendReport<SavingLocksReport>& r)
00343       : solvs(s), query(q),report(r),aborted_(false) {}
00344 
00345   bool operator()(const PoolQuery& q)
00346   {
00347     if (aborted())
00348       return false;
00349     if( q==query )
00350     {//identical
00351       DBG << "identical queries" << endl;
00352       return true;
00353     }
00354 
00355     SavingLocksReport::ConflictState cs;
00356     switch( contains(q,solvs) )
00357     {
00358     case 0:
00359       return false; //another lock
00360     case 1:
00361       cs = SavingLocksReport::SAME_RESULTS;
00362       break;
00363     case 2:
00364       cs = SavingLocksReport::INTERSECT;
00365       break;
00366     default:
00367       return true;
00368     }
00369     MIL << "find conflict: " << cs << endl;
00370     switch (report->conflict(q,cs))
00371     {
00372     case SavingLocksReport::ABORT:
00373       aborted_ = true;
00374       DBG << "abort merging" << endl;
00375       return false;
00376     case SavingLocksReport::DELETE:
00377       DBG << "force delete" << endl;
00378       return true;
00379     case SavingLocksReport::IGNORE:
00380       DBG << "skip lock" << endl;
00381       return false;
00382     }
00383     WAR << "should not reached, some state is missing" << endl;
00384     return false;
00385   }
00386 
00387   bool aborted(){ return aborted_; }
00388 };
00389 
00390 bool Locks::Impl::mergeList(callback::SendReport<SavingLocksReport>& report)
00391 {
00392   MIL << "merging list old: " << locks.size()
00393     << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
00394   for_(it,toRemove.begin(),toRemove.end())
00395   {
00396     std::set<sat::Solvable> s(it->begin(),it->end());
00397     locks.remove_if(LocksRemovePredicate(s,*it, report));
00398   }
00399 
00400   if (!report->progress())
00401     return false;
00402 
00403   for_( it, toAdd.begin(), toAdd.end() )
00404   {
00405     if( std::find( locks.begin(), locks.end(), *it ) == locks.end() )
00406       locks.push_back( *it );
00407   }
00408 
00409   toAdd.clear();
00410   toRemove.clear();
00411 
00412   return true;
00413 }
00414 
00415 void Locks::merge()
00416 {
00417   if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
00418   {
00419     return; //nothing to merge
00420   }
00421 
00422   callback::SendReport<SavingLocksReport> report;
00423   report->start();
00424   if (!_pimpl->mergeList(report))
00425   {
00426     report->finish(SavingLocksReport::ABORTED);
00427     return;
00428   }
00429   DBG << "locks merged" << endl;
00430   report->finish(SavingLocksReport::NO_ERROR);
00431   _pimpl->locksDirty = true;
00432 }
00433 
00434 void Locks::save( const Pathname& file )
00435 {
00436   if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
00437       && !_pimpl->locksDirty )
00438   {
00439     DBG << "nothing changed in locks - no write to file" << endl;
00440     return;
00441   }
00442 
00443   callback::SendReport<SavingLocksReport> report;
00444   report->start();
00445 
00446   if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
00447   {
00448     if (!_pimpl->mergeList(report))
00449     {
00450       report->finish(SavingLocksReport::ABORTED);
00451       return;
00452     }
00453   }
00454 
00455   DBG << "writed "<< _pimpl->locks.size() << "locks" << endl;
00456   writePoolQueriesToFile( file, _pimpl->locks.begin(), _pimpl->locks.end() );
00457   report->finish(SavingLocksReport::NO_ERROR);
00458 }
00459 
00460 void Locks::removeDuplicates()
00461 {
00462   size_type sum = size();
00463   for_(it,_pimpl->locks.begin(),_pimpl->locks.end())
00464   {
00465     if ( find(_pimpl->locks.begin(),it,*it) != it )
00466       _pimpl->locks.erase(it--); //-- to avoid using break iterator
00467   }
00468   
00469   if (sum!=size())
00470     _pimpl->locksDirty = true;
00471 }
00472 
00473 } // ns zypp