1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/sat/Transaction.cc
13 #include <solv/transaction.h>
14 #include <solv/solver.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/sat/Map.h"
28 #include "zypp/ResPool.h"
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
39 /** Transaction implementation.
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).
47 struct Transaction::Impl : protected detail::PoolMember
48 , private base::NonCopyable
50 friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
53 typedef std::tr1::unordered_set<detail::IdType> set_type;
54 typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
60 PostMortem( const sat::Solvable & solv_r )
61 : _ident( solv_r.ident() )
62 , _edition( solv_r.edition() )
63 , _arch( solv_r.arch() )
70 typedef std::tr1::unordered_map<detail::IdType,PostMortem> pmmap_type;
74 : _trans( ::transaction_create( nullptr ) )
75 { memset( _trans, 0, sizeof(*_trans) ); }
77 Impl( LoadFromPoolType )
78 : _watcher( myPool().serial() )
82 for_( it, ResPool::instance().begin(), ResPool::instance().end() )
84 if ( ! (*it).status().transacts() )
86 sat::Solvable solv( (*it).satSolvable() );
87 decisionq.push( solv.isSystem() ? -solv.id() : solv.id() );
90 for_( it, sat::Pool::instance().multiversionBegin(), sat::Pool::instance().multiversionEnd() )
92 noobsq.push( SOLVER_NOOBSOLETES | SOLVER_SOLVABLE_NAME );
93 noobsq.push( it->id() );
96 ::solver_calculate_noobsmap( myPool().getPool(), noobsq, noobsmap );
97 _trans = ::transaction_create_decisionq( myPool().getPool(), decisionq, noobsmap );
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 )
105 sat::Solvable solv( *it );
107 if ( ! solv.isKind<Package>() )
112 _linkMap[*it] = pi.buddy().id();
115 if ( solv.isSystem() )
118 if ( stepType( solv ) == TRANSACTION_ERASE )
120 _systemErase.insert( *it );
129 { ::transaction_free( _trans ); }
133 { return _watcher.isClean( myPool().serial() ); }
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;
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
161 ::transaction_order( _trans, 0 );
168 { return( _trans->steps.count == 0 ); }
171 { return _trans->steps.count; }
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 ); }
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 ); }
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 ); }
189 int installedResult( Queue & result_r ) const
190 { return ::transaction_installedresult( _trans, result_r ); }
192 StringQueue autoInstalled() const
193 { return _autoInstalled; }
195 void autoInstalled( const StringQueue & queue_r )
196 { _autoInstalled = queue_r; }
199 StepType stepType( Solvable solv_r ) const
203 // post mortem @System solvable
204 return isIn( _systemErase, solv_r.id() ) ? TRANSACTION_ERASE : TRANSACTION_IGNORE;
207 switch( ::transaction_type( _trans, solv_r.id(), SOLVER_TRANSACTION_RPM_ONLY ) )
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;
213 return TRANSACTION_IGNORE;
216 StepStage stepStage( Solvable solv_r ) const
217 { return stepStage( resolve( solv_r ) ); }
219 void stepStage( Solvable solv_r, StepStage newval_r )
220 { stepStage( resolve( solv_r ), newval_r ); }
222 const PostMortem & pmdata( Solvable solv_r ) const
224 static PostMortem _none;
225 pmmap_type::const_iterator it( _pmMap.find( solv_r.id() ) );
226 return( it == _pmMap.end() ? _none : it->second );
230 detail::IdType resolve( const Solvable & solv_r ) const
232 map_type::const_iterator res( _linkMap.find( solv_r.id() ) );
233 return( res == _linkMap.end() ? solv_r.id() : res->second );
236 bool isIn( const set_type & set_r, detail::IdType sid_r ) const
237 { return( set_r.find( sid_r ) != set_r.end() ); }
239 StepStage stepStage( detail::IdType sid_r ) const
241 if ( isIn( _doneSet, sid_r ) )
243 if ( isIn( _errSet, sid_r ) )
248 void stepStage( detail::IdType sid_r, StepStage newval_r )
250 StepStage stage( stepStage( sid_r ) );
251 if ( stage != newval_r )
254 if ( stage != STEP_TODO )
256 (stage == STEP_DONE ? _doneSet : _errSet).erase( sid_r );
258 if ( newval_r != STEP_TODO )
260 (newval_r == STEP_DONE ? _doneSet : _errSet).insert( sid_r );
266 detail::IdType * _find( const sat::Solvable & solv_r ) const
268 if ( solv_r && _trans->steps.elements )
270 for_( it, _trans->steps.elements, _trans->steps.elements + _trans->steps.count )
272 if ( *it == detail::IdType(solv_r.id()) )
280 SerialNumberWatcher _watcher;
281 mutable ::Transaction * _trans;
282 DefaultIntegral<bool,false> _ordered;
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
290 StringQueue _autoInstalled; // ident strings of all packages that would be auto-installed after the transaction is run.
293 /** Offer default Impl. */
294 static shared_ptr<Impl> nullimpl()
296 static shared_ptr<Impl> _nullimpl( new Impl );
301 /** \relates Transaction::Impl Stream output */
302 inline std::ostream & operator<<( std::ostream & str, const Transaction::Impl & obj )
304 return str << "Transaction: " << obj.size() << " (" << (obj.valid()?"valid":"INVALID") << ")";
307 ///////////////////////////////////////////////////////////////////
309 // CLASS NAME : Transaction
311 ///////////////////////////////////////////////////////////////////
313 Transaction::Transaction()
314 : _pimpl( Impl::nullimpl() )
317 Transaction::Transaction( LoadFromPoolType )
318 : _pimpl( new Impl( loadFromPool ) )
321 Transaction::~Transaction()
324 bool Transaction::valid() const
325 { return _pimpl->valid(); }
327 bool Transaction::order()
328 { return _pimpl->order(); }
330 bool Transaction::empty() const
331 { return _pimpl->empty(); }
333 size_t Transaction::size() const
334 { return _pimpl->size(); }
336 Transaction::const_iterator Transaction::begin() const
337 { return _pimpl->begin( _pimpl ); }
339 Transaction::iterator Transaction::begin()
340 { return _pimpl->begin( _pimpl ); }
342 Transaction::const_iterator Transaction::end() const
343 { return _pimpl->end( _pimpl ); }
345 Transaction::iterator Transaction::end()
346 { return _pimpl->end( _pimpl ); }
348 Transaction::const_iterator Transaction::find( const sat::Solvable & solv_r ) const
349 { return _pimpl->find( _pimpl, solv_r ); }
351 Transaction::iterator Transaction::find( const sat::Solvable & solv_r )
352 { return _pimpl->find( _pimpl, solv_r ); }
354 int Transaction::installedResult( Queue & result_r ) const
355 { return _pimpl->installedResult( result_r ); }
357 StringQueue Transaction::autoInstalled() const
358 { return _pimpl->autoInstalled(); }
360 void Transaction::autoInstalled( const StringQueue & queue_r )
361 { _pimpl->autoInstalled( queue_r ); }
363 std::ostream & operator<<( std::ostream & str, const Transaction & obj )
364 { return str << *obj._pimpl; }
366 std::ostream & dumpOn( std::ostream & str, const Transaction & obj )
368 for_( it, obj.begin(), obj.end() )
375 bool operator==( const Transaction & lhs, const Transaction & rhs )
376 { return lhs._pimpl == rhs._pimpl; }
378 ///////////////////////////////////////////////////////////////////
380 // CLASS NAME : Transaction::Step
382 ///////////////////////////////////////////////////////////////////
384 Transaction::Step::Step()
387 Transaction::StepType Transaction::Step::stepType() const
388 { return _pimpl->stepType( _solv ); }
390 Transaction::StepStage Transaction::Step::stepStage() const
391 { return _pimpl->stepStage( _solv ); }
393 void Transaction::Step::stepStage( StepStage val_r )
394 { _pimpl->stepStage( _solv, val_r ); }
396 IdString Transaction::Step::ident() const
397 { return _solv ? _solv.ident() : _pimpl->pmdata(_solv )._ident; }
399 Edition Transaction::Step::edition() const
400 { return _solv ? _solv.edition() : _pimpl->pmdata(_solv )._edition; }
402 Arch Transaction::Step::arch() const
403 { return _solv ? _solv.arch() : _pimpl->pmdata(_solv )._arch; }
405 std::ostream & operator<<( std::ostream & str, const Transaction::Step & obj )
407 str << obj.stepType() << obj.stepStage() << " ";
408 if ( obj.satSolvable() )
409 str << PoolItem( obj.satSolvable() );
411 str << '[' << obj.ident() << '-' << obj.edition() << '.' << obj.arch() << ']';
415 std::ostream & operator<<( std::ostream & str, Transaction::StepType obj )
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] );
429 std::ostream & operator<<( std::ostream & str, Transaction::StepStage obj )
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, [**] );
439 return str << "[??]";
441 ///////////////////////////////////////////////////////////////////
443 { /////////////////////////////////////////////////////////////////
444 ///////////////////////////////////////////////////////////////////
446 // CLASS NAME : Transaction::const_iterator/iterator
448 ///////////////////////////////////////////////////////////////////
450 Transaction_const_iterator::Transaction_const_iterator()
451 : Transaction_const_iterator::iterator_adaptor_( 0 )
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 )
459 Transaction_iterator::Transaction_iterator()
460 : Transaction_iterator::iterator_adaptor_( 0 )
463 /////////////////////////////////////////////////////////////////
464 } // namespace detail
465 ///////////////////////////////////////////////////////////////////
466 /////////////////////////////////////////////////////////////////
468 ///////////////////////////////////////////////////////////////////
469 /////////////////////////////////////////////////////////////////
471 ///////////////////////////////////////////////////////////////////