libzypp  10.5.0
Transaction.cc
Go to the documentation of this file.
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