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

KDE's Doxygen guidelines are available online.