CommitPackageCacheReadAhead.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 
00014 #include "zypp/base/Logger.h"
00015 #include "zypp/base/Exception.h"
00016 
00017 #include "zypp/target/CommitPackageCacheReadAhead.h"
00018 
00019 using std::endl;
00020 
00022 namespace zypp
00023 { 
00024 
00025   namespace target
00026   { 
00027 
00029     //
00030     //  CLASS NAME : IMediaKey
00031     //
00033 
00034     std::ostream & operator<<( std::ostream & str, const IMediaKey & obj )
00035     {
00036       return str << "[S" << obj._source.numericId() << ":" << obj._mediaNr << "]"
00037                  << " " << obj._source.alias();
00038     }
00039 
00041     //
00042     //  CLASS NAME : CommitPackageCacheReadAhead
00043     //
00045 
00047     //
00048     //  METHOD NAME : CommitPackageCacheReadAhead::CommitPackageCacheReadAhead
00049     //  METHOD TYPE : Ctor
00050     //
00051     CommitPackageCacheReadAhead::CommitPackageCacheReadAhead( const_iterator          begin_r,
00052                                                               const_iterator          end_r,
00053                                                               const Pathname &        rootDir_r,
00054                                                               const PackageProvider & packageProvider_r )
00055     : CommitPackageCache::Impl( packageProvider_r )
00056     , _commitListEnd( end_r )
00057     , _rootDir( rootDir_r )
00058     {}
00059 
00061     //
00062     //  METHOD NAME : CommitPackageCacheReadAhead::onInteractiveMedia
00063     //  METHOD TYPE : bool
00064     //
00065     bool CommitPackageCacheReadAhead::onInteractiveMedia( const PoolItem & pi ) const
00066     {
00067       if ( pi->sourceMediaNr() == 0 ) // no media access at all
00068         return false;
00069       std::string scheme( pi->source().url().getScheme() );
00070       return ( scheme == "dvd" || scheme == "cd" );
00071     }
00072 
00074     //
00075     //  METHOD NAME : CommitPackageCacheReadAhead::cacheLastInteractive
00076     //  METHOD TYPE : void
00077     //
00078     void CommitPackageCacheReadAhead::cacheLastInteractive( const_iterator citem_r )
00079     {
00080       // Fill cache errors are never proagated.
00081       try
00082         {
00083           doCacheLastInteractive( citem_r );
00084         }
00085       catch ( const Exception & excpt_r )
00086         {
00087           ZYPP_CAUGHT( excpt_r );
00088           WAR << "Failed to cache " << _lastInteractive << endl;
00089         }
00090     }
00091 
00093     //
00094     //  METHOD NAME : CommitPackageCacheReadAhead::doCacheLastInteractive
00095     //  METHOD TYPE : void
00096     //
00097     void CommitPackageCacheReadAhead::doCacheLastInteractive( const_iterator citem_r )
00098     {
00099       CacheMap  addToCache;
00100       ByteCount addSize;
00101 
00102       // Collect all remaining packages to install from
00103       // _lastInteractive media. (just the PoolItem data)
00104       for ( const_iterator it = citem_r; it != _commitListEnd; ++it )
00105         {
00106           if ( IMediaKey( *it ) == _lastInteractive
00107                && isKind<Package>(it->resolvable())
00108                && it->status().isToBeInstalled() )
00109             {
00110               if ( _cacheMap.find( *it ) == _cacheMap.end() )
00111                 {
00112                   addToCache[*it];
00113                   addSize += it->resolvable()->archivesize();
00114                 }
00115             }
00116         }
00117 
00118       if ( addToCache.empty() )
00119         return;
00120       MIL << "could cache " << _lastInteractive << ": " << addToCache.size() << " items: " <<  addSize << endl;
00121 
00122       // Check whether we can afford caching the items. We cache them all or
00123       // nothing. It does not make sense to cache only some packages, if a
00124       // CD change can't be avoided.
00125       if ( ! _cacheDir )
00126         {
00127           _cacheDir.reset( new filesystem::TmpDir( _rootDir, "commitCache." ) );
00128           PathInfo pi( _cacheDir->path() );
00129           if ( ! pi.isDir() )
00130             {
00131               ERR << "Can not initialize cache dir " << pi << endl;
00132               return;
00133             }
00134         }
00135 
00136       // In case someone removes cacheDir behind our back, df will be
00137       // -1, so we won't cache.
00138       ByteCount df( filesystem::df( _cacheDir->path() ) );
00139       MIL << "available disk space in " << _cacheDir->path() << ": " << df << endl;
00140 
00141       if ( df / 10 < addSize )
00142         {
00143           WAR << "cache would require more than 10% of the available " << df << " disk space " << endl;
00144           WAR << "not caching " << _lastInteractive << endl;
00145           return;
00146         }
00147 
00148       // Get all files to cache from the Source and copy them to
00149       // the cache.
00150       // NOTE: All files copied to the cache directory are stored in addToCache,
00151       // which is a local variable. If we throw on error, addToCache will be
00152       // deleted and all the ManagedFiles stored so far will delete themself.
00153       // THIS IS EXACTLY WHAT WE WANT.
00154       for ( CacheMap::iterator it = addToCache.begin(); it != addToCache.end(); ++it )
00155         {
00156           // let the source provide the file
00157           ManagedFile fromSource( sourceProvidePackage( it->first ) );
00158 
00159           // copy it to the cachedir
00160           std::string destName( str::form( "S%lu_%u_%s",
00161                                            it->first->source().numericId(),
00162                                            it->first->sourceMediaNr(),
00163                                            fromSource.value().basename().c_str() ) );
00164 
00165           ManagedFile fileInCache( _cacheDir->path() / destName,
00166                                    filesystem::unlink );
00167 
00168           if ( filesystem::copy( fromSource.value(), fileInCache ) != 0 )
00169             {
00170               // copy to cache failed.
00171               ERR << "Copy to cache failed on " << fromSource.value() << endl;
00172               ZYPP_THROW( Exception("Copy to cache failed.") );
00173             }
00174 
00175           // remember the cached file.
00176           it->second = fileInCache;
00177         }
00178 
00179       // Here: All files are sucessfully copied to the cache.
00180       // Update the real cache map.
00181       _cacheMap.insert( addToCache.begin(), addToCache.end() );
00182       return;
00183     }
00184 
00186     //
00187     //  METHOD NAME : CommitPackageCacheReadAhead::get
00188     //  METHOD TYPE : ManagedFile
00189     //
00190     ManagedFile CommitPackageCacheReadAhead::get( const_iterator citem_r )
00191     {
00192       // Non CD/DVD media provide their packages without cache.
00193       if ( ! onInteractiveMedia( *citem_r ) )
00194         {
00195           return sourceProvidePackage( *citem_r );
00196         }
00197 
00198       // Check whether it's cached.
00199       CacheMap::iterator it = _cacheMap.find( *citem_r );
00200       if ( it != _cacheMap.end() )
00201         {
00202           // ManagedFile delivered to the application is removed
00203           // from the cache. So if the application releases the
00204           // file, it actually gets deleted from disk.
00205           ManagedFile cacheHit( it->second );
00206           _cacheMap.erase( it );
00207 
00208           // safety check whether the file still exists
00209           PathInfo pi( cacheHit.value() );
00210           if ( pi.isFile() )
00211             {
00212               MIL << "Cache package provide " << cacheHit << endl;
00213               return cacheHit;
00214             }
00215 
00216           WAR << "Cached file vanished: " << pi << endl;
00217         }
00218 
00219       // HERE: It's not in the cache.
00220       // In case we have to change the media to provide the requested
00221       // file, try to cache files from the current media, that are
00222       // required later.
00223       IMediaKey current( *citem_r );
00224       if ( current != _lastInteractive )
00225         {
00226           if ( _lastInteractive != IMediaKey() )
00227             {
00228               cacheLastInteractive( citem_r );
00229             }
00230 
00231           DBG << "Interactive change [" << ++_dbgChanges << "] from " << _lastInteractive
00232           << " to " << current << endl;
00233           _lastInteractive = current;
00234         }
00235 
00236       // Provide and return the file from media.
00237       return sourceProvidePackage( *citem_r );
00238     }
00239 
00240 
00242   } // namespace target
00245 } // namespace zypp

Generated on Fri Jul 4 16:58:00 2008 for zypp by  doxygen 1.5.0