libzypp  17.14.0
Locks.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 
10 #include <set>
11 #include <fstream>
12 #include <boost/function.hpp>
13 #include <boost/function_output_iterator.hpp>
14 #include <algorithm>
15 
16 #include "zypp/base/Regex.h"
17 #include "zypp/base/String.h"
18 #include "zypp/base/LogTools.h"
19 #include "zypp/base/IOStream.h"
20 #include "zypp/PoolItem.h"
21 #include "zypp/PoolQueryUtil.tcc"
22 #include "zypp/ZYppCallbacks.h"
23 #include "zypp/sat/SolvAttr.h"
24 #include "zypp/sat/Solvable.h"
25 #include "zypp/PathInfo.h"
26 
27 #undef ZYPP_BASE_LOGGER_LOGGROUP
28 #define ZYPP_BASE_LOGGER_LOGGROUP "locks"
29 
30 #include "zypp/Locks.h"
31 
32 using std::endl;
33 
34 namespace zypp
35 {
36 
38 {
39  static Locks _instance;
40  return _instance;
41 }
42 
43 typedef std::set<PoolQuery> LockSet;
44 
45 template <typename TPredicate>
46 void remove_if( LockSet & lockset_r, TPredicate pred_r )
47 {
48  LockSet::iterator first = lockset_r.begin();
49  LockSet::iterator last = lockset_r.end();
50  while ( first != last )
51  {
52  LockSet::iterator next = first;
53  ++next;
54  if ( pred_r( *first ) )
55  lockset_r.erase( first );
56  first = next;
57  }
58 }
59 
61 {
62 public:
65  bool locksDirty;
66 
68 
69  Impl()
70  : locksDirty( false )
71  , _APIdirty( false )
72  {}
73 
74 
75  // need to control manip locks _locks to maintain the legacy API LockList::iterator begin/end
76 
77  const LockSet & locks() const
78  { return _locks; }
79 
81  { if ( !_APIdirty ) _APIdirty = true; return _locks; }
82 
83  const LockList & APIlocks() const
84  {
85  if ( _APIdirty )
86  {
87  _APIlocks.clear();
88  _APIlocks.insert( _APIlocks.end(), _locks.begin(), _locks.end() );
89  _APIdirty = false;
90  }
91  return _APIlocks;
92  }
93 
94 private:
95  // need to control manip in ordert to maintain the legacy API LockList::iterator begin/end
98  mutable bool _APIdirty;
99 };
100 
101 Locks::Locks() : _pimpl(new Impl){}
102 
104 { return _pimpl->APIlocks().begin(); }
105 
107 { return _pimpl->APIlocks().end(); }
108 
110 { return _pimpl->locks().size(); }
111 
112 bool Locks::empty() const
113 { return _pimpl->locks().empty(); }
114 
115 struct ApplyLock
116 {
117  void operator()(const PoolQuery& query) const
118  {
119  for ( const PoolItem & item : query.poolItem() )
120  {
121  item.status().setLock(true,ResStatus::USER);
122  DBG << "lock "<< item.name();
123  }
124  }
125 };
126 
131 template <class OutputIterator>
133 {
134  LockingOutputIterator(OutputIterator& out_)
135  : out(out_)
136  {}
137 
138  void operator()(const PoolQuery& query) const
139  {
140  ApplyLock a;a(query);
141  *out++ = query;
142  }
143 
144  private:
145  OutputIterator& out;
146 };
147 
148 void Locks::readAndApply( const Pathname& file )
149 {
150  MIL << "read and apply locks from "<<file << endl;
151  PathInfo pinfo(file);
152  if ( pinfo.isExist() )
153  {
154  std::insert_iterator<LockSet> ii( _pimpl->MANIPlocks(), _pimpl->MANIPlocks().end() );
156  readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
157  }
158  else
159  MIL << "file does not exist(or cannot be stat), no lock added." << endl;
160 
161 }
162 
163 void Locks::read( const Pathname& file )
164 {
165  MIL << "read locks from "<<file << endl;
166  PathInfo pinfo(file);
167  if ( pinfo.isExist() )
168  readPoolQueriesFromFile( file, std::insert_iterator<LockSet>(_pimpl->MANIPlocks(), _pimpl->MANIPlocks().end()) );
169  else
170  MIL << "file does not exist(or cannot be stat), no lock added." << endl;
171 }
172 
173 
174 void Locks::apply() const
175 {
176  DBG << "apply locks" << endl;
177  for_each(_pimpl->locks().begin(), _pimpl->locks().end(), ApplyLock());
178 }
179 
180 
181 void Locks::addLock( const PoolQuery& query )
182 {
183  MIL << "add new lock" << endl;
184  for_( it,query.begin(),query.end() )
185  {
186  PoolItem item(*it);
187  item.status().setLock(true,ResStatus::USER);
188  }
189  if ( _pimpl->toRemove.erase( query ) )
190  {
191  DBG << "query removed from toRemove" << endl;
192  }
193  else
194  {
195  DBG << "query added as new" << endl;
196  _pimpl->toAdd.insert( query );
197  }
198 }
199 
200 void Locks::addLock( const IdString& ident_r )
201 {
202  sat::Solvable::SplitIdent id(ident_r);
203  addLock(id.kind(),id.name());
204 }
205 
206 void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
207 {
208  addLock(kind_r,IdString(name_r));
209 }
210 
211 void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
212 {
213  PoolQuery q;
215  q.addKind( kind_r );
216  q.setMatchExact();
217  q.setCaseSensitive(true);
218  DBG << "add lock by identifier" << endl;
219  addLock( q );
220 }
221 
222 void Locks::removeLock( const PoolQuery& query )
223 {
224  MIL << "remove lock" << endl;
225  for_( it,query.begin(),query.end() )
226  {
227  PoolItem item(*it);
228  item.status().setLock(false,ResStatus::USER);
229  }
230 
231  if ( _pimpl->toAdd.erase( query ) )
232  {
233  DBG << "query removed from added" << endl;
234  }
235  else
236  {
237  DBG << "need to remove some old lock" << endl;
238  _pimpl->toRemove.insert( query );
239  }
240 }
241 
242 void Locks::removeLock( const IdString& ident_r )
243 {
244  sat::Solvable::SplitIdent id(ident_r);
245  removeLock(id.kind(),id.name());
246 }
247 
248 void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
249 {
250  removeLock(kind_r,IdString(name_r));
251 }
252 
253 void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
254 {
255  PoolQuery q;
257  q.addKind( kind_r );
258  q.setMatchExact();
259  q.setCaseSensitive(true);
260  DBG << "remove lock by Selectable" << endl;
261  removeLock(q);
262 }
263 
264 bool Locks::existEmpty() const
265 {
266  for_( it, _pimpl->locks().begin(), _pimpl->locks().end() )
267  {
268  if( it->empty() )
269  return true;
270  }
271 
272  return false;
273 }
274 
275 //handle locks during removing
277 private:
278  bool skip_rest;
279  size_t searched;
280  size_t all;
282 
283 public:
284  LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
285 
286  bool aborted(){ return skip_rest; }
287 
288  bool operator()( const PoolQuery & q )
289  {
290  if( skip_rest )
291  return false;
292  searched++;
293  if( !q.empty() )
294  return false;
295 
296  if (!report->progress((100*searched)/all))
297  {
298  skip_rest = true;
299  return false;
300  }
301 
302  switch (report->execute(q))
303  {
306  skip_rest = true;
307  return false;
309  return true;
311  return false;
312  default:
313  INT << "Unexpected return value from callback. Need to adapt switch statement." << std::endl;
314  }
315 
316  return false;
317  }
318 
319 };
320 
322 {
323  MIL << "clean of locks" << endl;
325  report->start();
326  size_t sum = _pimpl->locks().size();
327  LocksCleanPredicate p(sum, report);
328 
329  remove_if( _pimpl->MANIPlocks(), p );
330 
331  if( p.aborted() )
332  {
333  MIL << "cleaning aborted" << endl;
335  }
336  else
337  {
339 
340  }
341 
342  if ( sum != _pimpl->locks().size() ) //some locks has been removed
343  _pimpl->locksDirty = true;
344 }
345 
347 {
348 private:
349  std::set<sat::Solvable>& solvs;
350  const PoolQuery& query;
352  bool aborted_;
353 
354  //1 for subset of set, 2 only intersect, 0 for not intersect
355  int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
356  {
357  bool intersect = false;
358  for_( it,q.begin(),q.end() )
359  {
360  if ( s.find(*it)!=s.end() )
361  {
362  intersect = true;
363  }
364  else
365  {
366  if (intersect)
367  return 2;
368  }
369  }
370  return intersect ? 1 : 0;
371  }
372 
373 public:
374  LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
376  : solvs(s), query(q),report(r),aborted_(false) {}
377 
378  bool operator()(const PoolQuery& q)
379  {
380  if (aborted())
381  return false;
382  if( q==query )
383  {//identical
384  DBG << "identical queries" << endl;
385  return true;
386  }
387 
389  switch( contains(q,solvs) )
390  {
391  case 0:
392  return false; //another lock
393  case 1:
395  break;
396  case 2:
398  break;
399  default:
400  return true;
401  }
402  MIL << "find conflict: " << cs << endl;
403  switch (report->conflict(q,cs))
404  {
406  aborted_ = true;
407  DBG << "abort merging" << endl;
408  return false;
410  DBG << "force delete" << endl;
411  return true;
413  DBG << "skip lock" << endl;
414  return false;
415  }
416  INT << "Unexpected return value from callback. Need to adapt switch statement." << std::endl;
417  return false;
418  }
419 
420  bool aborted(){ return aborted_; }
421 };
422 
424 {
425  MIL << "merge list old: " << locks().size()
426  << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
427  for_(it,toRemove.begin(),toRemove.end())
428  {
429  std::set<sat::Solvable> s(it->begin(),it->end());
431  }
432 
433  if (!report->progress())
434  return false;
435 
436  MANIPlocks().insert( toAdd.begin(), toAdd.end() );
437 
438  toAdd.clear();
439  toRemove.clear();
440 
441  return true;
442 }
443 
445 {
446  if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
447  {
448  return; //nothing to merge
449  }
450 
452  report->start();
453  if (!_pimpl->mergeList(report))
454  {
456  return;
457  }
458  DBG << "locks merged" << endl;
460  _pimpl->locksDirty = true;
461 }
462 
463 void Locks::save( const Pathname& file )
464 {
465  if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
466  && !_pimpl->locksDirty )
467  {
468  DBG << "nothing changed in locks - no write to file" << endl;
469  return;
470  }
471 
473  report->start();
474 
475  if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
476  {
477  if (!_pimpl->mergeList(report))
478  {
480  return;
481  }
482  }
483 
484  DBG << "wrote "<< _pimpl->locks().size() << "locks" << endl;
485  writePoolQueriesToFile( file, _pimpl->locks().begin(), _pimpl->locks().end() );
487 }
488 
490 { /* NOP since implementation uses std::set */ }
491 
492 } // ns zypp
const LockList & APIlocks() const
Definition: Locks.cc:83
LocksRemovePredicate(std::set< sat::Solvable > &s, const PoolQuery &q, callback::SendReport< SavingLocksReport > &r)
Definition: Locks.cc:374
#define MIL
Definition: Logger.h:79
void addAttribute(const sat::SolvAttr &attr, const std::string &value="")
Filter by the value of the specified attr attribute.
Definition: PoolQuery.cc:873
void removeEmpty()
Call callback for each empty lock.
Definition: Locks.cc:321
void operator()(const PoolQuery &query) const
Definition: Locks.cc:117
#define INT
Definition: Logger.h:83
LockingOutputIterator(OutputIterator &out_)
Definition: Locks.cc:134
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:204
bool existEmpty() const
Gets true if some lock doesn't lock any object in pool This can happen e.g.
Definition: Locks.cc:264
LockList::size_type size() const
Definition: Locks.cc:109
void setCaseSensitive(bool value=true)
Turn case sentitivity on or off (unsets or sets SEARCH_NOCASE flag).
Definition: PoolQuery.cc:1004
Access to the sat-pools string space.
Definition: IdString.h:41
void addKind(const ResKind &kind)
Filter by selectable kind.
Definition: PoolQuery.cc:867
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
delete conflicted lock
const_iterator begin() const
Definition: Locks.cc:103
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
Definition: Locks.h:148
void addLock(const PoolQuery &query)
TODO add: toBeAdded{Begin,End,Size,Empty} toBeRemoved{Begin,End,Size,Empty}.
Definition: Locks.cc:181
bool operator()(const PoolQuery &q)
Definition: Locks.cc:288
void operator()(const PoolQuery &query) const
Definition: Locks.cc:138
Singleton class which manipulate with locks file and apply locks on pool.
Definition: Locks.h:18
locks lock some file and unlocking lock unlock only part of iti, so removing old lock can unlock more...
LockSet toAdd
Definition: Locks.cc:63
std::list< PoolQuery > LockList
Definition: Locks.h:21
void removeDuplicates()
Delete all query duplicate in loaded locks.
Definition: Locks.cc:489
const_iterator end() const
Definition: Locks.cc:106
void apply() const
Applies locks in stable list (locks which is not changed during session).
Definition: Locks.cc:174
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
static Locks & instance()
Gets instance of this class.
Definition: Locks.cc:37
Convenience char* constructible from std::string and char*, it maps (char*)0 to an empty string.
Definition: String.h:90
void merge()
Merges toAdd and ToRemove list to stable list.
Definition: Locks.cc:444
cleaning aborted by user
const_iterator begin() const
Query result accessers.
Definition: PoolQuery.cc:1826
LockSet & MANIPlocks()
Definition: Locks.cc:80
const PoolQuery & query
Definition: Locks.cc:350
bool _APIdirty
Definition: Locks.cc:98
std::set< PoolQuery > LockSet
Definition: Locks.cc:43
locks lock same item in pool but his parameters is different
bool setLock(bool toLock_r, TransactByValue causer_r)
Apply a lock (prevent transaction).
Definition: ResStatus.h:379
static const SolvAttr name
Definition: SolvAttr.h:52
LocksCleanPredicate(size_t count, callback::SendReport< CleanEmptyLocksReport > &_report)
Definition: Locks.cc:284
bool mergeList(callback::SendReport< SavingLocksReport > &report)
Definition: Locks.cc:423
void save(const Pathname &file=ZConfig::instance().locksFile())
Merges toAdd and ToRemove list to stable list and save that stable list to file.
Definition: Locks.cc:463
const LockSet & locks() const
Definition: Locks.cc:77
const_iterator end() const
An iterator pointing to the end of the query result.
Definition: PoolQuery.h:614
void readAndApply(const Pathname &file=ZConfig::instance().locksFile())
Optimalized version of read and apply.
Definition: Locks.cc:148
SolvableIdType size_type
Definition: PoolMember.h:126
void remove_if(LockSet &lockset_r, TPredicate pred_r)
Definition: Locks.cc:46
bool empty() const
Definition: Locks.cc:112
bool locksDirty
Definition: Locks.cc:65
Meta-data query API.
Definition: PoolQuery.h:90
bool operator()(const PoolQuery &q)
Definition: Locks.cc:378
void setMatchExact()
Set to match exact string instead of substring.
Definition: PoolQuery.cc:952
OutputIterator & out
Definition: Locks.cc:145
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:184
LockSet toRemove
Definition: Locks.cc:64
Helper that splits an identifier into kind and name or vice versa.
Definition: Solvable.h:304
LockList _APIlocks
Definition: Locks.cc:97
abort and return error
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
bool empty() const
Whether the result is empty.
Definition: PoolQuery.cc:1021
Combining sat::Solvable and ResStatus.
Definition: PoolItem.h:50
std::string asString() const
Conversion to std::string
Definition: IdString.h:91
ConflictState
type of conflict of old and new lock
int contains(const PoolQuery &q, std::set< sat::Solvable > &s)
Definition: Locks.cc:355
callback::SendReport< SavingLocksReport > & report
Definition: Locks.cc:351
void read(const Pathname &file=ZConfig::instance().locksFile())
Read locks from file to list of stable locks (locks which is not changed during session)
Definition: Locks.cc:163
void removeLock(const PoolQuery &query)
unlocks by result of query and add to toRemove.
Definition: Locks.cc:222
callback::SendReport< CleanEmptyLocksReport > & report
Definition: Locks.cc:281
Iterable< PoolItem_iterator > poolItem() const
LockList::const_iterator const_iterator
Definition: Locks.h:22
std::set< sat::Solvable > & solvs
Definition: Locks.cc:349
Resolvable kinds.
Definition: ResKind.h:32
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
iterator that takes lock, lock all solvables from query and send query to output iterator
Definition: Locks.cc:132
#define DBG
Definition: Logger.h:78
LockSet _locks
Definition: Locks.cc:96