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