author | zecke <zecke> | 2005-02-06 21:39:24 (UTC) |
---|---|---|
committer | zecke <zecke> | 2005-02-06 21:39:24 (UTC) |
commit | ec33239c6edd9927fe2f82953fa48dec47d19567 (patch) (unidiff) | |
tree | d546238a10bf19641198f6f4eea32ac942a7116c | |
parent | f1a89d7deff682ea52f34a7d160eaa69886aa340 (diff) | |
download | opie-ec33239c6edd9927fe2f82953fa48dec47d19567.zip opie-ec33239c6edd9927fe2f82953fa48dec47d19567.tar.gz opie-ec33239c6edd9927fe2f82953fa48dec47d19567.tar.bz2 |
Rewrite Trolltechs Cache implementation.
-Update the used timestamp on access
-Do not play silly games with ConfigPrivate pointers
copying them is enough
In write save the old config group and restore it after
writing it
-rw-r--r-- | library/config.cpp | 238 |
1 files changed, 109 insertions, 129 deletions
diff --git a/library/config.cpp b/library/config.cpp index f68c336..e9cae4c 100644 --- a/library/config.cpp +++ b/library/config.cpp | |||
@@ -69,172 +69,152 @@ public: | |||
69 | #ifndef Q_OS_WIN32 | 69 | #ifndef Q_OS_WIN32 |
70 | 70 | ||
71 | //#define DEBUG_CONFIG_CACHE | 71 | //#define DEBUG_CONFIG_CACHE |
72 | |||
73 | const int CONFIG_CACHE_SIZE = 8192; | ||
74 | const int CONFIG_CACHE_TIMEOUT = 1000; | ||
75 | |||
76 | class ConfigData | 72 | class ConfigData |
77 | { | 73 | { |
78 | public: | 74 | public: |
79 | ConfigData(const ConfigData& o) : | 75 | ConfigData() {} |
80 | cfg(o.cfg), | 76 | ConfigData( const ConfigGroupMap& cf, const ConfigPrivate& pri, |
81 | priv(o.priv ? new ConfigPrivate(*o.priv) : 0), | 77 | struct stat sbuf ) |
82 | mtime(o.mtime), | 78 | : cfg( cf ), priv( pri ), mtime( sbuf.st_mtime ), |
83 | size(o.size), | 79 | size( sbuf.st_size ) |
84 | used(o.used) | ||
85 | { } | ||
86 | |||
87 | ConfigData& operator=(const ConfigData& o) | ||
88 | { | 80 | { |
89 | cfg = o.cfg; | 81 | gettimeofday(&used, 0 ); |
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 | } | 82 | } |
97 | 83 | ||
98 | ConfigData() : priv(0) {} | ||
99 | ~ConfigData() { delete priv; } | ||
100 | |||
101 | ConfigGroupMap cfg; | 84 | ConfigGroupMap cfg; |
102 | ConfigPrivate *priv; // Owned by this object | 85 | ConfigPrivate priv; // Owned by this object |
103 | time_t mtime; | 86 | time_t mtime; |
104 | unsigned int size; | 87 | unsigned int size; |
105 | struct timeval used; | 88 | struct timeval used; |
106 | }; | 89 | }; |
107 | 90 | ||
108 | class ConfigCache : public QObject | ||
109 | { | ||
110 | public: | ||
111 | ConfigCache(); | ||
112 | 91 | ||
113 | void insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv); | 92 | class ConfigCache : public QObject { |
114 | bool find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv); | 93 | public: |
115 | void remove(const QString &filename); | 94 | static ConfigCache* instance(); |
116 | 95 | ||
96 | void insert( const QString& fileName, const ConfigGroupMap& cfg, | ||
97 | const ConfigPrivate *priv ); | ||
98 | bool find(const QString& fileName, ConfigGroupMap& cfg, | ||
99 | ConfigPrivate** priv ); | ||
117 | protected: | 100 | protected: |
118 | void timerEvent(QTimerEvent *); | 101 | void timerEvent(QTimerEvent *); |
119 | 102 | ||
120 | private: | 103 | private: |
104 | ConfigCache(); | ||
105 | void remove( const QString& fileName ); | ||
121 | void removeLru(); | 106 | void removeLru(); |
122 | 107 | ||
123 | QMap<QString, ConfigData> configData; | 108 | private: |
124 | unsigned int totalsize; | 109 | QMap<QString, ConfigData> m_cached; |
125 | int tid; | 110 | unsigned int m_totalSize; |
111 | int m_tid; | ||
112 | private: | ||
113 | static ConfigCache* m_inst; | ||
114 | static const unsigned int CONFIG_CACHE_SIZE = 8192; | ||
115 | static const unsigned int CONFIG_CACHE_TIMEOUT = 1000; | ||
126 | }; | 116 | }; |
127 | 117 | ||
128 | ConfigCache::ConfigCache() : QObject(), totalsize(0), tid(0) | 118 | ConfigCache* ConfigCache::m_inst = 0; |
129 | { | 119 | /* |
120 | * get destroyed when qApp gets destroyed | ||
121 | */ | ||
122 | ConfigCache::ConfigCache() : QObject( qApp ), m_totalSize( 0 ), m_tid( 0 ) {} | ||
123 | ConfigCache* ConfigCache::instance() { | ||
124 | if ( !m_inst ) | ||
125 | m_inst = new ConfigCache(); | ||
126 | |||
127 | return m_inst; | ||
130 | } | 128 | } |
131 | 129 | ||
132 | void ConfigCache::insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv) | 130 | void ConfigCache::remove( const QString& fileName ) { |
133 | { | 131 | QMap<QString, ConfigData>::Iterator it = m_cached.find( fileName ); |
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 | 132 | ||
146 | remove(filename); | 133 | if ( it == m_cached.end() ) |
147 | configData.insert(filename, data); | 134 | return; |
148 | 135 | ||
149 | totalsize += data.size; | 136 | m_totalSize -= (*it).size; |
150 | #ifdef DEBUG_CONFIG_CACHE | 137 | m_cached.remove( it ); |
151 | qDebug("++++++ insert %s", filename.latin1()); | ||
152 | #endif | ||
153 | } | 138 | } |
154 | 139 | ||
155 | if (totalsize > (uint)CONFIG_CACHE_SIZE) { | 140 | void ConfigCache::removeLru() { |
156 | // We'll delay deleting anything until later. | 141 | QMap<QString, ConfigData>::Iterator it = m_cached.begin(); |
157 | // This lets us grow quite large during some operations, | 142 | QMap<QString, ConfigData>::Iterator lru = it; |
158 | // but we'll be reduced to a decent size later. | 143 | ++it; |
159 | // This works well with the main use case - app startup. | 144 | for (; it != m_cached.end(); ++it) |
160 | if (!tid) | 145 | if ((*it).used.tv_sec < (*lru).used.tv_sec || |
161 | tid = startTimer(CONFIG_CACHE_TIMEOUT); | 146 | ((*it).used.tv_sec == (*lru).used.tv_sec && |
162 | } | 147 | (*it).used.tv_usec < (*lru).used.tv_usec)) |
148 | lru = it; | ||
149 | |||
150 | qWarning( "Removing item" ); | ||
151 | m_totalSize -= (*lru).size; | ||
152 | m_cached.remove(lru); | ||
163 | } | 153 | } |
164 | 154 | ||
165 | bool ConfigCache::find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv) | 155 | void ConfigCache::timerEvent( QTimerEvent* ) { |
166 | { | 156 | while ( m_totalSize > CONFIG_CACHE_SIZE ) |
167 | QMap<QString, ConfigData>::Iterator it = configData.find(filename); | 157 | removeLru(); |
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 | 158 | ||
174 | if (data.mtime == sbuf.st_mtime && (int)data.size == sbuf.st_size) { | 159 | killTimer(m_tid); |
175 | cfg = data.cfg; | 160 | m_tid = 0; |
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 | } | 161 | } |
185 | 162 | ||
186 | #ifdef DEBUG_CONFIG_CACHE | 163 | void ConfigCache::insert( const QString& fileName, const ConfigGroupMap& cfg, |
187 | qDebug("------- Cache miss: %s", filename.latin1()); | 164 | const ConfigPrivate* _priv ) { |
188 | #endif | ||
189 | 165 | ||
190 | return FALSE; | ||
191 | } | ||
192 | 166 | ||
193 | void ConfigCache::remove(const QString &filename) | 167 | struct stat sbuf; |
194 | { | 168 | ::stat( QFile::encodeName(fileName), &sbuf ); |
195 | QMap<QString, ConfigData>::Iterator it = configData.find(filename); | 169 | if ( static_cast<unsigned int>(sbuf.st_size) >= CONFIG_CACHE_SIZE>>1) |
196 | if (it != configData.end()) { | 170 | return; |
197 | totalsize -= (*it).size; | ||
198 | configData.remove(it); | ||
199 | } | ||
200 | } | ||
201 | 171 | ||
202 | void ConfigCache::timerEvent(QTimerEvent *) | 172 | /* |
203 | { | 173 | * remove the old version and use the new one |
204 | #ifdef DEBUG_CONFIG_CACHE | 174 | */ |
205 | qDebug( "cache size: %d", totalsize); | 175 | ConfigPrivate priv = _priv ? *_priv : ConfigPrivate(); |
206 | #endif | 176 | ConfigData data( cfg, priv, sbuf ); |
207 | while (totalsize > (uint)CONFIG_CACHE_SIZE) | 177 | m_totalSize += data.size; |
208 | removeLru(); | ||
209 | killTimer(tid); | ||
210 | tid = 0; | ||
211 | } | ||
212 | 178 | ||
213 | void ConfigCache::removeLru() | 179 | remove( fileName ); |
214 | { | 180 | m_cached.insert( fileName, data ); |
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 | 181 | ||
225 | #ifdef DEBUG_CONFIG_CACHE | 182 | /* |
226 | qDebug("Cache full, removing: %s", lru.key().latin1()); | 183 | * we've overcommited allocation, let us clean up |
227 | #endif | 184 | * soon |
228 | totalsize -= (*lru).size; | 185 | */ |
229 | configData.remove(lru); | 186 | if ( m_totalSize >= CONFIG_CACHE_SIZE ) |
187 | if ( !m_tid ) | ||
188 | m_tid = startTimer(CONFIG_CACHE_TIMEOUT); | ||
230 | } | 189 | } |
231 | 190 | ||
232 | static ConfigCache *qpe_configCache = 0; | 191 | bool ConfigCache::find( const QString& fileName, ConfigGroupMap& cfg, |
192 | ConfigPrivate **ppriv ) { | ||
193 | QMap<QString, ConfigData>::Iterator it = m_cached.find(fileName); | ||
194 | if (it != m_cached.end()) { | ||
195 | ConfigData &data = *it; | ||
196 | struct stat sbuf; | ||
197 | ::stat(QFile::encodeName( fileName ), &sbuf); | ||
233 | 198 | ||
234 | #endif /* Q_OS_WIN32 */ | 199 | if (data.mtime == sbuf.st_mtime && (int)data.size == sbuf.st_size) { |
200 | cfg = data.cfg; | ||
235 | 201 | ||
202 | /* | ||
203 | * null pointer | ||
204 | */ | ||
205 | if ( *ppriv == 0 ) | ||
206 | *ppriv = new ConfigPrivate( data.priv ); | ||
207 | **ppriv = data.priv; | ||
208 | gettimeofday(&data.used, 0); | ||
236 | 209 | ||
237 | // ========================================================================== | 210 | return true; |
211 | } | ||
212 | } | ||
213 | |||
214 | return false; | ||
215 | } | ||
216 | |||
217 | #endif | ||
238 | 218 | ||
239 | 219 | ||
240 | /*! | 220 | /*! |
@@ -695,6 +675,8 @@ void Config::clearGroup() | |||
695 | */ | 675 | */ |
696 | void Config::write( const QString &fn ) | 676 | void Config::write( const QString &fn ) |
697 | { | 677 | { |
678 | QString oldGroup = git.key(); | ||
679 | |||
698 | QString strNewFile; | 680 | QString strNewFile; |
699 | if ( !fn.isEmpty() ) | 681 | if ( !fn.isEmpty() ) |
700 | filename = fn; | 682 | filename = fn; |
@@ -739,8 +721,8 @@ void Config::write( const QString &fn ) | |||
739 | } | 721 | } |
740 | 722 | ||
741 | #ifndef Q_OS_WIN32 | 723 | #ifndef Q_OS_WIN32 |
742 | if (qpe_configCache) | 724 | ConfigCache::instance()->insert( filename, groups, d ); |
743 | qpe_configCache->insert(filename, groups, d); | 725 | setGroup( oldGroup ); |
744 | #endif | 726 | #endif |
745 | changed = FALSE; | 727 | changed = FALSE; |
746 | } | 728 | } |
@@ -781,10 +763,8 @@ void Config::read() | |||
781 | } | 763 | } |
782 | 764 | ||
783 | #ifndef Q_OS_WIN32 | 765 | #ifndef Q_OS_WIN32 |
784 | if (!qpe_configCache) | ||
785 | qpe_configCache = new ConfigCache; | ||
786 | 766 | ||
787 | if (qpe_configCache->find(readFilename, groups, d)) { | 767 | if (ConfigCache::instance()->find(readFilename, groups, &d)) { |
788 | if ( d && d->multilang ) { | 768 | if ( d && d->multilang ) { |
789 | QStringList l = Global::languageList(); | 769 | QStringList l = Global::languageList(); |
790 | lang = l[0]; | 770 | lang = l[0]; |
@@ -812,7 +792,7 @@ void Config::read() | |||
812 | f.close(); | 792 | f.close(); |
813 | 793 | ||
814 | #ifndef Q_OS_WIN32 | 794 | #ifndef Q_OS_WIN32 |
815 | qpe_configCache->insert(readFilename, groups, d); | 795 | ConfigCache::instance()->insert(readFilename, groups, d); |
816 | #endif | 796 | #endif |
817 | } | 797 | } |
818 | 798 | ||