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