06dde4986d45b8a3389dce4a0db50704b07176e8
[platform/upstream/libzypp.git] / zypp / sat / Transaction.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/Transaction.cc
10  */
11 extern "C"
12 {
13 #include <satsolver/transaction.h>
14 #include <satsolver/bitmap.h>
15 }
16 #include <iostream>
17 #include "zypp/base/LogTools.h"
18 #include "zypp/base/SerialNumber.h"
19 #include "zypp/base/DefaultIntegral.h"
20 #include "zypp/base/NonCopyable.h"
21 #include "zypp/base/Tr1hash.h"
22
23 #include "zypp/sat/detail/PoolImpl.h"
24 #include "zypp/sat/Transaction.h"
25 #include "zypp/sat/Solvable.h"
26 #include "zypp/sat/Queue.h"
27 #include "zypp/ResPool.h"
28
29 using std::endl;
30
31 ///////////////////////////////////////////////////////////////////
32 namespace zypp
33 { /////////////////////////////////////////////////////////////////
34   ///////////////////////////////////////////////////////////////////
35   namespace sat
36   { /////////////////////////////////////////////////////////////////
37
38     /** Transaction implementation.
39      *
40      * \NOTE After commit the @System repo is reloaded. This invalidates
41      * the ids off all installed items in the transaction, including their
42      * stepType. Thats why some information (stepType, NVRA) is be stored
43      * for post mortem access (i.e. tell after commit which NVRA were deleted).
44      *
45      */
46     struct Transaction::Impl : protected detail::PoolMember
47     {
48       friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
49
50       public:
51         typedef std::tr1::unordered_set<detail::IdType> set_type;
52         typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
53
54         struct PostMortem
55         {
56           PostMortem()
57           {}
58           PostMortem( const sat::Solvable & solv_r )
59             : _ident( solv_r.ident() )
60             , _edition( solv_r.edition() )
61             , _arch( solv_r.arch() )
62           {}
63
64           IdString _ident;
65           Edition  _edition;
66           Arch     _arch;
67         };
68         typedef std::tr1::unordered_map<detail::IdType,PostMortem> pmmap_type;
69
70       public:
71         Impl()
72         { memset( &_trans, 0, sizeof(_trans) ); }
73
74         Impl( ::_Transaction & trans_r )
75           : _watcher( myPool().serial() )
76         {
77           memset( &_trans, 0, sizeof(_trans) );
78           ::transaction_init( &_trans, myPool().getPool() );
79
80           Queue decisionq;
81           for_( it, ResPool::instance().begin(), ResPool::instance().end() )
82           {
83             if ( ! (*it).status().transacts() )
84               continue;
85             sat::Solvable solv( (*it).satSolvable() );
86             decisionq.push( solv.isSystem() ? -solv.id() : solv.id() );
87           }
88           if ( trans_r.noobsmap.size )
89             ::map_grow( &trans_r.noobsmap, myPool()->nsolvables );
90           ::transaction_calculate( &_trans, decisionq, &trans_r.noobsmap );
91
92           // NOTE: package/product buddies share the same ResStatus
93           // so we also link the buddies stepStages. This assumes
94           // only one buddy is acting during commit (package is installed,
95           // but no extra operation for the product).
96           for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
97           {
98             sat::Solvable solv( *it );
99             // buddy list:
100             if ( ! solv.isKind<Package>() )
101             {
102               PoolItem pi( solv );
103               if ( pi.buddy() )
104               {
105                 _linkMap[*it] = pi.buddy().id();
106               }
107             }
108             if ( solv.isSystem() )
109             {
110               // to delete list:
111               if ( stepType( solv ) == TRANSACTION_ERASE )
112               {
113                 _systemErase.insert( *it );
114               }
115               // post mortem data
116               _pmMap[*it] = solv;
117             }
118           }
119         }
120
121         ~Impl()
122         { ::transaction_free( &_trans ); }
123
124       public:
125         bool valid() const
126         { return _watcher.isClean( myPool().serial() ); }
127
128         bool order()
129         {
130           if ( ! valid() )
131             return false;
132           if ( empty() )
133             return true;
134 #if 0
135           // This is hwo we could implement out own order method.
136           // As ::transaction already groups by MediaNr, we don't
137           // need it for ORDER_BY_MEDIANR.
138           ::transaction_order( &_trans, SOLVER_TRANSACTION_KEEP_ORDERDATA );
139           detail::IdType chosen = 0;
140           Queue choices;
141
142           while ( true )
143           {
144             int ret = transaction_order_add_choices( &_trans, chosen, choices );
145             MIL << ret << ": " << chosen << ": " << choices << endl;
146             chosen = choices.pop_front(); // pick one out of choices
147             if ( ! chosen )
148               break;
149           }
150           return true;
151 #endif
152           if ( !_ordered )
153           {
154             ::transaction_order( &_trans, 0 );
155             _ordered = true;
156           }
157           return true;
158         }
159
160         bool empty() const
161         { return( _trans.steps.count == 0 ); }
162
163         size_t size() const
164         { return _trans.steps.count; }
165
166         const_iterator begin( const RW_pointer<Transaction::Impl> & self_r ) const
167         { return const_iterator( self_r, _trans.steps.elements ); }
168         iterator begin( const RW_pointer<Transaction::Impl> & self_r )
169         { return iterator( self_r, _trans.steps.elements ); }
170
171         const_iterator end( const RW_pointer<Transaction::Impl> & self_r ) const
172         { return const_iterator( self_r, _trans.steps.elements + _trans.steps.count ); }
173         iterator end( const RW_pointer<Transaction::Impl> & self_r )
174         { return iterator( self_r, _trans.steps.elements + _trans.steps.count ); }
175
176         const_iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r ) const
177         { detail::IdType * it( _find( solv_r ) ); return it ? const_iterator( self_r, it ) : end( self_r ); }
178         iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r )
179         { detail::IdType * it( _find( solv_r ) ); return it ? iterator( self_r, it ) : end( self_r ); }
180
181       public:
182         StepType stepType( Solvable solv_r ) const
183         {
184           if ( ! solv_r )
185           {
186             // post mortem @System solvable
187             return isIn( _systemErase, solv_r.id() ) ? TRANSACTION_ERASE : TRANSACTION_IGNORE;
188           }
189
190           switch( ::transaction_type( &_trans, solv_r.id(), SOLVER_TRANSACTION_RPM_ONLY ) )
191           {
192             case SOLVER_TRANSACTION_ERASE: return TRANSACTION_ERASE; break;
193             case SOLVER_TRANSACTION_INSTALL: return TRANSACTION_INSTALL; break;
194             case SOLVER_TRANSACTION_MULTIINSTALL: return TRANSACTION_MULTIINSTALL; break;
195           }
196           return TRANSACTION_IGNORE;
197         }
198
199         StepStage stepStage( Solvable solv_r ) const
200         { return stepStage( resolve( solv_r ) ); }
201
202         void stepStage( Solvable solv_r, StepStage newval_r )
203         { stepStage( resolve( solv_r ), newval_r ); }
204
205         const PostMortem & pmdata( Solvable solv_r ) const
206         {
207           static PostMortem _none;
208           pmmap_type::const_iterator it( _pmMap.find( solv_r.id() ) );
209           return( it == _pmMap.end() ? _none : it->second );
210         }
211
212       private:
213         detail::IdType resolve( const Solvable & solv_r ) const
214         {
215           map_type::const_iterator res( _linkMap.find( solv_r.id() ) );
216           return( res == _linkMap.end() ? solv_r.id() : res->second );
217         }
218
219         bool isIn( const set_type & set_r, detail::IdType sid_r ) const
220         { return( set_r.find( sid_r ) != set_r.end() ); }
221
222         StepStage stepStage( detail::IdType sid_r ) const
223         {
224           if ( isIn( _doneSet, sid_r ) )
225             return STEP_DONE;
226           if ( isIn( _errSet, sid_r ) )
227             return STEP_ERROR;
228           return STEP_TODO;
229         }
230
231         void stepStage( detail::IdType sid_r, StepStage newval_r )
232         {
233           StepStage stage( stepStage( sid_r ) );
234           if ( stage != newval_r )
235           {
236             // reset old stage
237             if ( stage != STEP_TODO )
238             {
239               (stage == STEP_DONE ? _doneSet : _errSet).erase( sid_r );
240             }
241             if ( newval_r != STEP_TODO )
242             {
243               (newval_r == STEP_DONE ? _doneSet : _errSet).insert( sid_r );
244             }
245           }
246         }
247
248       private:
249         detail::IdType * _find( const sat::Solvable & solv_r ) const
250         {
251           if ( solv_r && _trans.steps.elements )
252           {
253             for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
254             {
255               if ( *it == detail::IdType(solv_r.id()) )
256                 return it;
257             }
258           }
259           return 0;
260         }
261
262      private:
263         SerialNumberWatcher _watcher;
264         mutable ::Transaction _trans;
265         DefaultIntegral<bool,false> _ordered;
266         //
267         set_type        _doneSet;
268         set_type        _errSet;
269         map_type        _linkMap;       // buddy map to adopt buddies StepResult
270         set_type        _systemErase;   // @System packages to be eased (otherse are TRANSACTION_IGNORE)
271         pmmap_type      _pmMap;         // Post mortem data of deleted @System solvables
272
273       public:
274         /** Offer default Impl. */
275         static shared_ptr<Impl> nullimpl()
276         {
277           static shared_ptr<Impl> _nullimpl( new Impl );
278           return _nullimpl;
279         }
280     };
281
282     /** \relates Transaction::Impl Stream output */
283     inline std::ostream & operator<<( std::ostream & str, const Transaction::Impl & obj )
284     {
285       return str << "Transaction: " << obj.size() << " (" << (obj.valid()?"valid":"INVALID") << ")";
286     }
287
288     ///////////////////////////////////////////////////////////////////
289     //
290     //  CLASS NAME : Transaction
291     //
292     ///////////////////////////////////////////////////////////////////
293
294     Transaction::Transaction()
295       : _pimpl( Impl::nullimpl() )
296     {}
297
298     Transaction::Transaction( ::_Transaction & trans_r )
299       : _pimpl( new Impl( trans_r ) )
300     {}
301
302     Transaction::~Transaction()
303     {}
304
305     bool Transaction::valid() const
306     { return _pimpl->valid(); }
307
308     bool Transaction::order()
309     { return _pimpl->order(); }
310
311     bool Transaction::empty() const
312     { return _pimpl->empty(); }
313
314     size_t Transaction::size() const
315     { return _pimpl->size(); }
316
317     Transaction::const_iterator Transaction::begin() const
318     { return _pimpl->begin( _pimpl ); }
319
320     Transaction::iterator Transaction::begin()
321     { return _pimpl->begin( _pimpl ); }
322
323     Transaction::const_iterator Transaction::end() const
324     { return _pimpl->end( _pimpl ); }
325
326     Transaction::iterator Transaction::end()
327     { return _pimpl->end( _pimpl ); }
328
329     Transaction::const_iterator Transaction::find( const sat::Solvable & solv_r ) const
330     { return _pimpl->find( _pimpl, solv_r ); }
331
332     Transaction::iterator Transaction::find( const sat::Solvable & solv_r )
333     { return _pimpl->find( _pimpl, solv_r ); }
334
335     std::ostream & operator<<( std::ostream & str, const Transaction & obj )
336     { return str << *obj._pimpl; }
337
338     std::ostream & dumpOn( std::ostream & str, const Transaction & obj )
339     {
340       for_( it, obj.begin(), obj.end() )
341       {
342         str << *it << endl;
343       }
344       return str;
345     }
346
347     bool operator==( const Transaction & lhs, const Transaction & rhs )
348     { return lhs._pimpl == rhs._pimpl; }
349
350     ///////////////////////////////////////////////////////////////////
351     //
352     //  CLASS NAME : Transaction::Step
353     //
354     ///////////////////////////////////////////////////////////////////
355
356     Transaction::Step::Step()
357     {}
358
359     Transaction::StepType Transaction::Step::stepType() const
360     { return _pimpl->stepType( _solv ); }
361
362     Transaction::StepStage Transaction::Step::stepStage() const
363     { return _pimpl->stepStage( _solv ); }
364
365     void Transaction::Step::stepStage( StepStage val_r )
366     { _pimpl->stepStage( _solv, val_r ); }
367
368     IdString Transaction::Step::ident() const
369     { return _solv ? _solv.ident() : _pimpl->pmdata(_solv )._ident; }
370
371     Edition Transaction::Step::edition() const
372     { return _solv ? _solv.edition() : _pimpl->pmdata(_solv )._edition; }
373
374     Arch Transaction::Step::arch() const
375     { return _solv ? _solv.arch() : _pimpl->pmdata(_solv )._arch; }
376
377     std::ostream & operator<<( std::ostream & str, const Transaction::Step & obj )
378     {
379       str << obj.stepType() << obj.stepStage() << " ";
380       if ( obj.satSolvable() )
381         str << PoolItem( obj.satSolvable() );
382       else
383         str << '[' << obj.ident() << '-' << obj.edition() << '.' << obj.arch() << ']';
384       return str;
385     }
386
387     std::ostream & operator<<( std::ostream & str, Transaction::StepType obj )
388     {
389       switch ( obj )
390       {
391         #define OUTS(E,S) case Transaction::E: return str << #S; break
392         OUTS( TRANSACTION_IGNORE,       [ ] );
393         OUTS( TRANSACTION_ERASE,        [-] );
394         OUTS( TRANSACTION_INSTALL,      [+] );
395         OUTS( TRANSACTION_MULTIINSTALL, [M] );
396         #undef OUTS
397       }
398       return str << "[?]";
399     }
400
401     std::ostream & operator<<( std::ostream & str, Transaction::StepStage obj )
402     {
403       switch ( obj )
404       {
405         #define OUTS(E,S) case Transaction::E: return str << #S; break
406         OUTS( STEP_TODO,        [__] );
407         OUTS( STEP_DONE,        [OK] );
408         OUTS( STEP_ERROR,       [**] );
409         #undef OUTS
410       }
411       return str << "[??]";
412     }
413     ///////////////////////////////////////////////////////////////////
414     namespace detail
415     { /////////////////////////////////////////////////////////////////
416       ///////////////////////////////////////////////////////////////////
417       //
418       //        CLASS NAME : Transaction::const_iterator/iterator
419       //
420       ///////////////////////////////////////////////////////////////////
421
422       Transaction_const_iterator::Transaction_const_iterator()
423       : Transaction_const_iterator::iterator_adaptor_( 0 )
424       {}
425
426       Transaction_const_iterator::Transaction_const_iterator( const Transaction_iterator & iter_r )
427       : Transaction_const_iterator::iterator_adaptor_( iter_r.base() )
428       , _pimpl( iter_r._pimpl )
429       {}
430
431       Transaction_iterator::Transaction_iterator()
432       : Transaction_iterator::iterator_adaptor_( 0 )
433       {}
434
435       /////////////////////////////////////////////////////////////////
436     } // namespace detail
437     ///////////////////////////////////////////////////////////////////
438     /////////////////////////////////////////////////////////////////
439   } // namespace sat
440   ///////////////////////////////////////////////////////////////////
441   /////////////////////////////////////////////////////////////////
442 } // namespace zypp
443 ///////////////////////////////////////////////////////////////////