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

doxygen