Marble

DiscCache.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org>
4//
5
6
7// Own
8#include "DiscCache.h"
9
10// Qt
11#include <QtGlobal>
12#include <QFile>
13#include <QDirIterator>
14#include <QDataStream>
15
16using namespace Marble;
17
18static QString indexFileName( const QString &cacheDirectory )
19{
20 return cacheDirectory + QLatin1String("/cache_index.idx");
21}
22
23DiscCache::DiscCache( const QString &cacheDirectory )
24 : m_CacheDirectory( cacheDirectory ),
25 m_CacheLimit( 300 * 1024 * 1024 ),
26 m_CurrentCacheSize( 0 )
27{
28 Q_ASSERT( !m_CacheDirectory.isEmpty() && "Passed empty cache directory!" );
29
30 QFile file( indexFileName( m_CacheDirectory ) );
31
32 if ( file.exists() ) {
33 if ( file.open( QIODevice::ReadOnly ) ) {
34 QDataStream s( &file );
35 s.setVersion( 8 );
36
37 s >> m_CacheLimit;
38 s >> m_CurrentCacheSize;
39 s >> m_Entries;
40
41 } else {
42 qWarning( "Unable to open cache directory %s", qPrintable( m_CacheDirectory ) );
43 }
44 }
45}
46
47DiscCache::~DiscCache()
48{
49 QFile file( indexFileName( m_CacheDirectory ) );
50
51 if ( file.open( QIODevice::WriteOnly ) ) {
52 QDataStream s( &file );
53 s.setVersion( 8 );
54
55 s << m_CacheLimit;
56 s << m_CurrentCacheSize;
57 s << m_Entries;
58 }
59
60 file.close();
61}
62
63quint64 DiscCache::cacheLimit() const
64{
65 return m_CacheLimit;
66}
67
68void DiscCache::clear()
69{
70 QDirIterator it( m_CacheDirectory );
71
72 // Remove all files from cache directory
73 while ( it.hasNext() ) {
74 it.next();
75
76 if ( it.fileName() == indexFileName( m_CacheDirectory ) ) // skip index file
77 continue;
78
79 QFile::remove( it.fileName() );
80 }
81
82 // Delete entries
83 m_Entries.clear();
84
85 // Reset current cache size
86 m_CurrentCacheSize = 0;
87}
88
89bool DiscCache::exists( const QString &key ) const
90{
91 return m_Entries.contains( key );
92}
93
94bool DiscCache::find( const QString &key, QByteArray &data )
95{
96 // Return error if we don't know this key
97 if ( !m_Entries.contains( key ) )
98 return false;
99
100 // If we can open the file, load all data and update access timestamp
101 QFile file( keyToFileName( key ) );
102 if ( file.open( QIODevice::ReadOnly ) ) {
103 data = file.readAll();
104
105 m_Entries[ key ].first = QDateTime::currentDateTime();
106 return true;
107 }
108
109 return false;
110}
111
112bool DiscCache::insert( const QString &key, const QByteArray &data )
113{
114 // If we can't open/create a file for this entry signal an error
115 QFile file( keyToFileName( key ) );
116 if ( !file.open( QIODevice::WriteOnly ) )
117 return false;
118
119 // If we overwrite an existing entry, subtract the size first
120 if ( m_Entries.contains( key ) )
121 m_CurrentCacheSize -= m_Entries.value( key ).second;
122
123 // Store the data on disc
124 file.write( data );
125
126 // Create/Overwrite with a new entry
127 m_Entries.insert( key, QPair<QDateTime, quint64>(QDateTime::currentDateTime(), data.length()) );
128
129 // Add the size of the new entry
130 m_CurrentCacheSize += data.length();
131
132 cleanup();
133
134 return true;
135}
136
137void DiscCache::remove( const QString &key )
138{
139 // Do nothing if we don't know the key
140 if ( !m_Entries.contains( key ) )
141 return;
142
143 // If we can't remove the file we don't remove
144 // the entry to prevent inconsistency
145 if ( !QFile::remove( keyToFileName( key ) ) )
146 return;
147
148 // Subtract from current size
149 m_CurrentCacheSize -= m_Entries.value( key ).second;
150
151 // Finally remove entry
152 m_Entries.remove( key );
153}
154
155void DiscCache::setCacheLimit( quint64 n )
156{
157 m_CacheLimit = n;
158
159 cleanup();
160}
161
162QString DiscCache::keyToFileName( const QString &key ) const
163{
164 QString fileName( key );
165 fileName.replace(QLatin1Char('/'), QLatin1Char('_'));
166
167 return m_CacheDirectory + QLatin1Char('/') + fileName;
168}
169
170void DiscCache::cleanup()
171{
172 // Calculate 5% of our current cache limit
173 quint64 fivePercent = quint64( m_CacheLimit * 0.05 );
174
175 while ( m_CurrentCacheSize > (m_CacheLimit - fivePercent) ) {
177 QString oldestKey;
178
180 while ( it.hasNext() ) {
181 it.next();
182
183 if ( it.value().first < oldestDate ) {
184 oldestDate = it.value().first;
185 oldestKey = it.key();
186 }
187 }
188
189 if ( !oldestKey.isEmpty() ) {
190 // We found the oldest key, so using remove() to
191 // remove it from cache
192 remove( oldestKey );
193 }
194 }
195}
Binds a QML item to a specific geodetic location in screen coordinates.
qsizetype length() const const
QDateTime currentDateTime()
bool remove()
void clear()
bool contains(const Key &key) const const
T & first()
iterator insert(const Key &key, const T &value)
size_type remove(const Key &key)
T value(const Key &key, const T &defaultValue) const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.