1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/CommitPackageCacheReadAhead.cc
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Exception.h"
16 #include "zypp/PathInfo.h"
17 #include "zypp/RepoInfo.h"
18 #include "zypp/target/CommitPackageCacheReadAhead.h"
22 ///////////////////////////////////////////////////////////////////
24 { /////////////////////////////////////////////////////////////////
25 ///////////////////////////////////////////////////////////////////
27 { /////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////
31 // CLASS NAME : IMediaKey
33 ///////////////////////////////////////////////////////////////////
35 std::ostream & operator<<( std::ostream & str, const IMediaKey & obj )
37 return str << "[S" << obj._repo.id() << ":" << obj._mediaNr << "]"
38 << " " << obj._repo.info().alias();
41 ///////////////////////////////////////////////////////////////////
43 // CLASS NAME : CommitPackageCacheReadAhead
45 ///////////////////////////////////////////////////////////////////
47 ///////////////////////////////////////////////////////////////////
49 // METHOD NAME : CommitPackageCacheReadAhead::CommitPackageCacheReadAhead
52 CommitPackageCacheReadAhead::CommitPackageCacheReadAhead( const Pathname & rootDir_r,
53 const PackageProvider & packageProvider_r )
54 : CommitPackageCache::Impl( packageProvider_r )
55 , _rootDir( rootDir_r )
58 ///////////////////////////////////////////////////////////////////
60 // METHOD NAME : CommitPackageCacheReadAhead::onInteractiveMedia
63 bool CommitPackageCacheReadAhead::onInteractiveMedia( const PoolItem & pi ) const
65 if ( pi->mediaNr() == 0 ) // no media access at all
67 if ( pi->repoInfo().baseUrlsEmpty() )
68 return false; // no Url - should actually not happen
69 std::string scheme( pi->repoInfo().baseUrlsBegin()->getScheme() );
70 return ( scheme == "dvd" || scheme == "cd" );
73 ///////////////////////////////////////////////////////////////////
75 // METHOD NAME : CommitPackageCacheReadAhead::cacheLastInteractive
78 void CommitPackageCacheReadAhead::cacheLastInteractive( const PoolItem & citem_r )
80 // Fill cache errors are never proagated.
83 doCacheLastInteractive( citem_r );
85 catch ( const Exception & excpt_r )
87 ZYPP_CAUGHT( excpt_r );
88 WAR << "Failed to cache " << _lastInteractive << endl;
92 ///////////////////////////////////////////////////////////////////
94 // METHOD NAME : CommitPackageCacheReadAhead::doCacheLastInteractive
97 void CommitPackageCacheReadAhead::doCacheLastInteractive( const PoolItem & citem_r )
102 // Collect all remaining packages to install from
103 // _lastInteractive media. (just the PoolItem data)
104 for_( it,_commitList.begin(), _commitList.end() )
107 if ( IMediaKey( pi ) == _lastInteractive
108 && isKind<Package>(pi.resolvable())
109 && pi.status().isToBeInstalled() )
111 if ( _cacheMap.find( pi ) == _cacheMap.end() )
114 addSize += pi->downloadSize();
119 if ( addToCache.empty() )
121 MIL << "could cache " << _lastInteractive << ": " << addToCache.size() << " items: " << addSize << endl;
123 // Check whether we can afford caching the items. We cache them all or
124 // nothing. It does not make sense to cache only some packages, if a
125 // CD change can't be avoided.
128 _cacheDir.reset( new filesystem::TmpDir( _rootDir, "commitCache." ) );
129 PathInfo pi( _cacheDir->path() );
132 ERR << "Can not initialize cache dir " << pi << endl;
137 // In case someone removes cacheDir behind our back, df will be
138 // -1, so we won't cache.
139 ByteCount df( filesystem::df( _cacheDir->path() ) );
140 MIL << "available disk space in " << _cacheDir->path() << ": " << df << endl;
142 if ( df / 10 < addSize )
144 WAR << "cache would require more than 10% of the available " << df << " disk space " << endl;
145 WAR << "not caching " << _lastInteractive << endl;
149 // Get all files to cache from the Source and copy them to
151 // NOTE: All files copied to the cache directory are stored in addToCache,
152 // which is a local variable. If we throw on error, addToCache will be
153 // deleted and all the ManagedFiles stored so far will delete themself.
154 // THIS IS EXACTLY WHAT WE WANT.
155 for ( CacheMap::iterator it = addToCache.begin(); it != addToCache.end(); ++it )
157 // let the source provide the file
158 ManagedFile fromSource( sourceProvidePackage( it->first ) );
160 // copy it to the cachedir
161 std::string destName( str::form( "S%p_%u_%s",
162 it->first->repository().id(),
163 it->first->mediaNr(),
164 fromSource.value().basename().c_str() ) );
166 ManagedFile fileInCache( _cacheDir->path() / destName,
167 filesystem::unlink );
169 if ( filesystem::copy( fromSource.value(), fileInCache ) != 0 )
171 // copy to cache failed.
172 ERR << "Copy to cache failed on " << fromSource.value() << endl;
173 ZYPP_THROW( Exception("Copy to cache failed.") );
176 // remember the cached file.
177 it->second = fileInCache;
180 // Here: All files are sucessfully copied to the cache.
181 // Update the real cache map.
182 _cacheMap.insert( addToCache.begin(), addToCache.end() );
186 ///////////////////////////////////////////////////////////////////
188 // METHOD NAME : CommitPackageCacheReadAhead::get
189 // METHOD TYPE : ManagedFile
191 ManagedFile CommitPackageCacheReadAhead::get( const PoolItem & citem_r )
193 // Non CD/DVD media provide their packages without cache.
194 if ( ! onInteractiveMedia( citem_r ) )
196 return sourceProvidePackage( citem_r );
199 // Check whether it's cached.
200 CacheMap::iterator it = _cacheMap.find( citem_r );
201 if ( it != _cacheMap.end() )
203 // ManagedFile delivered to the application is removed
204 // from the cache. So if the application releases the
205 // file, it actually gets deleted from disk.
206 ManagedFile cacheHit( it->second );
207 _cacheMap.erase( it );
209 // safety check whether the file still exists
210 PathInfo pi( cacheHit.value() );
213 MIL << "Cache package provide " << cacheHit << endl;
217 WAR << "Cached file vanished: " << pi << endl;
220 // HERE: It's not in the cache.
221 // In case we have to change the media to provide the requested
222 // file, try to cache files from the current media, that are
224 IMediaKey current( citem_r );
225 if ( current != _lastInteractive )
227 if ( _lastInteractive != IMediaKey() )
229 cacheLastInteractive( citem_r );
232 DBG << "Interactive change [" << ++_dbgChanges << "] from " << _lastInteractive
233 << " to " << current << endl;
234 _lastInteractive = current;
237 // Provide and return the file from media.
238 return sourceProvidePackage( citem_r );
242 /////////////////////////////////////////////////////////////////
243 } // namespace target
244 ///////////////////////////////////////////////////////////////////
245 /////////////////////////////////////////////////////////////////
247 ///////////////////////////////////////////////////////////////////