libzypp  17.7.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  q.requireAll();
261  DBG << "remove lock by Selectable" << endl;
262  removeLock(q);
263 }
264 
265 bool Locks::existEmpty() const
266 {
267  for_( it, _pimpl->locks().begin(), _pimpl->locks().end() )
268  {
269  if( it->empty() )
270  return true;
271  }
272 
273  return false;
274 }
275 
276 //handle locks during removing
278 private:
279  bool skip_rest;
280  size_t searched;
281  size_t all;
283 
284 public:
285  LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
286 
287  bool aborted(){ return skip_rest; }
288 
289  bool operator()( const PoolQuery & q )
290  {
291  if( skip_rest )
292  return false;
293  searched++;
294  if( !q.empty() )
295  return false;
296 
297  if (!report->progress((100*searched)/all))
298  {
299  skip_rest = true;
300  return false;
301  }
302 
303  switch (report->execute(q))
304  {
307  skip_rest = true;
308  return false;
310  return true;
312  return false;
313  default:
314  INT << "Unexpected return value from callback. Need to adapt switch statement." << std::endl;
315  }
316 
317  return false;
318  }
319 
320 };
321 
323 {
324  MIL << "clean of locks" << endl;
326  report->start();
327  size_t sum = _pimpl->locks().size();
328  LocksCleanPredicate p(sum, report);
329 
330  remove_if( _pimpl->MANIPlocks(), p );
331 
332  if( p.aborted() )
333  {
334  MIL << "cleaning aborted" << endl;
336  }
337  else
338  {
340 
341  }
342 
343  if ( sum != _pimpl->locks().size() ) //some locks has been removed
344  _pimpl->locksDirty = true;
345 }
346 
348 {
349 private:
350  std::set<sat::Solvable>& solvs;
351  const PoolQuery& query;
353  bool aborted_;
354 
355  //1 for subset of set, 2 only intersect, 0 for not intersect
356  int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
357  {
358  bool intersect = false;
359  for_( it,q.begin(),q.end() )
360  {
361  if ( s.find(*it)!=s.end() )
362  {
363  intersect = true;
364  }
365  else
366  {
367  if (intersect)
368  return 2;
369  }
370  }
371  return intersect ? 1 : 0;
372  }
373 
374 public:
375  LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
377  : solvs(s), query(q),report(r),aborted_(false) {}
378 
379  bool operator()(const PoolQuery& q)
380  {
381  if (aborted())
382  return false;
383  if( q==query )
384  {//identical
385  DBG << "identical queries" << endl;
386  return true;
387  }
388 
390  switch( contains(q,solvs) )
391  {
392  case 0:
393  return false; //another lock
394  case 1:
396  break;
397  case 2:
399  break;
400  default:
401  return true;
402  }
403  MIL << "find conflict: " << cs << endl;
404  switch (report->conflict(q,cs))
405  {
407  aborted_ = true;
408  DBG << "abort merging" << endl;
409  return false;
411  DBG << "force delete" << endl;
412  return true;
414  DBG << "skip lock" << endl;
415  return false;
416  }
417  INT << "Unexpected return value from callback. Need to adapt switch statement." << std::endl;
418  return false;
419  }
420 
421  bool aborted(){ return aborted_; }
422 };
423 
425 {
426  MIL << "merge list old: " << locks().size()
427  << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
428  for_(it,toRemove.begin(),toRemove.end())
429  {
430  std::set<sat::Solvable> s(it->begin(),it->end());
432  }
433 
434  if (!report->progress())
435  return false;
436 
437  MANIPlocks().insert( toAdd.begin(), toAdd.end() );
438 
439  toAdd.clear();
440  toRemove.clear();
441 
442  return true;
443 }
444 
446 {
447  if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
448  {
449  return; //nothing to merge
450  }
451 
453  report->start();
454  if (!_pimpl->mergeList(report))
455  {
457  return;
458  }
459  DBG << "locks merged" << endl;
461  _pimpl->locksDirty = true;
462 }
463 
464 void Locks::save( const Pathname& file )
465 {
466  if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
467  && !_pimpl->locksDirty )
468  {
469  DBG << "nothing changed in locks - no write to file" << endl;
470  return;
471  }
472 
474  report->start();
475 
476  if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
477  {
478  if (!_pimpl->mergeList(report))
479  {
481  return;
482  }
483  }
484 
485  DBG << "wrote "<< _pimpl->locks().size() << "locks" << endl;
486  writePoolQueriesToFile( file, _pimpl->locks().begin(), _pimpl->locks().end() );
488 }
489 
491 { /* NOP since implementation uses std::set */ }
492 
493 } // 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:375
#define MIL
Definition: Logger.h:64
void addAttribute(const sat::SolvAttr &attr, const std::string &value="")
Filter by the value of the specified attr attribute.
Definition: PoolQuery.cc:934
void removeEmpty()
Call callback for each empty lock.
Definition: Locks.cc:322
void operator()(const PoolQuery &query) const
Definition: Locks.cc:117
#define INT
Definition: Logger.h:68
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&#39;t lock any object in pool This can happen e.g.
Definition: Locks.cc:265
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:1073
Access to the sat-pools string space.
Definition: IdString.h:41
cleaning aborted by user
void addKind(const ResKind &kind)
Filter by selectable kind.
Definition: PoolQuery.cc:928
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
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:289
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:490
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:445
cleaning aborted by user
const_iterator begin() const
Query result accessers.
Definition: PoolQuery.cc:1856
LockSet & MANIPlocks()
Definition: Locks.cc:80
const PoolQuery & query
Definition: Locks.cc:351
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:285
bool mergeList(callback::SendReport< SavingLocksReport > &report)
Definition: Locks.cc:424
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:464
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:626
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:379
void setMatchExact()
Set to match exact string instead of substring.
Definition: PoolQuery.cc:1013
OutputIterator & out
Definition: Locks.cc:145
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:203
LockSet toRemove
Definition: Locks.cc:64
Helper that splits an identifier into kind and name or vice versa.
Definition: Solvable.h:301
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:1095
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:356
callback::SendReport< SavingLocksReport > & report
Definition: Locks.cc:352
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:282
Iterable< PoolItem_iterator > poolItem() const
LockList::const_iterator const_iterator
Definition: Locks.h:22
std::set< sat::Solvable > & solvs
Definition: Locks.cc:350
Resolvable kinds.
Definition: ResKind.h:32
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
bool requireAll() const
Whether all values added via addString() or addAttribute() are required to match the values of the re...
Definition: PoolQuery.cc:1089
iterator that takes lock, lock all solvables from query and send query to output iterator ...
Definition: Locks.cc:132
#define DBG
Definition: Logger.h:63
LockSet _locks
Definition: Locks.cc:96