- Remove obsolete product attributes.
[platform/upstream/libzypp.git] / zypp / pool / PoolImpl.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/pool/PoolImpl.h
10  *
11 */
12 #ifndef ZYPP_POOL_POOLIMPL_H
13 #define ZYPP_POOL_POOLIMPL_H
14
15 #include <iosfwd>
16
17 #include "zypp/base/Easy.h"
18 #include "zypp/base/LogTools.h"
19 #include "zypp/base/SerialNumber.h"
20 #include "zypp/base/Deprecated.h"
21
22 #include "zypp/pool/PoolTraits.h"
23 #include "zypp/ResPoolProxy.h"
24 #include "zypp/PoolQueryResult.h"
25
26 #include "zypp/sat/Pool.h"
27 #include "zypp/Product.h"
28
29 using std::endl;
30
31 ///////////////////////////////////////////////////////////////////
32 namespace zypp
33 { /////////////////////////////////////////////////////////////////
34
35   namespace resstatus
36   {
37     /** Manipulator for \ref ResStatus::UserLockQueryField.
38      * Field is not public available. It is intended to remember the
39      * initial lock status usually derived from /etc/zypp/locks. So
40      * we are able to detect changes we have to write back on commit.
41     */
42     struct UserLockQueryManip
43     {
44       /** Set lock and UserLockQuery bit according to \c yesno_r. */
45       static void setLock( ResStatus & status_r, bool yesno_r )
46       {
47         status_r.setLock( yesno_r, ResStatus::USER );
48         status_r.setUserLockQueryMatch( yesno_r );
49       }
50
51       /** Update lock and UserLockQuery bit IFF the item gained the bit. */
52       static void reapplyLock( ResStatus & status_r, bool yesno_r )
53       {
54         if ( yesno_r && ! status_r.isUserLockQueryMatch() )
55         {
56           status_r.setLock( yesno_r, ResStatus::USER );
57           status_r.setUserLockQueryMatch( yesno_r );
58         }
59       }
60
61       /** Test whether the lock status differs from the remembered UserLockQuery bit. */
62       static int diffLock( const ResStatus & status_r )
63       {
64         if ( status_r.isLocked() == status_r.isUserLockQueryMatch() )
65           return 0;
66         return status_r.isLocked() ? 1 : -1;
67       }
68
69     };
70   }
71
72   namespace
73   {
74     inline PoolQuery makeTrivialQuery( IdString ident_r )
75     {
76       sat::Solvable::SplitIdent ident( ident_r );
77
78       PoolQuery q;
79       q.addAttribute( sat::SolvAttr::name, ident.name().asString() );
80       q.addKind( ident.kind() );
81       q.setMatchExact();
82       q.setCaseSensitive(true);
83       return q;
84    }
85
86     inline bool hardLockQueriesRemove( pool::PoolTraits::HardLockQueries & activeLocks_r, IdString ident_r )
87     {
88       unsigned s( activeLocks_r.size() );
89       activeLocks_r.remove( makeTrivialQuery( ident_r ) );
90       return( activeLocks_r.size() != s );
91     }
92
93     inline bool hardLockQueriesAdd( pool::PoolTraits::HardLockQueries & activeLocks_r, IdString ident_r )
94     {
95       PoolQuery q( makeTrivialQuery( ident_r ) );
96       for_( it, activeLocks_r.begin(), activeLocks_r.end() )
97       {
98         if ( *it == q )
99           return false;
100       }
101       activeLocks_r.push_back( q );
102       return true;
103     }
104   }
105
106   ///////////////////////////////////////////////////////////////////
107   namespace pool
108   { /////////////////////////////////////////////////////////////////
109
110     ///////////////////////////////////////////////////////////////////
111     //
112     //  CLASS NAME : PoolImpl
113     //
114     /** */
115     class PoolImpl
116     {
117       friend std::ostream & operator<<( std::ostream & str, const PoolImpl & obj );
118
119       public:
120         /** */
121         typedef PoolTraits::ItemContainerT              ContainerT;
122         typedef PoolTraits::size_type                   size_type;
123         typedef PoolTraits::const_iterator              const_iterator;
124         typedef PoolTraits::Id2ItemT                    Id2ItemT;
125
126         typedef PoolTraits::repository_iterator         repository_iterator;
127
128         typedef sat::detail::SolvableIdType             SolvableIdType;
129
130       public:
131         /** Default ctor */
132         PoolImpl();
133         /** Dtor */
134         ~PoolImpl();
135
136       public:
137         /** convenience. */
138         const sat::Pool satpool() const
139         { return sat::Pool::instance(); }
140
141         /** Housekeeping data serial number. */
142         const SerialNumber & serial() const
143         { return satpool().serial(); }
144
145         ///////////////////////////////////////////////////////////////////
146         //
147         ///////////////////////////////////////////////////////////////////
148       public:
149         /**  */
150         bool empty() const
151         { return satpool().solvablesEmpty(); }
152
153         /**  */
154         size_type size() const
155         { return satpool().solvablesSize(); }
156
157         const_iterator begin() const
158         { return make_filter_begin( pool::ByPoolItem(), store() ); }
159
160         const_iterator end() const
161         { return make_filter_end( pool::ByPoolItem(), store() ); }
162
163       public:
164         /** Return the corresponding \ref PoolItem.
165          * Pool and sat pool should be in sync. Returns an empty
166          * \ref PoolItem if there is no corresponding \ref PoolItem.
167          * \see \ref PoolItem::satSolvable.
168          */
169         PoolItem find( const sat::Solvable & slv_r ) const
170         {
171           const ContainerT & mystore( store() );
172           return( slv_r.id() < mystore.size() ? mystore[slv_r.id()] : PoolItem() );
173         }
174
175         ///////////////////////////////////////////////////////////////////
176         //
177         ///////////////////////////////////////////////////////////////////
178       public:
179         /** \name Save and restore state. */
180         //@{
181         void SaveState( const ResObject::Kind & kind_r );
182
183         void RestoreState( const ResObject::Kind & kind_r );
184         //@}
185
186         ///////////////////////////////////////////////////////////////////
187         //
188         ///////////////////////////////////////////////////////////////////
189       public:
190         ResPoolProxy proxy( ResPool self ) const
191         {
192           checkSerial();
193           if ( !_poolProxy )
194           {
195             _poolProxy.reset( new ResPoolProxy( self, *this ) );
196           }
197           return *_poolProxy;
198         }
199
200       public:
201         /** Forward list of Repositories that contribute ResObjects from \ref sat::Pool */
202         size_type knownRepositoriesSize() const
203         { checkSerial(); return satpool().reposSize(); }
204
205         repository_iterator knownRepositoriesBegin() const
206         { checkSerial(); return satpool().reposBegin(); }
207
208         repository_iterator knownRepositoriesEnd() const
209         { checkSerial(); return satpool().reposEnd(); }
210
211         Repository reposFind( const std::string & alias_r ) const
212         { checkSerial(); return satpool().reposFind( alias_r ); }
213
214         ///////////////////////////////////////////////////////////////////
215         //
216         ///////////////////////////////////////////////////////////////////
217       public:
218         typedef PoolTraits::HardLockQueries           HardLockQueries;
219         typedef PoolTraits::hardLockQueries_iterator  hardLockQueries_iterator;
220
221         const HardLockQueries & hardLockQueries() const
222         { return _hardLockQueries; }
223
224         void reapplyHardLocks() const
225         {
226           // It is assumed that reapplyHardLocks is called after new
227           // items were added to the pool, but the _hardLockQueries
228           // did not change since. Action is to be performed only on
229           // those items that gained the bit in the UserLockQueryField.
230           MIL << "Re-apply " << _hardLockQueries.size() << " HardLockQueries" << endl;
231           PoolQueryResult locked;
232           for_( it, _hardLockQueries.begin(), _hardLockQueries.end() )
233           {
234             locked += *it;
235           }
236           MIL << "HardLockQueries match " << locked.size() << " Solvables." << endl;
237           for_( it, begin(), end() )
238           {
239             resstatus::UserLockQueryManip::reapplyLock( it->status(), locked.contains( *it ) );
240           }
241         }
242
243         void setHardLockQueries( const HardLockQueries & newLocks_r )
244         {
245           MIL << "Apply " << newLocks_r.size() << " HardLockQueries" << endl;
246           _hardLockQueries = newLocks_r;
247           // now adjust the pool status
248           PoolQueryResult locked;
249           for_( it, _hardLockQueries.begin(), _hardLockQueries.end() )
250           {
251             locked += *it;
252           }
253           MIL << "HardLockQueries match " << locked.size() << " Solvables." << endl;
254           for_( it, begin(), end() )
255           {
256             resstatus::UserLockQueryManip::setLock( it->status(), locked.contains( *it ) );
257           }
258         }
259
260         bool getHardLockQueries( HardLockQueries & activeLocks_r )
261         {
262           activeLocks_r = _hardLockQueries; // current queries
263           // Now diff to the pool collecting names only.
264           // Thus added and removed locks are not necessarily
265           // disjoint. Added locks win.
266           typedef std::tr1::unordered_set<IdString> IdentSet;
267           IdentSet addedLocks;
268           IdentSet removedLocks;
269           for_( it, begin(), end() )
270           {
271             switch ( resstatus::UserLockQueryManip::diffLock( it->status() ) )
272             {
273               case 0:  // unchanged
274                 break;
275               case 1:
276                 addedLocks.insert( it->satSolvable().ident() );
277                 break;
278               case -1:
279                 removedLocks.insert( it->satSolvable().ident() );
280                break;
281             }
282           }
283           // now the bad part - adjust the queries
284           bool setChanged = false;
285           for_( it, removedLocks.begin(), removedLocks.end() )
286           {
287             if ( addedLocks.find( *it ) != addedLocks.end() )
288               continue; // Added locks win
289             if ( hardLockQueriesRemove( activeLocks_r, *it ) && ! setChanged )
290               setChanged = true;
291           }
292           for_( it, addedLocks.begin(), addedLocks.end() )
293           {
294             if ( hardLockQueriesAdd( activeLocks_r, *it ) && ! setChanged )
295               setChanged = true;
296           }
297           return setChanged;
298        }
299
300       public:
301         typedef PoolTraits::AutoSoftLocks          AutoSoftLocks;
302         typedef PoolTraits::autoSoftLocks_iterator autoSoftLocks_iterator;
303
304         const AutoSoftLocks & autoSoftLocks() const
305         { return _autoSoftLocks; }
306
307         bool autoSoftLockAppliesTo( sat::Solvable solv_r ) const
308         { return( _autoSoftLocks.find( solv_r.ident() ) != _autoSoftLocks.end() ); }
309
310         void setAutoSoftLocks( const AutoSoftLocks & newLocks_r )
311         {
312           MIL << "Apply " << newLocks_r.size() << " AutoSoftLocks: " << newLocks_r << endl;
313           _autoSoftLocks = newLocks_r;
314           // now adjust the pool status
315           for_( it, begin(), end() )
316           {
317             if ( ! it->status().isKept() )
318               continue;
319
320             if ( autoSoftLockAppliesTo( it->satSolvable() ) )
321               it->status().setSoftLock( ResStatus::USER );
322             else
323               it->status().resetTransact( ResStatus::USER );
324           }
325         }
326
327         void getActiveSoftLocks( AutoSoftLocks & activeLocks_r )
328         {
329           activeLocks_r = _autoSoftLocks; // current soft-locks
330           AutoSoftLocks todel;            // + names to be deleted
331           AutoSoftLocks toins;            // - names to be installed
332
333           for_( it, begin(), end() )
334           {
335             ResStatus & status( it->status() );
336             if ( ! status.isByUser() )
337               continue; // ignore non-uer requests
338
339             switch ( status.getTransactValue() )
340             {
341               case ResStatus::KEEP_STATE:
342                 // Filter only items included in the last recommended set.
343                 if ( status.isRecommended() )
344                   activeLocks_r.insert( it->satSolvable().ident() );
345                 break;
346               case ResStatus::LOCKED:
347                 //  NOOP
348                 break;
349               case ResStatus::TRANSACT:
350                 (status.isInstalled() ? todel : toins).insert( it->satSolvable().ident() );
351                 break;
352             }
353           }
354           for_( it, todel.begin(), todel.end() )
355           {
356             activeLocks_r.insert( *it );
357           }
358           for_( it, toins.begin(), toins.end() )
359           {
360             activeLocks_r.erase( *it );
361           }
362         }
363
364       public:
365         const ContainerT & store() const
366         {
367           checkSerial();
368           if ( _storeDirty )
369           {
370             sat::Pool pool( satpool() );
371             bool addedItems = false;
372             std::list<PoolItem> addedProducts;
373
374             if ( pool.capacity() != _store.capacity() )
375             {
376               _store.resize( pool.capacity() );
377             }
378
379             if ( pool.capacity() )
380             {
381               for ( sat::detail::SolvableIdType i = pool.capacity()-1; i != 0; --i )
382               {
383                 sat::Solvable s( i );
384                 PoolItem & pi( _store[i] );
385                 if ( ! s &&  pi )
386                 {
387                   // the PoolItem got invalidated (e.g unloaded repo)
388                   pi = PoolItem();
389                 }
390                 else if ( s && ! pi )
391                 {
392                   // new PoolItem to add
393                   pi = PoolItem::makePoolItem( s ); // the only way to create a new one!
394                   // remember products for buddy processing (requires clean store)
395                   if ( s.isKind( ResKind::product ) )
396                     addedProducts.push_back( pi );
397                   // and on the fly check for weak locks...
398                   if ( autoSoftLockAppliesTo( s ) )
399                   {
400                     pi.status().setSoftLock( ResStatus::USER );
401                   }
402                   if ( !addedItems )
403                     addedItems = true;
404                 }
405               }
406             }
407             _storeDirty = false;
408
409             // Now, as the pool is adjusted, ....
410
411             // .... we check for product buddies.
412             if ( ! addedProducts.empty() )
413             {
414               for_( it, addedProducts.begin(), addedProducts.end() )
415               {
416                 it->setBuddy( asKind<Product>(*it)->referencePackage() );
417               }
418             }
419
420             // .... we must reapply those query based hard locks.
421             if ( addedItems )
422             {
423               reapplyHardLocks();
424             }
425           }
426           return _store;
427         }
428
429         const Id2ItemT & id2item () const
430         {
431           checkSerial();
432           if ( _id2itemDirty )
433           {
434             store();
435             _id2item = Id2ItemT( size() );
436             for_( it, begin(), end() )
437             {
438               const sat::Solvable &s = (*it)->satSolvable();
439               sat::detail::IdType id = s.ident().id();
440               if ( s.isKind( ResKind::srcpackage ) )
441                 id = -id;
442               _id2item.insert( std::make_pair( id, *it ) );
443             }
444             //INT << _id2item << endl;
445             _id2itemDirty = false;
446           }
447           return _id2item;
448         }
449
450         ///////////////////////////////////////////////////////////////////
451         //
452         ///////////////////////////////////////////////////////////////////
453       private:
454         void checkSerial() const
455         {
456           if ( _watcher.remember( serial() ) )
457             invalidate();
458           satpool().prepare(); // always ajust dependencies.
459         }
460
461         void invalidate() const
462         {
463           _storeDirty = true;
464           _id2itemDirty = true;
465           _id2item.clear();
466           _poolProxy.reset();
467         }
468
469       private:
470         /** Watch sat pools serial number. */
471         SerialNumberWatcher                   _watcher;
472         mutable ContainerT                    _store;
473         mutable DefaultIntegral<bool,true>    _storeDirty;
474         mutable Id2ItemT                      _id2item;
475         mutable DefaultIntegral<bool,true>    _id2itemDirty;
476
477       private:
478         mutable shared_ptr<ResPoolProxy>      _poolProxy;
479
480       private:
481         /** Set of solvable idents that should be soft locked per default. */
482         AutoSoftLocks                         _autoSoftLocks;
483         /** Set of queries that define hardlocks. */
484         HardLockQueries                       _hardLockQueries;
485     };
486     ///////////////////////////////////////////////////////////////////
487
488     /////////////////////////////////////////////////////////////////
489   } // namespace pool
490   ///////////////////////////////////////////////////////////////////
491   /////////////////////////////////////////////////////////////////
492 } // namespace zypp
493 ///////////////////////////////////////////////////////////////////
494 #endif // ZYPP_POOL_POOLIMPL_H