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