9c0aeb5a20074a8f4a365b0404c313905e094175
[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/APIConfig.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         bool userLock( status_r.isUserLocked() );
65         if ( userLock == status_r.isUserLockQueryMatch() )
66           return 0;
67         return userLock ? 1 : -1;
68       }
69
70     };
71   }
72
73   namespace
74   {
75     inline PoolQuery makeTrivialQuery( IdString ident_r )
76     {
77       sat::Solvable::SplitIdent ident( ident_r );
78
79       PoolQuery q;
80       q.addAttribute( sat::SolvAttr::name, ident.name().asString() );
81       q.addKind( ident.kind() );
82       q.setMatchExact();
83       q.setCaseSensitive(true);
84       return q;
85    }
86
87     inline bool hardLockQueriesRemove( pool::PoolTraits::HardLockQueries & activeLocks_r, IdString ident_r )
88     {
89       unsigned s( activeLocks_r.size() );
90       activeLocks_r.remove( makeTrivialQuery( ident_r ) );
91       return( activeLocks_r.size() != s );
92     }
93
94     inline bool hardLockQueriesAdd( pool::PoolTraits::HardLockQueries & activeLocks_r, IdString ident_r )
95     {
96       PoolQuery q( makeTrivialQuery( ident_r ) );
97       for_( it, activeLocks_r.begin(), activeLocks_r.end() )
98       {
99         if ( *it == q )
100           return false;
101       }
102       activeLocks_r.push_back( q );
103       return true;
104     }
105   }
106
107   ///////////////////////////////////////////////////////////////////
108   namespace pool
109   { /////////////////////////////////////////////////////////////////
110
111     ///////////////////////////////////////////////////////////////////
112     //
113     //  CLASS NAME : PoolImpl
114     //
115     /** */
116     class PoolImpl
117     {
118       friend std::ostream & operator<<( std::ostream & str, const PoolImpl & obj );
119
120       public:
121         /** */
122         typedef PoolTraits::ItemContainerT              ContainerT;
123         typedef PoolTraits::size_type                   size_type;
124         typedef PoolTraits::const_iterator              const_iterator;
125         typedef PoolTraits::Id2ItemT                    Id2ItemT;
126
127         typedef PoolTraits::repository_iterator         repository_iterator;
128
129         typedef sat::detail::SolvableIdType             SolvableIdType;
130
131       public:
132         /** Default ctor */
133         PoolImpl();
134         /** Dtor */
135         ~PoolImpl();
136
137       public:
138         /** convenience. */
139         const sat::Pool satpool() const
140         { return sat::Pool::instance(); }
141
142         /** Housekeeping data serial number. */
143         const SerialNumber & serial() const
144         { return satpool().serial(); }
145
146         ///////////////////////////////////////////////////////////////////
147         //
148         ///////////////////////////////////////////////////////////////////
149       public:
150         /**  */
151         bool empty() const
152         { return satpool().solvablesEmpty(); }
153
154         /**  */
155         size_type size() const
156         { return satpool().solvablesSize(); }
157
158         const_iterator begin() const
159         { return make_filter_begin( pool::ByPoolItem(), store() ); }
160
161         const_iterator end() const
162         { return make_filter_end( pool::ByPoolItem(), store() ); }
163
164       public:
165         /** Return the corresponding \ref PoolItem.
166          * Pool and sat pool should be in sync. Returns an empty
167          * \ref PoolItem if there is no corresponding \ref PoolItem.
168          * \see \ref PoolItem::satSolvable.
169          */
170         PoolItem find( const sat::Solvable & slv_r ) const
171         {
172           const ContainerT & mystore( store() );
173           return( slv_r.id() < mystore.size() ? mystore[slv_r.id()] : PoolItem() );
174         }
175
176         ///////////////////////////////////////////////////////////////////
177         //
178         ///////////////////////////////////////////////////////////////////
179       public:
180         /** \name Save and restore state. */
181         //@{
182         void SaveState( const ResObject::Kind & kind_r );
183
184         void RestoreState( const ResObject::Kind & kind_r );
185         //@}
186
187         ///////////////////////////////////////////////////////////////////
188         //
189         ///////////////////////////////////////////////////////////////////
190       public:
191         ResPoolProxy proxy( ResPool self ) const
192         {
193           checkSerial();
194           if ( !_poolProxy )
195           {
196             _poolProxy.reset( new ResPoolProxy( self, *this ) );
197           }
198           return *_poolProxy;
199         }
200
201       public:
202         /** Forward list of Repositories that contribute ResObjects from \ref sat::Pool */
203         size_type knownRepositoriesSize() const
204         { checkSerial(); return satpool().reposSize(); }
205
206         repository_iterator knownRepositoriesBegin() const
207         { checkSerial(); return satpool().reposBegin(); }
208
209         repository_iterator knownRepositoriesEnd() const
210         { checkSerial(); return satpool().reposEnd(); }
211
212         Repository reposFind( const std::string & alias_r ) const
213         { checkSerial(); return satpool().reposFind( alias_r ); }
214
215         ///////////////////////////////////////////////////////////////////
216         //
217         ///////////////////////////////////////////////////////////////////
218       public:
219         typedef PoolTraits::HardLockQueries           HardLockQueries;
220         typedef PoolTraits::hardLockQueries_iterator  hardLockQueries_iterator;
221
222         const HardLockQueries & hardLockQueries() const
223         { return _hardLockQueries; }
224
225         void reapplyHardLocks() const
226         {
227           // It is assumed that reapplyHardLocks is called after new
228           // items were added to the pool, but the _hardLockQueries
229           // did not change since. Action is to be performed only on
230           // those items that gained the bit in the UserLockQueryField.
231           MIL << "Re-apply " << _hardLockQueries.size() << " HardLockQueries" << endl;
232           PoolQueryResult locked;
233           for_( it, _hardLockQueries.begin(), _hardLockQueries.end() )
234           {
235             locked += *it;
236           }
237           MIL << "HardLockQueries match " << locked.size() << " Solvables." << endl;
238           for_( it, begin(), end() )
239           {
240             resstatus::UserLockQueryManip::reapplyLock( it->status(), locked.contains( *it ) );
241           }
242         }
243
244         void setHardLockQueries( const HardLockQueries & newLocks_r )
245         {
246           MIL << "Apply " << newLocks_r.size() << " HardLockQueries" << endl;
247           _hardLockQueries = newLocks_r;
248           // now adjust the pool status
249           PoolQueryResult locked;
250           for_( it, _hardLockQueries.begin(), _hardLockQueries.end() )
251           {
252             locked += *it;
253           }
254           MIL << "HardLockQueries match " << locked.size() << " Solvables." << endl;
255           for_( it, begin(), end() )
256           {
257             resstatus::UserLockQueryManip::setLock( it->status(), locked.contains( *it ) );
258           }
259         }
260
261         bool getHardLockQueries( HardLockQueries & activeLocks_r )
262         {
263           activeLocks_r = _hardLockQueries; // current queries
264           // Now diff to the pool collecting names only.
265           // Thus added and removed locks are not necessarily
266           // disjoint. Added locks win.
267           typedef std::tr1::unordered_set<IdString> IdentSet;
268           IdentSet addedLocks;
269           IdentSet removedLocks;
270           for_( it, begin(), end() )
271           {
272             switch ( resstatus::UserLockQueryManip::diffLock( it->status() ) )
273             {
274               case 0:  // unchanged
275                 break;
276               case 1:
277                 addedLocks.insert( it->satSolvable().ident() );
278                 break;
279               case -1:
280                 removedLocks.insert( it->satSolvable().ident() );
281                break;
282             }
283           }
284           // now the bad part - adjust the queries
285           bool setChanged = false;
286           for_( it, removedLocks.begin(), removedLocks.end() )
287           {
288             if ( addedLocks.find( *it ) != addedLocks.end() )
289               continue; // Added locks win
290             if ( hardLockQueriesRemove( activeLocks_r, *it ) && ! setChanged )
291               setChanged = true;
292           }
293           for_( it, addedLocks.begin(), addedLocks.end() )
294           {
295             if ( hardLockQueriesAdd( activeLocks_r, *it ) && ! setChanged )
296               setChanged = true;
297           }
298           return setChanged;
299        }
300
301       public:
302         const ContainerT & store() const
303         {
304           checkSerial();
305           if ( _storeDirty )
306           {
307             sat::Pool pool( satpool() );
308             bool addedItems = false;
309             std::list<PoolItem> addedProducts;
310
311             _store.resize( pool.capacity() );
312
313             if ( pool.capacity() )
314             {
315               for ( sat::detail::SolvableIdType i = pool.capacity()-1; i != 0; --i )
316               {
317                 sat::Solvable s( i );
318                 PoolItem & pi( _store[i] );
319                 if ( ! s &&  pi )
320                 {
321                   // the PoolItem got invalidated (e.g unloaded repo)
322                   pi = PoolItem();
323                 }
324                 else if ( s && ! pi )
325                 {
326                   // new PoolItem to add
327                   pi = PoolItem::makePoolItem( s ); // the only way to create a new one!
328                   // remember products for buddy processing (requires clean store)
329                   if ( s.isKind( ResKind::product ) )
330                     addedProducts.push_back( pi );
331                   if ( !addedItems )
332                     addedItems = true;
333                 }
334               }
335             }
336             _storeDirty = false;
337
338             // Now, as the pool is adjusted, ....
339
340             // .... we check for product buddies.
341             if ( ! addedProducts.empty() )
342             {
343               for_( it, addedProducts.begin(), addedProducts.end() )
344               {
345                 it->setBuddy( asKind<Product>(*it)->referencePackage() );
346               }
347             }
348
349             // .... we must reapply those query based hard locks.
350             if ( addedItems )
351             {
352               reapplyHardLocks();
353             }
354           }
355           return _store;
356         }
357
358         const Id2ItemT & id2item () const
359         {
360           checkSerial();
361           if ( _id2itemDirty )
362           {
363             store();
364             _id2item = Id2ItemT( size() );
365             for_( it, begin(), end() )
366             {
367               const sat::Solvable &s = (*it)->satSolvable();
368               sat::detail::IdType id = s.ident().id();
369               if ( s.isKind( ResKind::srcpackage ) )
370                 id = -id;
371               _id2item.insert( std::make_pair( id, *it ) );
372             }
373             //INT << _id2item << endl;
374             _id2itemDirty = false;
375           }
376           return _id2item;
377         }
378
379         ///////////////////////////////////////////////////////////////////
380         //
381         ///////////////////////////////////////////////////////////////////
382       private:
383         void checkSerial() const
384         {
385           if ( _watcher.remember( serial() ) )
386             invalidate();
387           satpool().prepare(); // always ajust dependencies.
388         }
389
390         void invalidate() const
391         {
392           _storeDirty = true;
393           _id2itemDirty = true;
394           _id2item.clear();
395           _poolProxy.reset();
396         }
397
398       private:
399         /** Watch sat pools serial number. */
400         SerialNumberWatcher                   _watcher;
401         mutable ContainerT                    _store;
402         mutable DefaultIntegral<bool,true>    _storeDirty;
403         mutable Id2ItemT                      _id2item;
404         mutable DefaultIntegral<bool,true>    _id2itemDirty;
405
406       private:
407         mutable shared_ptr<ResPoolProxy>      _poolProxy;
408
409       private:
410         /** Set of queries that define hardlocks. */
411         HardLockQueries                       _hardLockQueries;
412     };
413     ///////////////////////////////////////////////////////////////////
414
415     /////////////////////////////////////////////////////////////////
416   } // namespace pool
417   ///////////////////////////////////////////////////////////////////
418   /////////////////////////////////////////////////////////////////
419 } // namespace zypp
420 ///////////////////////////////////////////////////////////////////
421 #endif // ZYPP_POOL_POOLIMPL_H