99ece4d92a8b9d0d837773d7cc487031183d0c46
[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 }
15 #include <iostream>
16 #include "zypp/base/LogTools.h"
17 #include "zypp/base/SerialNumber.h"
18 #include "zypp/base/DefaultIntegral.h"
19 #include "zypp/base/NonCopyable.h"
20 #include "zypp/base/Tr1hash.h"
21
22 #include "zypp/sat/detail/PoolImpl.h"
23 #include "zypp/sat/Transaction.h"
24 #include "zypp/sat/Solvable.h"
25 #include "zypp/sat/Queue.h"
26 #include "zypp/PoolItem.h"
27
28 using std::endl;
29
30 ///////////////////////////////////////////////////////////////////
31 namespace zypp
32 { /////////////////////////////////////////////////////////////////
33   ///////////////////////////////////////////////////////////////////
34   namespace sat
35   { /////////////////////////////////////////////////////////////////
36
37     /** Transaction implementation.
38      * \todo check whether the pool serial number changed!
39      */
40     struct Transaction::Impl : protected detail::PoolMember
41     {
42       friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
43
44       public:
45       typedef std::tr1::unordered_set<detail::IdType> set_type;
46       typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
47
48       public:
49         Impl()
50         { memset( &_trans, 0, sizeof(_trans) ); }
51
52         Impl( ::_Transaction & trans_r )
53           : _watcher(  myPool().serial() )
54         {
55           ::transaction_init_clone( &_trans, &trans_r );
56           // NOTE: package/product buddies share the same ResStatus
57           // so we also link the buddies stepStages. This assumes
58           // only one buddy is acting during commit (package is installed,
59           // but no extra operation for the product).
60           for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
61           {
62             sat::Solvable solv( *it );
63             if ( ! solv.isKind<Package>() )
64             {
65               PoolItem pi( solv );
66               if ( pi.buddy() )
67               {
68                 _linkMap[*it] = pi.buddy().id();
69               }
70             }
71           }
72         }
73
74         ~Impl()
75         { ::transaction_free( &_trans ); }
76
77       public:
78         bool valid() const
79         { return _watcher.isClean( myPool().serial() ); }
80
81         bool order()
82         {
83           if ( ! valid() )
84             return false;
85 #if 0
86           ::transaction_order( &_trans, SOLVER_TRANSACTION_KEEP_ORDERDATA );
87           detail::IdType chosen = 0;
88           Queue choices;
89
90           unsigned stopper = 10;
91           while ( true )
92           {
93 //          choices.clear();
94             int ret = transaction_order_add_choices( &_trans, chosen, choices );
95 //
96             for_( it, choices.begin(), choices.end() )
97             {
98               if ( chosen )
99               {
100                 if ( *it == chosen )
101                   chosen = 0;
102                 continue;
103               }
104               if ( makeResObject( sat::Solvable(*it) )->mediaNr() > 1 )
105                 continue;
106               chosen = *it;
107               break;
108             }
109             MIL << ret << ": " << chosen << ": " << choices << endl;
110             if ( ! chosen )
111               break;
112             if ( !--stopper )
113               break;
114           }
115
116           return true;
117 #endif
118
119           if ( !_ordered )
120           {
121             ::transaction_order( &_trans, 0 );
122             _ordered = true;
123           }
124           return true;
125         }
126
127         bool empty() const
128         { return( _trans.steps.count == 0 ); }
129
130         size_t size() const
131         { return _trans.steps.count; }
132
133         const_iterator begin( const RW_pointer<Transaction::Impl> & self_r ) const
134         { return const_iterator( self_r, _trans.steps.elements ); }
135         iterator begin( const RW_pointer<Transaction::Impl> & self_r )
136         { return iterator( self_r, _trans.steps.elements ); }
137
138         const_iterator end( const RW_pointer<Transaction::Impl> & self_r ) const
139         { return const_iterator( self_r, _trans.steps.elements + _trans.steps.count ); }
140         iterator end( const RW_pointer<Transaction::Impl> & self_r )
141         { return iterator( self_r, _trans.steps.elements + _trans.steps.count ); }
142
143         const_iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r ) const
144         { detail::IdType * it( _find( solv_r ) ); return it ? const_iterator( self_r, it ) : end( self_r ); }
145         iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r )
146         { detail::IdType * it( _find( solv_r ) ); return it ? iterator( self_r, it ) : end( self_r ); }
147
148       private:
149         detail::IdType * _find( const sat::Solvable & solv_r ) const
150         {
151           if ( solv_r && _trans.steps.elements )
152           {
153             for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
154             {
155               if ( *it == detail::IdType(solv_r.id()) )
156                 return it;
157             }
158           }
159           return 0;
160         }
161
162       public:
163         StepType stepType( Solvable solv_r ) const
164         {
165           switch( ::transaction_type( &_trans, solv_r.id(), SOLVER_TRANSACTION_RPM_ONLY ) )
166           {
167             case SOLVER_TRANSACTION_ERASE: return TRANSACTION_ERASE; break;
168             case SOLVER_TRANSACTION_INSTALL: return TRANSACTION_INSTALL; break;
169             case SOLVER_TRANSACTION_MULTIINSTALL: return TRANSACTION_MULTIINSTALL; break;
170           }
171           return TRANSACTION_IGNORE;
172         }
173
174         StepStage stepStage( Solvable solv_r ) const
175         { return stepStage( resolve( solv_r ) ); }
176
177         void stepStage( Solvable solv_r, StepStage newval_r )
178         { stepStage( resolve( solv_r ), newval_r ); }
179
180       private:
181
182         detail::IdType resolve( const Solvable & solv_r ) const
183         {
184           map_type::const_iterator res( _linkMap.find( solv_r.id() ) );
185           return( res == _linkMap.end() ? solv_r.id() : res->second );
186         }
187
188         bool isIn( const set_type & set_r, detail::IdType sid_r ) const
189         { return( set_r.find( sid_r ) != set_r.end() ); }
190
191         StepStage stepStage( detail::IdType sid_r ) const
192         {
193           if ( isIn( _doneSet, sid_r ) )
194             return STEP_DONE;
195           if ( isIn( _errSet, sid_r ) )
196             return STEP_ERROR;
197           return STEP_TODO;
198         }
199
200         void stepStage( detail::IdType sid_r, StepStage newval_r )
201         {
202           StepStage stage( stepStage( sid_r ) );
203           if ( stage != newval_r )
204           {
205             // reset old stage
206             if ( stage != STEP_TODO )
207             {
208               (stage == STEP_DONE ? _doneSet : _errSet).erase( sid_r );
209             }
210             if ( newval_r != STEP_TODO )
211             {
212               (newval_r == STEP_DONE ? _doneSet : _errSet).insert( sid_r );
213             }
214           }
215         }
216      private:
217         SerialNumberWatcher _watcher;
218         mutable ::Transaction _trans;
219         DefaultIntegral<bool,false> _ordered;
220         //
221         set_type _doneSet;
222         set_type _errSet;
223         map_type _linkMap;
224
225       public:
226         /** Offer default Impl. */
227         static shared_ptr<Impl> nullimpl()
228         {
229           static shared_ptr<Impl> _nullimpl( new Impl );
230           return _nullimpl;
231         }
232     };
233
234     /** \relates Transaction::Impl Stream output */
235     inline std::ostream & operator<<( std::ostream & str, const Transaction::Impl & obj )
236     {
237       return str << "Transaction: " << obj.size() << " (" << (obj.valid()?"valid":"INVALID") << ")";
238     }
239
240     ///////////////////////////////////////////////////////////////////
241     //
242     //  CLASS NAME : Transaction
243     //
244     ///////////////////////////////////////////////////////////////////
245
246     Transaction::Transaction()
247       : _pimpl( Impl::nullimpl() )
248     {}
249
250     Transaction::Transaction( ::_Transaction & trans_r )
251       : _pimpl( new Impl( trans_r ) )
252     {}
253
254     Transaction::~Transaction()
255     {}
256
257     bool Transaction::valid() const
258     { return _pimpl->valid(); }
259
260     bool Transaction::order()
261     { return _pimpl->order(); }
262
263     bool Transaction::empty() const
264     { return _pimpl->empty(); }
265
266     size_t Transaction::size() const
267     { return _pimpl->size(); }
268
269     Transaction::const_iterator Transaction::begin() const
270     { return _pimpl->begin( _pimpl ); }
271
272     Transaction::iterator Transaction::begin()
273     { return _pimpl->begin( _pimpl ); }
274
275     Transaction::const_iterator Transaction::end() const
276     { return _pimpl->end( _pimpl ); }
277
278     Transaction::iterator Transaction::end()
279     { return _pimpl->end( _pimpl ); }
280
281     Transaction::const_iterator Transaction::find( const sat::Solvable & solv_r ) const
282     { return _pimpl->find( _pimpl, solv_r ); }
283
284     Transaction::iterator Transaction::find( const sat::Solvable & solv_r )
285     { return _pimpl->find( _pimpl, solv_r ); }
286
287     std::ostream & operator<<( std::ostream & str, const Transaction & obj )
288     { return str << *obj._pimpl; }
289
290     std::ostream & dumpOn( std::ostream & str, const Transaction & obj )
291     {
292       for_( it, obj.begin(), obj.end() )
293       {
294         str << *it << endl;
295       }
296       return str;
297     }
298
299     bool operator==( const Transaction & lhs, const Transaction & rhs )
300     { return lhs._pimpl == rhs._pimpl; }
301
302     ///////////////////////////////////////////////////////////////////
303     //
304     //  CLASS NAME : Transaction::Step
305     //
306     ///////////////////////////////////////////////////////////////////
307
308     Transaction::Step::Step()
309     {}
310
311     Transaction::StepType Transaction::Step::stepType() const
312     { return _pimpl->stepType( _solv ); }
313
314     Transaction::StepStage Transaction::Step::stepStage() const
315     { return _pimpl->stepStage( _solv ); }
316
317     void Transaction::Step::stepStage( StepStage val_r )
318     { _pimpl->stepStage( _solv, val_r ); }
319
320     std::ostream & operator<<( std::ostream & str, const Transaction::Step & obj )
321     { return str << obj.stepType() << obj.stepStage() << " " << PoolItem( obj.satSolvable() ); }
322
323     std::ostream & operator<<( std::ostream & str, Transaction::StepType obj )
324     {
325       switch ( obj )
326       {
327         #define OUTS(E,S) case Transaction::E: return str << #S; break
328         OUTS( TRANSACTION_IGNORE,       [ ] );
329         OUTS( TRANSACTION_ERASE,        [-] );
330         OUTS( TRANSACTION_INSTALL,      [+] );
331         OUTS( TRANSACTION_MULTIINSTALL, [M] );
332         #undef OUTS
333       }
334     }
335
336     std::ostream & operator<<( std::ostream & str, Transaction::StepStage obj )
337     {
338       switch ( obj )
339       {
340         #define OUTS(E,S) case Transaction::E: return str << #S; break
341         OUTS( STEP_TODO,        [__] );
342         OUTS( STEP_DONE,        [OK] );
343         OUTS( STEP_ERROR,       [**] );
344         #undef OUTS
345       }
346     }
347     ///////////////////////////////////////////////////////////////////
348     namespace detail
349     { /////////////////////////////////////////////////////////////////
350       ///////////////////////////////////////////////////////////////////
351       //
352       //        CLASS NAME : Transaction::const_iterator/iterator
353       //
354       ///////////////////////////////////////////////////////////////////
355
356       Transaction_const_iterator::Transaction_const_iterator()
357       : Transaction_const_iterator::iterator_adaptor_( 0 )
358       {}
359
360       Transaction_const_iterator::Transaction_const_iterator( const Transaction_iterator & iter_r )
361       : Transaction_const_iterator::iterator_adaptor_( iter_r.base() )
362       , _pimpl( iter_r._pimpl )
363       {}
364
365       Transaction_iterator::Transaction_iterator()
366       : Transaction_iterator::iterator_adaptor_( 0 )
367       {}
368
369       /////////////////////////////////////////////////////////////////
370     } // namespace detail
371     ///////////////////////////////////////////////////////////////////
372     /////////////////////////////////////////////////////////////////
373   } // namespace sat
374   ///////////////////////////////////////////////////////////////////
375   /////////////////////////////////////////////////////////////////
376 } // namespace zypp
377 ///////////////////////////////////////////////////////////////////