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