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