libzypp  12.16.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/Logger.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 namespace std;
33 using namespace zypp;
34 using namespace zypp::str;
35 
36 namespace zypp
37 {
38 
39 Locks& Locks::instance()
40 {
41  static Locks _instance;
42  return _instance;
43 }
44 
46 {
47 public:
51  bool locksDirty;
52 
54 
55  Impl():locksDirty(false){}
56 };
57 
58 Locks::Locks() : _pimpl(new Impl){}
59 
61 { return _pimpl->locks.begin(); }
62 
64 { return _pimpl->locks.end(); }
65 
67 { return _pimpl->locks.size(); }
68 
69 bool Locks::empty() const
70 { return _pimpl->locks.empty(); }
71 
72 struct ApplyLock
73 {
74  void operator()(const PoolQuery& query) const
75  {
76  for_( it,query.begin(),query.end() )
77  {
78  PoolItem item(*it);
79  item.status().setLock(true,ResStatus::USER);
80  DBG << "lock "<< item.resolvable()->name();
81  }
82  }
83 };
84 
89 template <class OutputIterator>
91 {
92  LockingOutputIterator(OutputIterator& out_)
93  : out(out_)
94  {}
95 
96  void operator()(const PoolQuery& query) const
97  {
98  ApplyLock a;a(query);
99  *out++ = query;
100  }
101 
102  private:
103  OutputIterator& out;
104 };
105 
106 void Locks::readAndApply( const Pathname& file )
107 {
108  MIL << "read and apply locks from "<<file << endl;
109  PathInfo pinfo(file);
110  if ( pinfo.isExist() )
111  {
112  insert_iterator<LockList> ii( _pimpl->locks,
113  _pimpl->locks.end() );
115  readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
116  }
117  else
118  MIL << "file not exist(or cannot be stat), no lock added." << endl;
119 
120 }
121 
122 void Locks::read( const Pathname& file )
123 {
124  MIL << "read locks from "<<file << endl;
125  PathInfo pinfo(file);
126  if ( pinfo.isExist() )
128  file, insert_iterator<LockList>(_pimpl->locks, _pimpl->locks.end()) );
129  else
130  MIL << "file not exist(or cannot be stat), no lock added." << endl;
131 }
132 
133 
134 void Locks::apply() const
135 {
136  DBG << "apply locks" << endl;
137  for_each(begin(), end(), ApplyLock());
138 }
139 
140 
141 void Locks::addLock( const PoolQuery& query )
142 {
143  MIL << "add new lock" << endl;
144  for_( it,query.begin(),query.end() )
145  {
146  PoolItem item(*it);
147  item.status().setLock(true,ResStatus::USER);
148  }
149  LockList::iterator i = find(_pimpl->toRemove.begin(),
150  _pimpl->toRemove.end(), query);
151  if ( i != _pimpl->toRemove.end() )
152  {
153  DBG << "query removed from toRemove" << endl;
154  _pimpl->toRemove.erase(i);
155  }
156  else
157  {
158  DBG << "query added as new" << endl;
159  _pimpl->toAdd.push_back( query );
160  }
161 }
162 
163 void Locks::addLock( const IdString& ident_r )
164 {
165  sat::Solvable::SplitIdent id(ident_r);
166  addLock(id.kind(),id.name());
167 }
168 
169 void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
170 {
171  addLock(kind_r,IdString(name_r));
172 }
173 
174 void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
175 {
176  PoolQuery q;
178  q.addKind( kind_r );
179  q.setMatchExact();
180  q.setCaseSensitive(true);
181  DBG << "add lock by identifier" << endl;
182  addLock( q );
183 }
184 
185 void Locks::removeLock( const PoolQuery& query )
186 {
187  MIL << "remove lock" << endl;
188  for_( it,query.begin(),query.end() )
189  {
190  PoolItem item(*it);
191  item.status().setLock(false,ResStatus::USER);
192  }
193 
194  LockList::iterator i = find(_pimpl->toAdd.begin(),
195  _pimpl->toAdd.end(), query);
196  if ( i != _pimpl->toAdd.end() )
197  {
198  DBG << "query removed from added" << endl;
199  _pimpl->toAdd.erase(i);
200  }
201  else
202  {
203  DBG << "needed remove some old lock" << endl;
204  _pimpl->toRemove.push_back( query );
205  }
206 }
207 
208 void Locks::removeLock( const IdString& ident_r )
209 {
210  sat::Solvable::SplitIdent id(ident_r);
211  removeLock(id.kind(),id.name());
212 }
213 
214 void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
215 {
216  removeLock(kind_r,IdString(name_r));
217 }
218 
219 void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
220 {
221  PoolQuery q;
223  q.addKind( kind_r );
224  q.setMatchExact();
225  q.setCaseSensitive(true);
226  q.requireAll();
227  DBG << "remove lock by selectactable" << endl;
228  removeLock(q);
229 }
230 
231 bool Locks::existEmpty() const
232 {
233  for_( it, _pimpl->locks.begin(), _pimpl->locks.end() )
234  {
235  if( it->empty() )
236  return true;
237  }
238 
239  return false;
240 }
241 
242 //handle locks during removing
244 private:
245  bool skip_rest;
246  size_t searched;
247  size_t all;
249 
250 public:
251  LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
252 
253  bool aborted(){ return skip_rest; }
254 
256  {
257  if( skip_rest )
258  return false;
259  searched++;
260  if( !q.empty() )
261  return false;
262 
263  if (!report->progress((100*searched)/all))
264  {
265  skip_rest = true;
266  return false;
267  }
268 
269  switch (report->execute(q))
270  {
273  skip_rest = true;
274  return false;
276  return true;
278  return false;
279  default:
280  WAR << "Unknown returned value. Callback have more value then"
281  << " this switch. Need correct handle all enum values." << std::endl;
282  }
283 
284  return false;
285  }
286 
287 };
288 
290 {
291  MIL << "cleaning of locks" << endl;
293  report->start();
294  size_t sum = _pimpl->locks.size();
295  LocksCleanPredicate p(sum, report);
296 
297  _pimpl->locks.remove_if(p);
298 
299  if( p.aborted() )
300  {
301  MIL << "cleaning aborted" << endl;
302  report->finish(CleanEmptyLocksReport::ABORTED);
303  }
304  else
305  {
306  report->finish(CleanEmptyLocksReport::NO_ERROR);
307 
308  }
309 
310  if ( sum != _pimpl->locks.size() ) //some locks has been removed
311  _pimpl->locksDirty = true;
312 }
313 
315 {
316 private:
317  std::set<sat::Solvable>& solvs;
318  const PoolQuery& query;
320  bool aborted_;
321 
322  //1 for subset of set, 2 only intersect, 0 for not intersect
323  int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
324  {
325  bool intersect = false;
326  for_( it,q.begin(),q.end() )
327  {
328  if ( s.find(*it)!=s.end() )
329  {
330  intersect = true;
331  }
332  else
333  {
334  if (intersect)
335  return 2;
336  }
337  }
338  return intersect ? 1 : 0;
339  }
340 
341 public:
342  LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
344  : solvs(s), query(q),report(r),aborted_(false) {}
345 
346  bool operator()(const PoolQuery& q)
347  {
348  if (aborted())
349  return false;
350  if( q==query )
351  {//identical
352  DBG << "identical queries" << endl;
353  return true;
354  }
355 
357  switch( contains(q,solvs) )
358  {
359  case 0:
360  return false; //another lock
361  case 1:
363  break;
364  case 2:
366  break;
367  default:
368  return true;
369  }
370  MIL << "find conflict: " << cs << endl;
371  switch (report->conflict(q,cs))
372  {
374  aborted_ = true;
375  DBG << "abort merging" << endl;
376  return false;
378  DBG << "force delete" << endl;
379  return true;
381  DBG << "skip lock" << endl;
382  return false;
383  }
384  WAR << "should not reached, some state is missing" << endl;
385  return false;
386  }
387 
388  bool aborted(){ return aborted_; }
389 };
390 
392 {
393  MIL << "merging list old: " << locks.size()
394  << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
395  for_(it,toRemove.begin(),toRemove.end())
396  {
397  std::set<sat::Solvable> s(it->begin(),it->end());
398  locks.remove_if(LocksRemovePredicate(s,*it, report));
399  }
400 
401  if (!report->progress())
402  return false;
403 
404  for_( it, toAdd.begin(), toAdd.end() )
405  {
406  if( std::find( locks.begin(), locks.end(), *it ) == locks.end() )
407  locks.push_back( *it );
408  }
409 
410  toAdd.clear();
411  toRemove.clear();
412 
413  return true;
414 }
415 
417 {
418  if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
419  {
420  return; //nothing to merge
421  }
422 
424  report->start();
425  if (!_pimpl->mergeList(report))
426  {
427  report->finish(SavingLocksReport::ABORTED);
428  return;
429  }
430  DBG << "locks merged" << endl;
431  report->finish(SavingLocksReport::NO_ERROR);
432  _pimpl->locksDirty = true;
433 }
434 
435 void Locks::save( const Pathname& file )
436 {
437  if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
438  && !_pimpl->locksDirty )
439  {
440  DBG << "nothing changed in locks - no write to file" << endl;
441  return;
442  }
443 
445  report->start();
446 
447  if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
448  {
449  if (!_pimpl->mergeList(report))
450  {
451  report->finish(SavingLocksReport::ABORTED);
452  return;
453  }
454  }
455 
456  DBG << "writed "<< _pimpl->locks.size() << "locks" << endl;
457  writePoolQueriesToFile( file, _pimpl->locks.begin(), _pimpl->locks.end() );
458  report->finish(SavingLocksReport::NO_ERROR);
459 }
460 
462 {
463  size_type sum = size();
464  for_(it,_pimpl->locks.begin(),_pimpl->locks.end())
465  {
466  if ( find(_pimpl->locks.begin(),it,*it) != it )
467  _pimpl->locks.erase(it--); //-- to avoid using break iterator
468  }
469 
470  if (sum!=size())
471  _pimpl->locksDirty = true;
472 }
473 
474 } // ns zypp