• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.12
  • kdeedu
  • marble
  • src
  • lib
  • marble
FileStorageWatcher.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2009 Bastian Holst <bastianholst@gmx.de>
9 //
10 
11 // Own
12 #include "FileStorageWatcher.h"
13 
14 // Qt
15 #include <QDateTime>
16 #include <QDir>
17 #include <QDirIterator>
18 #include <QFileInfo>
19 #include <QTimer>
20 
21 // Marble
22 #include "MarbleGlobal.h"
23 #include "MarbleDebug.h"
24 #include "MarbleDirs.h"
25 
26 using namespace Marble;
27 
28 // Only remove 20 files without checking
29 // changed cacheLimits and changed themes etc.
30 static const int maxFilesDelete = 20;
31 // Delete only files that are older than 120 Seconds
32 static const int deleteOnlyFilesOlderThan = 120;
33 static const int softLimitPercent = 5;
34 
35 
36 // Methods of FileStorageWatcherThread
37 FileStorageWatcherThread::FileStorageWatcherThread( const QString &dataDirectory, QObject *parent )
38  : QObject( parent ),
39  m_dataDirectory( dataDirectory ),
40  m_deleting( false ),
41  m_willQuit( false )
42 {
43  // For now setting cache limit to 0. This won't delete anything
44  setCacheLimit( 0 );
45 
46  connect( this, SIGNAL(variableChanged()),
47  this, SLOT(ensureCacheSize()),
48  Qt::QueuedConnection );
49  emit variableChanged();
50 }
51 
52 FileStorageWatcherThread::~FileStorageWatcherThread()
53 {
54 }
55 
56 quint64 FileStorageWatcherThread::cacheLimit()
57 {
58  return m_cacheLimit;
59 }
60 
61 void FileStorageWatcherThread::setCacheLimit( quint64 bytes )
62 {
63  m_limitMutex.lock();
64  m_cacheLimit = bytes;
65  m_cacheSoftLimit = bytes / 100 * ( 100 - softLimitPercent );
66  m_limitMutex.unlock();
67  emit variableChanged();
68 }
69 
70 void FileStorageWatcherThread::addToCurrentSize( qint64 bytes )
71 {
72 // mDebug() << "Current cache size changed by " << bytes;
73  qint64 changedSize = bytes + m_currentCacheSize;
74  if( changedSize >= 0 )
75  m_currentCacheSize = changedSize;
76  else
77  m_currentCacheSize = 0;
78  emit variableChanged();
79 }
80 
81 void FileStorageWatcherThread::resetCurrentSize()
82 {
83  m_currentCacheSize = 0;
84  emit variableChanged();
85 }
86 
87 void FileStorageWatcherThread::updateTheme( const QString &mapTheme )
88 {
89  mDebug() << "Theme changed to " << mapTheme;
90  m_themeMutex.lock();
91  m_mapThemeId = mapTheme;
92  m_themeMutex.unlock();
93  emit variableChanged();
94 }
95 
96 void FileStorageWatcherThread::prepareQuit()
97 {
98  m_willQuit = true;
99 }
100 
101 void FileStorageWatcherThread::getCurrentCacheSize()
102 {
103  mDebug() << "FileStorageWatcher: Creating cache size";
104  quint64 dataSize = 0;
105  QDirIterator it( m_dataDirectory, QDir::Files, QDirIterator::Subdirectories );
106 
107  while( it.hasNext() && !m_willQuit )
108  {
109  it.next();
110  QFileInfo file = it.fileInfo();
111  dataSize += file.size();
112  }
113  m_currentCacheSize = dataSize;
114 }
115 
116 void FileStorageWatcherThread::ensureCacheSize()
117 {
118 // mDebug() << "Size of tile cache: " << m_currentCacheSize;
119  // We start deleting files if m_currentCacheSize is larger than
120  // the hard cache limit. Then we delete files until our cache size
121  // is smaller than the cache limit.
122  // m_cacheLimit = 0 means no limit.
123  if( ( ( m_currentCacheSize > m_cacheLimit )
124  || ( m_deleting && ( m_currentCacheSize > m_cacheSoftLimit ) ) )
125  && ( m_cacheLimit != 0 )
126  && ( m_cacheSoftLimit != 0 )
127  && !( m_mapThemeId.isEmpty() )
128  && !m_willQuit )
129  {
130  // The counter for deleted files
131  m_filesDeleted = 0;
132  // We have not reached our soft limit, yet.
133  m_deleting = true;
134 
135  // Make sure that we are in the right directory
136  if ( m_dataDirectory.isEmpty() ||
137  !m_dataDirectory.endsWith(QLatin1String( "data" )) )
138  {
139  mDebug()
140  << "Error: Refusing to erase files under"
141  << "unknown conditions for safety reasons!";
142  return;
143  }
144 
145  // Which planet do we show now.
146  // We have to delete files for this planet at last
147  QStringList currentList = m_mapThemeId.split( '/' );
148  QString shownPlanet( currentList.first() );
149  currentList.removeFirst();
150  // The QString to save the path of the directory to the current planet
151  QString lastPlanet;
152 
153  QString cachedMapsDirectory = m_dataDirectory + "/maps";
154 
155  // Iterator over planet directories
156  QDirIterator it( cachedMapsDirectory,
157  QDir::NoDotAndDotDot | QDir::Dirs );
158 
159  while ( it.hasNext() &&
160  keepDeleting() ) {
161  it.next();
162 
163  // Our current planet directory
164  QString planetDirectory = it.filePath();
165  QFileInfo fileInfo = it.fileInfo();
166 
167  // We have found the currently shown planet.
168  // Please delete here at last.
169  if( fileInfo.fileName() == shownPlanet ) {
170  lastPlanet = planetDirectory;
171  continue;
172  }
173 
174  ensureSizePerPlanet( planetDirectory );
175  }
176 
177  if( keepDeleting() ) {
178  ensureSizePerPlanet( lastPlanet, currentList.first() );
179  }
180 
181  // We have deleted enough files.
182  // Perhaps there are changes.
183  if( m_filesDeleted > maxFilesDelete ) {
184  QTimer::singleShot( 100, this, SLOT(ensureCacheSize()) );
185  return;
186  }
187  else {
188  // We haven't stopped because of to many files
189  m_deleting = false;
190  }
191 
192  if( m_currentCacheSize > m_cacheSoftLimit ) {
193  mDebug() << "FileStorageWatcher: Could not set cache size.";
194  // Set the cache limit to a higher value, so we won't start
195  // trying to delete something next time. Softlimit is now exactly
196  // on the current cache size.
197  setCacheLimit( m_currentCacheSize / ( 100 - softLimitPercent ) * 100 );
198  }
199  }
200 }
201 
202 void FileStorageWatcherThread::ensureSizePerPlanet( const QString &planetDirectory,
203  const QString &currentTheme )
204 {
205  mDebug() << "Deleting from folder: " << planetDirectory;
206 
207  // lastTheme will store the path to our currentTheme
208  QString lastTheme;
209 
210  QDirIterator itPlanet( planetDirectory,
211  QDir::NoDotAndDotDot | QDir::Dirs );
212  while( itPlanet.hasNext() &&
213  keepDeleting() ) {
214  itPlanet.next();
215  QString themeDirectory = itPlanet.filePath();
216  QFileInfo fileInfo = itPlanet.fileInfo();
217 
218  // We have found the currently shown theme.
219  // Please delete here at last.
220  if( !currentTheme.isEmpty() && fileInfo.fileName() == currentTheme ) {
221  mDebug() << "FileStorageWatcher: Skipping " << themeDirectory
222  << " for now";
223  lastTheme = themeDirectory;
224  continue;
225  }
226 
227  ensureSizePerTheme( themeDirectory );
228  }
229 
230  if( keepDeleting() ) {
231  mDebug() << "Removing files of: "
232  << lastTheme;
233  ensureSizePerTheme( lastTheme );
234  }
235 }
236 
237 static bool greaterThanByNumber( const QString &s1, const QString &s2)
238 {
239  return s1.toInt() > s2.toInt();
240 }
241 
242 void FileStorageWatcherThread::ensureSizePerTheme( const QString &themeDirectory )
243 {
244  mDebug() << "Deleting from folder: " << themeDirectory;
245 
246  // Delete from folders with high numbers first
247  QStringList folders =
248  QDir( themeDirectory ).entryList( QDir::Dirs
249  | QDir::NoDotAndDotDot );
250  qSort( folders.begin(), folders.end(), greaterThanByNumber );
251 
252  QStringListIterator itTheme( folders );
253  while ( itTheme.hasNext() &&
254  keepDeleting() ) {
255  QString subDirectory = itTheme.next();
256 
257  // Do not delete base tiles
258  if ( subDirectory.toInt() <= maxBaseTileLevel ) {
259  continue;
260  }
261 
262  QString tileDirectory = themeDirectory + '/' + subDirectory;
263 
264  QDirIterator itTile( tileDirectory,
265  QDir::Files | QDir::NoSymLinks,
266  QDirIterator::Subdirectories );
267  while ( itTile.hasNext() &&
268  keepDeleting() ) {
269  itTile.next();
270  QString filePath = itTile.filePath();
271  QString lowerCase = filePath.toLower();
272 
273  QFileInfo info( filePath );
274 
275  // We try to be very careful and just delete images
276  // Do not delete files younger than two minutes.
277  // FIXME, when vectortiling I suppose also vector tiles will have
278  // to be deleted
279  if ( ( lowerCase.endsWith( QLatin1String( ".jpg" ) )
280  || lowerCase.endsWith( QLatin1String( ".png" ) )
281  || lowerCase.endsWith( QLatin1String( ".gif" ) )
282  || lowerCase.endsWith( QLatin1String( ".svg" ) ) )
283  && ( info.lastModified().secsTo( QDateTime::currentDateTime() )
284  > deleteOnlyFilesOlderThan ) )
285  {
286  mDebug() << "FileStorageWatcher: Delete "
287  << filePath;
288  m_filesDeleted++;
289  m_currentCacheSize -= info.size();
290  QFile::remove( filePath );
291  }
292  }
293  }
294 }
295 
296 bool FileStorageWatcherThread::keepDeleting() const
297 {
298  return ( ( m_currentCacheSize > m_cacheSoftLimit ) &&
299  ( m_filesDeleted <= maxFilesDelete ) &&
300  !m_willQuit );
301 }
302 // End of methods of our Thread
303 
304 
305 // Beginning of Methods of the main class
306 FileStorageWatcher::FileStorageWatcher( const QString &dataDirectory, QObject * parent )
307  : QThread( parent ),
308  m_dataDirectory( dataDirectory )
309 {
310  if ( m_dataDirectory.isEmpty() )
311  m_dataDirectory = MarbleDirs::localPath() + "/cache/";
312 
313  if ( ! QDir( m_dataDirectory ).exists() )
314  QDir::root().mkpath( m_dataDirectory );
315 
316  m_started = false;
317  m_themeLimitMutex = new QMutex();
318 
319  m_thread = 0;
320  m_quitting = false;
321 }
322 
323 FileStorageWatcher::~FileStorageWatcher()
324 {
325  mDebug() << "Deleting FileStorageWatcher";
326 
327  // Making sure that Thread is stopped.
328  m_quitting = true;
329 
330  if( m_thread )
331  m_thread->prepareQuit();
332  quit();
333  if( !wait( 5000 ) ) {
334  mDebug() << "Failed to stop FileStorageWatcher-Thread, terminating!";
335  terminate();
336  }
337 
338  delete m_thread;
339 
340  delete m_themeLimitMutex;
341 }
342 
343 void FileStorageWatcher::setCacheLimit( quint64 bytes )
344 {
345  QMutexLocker locker( m_themeLimitMutex );
346  if( m_started )
347  // This is done directly to ensure that a running ensureCacheSize()
348  // recognizes the new size.
349  m_thread->setCacheLimit( bytes );
350  // Save the limit, thread has to be initialized with the right one.
351  m_limit = bytes;
352 }
353 
354 quint64 FileStorageWatcher::cacheLimit()
355 {
356  if( m_started )
357  return m_thread->cacheLimit();
358  else
359  return m_limit;
360 }
361 
362 void FileStorageWatcher::addToCurrentSize( qint64 bytes )
363 {
364  emit sizeChanged( bytes );
365 }
366 
367 void FileStorageWatcher::resetCurrentSize()
368 {
369  emit cleared();
370 }
371 
372 void FileStorageWatcher::updateTheme( const QString &mapTheme )
373 {
374  QMutexLocker locker( m_themeLimitMutex );
375  if( m_started )
376  // This is done directly
377  m_thread->updateTheme( mapTheme );
378  // Save the theme, thread has to initialized with the right one.
379  m_theme = mapTheme;
380 }
381 
382 void FileStorageWatcher::run()
383 {
384  m_thread = new FileStorageWatcherThread( m_dataDirectory );
385  if( !m_quitting ) {
386  m_themeLimitMutex->lock();
387  m_thread->setCacheLimit( m_limit );
388  m_thread->updateTheme( m_theme );
389  m_started = true;
390  mDebug() << m_started;
391  m_themeLimitMutex->unlock();
392 
393  m_thread->getCurrentCacheSize();
394 
395  connect( this, SIGNAL(sizeChanged(qint64)),
396  m_thread, SLOT(addToCurrentSize(qint64)) );
397  connect( this, SIGNAL(cleared()),
398  m_thread, SLOT(resetCurrentSize()) );
399 
400  // Make sure that we don't want to stop process.
401  // The thread wouldn't exit from event loop.
402  if( !m_quitting )
403  exec();
404 
405  m_started = false;
406  }
407  delete m_thread;
408  m_thread = 0;
409 }
410 // End of all methods
411 
412 #include "FileStorageWatcher.moc"
Marble::FileStorageWatcher::cleared
void cleared()
Marble::FileStorageWatcherThread::variableChanged
void variableChanged()
Is emitted when a variable has changed.
softLimitPercent
static const int softLimitPercent
Definition: FileStorageWatcher.cpp:33
Marble::FileStorageWatcherThread::cacheLimit
quint64 cacheLimit()
Definition: FileStorageWatcher.cpp:56
Marble::MarbleDirs::localPath
static QString localPath()
Definition: MarbleDirs.cpp:217
Marble::FileStorageWatcher::FileStorageWatcher
FileStorageWatcher(const QString &dataDirectory=QString(), QObject *parent=0)
Creates a new FileStorageWatcher, which is a thread watching the space Marble takes on the hard drive...
Definition: FileStorageWatcher.cpp:306
QObject
MarbleDebug.h
FileStorageWatcher.h
Marble::FileStorageWatcherThread::addToCurrentSize
void addToCurrentSize(qint64 bytes)
Add bytes to the current cache size.
Definition: FileStorageWatcher.cpp:70
Marble::FileStorageWatcher::sizeChanged
void sizeChanged(qint64 bytes)
Marble::maxBaseTileLevel
const int maxBaseTileLevel
Definition: MarbleGlobal.h:241
Marble::FileStorageWatcher::cacheLimit
quint64 cacheLimit()
Returns the limit of the cache in bytes.
Definition: FileStorageWatcher.cpp:354
Marble::FileStorageWatcher::run
void run()
The function being called at starting Thread.
Definition: FileStorageWatcher.cpp:382
Marble::FileStorageWatcher::resetCurrentSize
void resetCurrentSize()
Setting current cache size to 0.
Definition: FileStorageWatcher.cpp:367
greaterThanByNumber
static bool greaterThanByNumber(const QString &s1, const QString &s2)
Definition: FileStorageWatcher.cpp:237
MarbleDirs.h
Marble::FileStorageWatcherThread::getCurrentCacheSize
void getCurrentCacheSize()
Getting the current size of the data stored on the disc.
Definition: FileStorageWatcher.cpp:101
Marble::FileStorageWatcher::addToCurrentSize
void addToCurrentSize(qint64 bytes)
Add bytes to the current cache size.
Definition: FileStorageWatcher.cpp:362
Marble::FileStorageWatcher::updateTheme
void updateTheme(const QString &mapTheme)
Updates the name of the theme.
Definition: FileStorageWatcher.cpp:372
maxFilesDelete
static const int maxFilesDelete
Definition: FileStorageWatcher.cpp:30
MarbleGlobal.h
deleteOnlyFilesOlderThan
static const int deleteOnlyFilesOlderThan
Definition: FileStorageWatcher.cpp:32
Marble::FileStorageWatcherThread::updateTheme
void updateTheme(const QString &mapTheme)
Updates the name of the theme.
Definition: FileStorageWatcher.cpp:87
Marble::FileStorageWatcher::setCacheLimit
void setCacheLimit(quint64 bytes)
Sets the limit of the cache in bytes.
Definition: FileStorageWatcher.cpp:343
Marble::FileStorageWatcherThread::~FileStorageWatcherThread
~FileStorageWatcherThread()
Definition: FileStorageWatcher.cpp:52
Marble::FileStorageWatcherThread::resetCurrentSize
void resetCurrentSize()
Setting current cache size to 0.
Definition: FileStorageWatcher.cpp:81
Marble::FileStorageWatcherThread::FileStorageWatcherThread
FileStorageWatcherThread(const QString &dataDirectory, QObject *parent=0)
Definition: FileStorageWatcher.cpp:37
QThread
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
Marble::FileStorageWatcherThread::setCacheLimit
void setCacheLimit(quint64 bytes)
Sets the limit of the cache in bytes.
Definition: FileStorageWatcher.cpp:61
Marble::FileStorageWatcherThread::prepareQuit
void prepareQuit()
Stop doing things that take a long time to quit.
Definition: FileStorageWatcher.cpp:96
Marble::FileStorageWatcher::~FileStorageWatcher
~FileStorageWatcher()
Definition: FileStorageWatcher.cpp:323
Marble::FileStorageWatcherThread
Definition: FileStorageWatcher.h:22
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:49 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal