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

Generated on Tue Sep 25 19:23:08 2007 for libzypp by  doxygen 1.5.3