libzypp 9.41.1
|
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