00001
00002
00003
00004
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
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() )
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
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 {
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;
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;
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--);
00468 }
00469
00470 if (sum!=size())
00471 _pimpl->locksDirty = true;
00472 }
00473
00474 }