summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--library/config.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/library/config.cpp b/library/config.cpp
index bdfcb3f..f68c336 100644
--- a/library/config.cpp
+++ b/library/config.cpp
@@ -29,4 +29,6 @@
29#include <sys/types.h> 29#include <sys/types.h>
30#include <sys/time.h>
30#include <fcntl.h> 31#include <fcntl.h>
31#include <stdlib.h> 32#include <stdlib.h>
33#include <time.h>
32#include <unistd.h> 34#include <unistd.h>
@@ -66,2 +68,173 @@ public:
66 68
69#ifndef Q_OS_WIN32
70
71//#define DEBUG_CONFIG_CACHE
72
73const int CONFIG_CACHE_SIZE = 8192;
74const int CONFIG_CACHE_TIMEOUT = 1000;
75
76class ConfigData
77{
78public:
79 ConfigData(const ConfigData& o) :
80 cfg(o.cfg),
81 priv(o.priv ? new ConfigPrivate(*o.priv) : 0),
82 mtime(o.mtime),
83 size(o.size),
84 used(o.used)
85 { }
86
87 ConfigData& operator=(const ConfigData& o)
88 {
89 cfg = o.cfg;
90 delete priv;
91 priv = o.priv ? new ConfigPrivate(*o.priv) : 0;
92 mtime = o.mtime;
93 size = o.size;
94 used = o.used;
95 return *this;
96 }
97
98 ConfigData() : priv(0) {}
99 ~ConfigData() { delete priv; }
100
101 ConfigGroupMap cfg;
102 ConfigPrivate *priv; // Owned by this object
103 time_t mtime;
104 unsigned int size;
105 struct timeval used;
106};
107
108class ConfigCache : public QObject
109{
110public:
111 ConfigCache();
112
113 void insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv);
114 bool find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv);
115 void remove(const QString &filename);
116
117protected:
118 void timerEvent(QTimerEvent *);
119
120private:
121 void removeLru();
122
123 QMap<QString, ConfigData> configData;
124 unsigned int totalsize;
125 int tid;
126};
127
128ConfigCache::ConfigCache() : QObject(), totalsize(0), tid(0)
129{
130}
131
132void ConfigCache::insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv)
133{
134 // use stat() rather than QFileInfo for speed.
135 struct stat sbuf;
136 stat(filename.local8Bit().data(), &sbuf);
137
138 if (sbuf.st_size < CONFIG_CACHE_SIZE/2) {
139 ConfigData data;
140 data.cfg = cfg;
141 data.priv = priv ? new ConfigPrivate(*priv) : 0;
142 data.mtime = sbuf.st_mtime;
143 data.size = sbuf.st_size;
144 gettimeofday(&data.used, 0);
145
146 remove(filename);
147 configData.insert(filename, data);
148
149 totalsize += data.size;
150#ifdef DEBUG_CONFIG_CACHE
151 qDebug("++++++ insert %s", filename.latin1());
152#endif
153 }
154
155 if (totalsize > (uint)CONFIG_CACHE_SIZE) {
156 // We'll delay deleting anything until later.
157 // This lets us grow quite large during some operations,
158 // but we'll be reduced to a decent size later.
159 // This works well with the main use case - app startup.
160 if (!tid)
161 tid = startTimer(CONFIG_CACHE_TIMEOUT);
162 }
163}
164
165bool ConfigCache::find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv)
166{
167 QMap<QString, ConfigData>::Iterator it = configData.find(filename);
168 if (it != configData.end()) {
169 ConfigData data = *it;
170 // use stat() rather than QFileInfo for speed.
171 struct stat sbuf;
172 stat(filename.local8Bit().data(), &sbuf);
173
174 if (data.mtime == sbuf.st_mtime && (int)data.size == sbuf.st_size) {
175 cfg = data.cfg;
176 delete priv;
177 priv = data.priv ? new ConfigPrivate(*data.priv) : 0;
178 gettimeofday(&data.used, 0);
179#ifdef DEBUG_CONFIG_CACHE
180 qDebug("******* Cache hit: %s", filename.latin1());
181#endif
182 return TRUE;
183 }
184 }
185
186#ifdef DEBUG_CONFIG_CACHE
187 qDebug("------- Cache miss: %s", filename.latin1());
188#endif
189
190 return FALSE;
191}
192
193void ConfigCache::remove(const QString &filename)
194{
195 QMap<QString, ConfigData>::Iterator it = configData.find(filename);
196 if (it != configData.end()) {
197 totalsize -= (*it).size;
198 configData.remove(it);
199 }
200}
201
202void ConfigCache::timerEvent(QTimerEvent *)
203{
204#ifdef DEBUG_CONFIG_CACHE
205 qDebug( "cache size: %d", totalsize);
206#endif
207 while (totalsize > (uint)CONFIG_CACHE_SIZE)
208 removeLru();
209 killTimer(tid);
210 tid = 0;
211}
212
213void ConfigCache::removeLru()
214{
215 QMap<QString, ConfigData>::Iterator it = configData.begin();
216 QMap<QString, ConfigData>::Iterator lru = it;
217 ++it;
218 for (; it != configData.end(); ++it) {
219 if ((*it).used.tv_sec < (*lru).used.tv_sec ||
220 ((*it).used.tv_sec == (*lru).used.tv_sec &&
221 (*it).used.tv_usec < (*lru).used.tv_usec))
222 lru = it;
223 }
224
225#ifdef DEBUG_CONFIG_CACHE
226 qDebug("Cache full, removing: %s", lru.key().latin1());
227#endif
228 totalsize -= (*lru).size;
229 configData.remove(lru);
230}
231
232static ConfigCache *qpe_configCache = 0;
233
234#endif /* Q_OS_WIN32 */
235
236
237// ==========================================================================
238
239
67/*! 240/*!
@@ -567,2 +740,6 @@ void Config::write( const QString &fn )
567 740
741#ifndef Q_OS_WIN32
742 if (qpe_configCache)
743 qpe_configCache->insert(filename, groups, d);
744#endif
568 changed = FALSE; 745 changed = FALSE;
@@ -605,2 +782,16 @@ void Config::read()
605 782
783#ifndef Q_OS_WIN32
784 if (!qpe_configCache)
785 qpe_configCache = new ConfigCache;
786
787 if (qpe_configCache->find(readFilename, groups, d)) {
788 if ( d && d->multilang ) {
789 QStringList l = Global::languageList();
790 lang = l[0];
791 glang = l[1];
792 }
793 git = groups.begin();
794 return;
795 }
796#endif
606 797
@@ -621,2 +812,6 @@ void Config::read()
621 f.close(); 812 f.close();
813
814#ifndef Q_OS_WIN32
815 qpe_configCache->insert(readFilename, groups, d);
816#endif
622} 817}