--- branches/KDE/4.4/kdelibs/kdeui/util/kpixmapcache.cpp 2010/01/24 02:37:20 1079318 +++ branches/KDE/4.4/kdelibs/kdeui/util/kpixmapcache.cpp 2010/03/25 02:24:54 1107210 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -633,6 +634,10 @@ qint32 leftchild, rightchild; stream >> fkey >> foffset >> timesused >> lastused >> leftchild >> rightchild; + if (fkey.isEmpty()) { + return start; + } + if (key < fkey) { if (leftchild) { return binarySearchKey(stream, key, leftchild); @@ -660,12 +665,23 @@ // exist yet and there are no entries. Otherwise, do a binary search // starting from the root node. if (!stream.atEnd()) { + // One exception is that the root node may exist but be invalid, + // which can happen when the cache data is discarded. This is + // represented by an empty fkey + QString fkey; + stream >> fkey; + + if (fkey.isEmpty()) { + delete device; + return -1; + } + int nodeoffset = binarySearchKey(stream, key, mIndexRootOffset); // Load the found entry and check if it's the one we're looking for. device->seek(nodeoffset); - QString fkey; stream >> fkey; + if (fkey == key) { // Read offset and statistics qint32 foffset; @@ -814,7 +830,9 @@ QString fkey; stream.device()->seek(parentoffset); stream >> fkey; - if (key == fkey) { + + // The key would be empty if the cache had been discarded. + if (key == fkey || fkey.isEmpty()) { // We're overwriting an existing entry offset = parentoffset; } @@ -1195,16 +1213,14 @@ return false; } - d->invalidateMmapFiles(); - d->unmmapFiles(); - - d->mEnabled = false; - KPCLockFile lock(d->mLockFileName); // Hope we got the lock... + d->invalidateMmapFiles(); + d->mEnabled = false; + // Create index file - QFile indexfile(d->mIndexFile); + KSaveFile indexfile(d->mIndexFile); if (!indexfile.open(QIODevice::WriteOnly)) { kError() << "Couldn't create index file" << d->mIndexFile; return false; @@ -1212,7 +1228,7 @@ d->mCacheId = ::time(0); d->mTimestamp = ::time(0); - + // We can't know the full size until custom headers written. // mmapFiles() will take care of correcting the size. KPixmapCacheIndexHeader indexHeader = { {0}, KPIXMAPCACHE_VERSION, 0, d->mCacheId, d->mTimestamp }; @@ -1221,7 +1237,7 @@ indexfile.write(reinterpret_cast(&indexHeader), sizeof indexHeader); // Create data file - QFile datafile(d->mDataFile); + KSaveFile datafile(d->mDataFile); if (!datafile.open(QIODevice::WriteOnly)) { kError() << "Couldn't create data file" << d->mDataFile; return false; @@ -1243,40 +1259,54 @@ // Close the files and mmap them (if mmapping is used) indexfile.close(); datafile.close(); + indexfile.finalize(); + datafile.finalize(); + d->mEnabled = true; d->mmapFiles(); + return true; } void KPixmapCache::deleteCache(const QString& name) { - foreach (KPixmapCache::Private *d, Private::mCaches) { - if (d->mName == name && d->mInited) { - d->q->discard(); - } - } + QString indexFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + name + ".index"); + QString dataFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + name + ".data"); + + QFile::remove(indexFile); + QFile::remove(dataFile); } void KPixmapCache::discard() { - d->invalidateMmapFiles(); - d->unmmapFiles(); - d->mInited = false; + // To "discard" the cache we simply have to make sure that every that + // was in there before is no longer present when we search for them. + // Easiest way to do *that* is to simply delete the index. + + KPCLockFile lock(d->mLockFileName); + if(!lock.isValid()) { + kError(264) << "Unable to lock pixmap cache when trying to discard it"; + return; + } + + QIODevice *device = d->indexDevice(); + if (!device) { + kError(264) << "Unable to access index when trying to discard cache"; + return; + } + + device->seek(d->mIndexRootOffset); + QDataStream stream(device); + + // Stream an empty QString as the hash key to signify that the cache + // has been discarded. + stream << QString(); if (d->mUseQPixmapCache) { // TODO: This is broken, it removes every cached QPixmap in the whole // process, not just this KPixmapCache. QPixmapCache::clear(); } - - QString indexFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + d->mName + ".index"); - QString dataFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + d->mName + ".data"); - - QFile::remove(indexFile); - QFile::remove(dataFile); - - // No need to remove the lockfile - d->init(); } void KPixmapCache::removeEntries(int newsize)