libzypp 8.13.6
|
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