KHTML
khtml_pagecache.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "khtml_pagecache.h"
00023
00024 #include <kfilterdev.h>
00025 #include <QTemporaryFile>
00026 #include <kstandarddirs.h>
00027
00028 #include <QQueue>
00029 #include <QHash>
00030 #include <QList>
00031 #include <QtCore/QTimer>
00032 #include <QtCore/QFile>
00033 #include <errno.h>
00034 #include <sys/types.h>
00035 #include <unistd.h>
00036 #include <assert.h>
00037
00038
00039 #ifndef KHTML_PAGE_CACHE_SIZE
00040 #define KHTML_PAGE_CACHE_SIZE 12
00041 #endif
00042
00043 template class QList<KHTMLPageCacheDelivery*>;
00044 class KHTMLPageCacheEntry
00045 {
00046 friend class KHTMLPageCache;
00047 public:
00048 KHTMLPageCacheEntry(long id);
00049
00050 ~KHTMLPageCacheEntry();
00051
00052 void addData(const QByteArray &data);
00053 void endData();
00054
00055 bool isComplete() const {return m_complete;}
00056 QString fileName() const {return m_fileName;}
00057
00058 KHTMLPageCacheDelivery *fetchData(QObject *recvObj, const char *recvSlot);
00059 private:
00060 long m_id;
00061 bool m_complete;
00062 QByteArray m_buffer;
00063 QIODevice* m_file;
00064 QString m_fileName;
00065 };
00066
00067 class KHTMLPageCachePrivate
00068 {
00069 public:
00070 long newId;
00071 bool deliveryActive;
00072 QHash<int, KHTMLPageCacheEntry*> dict;
00073 QList<KHTMLPageCacheDelivery*> delivery;
00074 QQueue<long> expireQueue;
00075 };
00076
00077 KHTMLPageCacheEntry::KHTMLPageCacheEntry(long id)
00078 : m_id(id)
00079 , m_complete(false)
00080 {
00081
00082 QTemporaryFile* f=new QTemporaryFile(KStandardDirs::locateLocal("tmp", "")+"khtmlcacheXXXXXX.tmp");
00083 f->open();
00084 m_fileName=f->fileName();
00085 f->setAutoRemove(false);
00086 delete f;
00087
00088 m_file = KFilterDev::deviceForFile(m_fileName, "application/x-gzip");
00089 m_file->open(QIODevice::WriteOnly);
00090 }
00091
00092 KHTMLPageCacheEntry::~KHTMLPageCacheEntry()
00093 {
00094 delete m_file;
00095 QFile::remove(m_fileName);
00096 }
00097
00098
00099 void
00100 KHTMLPageCacheEntry::addData(const QByteArray &data)
00101 {
00102 m_buffer+=data;
00103 }
00104
00105 void
00106 KHTMLPageCacheEntry::endData()
00107 {
00108 m_complete = true;
00109 m_file->write(m_buffer);
00110 m_buffer.clear();
00111 m_file->close();
00112 }
00113
00114
00115 KHTMLPageCacheDelivery *
00116 KHTMLPageCacheEntry::fetchData(QObject *recvObj, const char *recvSlot)
00117 {
00118
00119 KHTMLPageCacheDelivery *delivery=new KHTMLPageCacheDelivery(
00120 KFilterDev::deviceForFile (m_fileName, "application/x-gzip")
00121 );
00122 delivery->file->open(QIODevice::ReadOnly);
00123
00124 recvObj->connect(delivery, SIGNAL(emitData(const QByteArray&)), recvSlot);
00125 delivery->recvObj = recvObj;
00126 return delivery;
00127 }
00128
00129 KHTMLPageCache *
00130 KHTMLPageCache::self()
00131 {
00132 K_GLOBAL_STATIC(KHTMLPageCache, _self)
00133 return _self;
00134 }
00135
00136 KHTMLPageCache::KHTMLPageCache()
00137 :d( new KHTMLPageCachePrivate)
00138 {
00139 d->newId = 1;
00140 d->deliveryActive = false;
00141 }
00142
00143 KHTMLPageCache::~KHTMLPageCache()
00144 {
00145 qDeleteAll(d->dict);
00146 qDeleteAll(d->delivery);
00147 delete d;
00148 }
00149
00150 long
00151 KHTMLPageCache::createCacheEntry()
00152 {
00153
00154 KHTMLPageCacheEntry *entry = new KHTMLPageCacheEntry(d->newId);
00155 d->dict.insert(d->newId, entry);
00156 d->expireQueue.append(d->newId);
00157 if (d->expireQueue.count() > KHTML_PAGE_CACHE_SIZE)
00158 delete d->dict.take(d->expireQueue.dequeue());
00159 return (d->newId++);
00160 }
00161
00162 void
00163 KHTMLPageCache::addData(long id, const QByteArray &data)
00164 {
00165
00166 KHTMLPageCacheEntry *entry = d->dict.value( id );
00167 if (entry)
00168 entry->addData(data);
00169 }
00170
00171 void
00172 KHTMLPageCache::endData(long id)
00173 {
00174 KHTMLPageCacheEntry *entry = d->dict.value( id );
00175 if (entry)
00176 entry->endData();
00177 }
00178
00179 void
00180 KHTMLPageCache::cancelEntry(long id)
00181 {
00182 KHTMLPageCacheEntry *entry = d->dict.take( id );
00183 if (entry)
00184 {
00185 d->expireQueue.removeAll(entry->m_id);
00186 delete entry;
00187 }
00188 }
00189
00190 bool
00191 KHTMLPageCache::isValid(long id)
00192 {
00193 return d->dict.contains(id);
00194 }
00195
00196 bool
00197 KHTMLPageCache::isComplete(long id)
00198 {
00199 KHTMLPageCacheEntry *entry = d->dict.value( id );
00200 if (entry)
00201 return entry->isComplete();
00202 return false;
00203 }
00204
00205 void
00206 KHTMLPageCache::fetchData(long id, QObject *recvObj, const char *recvSlot)
00207 {
00208 KHTMLPageCacheEntry *entry = d->dict.value( id );
00209 if (!entry || !entry->isComplete()) return;
00210
00211
00212 d->expireQueue.removeAll(entry->m_id);
00213 d->expireQueue.enqueue(entry->m_id);
00214
00215 d->delivery.append( entry->fetchData(recvObj, recvSlot) );
00216 if (!d->deliveryActive)
00217 {
00218 d->deliveryActive = true;
00219 QTimer::singleShot(20, this, SLOT(sendData()));
00220 }
00221 }
00222
00223 void
00224 KHTMLPageCache::cancelFetch(QObject *recvObj)
00225 {
00226 QMutableListIterator<KHTMLPageCacheDelivery*> it( d->delivery );
00227 while (it.hasNext()) {
00228 KHTMLPageCacheDelivery* delivery = it.next();
00229 if (delivery->recvObj == recvObj)
00230 {
00231 delete delivery;
00232 it.remove();
00233 }
00234 }
00235 }
00236
00237 void
00238 KHTMLPageCache::sendData()
00239 {
00240 if (d->delivery.isEmpty())
00241 {
00242 d->deliveryActive = false;
00243 return;
00244 }
00245
00246 KHTMLPageCacheDelivery *delivery = d->delivery.takeFirst();
00247 assert(delivery);
00248
00249 QByteArray byteArray(delivery->file->read(64*1024));
00250 delivery->emitData(byteArray);
00251
00252
00253 if (delivery->file->atEnd())
00254 {
00255
00256 delivery->file->close();
00257 delivery->emitData(QByteArray());
00258 delete delivery;
00259 }
00260 else
00261 d->delivery.append( delivery );
00262
00263 QTimer::singleShot(0, this, SLOT(sendData()));
00264 }
00265
00266 void
00267 KHTMLPageCache::saveData(long id, QDataStream *str)
00268 {
00269 assert(d->dict.contains( id ));
00270 KHTMLPageCacheEntry *entry = d->dict.value( id );
00271
00272 if (!entry->isComplete())
00273 {
00274 QTimer::singleShot(20, this, SLOT(saveData()));
00275 return;
00276 }
00277
00278 QIODevice* file = KFilterDev::deviceForFile (entry->fileName(), "application/x-gzip");
00279 if (!file->open(QIODevice::ReadOnly))
00280 return;
00281
00282 QByteArray byteArray(file->readAll());
00283 file->close();
00284
00285 str->writeRawData(byteArray.constData(), byteArray.length());
00286
00287 }
00288
00289 KHTMLPageCacheDelivery::~KHTMLPageCacheDelivery()
00290 {
00291 file->close();
00292 delete file;
00293 }
00294
00295 #include "khtml_pagecache.moc"