00001
00002
00003
00004
00005
00006
00007
00008
00011 extern "C"
00012 {
00013 #include <satsolver/transaction.h>
00014 #include <satsolver/bitmap.h>
00015 }
00016 #include <iostream>
00017 #include "zypp/base/LogTools.h"
00018 #include "zypp/base/SerialNumber.h"
00019 #include "zypp/base/DefaultIntegral.h"
00020 #include "zypp/base/NonCopyable.h"
00021 #include "zypp/base/Tr1hash.h"
00022
00023 #include "zypp/sat/detail/PoolImpl.h"
00024 #include "zypp/sat/Transaction.h"
00025 #include "zypp/sat/Solvable.h"
00026 #include "zypp/sat/Queue.h"
00027 #include "zypp/ResPool.h"
00028
00029 using std::endl;
00030
00032 namespace zypp
00033 {
00034
00035 namespace sat
00036 {
00037
00046 struct Transaction::Impl : protected detail::PoolMember
00047 {
00048 friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
00049
00050 public:
00051 typedef std::tr1::unordered_set<detail::IdType> set_type;
00052 typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
00053
00054 struct PostMortem
00055 {
00056 PostMortem()
00057 {}
00058 PostMortem( const sat::Solvable & solv_r )
00059 : _ident( solv_r.ident() )
00060 , _edition( solv_r.edition() )
00061 , _arch( solv_r.arch() )
00062 {}
00063
00064 IdString _ident;
00065 Edition _edition;
00066 Arch _arch;
00067 };
00068 typedef std::tr1::unordered_map<detail::IdType,PostMortem> pmmap_type;
00069
00070 public:
00071 Impl()
00072 { memset( &_trans, 0, sizeof(_trans) ); }
00073
00074 Impl( ::_Transaction & trans_r )
00075 : _watcher( myPool().serial() )
00076 {
00077 memset( &_trans, 0, sizeof(_trans) );
00078 ::transaction_init( &_trans, myPool().getPool() );
00079
00080 Queue decisionq;
00081 for_( it, ResPool::instance().begin(), ResPool::instance().end() )
00082 {
00083 if ( ! (*it).status().transacts() )
00084 continue;
00085 sat::Solvable solv( (*it).satSolvable() );
00086 decisionq.push( solv.isSystem() ? -solv.id() : solv.id() );
00087 }
00088 if ( trans_r.noobsmap.size )
00089 ::map_grow( &trans_r.noobsmap, myPool()->nsolvables );
00090 ::transaction_calculate( &_trans, decisionq, &trans_r.noobsmap );
00091
00092
00093
00094
00095
00096 for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
00097 {
00098 sat::Solvable solv( *it );
00099
00100 if ( ! solv.isKind<Package>() )
00101 {
00102 PoolItem pi( solv );
00103 if ( pi.buddy() )
00104 {
00105 _linkMap[*it] = pi.buddy().id();
00106 }
00107 }
00108 if ( solv.isSystem() )
00109 {
00110
00111 if ( stepType( solv ) == TRANSACTION_ERASE )
00112 {
00113 _systemErase.insert( *it );
00114 }
00115
00116 _pmMap[*it] = solv;
00117 }
00118 }
00119 }
00120
00121 ~Impl()
00122 { ::transaction_free( &_trans ); }
00123
00124 public:
00125 bool valid() const
00126 { return _watcher.isClean( myPool().serial() ); }
00127
00128 bool order()
00129 {
00130 if ( ! valid() )
00131 return false;
00132 if ( empty() )
00133 return true;
00134 #if 0
00135
00136
00137
00138 ::transaction_order( &_trans, SOLVER_TRANSACTION_KEEP_ORDERDATA );
00139 detail::IdType chosen = 0;
00140 Queue choices;
00141
00142 while ( true )
00143 {
00144 int ret = transaction_order_add_choices( &_trans, chosen, choices );
00145 MIL << ret << ": " << chosen << ": " << choices << endl;
00146 chosen = choices.pop_front();
00147 if ( ! chosen )
00148 break;
00149 }
00150 return true;
00151 #endif
00152 if ( !_ordered )
00153 {
00154 ::transaction_order( &_trans, 0 );
00155 _ordered = true;
00156 }
00157 return true;
00158 }
00159
00160 bool empty() const
00161 { return( _trans.steps.count == 0 ); }
00162
00163 size_t size() const
00164 { return _trans.steps.count; }
00165
00166 const_iterator begin( const RW_pointer<Transaction::Impl> & self_r ) const
00167 { return const_iterator( self_r, _trans.steps.elements ); }
00168 iterator begin( const RW_pointer<Transaction::Impl> & self_r )
00169 { return iterator( self_r, _trans.steps.elements ); }
00170
00171 const_iterator end( const RW_pointer<Transaction::Impl> & self_r ) const
00172 { return const_iterator( self_r, _trans.steps.elements + _trans.steps.count ); }
00173 iterator end( const RW_pointer<Transaction::Impl> & self_r )
00174 { return iterator( self_r, _trans.steps.elements + _trans.steps.count ); }
00175
00176 const_iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r ) const
00177 { detail::IdType * it( _find( solv_r ) ); return it ? const_iterator( self_r, it ) : end( self_r ); }
00178 iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r )
00179 { detail::IdType * it( _find( solv_r ) ); return it ? iterator( self_r, it ) : end( self_r ); }
00180
00181 public:
00182 StepType stepType( Solvable solv_r ) const
00183 {
00184 if ( ! solv_r )
00185 {
00186
00187 return isIn( _systemErase, solv_r.id() ) ? TRANSACTION_ERASE : TRANSACTION_IGNORE;
00188 }
00189
00190 switch( ::transaction_type( &_trans, solv_r.id(), SOLVER_TRANSACTION_RPM_ONLY ) )
00191 {
00192 case SOLVER_TRANSACTION_ERASE: return TRANSACTION_ERASE; break;
00193 case SOLVER_TRANSACTION_INSTALL: return TRANSACTION_INSTALL; break;
00194 case SOLVER_TRANSACTION_MULTIINSTALL: return TRANSACTION_MULTIINSTALL; break;
00195 }
00196 return TRANSACTION_IGNORE;
00197 }
00198
00199 StepStage stepStage( Solvable solv_r ) const
00200 { return stepStage( resolve( solv_r ) ); }
00201
00202 void stepStage( Solvable solv_r, StepStage newval_r )
00203 { stepStage( resolve( solv_r ), newval_r ); }
00204
00205 const PostMortem & pmdata( Solvable solv_r ) const
00206 {
00207 static PostMortem _none;
00208 pmmap_type::const_iterator it( _pmMap.find( solv_r.id() ) );
00209 return( it == _pmMap.end() ? _none : it->second );
00210 }
00211
00212 private:
00213 detail::IdType resolve( const Solvable & solv_r ) const
00214 {
00215 map_type::const_iterator res( _linkMap.find( solv_r.id() ) );
00216 return( res == _linkMap.end() ? solv_r.id() : res->second );
00217 }
00218
00219 bool isIn( const set_type & set_r, detail::IdType sid_r ) const
00220 { return( set_r.find( sid_r ) != set_r.end() ); }
00221
00222 StepStage stepStage( detail::IdType sid_r ) const
00223 {
00224 if ( isIn( _doneSet, sid_r ) )
00225 return STEP_DONE;
00226 if ( isIn( _errSet, sid_r ) )
00227 return STEP_ERROR;
00228 return STEP_TODO;
00229 }
00230
00231 void stepStage( detail::IdType sid_r, StepStage newval_r )
00232 {
00233 StepStage stage( stepStage( sid_r ) );
00234 if ( stage != newval_r )
00235 {
00236
00237 if ( stage != STEP_TODO )
00238 {
00239 (stage == STEP_DONE ? _doneSet : _errSet).erase( sid_r );
00240 }
00241 if ( newval_r != STEP_TODO )
00242 {
00243 (newval_r == STEP_DONE ? _doneSet : _errSet).insert( sid_r );
00244 }
00245 }
00246 }
00247
00248 private:
00249 detail::IdType * _find( const sat::Solvable & solv_r ) const
00250 {
00251 if ( solv_r && _trans.steps.elements )
00252 {
00253 for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
00254 {
00255 if ( *it == detail::IdType(solv_r.id()) )
00256 return it;
00257 }
00258 }
00259 return 0;
00260 }
00261
00262 private:
00263 SerialNumberWatcher _watcher;
00264 mutable ::Transaction _trans;
00265 DefaultIntegral<bool,false> _ordered;
00266
00267 set_type _doneSet;
00268 set_type _errSet;
00269 map_type _linkMap;
00270 set_type _systemErase;
00271 pmmap_type _pmMap;
00272
00273 public:
00275 static shared_ptr<Impl> nullimpl()
00276 {
00277 static shared_ptr<Impl> _nullimpl( new Impl );
00278 return _nullimpl;
00279 }
00280 };
00281
00283 inline std::ostream & operator<<( std::ostream & str, const Transaction::Impl & obj )
00284 {
00285 return str << "Transaction: " << obj.size() << " (" << (obj.valid()?"valid":"INVALID") << ")";
00286 }
00287
00289
00290
00291
00293
00294 Transaction::Transaction()
00295 : _pimpl( Impl::nullimpl() )
00296 {}
00297
00298 Transaction::Transaction( ::_Transaction & trans_r )
00299 : _pimpl( new Impl( trans_r ) )
00300 {}
00301
00302 Transaction::~Transaction()
00303 {}
00304
00305 bool Transaction::valid() const
00306 { return _pimpl->valid(); }
00307
00308 bool Transaction::order()
00309 { return _pimpl->order(); }
00310
00311 bool Transaction::empty() const
00312 { return _pimpl->empty(); }
00313
00314 size_t Transaction::size() const
00315 { return _pimpl->size(); }
00316
00317 Transaction::const_iterator Transaction::begin() const
00318 { return _pimpl->begin( _pimpl ); }
00319
00320 Transaction::iterator Transaction::begin()
00321 { return _pimpl->begin( _pimpl ); }
00322
00323 Transaction::const_iterator Transaction::end() const
00324 { return _pimpl->end( _pimpl ); }
00325
00326 Transaction::iterator Transaction::end()
00327 { return _pimpl->end( _pimpl ); }
00328
00329 Transaction::const_iterator Transaction::find( const sat::Solvable & solv_r ) const
00330 { return _pimpl->find( _pimpl, solv_r ); }
00331
00332 Transaction::iterator Transaction::find( const sat::Solvable & solv_r )
00333 { return _pimpl->find( _pimpl, solv_r ); }
00334
00335 std::ostream & operator<<( std::ostream & str, const Transaction & obj )
00336 { return str << *obj._pimpl; }
00337
00338 std::ostream & dumpOn( std::ostream & str, const Transaction & obj )
00339 {
00340 for_( it, obj.begin(), obj.end() )
00341 {
00342 str << *it << endl;
00343 }
00344 return str;
00345 }
00346
00347 bool operator==( const Transaction & lhs, const Transaction & rhs )
00348 { return lhs._pimpl == rhs._pimpl; }
00349
00351
00352
00353
00355
00356 Transaction::Step::Step()
00357 {}
00358
00359 Transaction::StepType Transaction::Step::stepType() const
00360 { return _pimpl->stepType( _solv ); }
00361
00362 Transaction::StepStage Transaction::Step::stepStage() const
00363 { return _pimpl->stepStage( _solv ); }
00364
00365 void Transaction::Step::stepStage( StepStage val_r )
00366 { _pimpl->stepStage( _solv, val_r ); }
00367
00368 IdString Transaction::Step::ident() const
00369 { return _solv ? _solv.ident() : _pimpl->pmdata(_solv )._ident; }
00370
00371 Edition Transaction::Step::edition() const
00372 { return _solv ? _solv.edition() : _pimpl->pmdata(_solv )._edition; }
00373
00374 Arch Transaction::Step::arch() const
00375 { return _solv ? _solv.arch() : _pimpl->pmdata(_solv )._arch; }
00376
00377 std::ostream & operator<<( std::ostream & str, const Transaction::Step & obj )
00378 {
00379 str << obj.stepType() << obj.stepStage() << " ";
00380 if ( obj.satSolvable() )
00381 str << PoolItem( obj.satSolvable() );
00382 else
00383 str << '[' << obj.ident() << '-' << obj.edition() << '.' << obj.arch() << ']';
00384 return str;
00385 }
00386
00387 std::ostream & operator<<( std::ostream & str, Transaction::StepType obj )
00388 {
00389 switch ( obj )
00390 {
00391 #define OUTS(E,S) case Transaction::E: return str << #S; break
00392 OUTS( TRANSACTION_IGNORE, [ ] );
00393 OUTS( TRANSACTION_ERASE, [-] );
00394 OUTS( TRANSACTION_INSTALL, [+] );
00395 OUTS( TRANSACTION_MULTIINSTALL, [M] );
00396 #undef OUTS
00397 }
00398 return str << "[?]";
00399 }
00400
00401 std::ostream & operator<<( std::ostream & str, Transaction::StepStage obj )
00402 {
00403 switch ( obj )
00404 {
00405 #define OUTS(E,S) case Transaction::E: return str << #S; break
00406 OUTS( STEP_TODO, [__] );
00407 OUTS( STEP_DONE, [OK] );
00408 OUTS( STEP_ERROR, [**] );
00409 #undef OUTS
00410 }
00411 return str << "[??]";
00412 }
00414 namespace detail
00415 {
00416
00417
00418
00419
00421
00422 Transaction_const_iterator::Transaction_const_iterator()
00423 : Transaction_const_iterator::iterator_adaptor_( 0 )
00424 {}
00425
00426 Transaction_const_iterator::Transaction_const_iterator( const Transaction_iterator & iter_r )
00427 : Transaction_const_iterator::iterator_adaptor_( iter_r.base() )
00428 , _pimpl( iter_r._pimpl )
00429 {}
00430
00431 Transaction_iterator::Transaction_iterator()
00432 : Transaction_iterator::iterator_adaptor_( 0 )
00433 {}
00434
00436 }
00439 }
00442 }