libzypp  14.48.5
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_( it,query.begin(),query.end() )
120  {
121  PoolItem item(*it);
122  item.status().setLock(true,ResStatus::USER);
123  DBG << "lock "<< item.resolvable()->name();
124  }
125  }
126 };
127 
132 template <class OutputIterator>
134 {
135  LockingOutputIterator(OutputIterator& out_)
136  : out(out_)
137  {}
138 
139  void operator()(const PoolQuery& query) const
140  {
141  ApplyLock a;a(query);
142  *out++ = query;
143  }
144 
145  private:
146  OutputIterator& out;
147 };
148 
149 void Locks::readAndApply( const Pathname& file )
150 {
151  MIL << "read and apply locks from "<<file << endl;
152  PathInfo pinfo(file);
153  if ( pinfo.isExist() )
154  {
155  std::insert_iterator<LockSet> ii( _pimpl->MANIPlocks(), _pimpl->MANIPlocks().end() );
157  readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
158  }
159  else
160  MIL << "file does not exist(or cannot be stat), no lock added." << endl;
161 
162 }
163 
164 void Locks::read( const Pathname& file )
165 {
166  MIL << "read locks from "<<file << endl;
167  PathInfo pinfo(file);
168  if ( pinfo.isExist() )
169  readPoolQueriesFromFile( file, std::insert_iterator<LockSet>(_pimpl->MANIPlocks(), _pimpl->MANIPlocks().end()) );
170  else
171  MIL << "file does not exist(or cannot be stat), no lock added." << endl;
172 }
173 
174 
175 void Locks::apply() const
176 {
177  DBG << "apply locks" << endl;
178  for_each(_pimpl->locks().begin(), _pimpl->locks().end(), ApplyLock());
179 }
180 
181 
182 void Locks::addLock( const PoolQuery& query )
183 {
184  MIL << "add new lock" << endl;
185  for_( it,query.begin(),query.end() )
186  {
187  PoolItem item(*it);
188  item.status().setLock(true,ResStatus::USER);
189  }
190  if ( _pimpl->toRemove.erase( query ) )
191  {
192  DBG << "query removed from toRemove" << endl;
193  }
194  else
195  {
196  DBG << "query added as new" << endl;
197  _pimpl->toAdd.insert( query );
198  }
199 }
200 
201 void Locks::addLock( const IdString& ident_r )
202 {
203  sat::Solvable::SplitIdent id(ident_r);
204  addLock(id.kind(),id.name());
205 }
206 
207 void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
208 {
209  addLock(kind_r,IdString(name_r));
210 }
211 
212 void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
213 {
214  PoolQuery q;
216  q.addKind( kind_r );
217  q.setMatchExact();
218  q.setCaseSensitive(true);
219  DBG << "add lock by identifier" << endl;
220  addLock( q );
221 }
222 
223 void Locks::removeLock( const PoolQuery& query )
224 {
225  MIL << "remove lock" << endl;
226  for_( it,query.begin(),query.end() )
227  {
228  PoolItem item(*it);
229  item.status().setLock(false,ResStatus::USER);
230  }
231 
232  if ( _pimpl->toAdd.erase( query ) )
233  {
234  DBG << "query removed from added" << endl;
235  }
236  else
237  {
238  DBG << "need to remove some old lock" << endl;
239  _pimpl->toRemove.insert( query );
240  }
241 }
242 
243 void Locks::removeLock( const IdString& ident_r )
244 {
245  sat::Solvable::SplitIdent id(ident_r);
246  removeLock(id.kind(),id.name());
247 }
248 
249 void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
250 {
251  removeLock(kind_r,IdString(name_r));
252 }
253 
254 void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
255 {
256  PoolQuery q;
258  q.addKind( kind_r );
259  q.setMatchExact();
260  q.setCaseSensitive(true);
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;
335  report->finish(CleanEmptyLocksReport::ABORTED);
336  }
337  else
338  {
339  report->finish(CleanEmptyLocksReport::NO_ERROR);
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());
431  remove_if( MANIPlocks(), LocksRemovePredicate(s,*it, report) );
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  {
456  report->finish(SavingLocksReport::ABORTED);
457  return;
458  }
459  DBG << "locks merged" << endl;
460  report->finish(SavingLocksReport::NO_ERROR);
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  {
480  report->finish(SavingLocksReport::ABORTED);
481  return;
482  }
483  }
484 
485  DBG << "wrote "<< _pimpl->locks().size() << "locks" << endl;
486  writePoolQueriesToFile( file, _pimpl->locks().begin(), _pimpl->locks().end() );
487  report->finish(SavingLocksReport::NO_ERROR);
488 }
489 
491 { /* NOP since implementation uses std::set */ }
492 
493 } // ns zypp
LocksRemovePredicate(std::set< sat::Solvable > &s, const PoolQuery &q, callback::SendReport< SavingLocksReport > &r)
Definition: Locks.cc:375
void operator()(const PoolQuery &query) const
Definition: Locks.cc:117
#define MIL
Definition: Logger.h:47
void addAttribute(const sat::SolvAttr &attr, const std::string &value="")
Filter by the value of the specified attr attribute.
Definition: PoolQuery.cc:826
void operator()(const PoolQuery &query) const
Definition: Locks.cc:139
void removeEmpty()
Call callback for each empty lock.
Definition: Locks.cc:322
void readPoolQueriesFromFile(const zypp::filesystem::Pathname &file, OutputIterator out)
sends to output iterator all queries readed from file.
#define INT
Definition: Logger.h:51
LockingOutputIterator(OutputIterator &out_)
Definition: Locks.cc:135
const_iterator begin() const
Definition: Locks.cc:103
const LockSet & locks() const
Definition: Locks.cc:77
void setCaseSensitive(bool value=true)
Turn case sentitivity on or off (unsets or sets SEARCH_NOCASE flag).
Definition: PoolQuery.cc:951
Access to the sat-pools string space.
Definition: IdString.h:39
cleaning aborted by user
void addKind(const ResKind &kind)
Filter by selectable kind.
Definition: PoolQuery.cc:820
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
delete conflicted lock
LockList::size_type size() const
Definition: Locks.cc:109
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:182
std::string asString() const
Conversion to std::string
Definition: IdString.h:83
bool operator()(const PoolQuery &q)
Definition: Locks.cc:289
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
void apply() const
Applies locks in stable list (locks which is not changed during session).
Definition: Locks.cc:175
std::list< PoolQuery > LockList
Definition: Locks.h:21
ResObject::constPtr resolvable() const
Returns the ResObject::constPtr.
Definition: PoolItem.cc:285
void removeDuplicates()
Delete all query duplicate in loaded locks.
Definition: Locks.cc:490
bool empty() const
Definition: Locks.cc:112
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:97
void merge()
Merges toAdd and ToRemove list to stable list.
Definition: Locks.cc:445
cleaning aborted by user
LockSet & MANIPlocks()
Definition: Locks.cc:80
const PoolQuery & query
Definition: Locks.cc:351
including fstream is not hell here because this header only included by implementation file...
bool _APIdirty
Definition: Locks.cc:98
std::set< PoolQuery > LockSet
Definition: Locks.cc:43
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:246
void writePoolQueriesToFile(const zypp::filesystem::Pathname &file, InputIterator begin, InputIterator end)
Writes all queries from begin to end.
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:376
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
const_iterator end() const
Definition: Locks.cc:106
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
void readAndApply(const Pathname &file=ZConfig::instance().locksFile())
Optimalized version of read and apply.
Definition: Locks.cc:149
SolvableIdType size_type
Definition: PoolMember.h:147
void remove_if(LockSet &lockset_r, TPredicate pred_r)
Definition: Locks.cc:46
const LockList & APIlocks() const
Definition: Locks.cc:83
bool locksDirty
Definition: Locks.cc:65
Meta-data query API.
Definition: PoolQuery.h:90
bool operator()(const PoolQuery &q)
Definition: Locks.cc:379
bool empty() const
Whether the result is empty.
Definition: PoolQuery.cc:968
void setMatchExact()
Set to match exact string instead of substring.
Definition: PoolQuery.cc:899
OutputIterator & out
Definition: Locks.cc:146
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:264
LockList _APIlocks
Definition: Locks.cc:97
abort and return error
Reference to a PoolItem connecting ResObject and ResStatus.
Definition: PoolItem.h:50
const_iterator begin() const
Query result accessers.
Definition: PoolQuery.cc:1773
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:164
void removeLock(const PoolQuery &query)
unlocks by result of query and add to toRemove.
Definition: Locks.cc:223
callback::SendReport< CleanEmptyLocksReport > & report
Definition: Locks.cc:282
const_iterator end() const
An iterator pointing to the end of the query result.
Definition: PoolQuery.h:605
LockList::const_iterator const_iterator
Definition: Locks.h:22
std::set< sat::Solvable > & solvs
Definition: Locks.cc:350
Resolvable kinds.
Definition: ResKind.h:32
bool existEmpty() const
Gets true if some lock doesn't lock any object in pool This can happen e.g.
Definition: Locks.cc:265
iterator that takes lock, lock all solvables from query and send query to output iterator ...
Definition: Locks.cc:133
#define DBG
Definition: Logger.h:46
LockSet _locks
Definition: Locks.cc:96