1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/sat/Transaction.cc
13 #include <satsolver/transaction.h>
14 #include <satsolver/bitmap.h>
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"
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"
31 ///////////////////////////////////////////////////////////////////
33 { /////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
38 /** Transaction implementation.
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).
46 struct Transaction::Impl : protected detail::PoolMember
48 friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
51 typedef std::tr1::unordered_set<detail::IdType> set_type;
52 typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
58 PostMortem( const sat::Solvable & solv_r )
59 : _ident( solv_r.ident() )
60 , _edition( solv_r.edition() )
61 , _arch( solv_r.arch() )
68 typedef std::tr1::unordered_map<detail::IdType,PostMortem> pmmap_type;
72 { memset( &_trans, 0, sizeof(_trans) ); }
74 Impl( ::_Transaction & trans_r )
75 : _watcher( myPool().serial() )
77 memset( &_trans, 0, sizeof(_trans) );
78 ::transaction_init( &_trans, myPool().getPool() );
81 for_( it, ResPool::instance().begin(), ResPool::instance().end() )
83 if ( ! (*it).status().transacts() )
85 sat::Solvable solv( (*it).satSolvable() );
86 decisionq.push( solv.isSystem() ? -solv.id() : solv.id() );
88 if ( trans_r.noobsmap.size )
89 ::map_grow( &trans_r.noobsmap, myPool()->nsolvables );
90 ::transaction_calculate( &_trans, decisionq, &trans_r.noobsmap );
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 )
98 sat::Solvable solv( *it );
100 if ( ! solv.isKind<Package>() )
105 _linkMap[*it] = pi.buddy().id();
108 if ( solv.isSystem() )
111 if ( stepType( solv ) == TRANSACTION_ERASE )
113 _systemErase.insert( *it );
122 { ::transaction_free( &_trans ); }
126 { return _watcher.isClean( myPool().serial() ); }
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;
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
154 ::transaction_order( &_trans, 0 );
161 { return( _trans.steps.count == 0 ); }
164 { return _trans.steps.count; }
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 ); }
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 ); }
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 ); }
182 StepType stepType( Solvable solv_r ) const
186 // post mortem @System solvable
187 return isIn( _systemErase, solv_r.id() ) ? TRANSACTION_ERASE : TRANSACTION_IGNORE;
190 switch( ::transaction_type( &_trans, solv_r.id(), SOLVER_TRANSACTION_RPM_ONLY ) )
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;
196 return TRANSACTION_IGNORE;
199 StepStage stepStage( Solvable solv_r ) const
200 { return stepStage( resolve( solv_r ) ); }
202 void stepStage( Solvable solv_r, StepStage newval_r )
203 { stepStage( resolve( solv_r ), newval_r ); }
205 const PostMortem & pmdata( Solvable solv_r ) const
207 static PostMortem _none;
208 pmmap_type::const_iterator it( _pmMap.find( solv_r.id() ) );
209 return( it == _pmMap.end() ? _none : it->second );
213 detail::IdType resolve( const Solvable & solv_r ) const
215 map_type::const_iterator res( _linkMap.find( solv_r.id() ) );
216 return( res == _linkMap.end() ? solv_r.id() : res->second );
219 bool isIn( const set_type & set_r, detail::IdType sid_r ) const
220 { return( set_r.find( sid_r ) != set_r.end() ); }
222 StepStage stepStage( detail::IdType sid_r ) const
224 if ( isIn( _doneSet, sid_r ) )
226 if ( isIn( _errSet, sid_r ) )
231 void stepStage( detail::IdType sid_r, StepStage newval_r )
233 StepStage stage( stepStage( sid_r ) );
234 if ( stage != newval_r )
237 if ( stage != STEP_TODO )
239 (stage == STEP_DONE ? _doneSet : _errSet).erase( sid_r );
241 if ( newval_r != STEP_TODO )
243 (newval_r == STEP_DONE ? _doneSet : _errSet).insert( sid_r );
249 detail::IdType * _find( const sat::Solvable & solv_r ) const
251 if ( solv_r && _trans.steps.elements )
253 for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
255 if ( *it == detail::IdType(solv_r.id()) )
263 SerialNumberWatcher _watcher;
264 mutable ::Transaction _trans;
265 DefaultIntegral<bool,false> _ordered;
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
274 /** Offer default Impl. */
275 static shared_ptr<Impl> nullimpl()
277 static shared_ptr<Impl> _nullimpl( new Impl );
282 /** \relates Transaction::Impl Stream output */
283 inline std::ostream & operator<<( std::ostream & str, const Transaction::Impl & obj )
285 return str << "Transaction: " << obj.size() << " (" << (obj.valid()?"valid":"INVALID") << ")";
288 ///////////////////////////////////////////////////////////////////
290 // CLASS NAME : Transaction
292 ///////////////////////////////////////////////////////////////////
294 Transaction::Transaction()
295 : _pimpl( Impl::nullimpl() )
298 Transaction::Transaction( ::_Transaction & trans_r )
299 : _pimpl( new Impl( trans_r ) )
302 Transaction::~Transaction()
305 bool Transaction::valid() const
306 { return _pimpl->valid(); }
308 bool Transaction::order()
309 { return _pimpl->order(); }
311 bool Transaction::empty() const
312 { return _pimpl->empty(); }
314 size_t Transaction::size() const
315 { return _pimpl->size(); }
317 Transaction::const_iterator Transaction::begin() const
318 { return _pimpl->begin( _pimpl ); }
320 Transaction::iterator Transaction::begin()
321 { return _pimpl->begin( _pimpl ); }
323 Transaction::const_iterator Transaction::end() const
324 { return _pimpl->end( _pimpl ); }
326 Transaction::iterator Transaction::end()
327 { return _pimpl->end( _pimpl ); }
329 Transaction::const_iterator Transaction::find( const sat::Solvable & solv_r ) const
330 { return _pimpl->find( _pimpl, solv_r ); }
332 Transaction::iterator Transaction::find( const sat::Solvable & solv_r )
333 { return _pimpl->find( _pimpl, solv_r ); }
335 std::ostream & operator<<( std::ostream & str, const Transaction & obj )
336 { return str << *obj._pimpl; }
338 std::ostream & dumpOn( std::ostream & str, const Transaction & obj )
340 for_( it, obj.begin(), obj.end() )
347 bool operator==( const Transaction & lhs, const Transaction & rhs )
348 { return lhs._pimpl == rhs._pimpl; }
350 ///////////////////////////////////////////////////////////////////
352 // CLASS NAME : Transaction::Step
354 ///////////////////////////////////////////////////////////////////
356 Transaction::Step::Step()
359 Transaction::StepType Transaction::Step::stepType() const
360 { return _pimpl->stepType( _solv ); }
362 Transaction::StepStage Transaction::Step::stepStage() const
363 { return _pimpl->stepStage( _solv ); }
365 void Transaction::Step::stepStage( StepStage val_r )
366 { _pimpl->stepStage( _solv, val_r ); }
368 IdString Transaction::Step::ident() const
369 { return _solv ? _solv.ident() : _pimpl->pmdata(_solv )._ident; }
371 Edition Transaction::Step::edition() const
372 { return _solv ? _solv.edition() : _pimpl->pmdata(_solv )._edition; }
374 Arch Transaction::Step::arch() const
375 { return _solv ? _solv.arch() : _pimpl->pmdata(_solv )._arch; }
377 std::ostream & operator<<( std::ostream & str, const Transaction::Step & obj )
379 str << obj.stepType() << obj.stepStage() << " ";
380 if ( obj.satSolvable() )
381 str << PoolItem( obj.satSolvable() );
383 str << '[' << obj.ident() << '-' << obj.edition() << '.' << obj.arch() << ']';
387 std::ostream & operator<<( std::ostream & str, Transaction::StepType obj )
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] );
401 std::ostream & operator<<( std::ostream & str, Transaction::StepStage obj )
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, [**] );
411 return str << "[??]";
413 ///////////////////////////////////////////////////////////////////
415 { /////////////////////////////////////////////////////////////////
416 ///////////////////////////////////////////////////////////////////
418 // CLASS NAME : Transaction::const_iterator/iterator
420 ///////////////////////////////////////////////////////////////////
422 Transaction_const_iterator::Transaction_const_iterator()
423 : Transaction_const_iterator::iterator_adaptor_( 0 )
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 )
431 Transaction_iterator::Transaction_iterator()
432 : Transaction_iterator::iterator_adaptor_( 0 )
435 /////////////////////////////////////////////////////////////////
436 } // namespace detail
437 ///////////////////////////////////////////////////////////////////
438 /////////////////////////////////////////////////////////////////
440 ///////////////////////////////////////////////////////////////////
441 /////////////////////////////////////////////////////////////////
443 ///////////////////////////////////////////////////////////////////