libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00011 extern "C" 00012 { 00013 #include <solv/transaction.h> 00014 #include <solv/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 , private base::NonCopyable 00048 { 00049 friend std::ostream & operator<<( std::ostream & str, const Impl & obj ); 00050 00051 public: 00052 typedef std::tr1::unordered_set<detail::IdType> set_type; 00053 typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type; 00054 00055 struct PostMortem 00056 { 00057 PostMortem() 00058 {} 00059 PostMortem( const sat::Solvable & solv_r ) 00060 : _ident( solv_r.ident() ) 00061 , _edition( solv_r.edition() ) 00062 , _arch( solv_r.arch() ) 00063 {} 00064 00065 IdString _ident; 00066 Edition _edition; 00067 Arch _arch; 00068 }; 00069 typedef std::tr1::unordered_map<detail::IdType,PostMortem> pmmap_type; 00070 00071 public: 00072 Impl() 00073 : _trans( ::transaction_create( nullptr ) ) 00074 { memset( _trans, 0, sizeof(_trans) ); } 00075 00076 Impl( ::_Transaction & trans_r ) 00077 : _watcher( myPool().serial() ) 00078 , _trans( nullptr ) 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 _trans = ::transaction_create_decisionq( myPool().getPool(), decisionq, &trans_r.noobsmap ); 00091 00092 // NOTE: package/product buddies share the same ResStatus 00093 // so we also link the buddies stepStages. This assumes 00094 // only one buddy is acting during commit (package is installed, 00095 // but no extra operation for the product). 00096 for_( it, _trans->steps.elements, _trans->steps.elements + _trans->steps.count ) 00097 { 00098 sat::Solvable solv( *it ); 00099 // buddy list: 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 // to delete list: 00111 if ( stepType( solv ) == TRANSACTION_ERASE ) 00112 { 00113 _systemErase.insert( *it ); 00114 } 00115 // post mortem data 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 // This is hwo we could implement out own order method. 00136 // As ::transaction already groups by MediaNr, we don't 00137 // need it for ORDER_BY_MEDIANR. 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(); // pick one out of choices 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 // post mortem @System solvable 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 // reset old stage 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; // buddy map to adopt buddies StepResult 00270 set_type _systemErase; // @System packages to be eased (otherse are TRANSACTION_IGNORE) 00271 pmmap_type _pmMap; // Post mortem data of deleted @System solvables 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 // CLASS NAME : Transaction 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 // CLASS NAME : Transaction::Step 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 // CLASS NAME : Transaction::const_iterator/iterator 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 } // namespace detail 00439 } // namespace sat 00442 } // namespace zypp