libzypp 17.31.23
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>
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
31using std::endl;
32
33namespace zypp
34{
35
37{
38 static Locks _instance;
39 return _instance;
40}
41
42typedef std::set<PoolQuery> LockSet;
43
44template <typename TPredicate>
45void 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{
61public:
65
67
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
93private:
94 // need to control manip in ordert to maintain the legacy API LockList::iterator begin/end
97 mutable bool _APIdirty;
98};
99
100Locks::Locks() : _pimpl(new Impl){}
101
103{ return _pimpl->APIlocks().begin(); }
104
106{ return _pimpl->APIlocks().end(); }
107
108Locks::LockList::size_type Locks::size() const
109{ return _pimpl->locks().size(); }
110
111bool Locks::empty() const
112{ return _pimpl->locks().empty(); }
113
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
130template <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
147void 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
162void 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
173void Locks::apply() const
174{
175 DBG << "apply locks" << endl;
176 for_each(_pimpl->locks().begin(), _pimpl->locks().end(), ApplyLock());
177}
178
179
180void 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
199void Locks::addLock( const IdString& ident_r )
200{
201 sat::Solvable::SplitIdent id(ident_r);
202 addLock(id.kind(),id.name());
203}
204
205void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
206{
207 addLock(kind_r,IdString(name_r));
208}
209
210void 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
221void 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
241void Locks::removeLock( const IdString& ident_r )
242{
243 sat::Solvable::SplitIdent id(ident_r);
244 removeLock(id.kind(),id.name());
245}
246
247void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
248{
249 removeLock(kind_r,IdString(name_r));
250}
251
252void 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
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
276private:
278 size_t searched;
279 size_t all;
281
282public:
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{
347private:
348 std::set<sat::Solvable>& solvs;
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
372public:
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
466void 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
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:283
callback::SendReport< CleanEmptyLocksReport > & report
Definition: Locks.cc:280
bool operator()(const PoolQuery &q)
Definition: Locks.cc:287
LocksRemovePredicate(std::set< sat::Solvable > &s, const PoolQuery &q, callback::SendReport< SavingLocksReport > &r)
Definition: Locks.cc:373
bool operator()(const PoolQuery &q)
Definition: Locks.cc:377
const PoolQuery & query
Definition: Locks.cc:349
callback::SendReport< SavingLocksReport > & report
Definition: Locks.cc:350
std::set< sat::Solvable > & solvs
Definition: Locks.cc:348
int contains(const PoolQuery &q, std::set< sat::Solvable > &s)
Definition: Locks.cc:354
bool _APIdirty
Definition: Locks.cc:97
LockList _APIlocks
Definition: Locks.cc:96
const LockSet & locks() const
Definition: Locks.cc:76
bool mergeList(callback::SendReport< SavingLocksReport > &report)
Definition: Locks.cc:422
LockSet toRemove
Definition: Locks.cc:63
bool locksDirty
Definition: Locks.cc:64
const LockList & APIlocks() const
Definition: Locks.cc:82
LockSet & MANIPlocks()
Definition: Locks.cc:79
LockSet _locks
Definition: Locks.cc:95
LockSet toAdd
Definition: Locks.cc:62
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:320
void apply() const
Applies locks in stable list (locks which is not changed during session).
Definition: Locks.cc:173
void merge()
Merges toAdd and ToRemove list to stable list.
Definition: Locks.cc:447
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_iterator end() const
Definition: Locks.cc:105
void addLock(const PoolQuery &query)
TODO add: toBeAdded{Begin,End,Size,Empty} toBeRemoved{Begin,End,Size,Empty}.
Definition: Locks.cc:180
bool empty() const
Definition: Locks.cc:111
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:147
void removeDuplicates()
Delete all query duplicate in loaded locks.
Definition: Locks.cc:492
const_iterator begin() const
Definition: Locks.cc:102
LockList::size_type size() const
Definition: Locks.cc:108
void removeLock(const PoolQuery &query)
unlocks by result of query and add to toRemove.
Definition: Locks.cc:221
bool existEmpty() const
Gets true if some lock doesn't lock any object in pool This can happen e.g.
Definition: Locks.cc:263
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
Definition: Locks.h:148
static Locks & instance()
Gets instance of this class.
Definition: Locks.cc:36
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
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
unsigned short a
unsigned short b
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:45
std::set< PoolQuery > LockSet
Definition: Locks.cc:42
void operator()(const PoolQuery &query) const
Definition: Locks.cc:116
@ 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:132
void operator()(const PoolQuery &query) const
Definition: Locks.cc:137
OutputIterator & out
Definition: Locks.cc:144
LockingOutputIterator(OutputIterator &out_)
Definition: Locks.cc:133
@ 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