libzypp  11.13.5
CommitPackageCacheReadAhead.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Exception.h"
16 #include "zypp/PathInfo.h"
17 #include "zypp/RepoInfo.h"
19 
20 using std::endl;
21 
23 namespace zypp
24 {
25 
26  namespace target
27  {
28 
30  //
31  // CLASS NAME : IMediaKey
32  //
34 
35  std::ostream & operator<<( std::ostream & str, const IMediaKey & obj )
36  {
37  return str << "[S" << obj._repo.id() << ":" << obj._mediaNr << "]"
38  << " " << obj._repo.info().alias();
39  }
40 
42  //
43  // CLASS NAME : CommitPackageCacheReadAhead
44  //
46 
48  //
49  // METHOD NAME : CommitPackageCacheReadAhead::CommitPackageCacheReadAhead
50  // METHOD TYPE : Ctor
51  //
53  const PackageProvider & packageProvider_r )
54  : CommitPackageCache::Impl( packageProvider_r )
55  , _rootDir( rootDir_r )
56  {}
57 
59  //
60  // METHOD NAME : CommitPackageCacheReadAhead::onInteractiveMedia
61  // METHOD TYPE : bool
62  //
64  {
65  if ( pi->mediaNr() == 0 ) // no media access at all
66  return false;
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" );
71  }
72 
74  //
75  // METHOD NAME : CommitPackageCacheReadAhead::cacheLastInteractive
76  // METHOD TYPE : void
77  //
79  {
80  // Fill cache errors are never proagated.
81  try
82  {
83  doCacheLastInteractive( citem_r );
84  }
85  catch ( const Exception & excpt_r )
86  {
87  ZYPP_CAUGHT( excpt_r );
88  WAR << "Failed to cache " << _lastInteractive << endl;
89  }
90  }
91 
93  //
94  // METHOD NAME : CommitPackageCacheReadAhead::doCacheLastInteractive
95  // METHOD TYPE : void
96  //
98  {
99  CacheMap addToCache;
100  ByteCount addSize;
101 
102  // Collect all remaining packages to install from
103  // _lastInteractive media. (just the PoolItem data)
104  for_( it,_commitList.begin(), _commitList.end() )
105  {
106  PoolItem pi( *it );
107  if ( IMediaKey( pi ) == _lastInteractive
108  && isKind<Package>(pi.resolvable())
109  && pi.status().isToBeInstalled() )
110  {
111  if ( _cacheMap.find( pi ) == _cacheMap.end() )
112  {
113  addToCache[pi];
114  addSize += pi->downloadSize();
115  }
116  }
117  }
118 
119  if ( addToCache.empty() )
120  return;
121  MIL << "could cache " << _lastInteractive << ": " << addToCache.size() << " items: " << addSize << endl;
122 
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.
126  if ( ! _cacheDir )
127  {
128  _cacheDir.reset( new filesystem::TmpDir( _rootDir, "commitCache." ) );
129  PathInfo pi( _cacheDir->path() );
130  if ( ! pi.isDir() )
131  {
132  ERR << "Can not initialize cache dir " << pi << endl;
133  return;
134  }
135  }
136 
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;
141 
142  if ( df / 10 < addSize )
143  {
144  WAR << "cache would require more than 10% of the available " << df << " disk space " << endl;
145  WAR << "not caching " << _lastInteractive << endl;
146  return;
147  }
148 
149  // Get all files to cache from the Source and copy them to
150  // the cache.
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 )
156  {
157  // let the source provide the file
158  ManagedFile fromSource( sourceProvidePackage( it->first ) );
159 
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() ) );
165 
166  ManagedFile fileInCache( _cacheDir->path() / destName,
168 
169  if ( filesystem::copy( fromSource.value(), fileInCache ) != 0 )
170  {
171  // copy to cache failed.
172  ERR << "Copy to cache failed on " << fromSource.value() << endl;
173  ZYPP_THROW( Exception("Copy to cache failed.") );
174  }
175 
176  // remember the cached file.
177  it->second = fileInCache;
178  }
179 
180  // Here: All files are sucessfully copied to the cache.
181  // Update the real cache map.
182  _cacheMap.insert( addToCache.begin(), addToCache.end() );
183  return;
184  }
185 
187  //
188  // METHOD NAME : CommitPackageCacheReadAhead::get
189  // METHOD TYPE : ManagedFile
190  //
192  {
193  // Non CD/DVD media provide their packages without cache.
194  if ( ! onInteractiveMedia( citem_r ) )
195  {
196  return sourceProvidePackage( citem_r );
197  }
198 
199  // Check whether it's cached.
200  CacheMap::iterator it = _cacheMap.find( citem_r );
201  if ( it != _cacheMap.end() )
202  {
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 );
208 
209  // safety check whether the file still exists
210  PathInfo pi( cacheHit.value() );
211  if ( pi.isFile() )
212  {
213  MIL << "Cache package provide " << cacheHit << endl;
214  return cacheHit;
215  }
216 
217  WAR << "Cached file vanished: " << pi << endl;
218  }
219 
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
223  // required later.
224  IMediaKey current( citem_r );
225  if ( current != _lastInteractive )
226  {
227  if ( _lastInteractive != IMediaKey() )
228  {
229  cacheLastInteractive( citem_r );
230  }
231 
232  DBG << "Interactive change [" << ++_dbgChanges << "] from " << _lastInteractive
233  << " to " << current << endl;
234  _lastInteractive = current;
235  }
236 
237  // Provide and return the file from media.
238  return sourceProvidePackage( citem_r );
239  }
240 
241 
243  } // namespace target
246 } // namespace zypp