libzypp 17.31.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/iterator/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>
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
32using std::endl;
33
34namespace zypp
35{
36
38{
39 static Locks _instance;
40 return _instance;
41}
42
43typedef std::set<PoolQuery> LockSet;
44
45template <typename TPredicate>
46void 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{
62public:
66
68
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
94private:
95 // need to control manip in ordert to maintain the legacy API LockList::iterator begin/end
98 mutable bool _APIdirty;
99};
100
101Locks::Locks() : _pimpl(new Impl){}
102
104{ return _pimpl->APIlocks().begin(); }
105
107{ return _pimpl->APIlocks().end(); }
108
110{ return _pimpl->locks().size(); }
111
112bool Locks::empty() const
113{ return _pimpl->locks().empty(); }
114
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
131template <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
148void 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
163void 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
174void Locks::apply() const
175{
176 DBG << "apply locks" << endl;
177 for_each(_pimpl->locks().begin(), _pimpl->locks().end(), ApplyLock());
178}
179
180
181void 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
200void Locks::addLock( const IdString& ident_r )
201{
202 sat::Solvable::SplitIdent id(ident_r);
203 addLock(id.kind(),id.name());
204}
205
206void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
207{
208 addLock(kind_r,IdString(name_r));
209}
210
211void 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
222void 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
242void Locks::removeLock( const IdString& ident_r )
243{
244 sat::Solvable::SplitIdent id(ident_r);
245 removeLock(id.kind(),id.name());
246}
247
248void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
249{
250 removeLock(kind_r,IdString(name_r));
251}
252
253void 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
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
277private:
279 size_t searched;
280 size_t all;
282
283public:
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;
334 report->finish(CleanEmptyLocksReport::ABORTED);
335 }
336 else
337 {
338 report->finish(CleanEmptyLocksReport::NO_ERROR);
339
340 }
341
342 if ( sum != _pimpl->locks().size() ) //some locks has been removed
343 _pimpl->locksDirty = true;
344}
345
347{
348private:
349 std::set<sat::Solvable>& solvs;
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
373public:
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());
430 remove_if( MANIPlocks(), LocksRemovePredicate(s,*it, report) );
431 }
432
433 if (!report->progress())
434 return false;
435
436 for ( const auto & q : toAdd ) {
437 const auto & [i,b] { MANIPlocks().insert( q ) };
438 if ( not b && i->comment() != q.comment() )
439 i->setComment( q.comment() ); // update comment if query already exists
440 }
441
442 toAdd.clear();
443 toRemove.clear();
444
445 return true;
446}
447
449{
450 if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
451 {
452 return; //nothing to merge
453 }
454
456 report->start();
457 if (!_pimpl->mergeList(report))
458 {
459 report->finish(SavingLocksReport::ABORTED);
460 return;
461 }
462 DBG << "locks merged" << endl;
463 report->finish(SavingLocksReport::NO_ERROR);
464 _pimpl->locksDirty = true;
465}
466
467void Locks::save( const Pathname& file )
468{
469 if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
470 && !_pimpl->locksDirty )
471 {
472 DBG << "nothing changed in locks - no write to file" << endl;
473 return;
474 }
475
477 report->start();
478
479 if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
480 {
481 if (!_pimpl->mergeList(report))
482 {
483 report->finish(SavingLocksReport::ABORTED);
484 return;
485 }
486 }
487
488 DBG << "wrote "<< _pimpl->locks().size() << "locks" << endl;
489 writePoolQueriesToFile( file, _pimpl->locks().begin(), _pimpl->locks().end() );
490 report->finish(SavingLocksReport::NO_ERROR);
491}
492
494{ /* NOP since implementation uses std::set */ }
495
496} // ns zypp
Convenience char* constructible from std::string and char*, it maps (char*)0 to an empty string.
Definition: String.h:91
Access to the sat-pools string space.
Definition: IdString.h:43
std::string asString() const
Conversion to std::string
Definition: IdString.h:98
LocksCleanPredicate(size_t count, callback::SendReport< CleanEmptyLocksReport > &_report)
Definition: Locks.cc:284
callback::SendReport< CleanEmptyLocksReport > & report
Definition: Locks.cc:281
bool operator()(const PoolQuery &q)
Definition: Locks.cc:288
LocksRemovePredicate(std::set< sat::Solvable > &s, const PoolQuery &q, callback::SendReport< SavingLocksReport > &r)
Definition: Locks.cc:374
bool operator()(const PoolQuery &q)
Definition: Locks.cc:378
const PoolQuery & query
Definition: Locks.cc:350
callback::SendReport< SavingLocksReport > & report
Definition: Locks.cc:351
std::set< sat::Solvable > & solvs
Definition: Locks.cc:349
int contains(const PoolQuery &q, std::set< sat::Solvable > &s)
Definition: Locks.cc:355
bool _APIdirty
Definition: Locks.cc:98
LockList _APIlocks
Definition: Locks.cc:97
const LockSet & locks() const
Definition: Locks.cc:77
bool mergeList(callback::SendReport< SavingLocksReport > &report)
Definition: Locks.cc:423
LockSet toRemove
Definition: Locks.cc:64
bool locksDirty
Definition: Locks.cc:65
const LockList & APIlocks() const
Definition: Locks.cc:83
LockSet & MANIPlocks()
Definition: Locks.cc:80
LockSet _locks
Definition: Locks.cc:96
LockSet toAdd
Definition: Locks.cc:63
Singleton class which manipulate with locks file and apply locks on pool.
Definition: Locks.h:19
void removeEmpty()
Call callback for each empty lock.
Definition: Locks.cc:321
void apply() const
Applies locks in stable list (locks which is not changed during session).
Definition: Locks.cc:174
void merge()
Merges toAdd and ToRemove list to stable list.
Definition: Locks.cc:448
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:467
const_iterator end() const
Definition: Locks.cc:106
void addLock(const PoolQuery &query)
TODO add: toBeAdded{Begin,End,Size,Empty} toBeRemoved{Begin,End,Size,Empty}.
Definition: Locks.cc:181
bool empty() const
Definition: Locks.cc:112
LockList::const_iterator const_iterator
Definition: Locks.h:22
std::list< PoolQuery > LockList
Definition: Locks.h:21
void readAndApply(const Pathname &file=ZConfig::instance().locksFile())
Optimalized version of read and apply.
Definition: Locks.cc:148
void removeDuplicates()
Delete all query duplicate in loaded locks.
Definition: Locks.cc:493
const_iterator begin() const
Definition: Locks.cc:103
LockList::size_type size() const
Definition: Locks.cc:109
void removeLock(const PoolQuery &query)
unlocks by result of query and add to toRemove.
Definition: Locks.cc:222
bool existEmpty() const
Gets true if some lock doesn't lock any object in pool This can happen e.g.
Definition: Locks.cc:264
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
Definition: Locks.h:148
static Locks & instance()
Gets instance of this class.
Definition: Locks.cc:37
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
Combining sat::Solvable and ResStatus.
Definition: PoolItem.h:51
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:211
Meta-data query API.
Definition: PoolQuery.h:91
void setMatchExact()
Set to match exact string instead of substring.
Definition: PoolQuery.cc:963
void setCaseSensitive(bool value=true)
Turn case sentitivity on or off (unsets or sets SEARCH_NOCASE flag).
Definition: PoolQuery.cc:1018
bool empty() const
Whether the result is empty.
Definition: PoolQuery.cc:1035
void addKind(const ResKind &kind)
Filter by selectable kind.
Definition: PoolQuery.cc:871
void addAttribute(const sat::SolvAttr &attr, const std::string &value="")
Filter by the value of the specified attr attribute.
Definition: PoolQuery.cc:884
const_iterator end() const
An iterator pointing to the end of the query result.
Definition: PoolQuery.h:624
const_iterator begin() const
Query result accessers.
Definition: PoolQuery.cc:1849
Resolvable kinds.
Definition: ResKind.h:33
bool setLock(bool toLock_r, TransactByValue causer_r)
Apply a lock (prevent transaction).
Definition: ResStatus.h:387
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
static const SolvAttr name
Definition: SolvAttr.h:52
Iterable< PoolItem_iterator > poolItem() const
Helper that splits an identifier into kind and name or vice versa.
Definition: Solvable.h:345
SolvableIdType size_type
Definition: PoolMember.h:126
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
void remove_if(LockSet &lockset_r, TPredicate pred_r)
Definition: Locks.cc:46
std::set< PoolQuery > LockSet
Definition: Locks.cc:43
void operator()(const PoolQuery &query) const
Definition: Locks.cc:117
@ ABORTED
cleaning aborted by user
@ ABORT
abort and return error
@ DELETE
delete empty lock
iterator that takes lock, lock all solvables from query and send query to output iterator
Definition: Locks.cc:133
void operator()(const PoolQuery &query) const
Definition: Locks.cc:138
OutputIterator & out
Definition: Locks.cc:145
LockingOutputIterator(OutputIterator &out_)
Definition: Locks.cc:134
@ DELETE
delete conflicted lock
@ IGNORE
skip conflict lock
@ ABORT
abort and return error
ConflictState
type of conflict of old and new lock
@ INTERSECT
locks lock some file and unlocking lock unlock only part of iti, so removing old lock can unlock more...
@ SAME_RESULTS
locks lock same item in pool but its parameters are different
@ ABORTED
cleaning aborted by user
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define INT
Definition: Logger.h:100