khtml_pagecache.cpp Source File (khtml Library)

| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# khtml_pagecache.cpp

    00001 /* This file is part of the KDE project
    00002  *
    00003  * Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
    00004  *
    00005  * This library is free software; you can redistribute it and/or
    00006  * modify it under the terms of the GNU Library General Public
    00007  * License as published by the Free Software Foundation; either
    00008  * version 2 of the License, or (at your option) any later version.
    00009  *
    00010  * This library is distributed in the hope that it will be useful,
    00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013  * Library General Public License for more details.
    00014  *
    00015  * You should have received a copy of the GNU Library General Public License
    00016  * along with this library; see the file COPYING.LIB.  If not, write to
    00017  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018  * Boston, MA 02111-1307, USA.
    00019  */
    00020
    00021 #include "khtml_pagecache.h"
    00022
    00023 #include <kstaticdeleter.h>
    00024 #include <ktempfile.h>
    00025 #include <kstandarddirs.h>
    00026
    00027 #include <qintdict.h>
    00028 #include <qtimer.h>
    00029
    00030 #include <sys/types.h>
    00031 #include <unistd.h>
    00032 #include <assert.h>
    00033
    00034 // We keep 12 pages in memory.
    00035 #ifndef KHTML_PAGE_CACHE_SIZE
    00036 #define KHTML_PAGE_CACHE_SIZE 12
    00037 #endif
    00038
    00039 template class QPtrList<KHTMLPageCacheDelivery>;
    00040 class KHTMLPageCacheEntry
    00041 {
    00042   friend class KHTMLPageCache;
    00043 public:
    00044   KHTMLPageCacheEntry(long id);
    00045
    00046   ~KHTMLPageCacheEntry();
    00047
    00048   void addData(const QByteArray &data);
    00049
    00050   void endData();
    00051
    00052   bool isValid()
    00053    { return m_valid; }
    00054
    00055   KHTMLPageCacheDelivery *fetchData(QObject *recvObj, const char *recvSlot);
    00056 private:
    00057   long m_id;
    00058   bool m_valid;
    00059   QValueList<QByteArray> m_data;
    00060   KTempFile *m_file;
    00061 };
    00062
    00063 class KHTMLPageCachePrivate
    00064 {
    00065 public:
    00066   long newId;
    00067   QIntDict<KHTMLPageCacheEntry> dict;
    00068   QPtrList<KHTMLPageCacheDelivery> delivery;
    00069   QPtrList<KHTMLPageCacheEntry> expireQueue;
    00070   bool deliveryActive;
    00071 };
    00072
    00073 KHTMLPageCacheEntry::KHTMLPageCacheEntry(long id) : m_id(id), m_valid(false)
    00074 {
    00075   QString path = locateLocal("tmp", "khtmlcache");
    00076   m_file = new KTempFile(path);
    00077   m_file->unlink();
    00078 }
    00079
    00080 KHTMLPageCacheEntry::~KHTMLPageCacheEntry()
    00081 {
    00082   delete m_file;
    00083 }
    00084
    00085
    00086 void
    00087 KHTMLPageCacheEntry::addData(const QByteArray &data)
    00088 {
    00089   if (m_file->status() == 0)
    00090      m_file->dataStream()->writeRawBytes(data.data(), data.size());
    00091 }
    00092
    00093 void
    00094 KHTMLPageCacheEntry::endData()
    00095 {
    00096   m_valid = true;
    00097   if ( m_file->status() == 0) {
    00098     m_file->dataStream()->device()->flush();
    00099     m_file->dataStream()->device()->at(0);
    00100   }
    00101 }
    00102
    00103
    00104 KHTMLPageCacheDelivery *
    00105 KHTMLPageCacheEntry::fetchData(QObject *recvObj, const char *recvSlot)
    00106 {
    00107   // Duplicate fd so that entry can be safely deleted while delivering the data.
    00108   int fd = dup(m_file->handle());
    00109   lseek(fd, 0, SEEK_SET);
    00110   KHTMLPageCacheDelivery *delivery = new KHTMLPageCacheDelivery(fd);
    00111   recvObj->connect(delivery, SIGNAL(emitData(const QByteArray&)), recvSlot);
    00112   delivery->recvObj = recvObj;
    00113   return delivery;
    00114 }
    00115
    00116 static KStaticDeleter<KHTMLPageCache> pageCacheDeleter;
    00117
    00118 KHTMLPageCache *KHTMLPageCache::_self = 0;
    00119
    00120 KHTMLPageCache *
    00121 KHTMLPageCache::self()
    00122 {
    00123   if (!_self)
    00124      _self = pageCacheDeleter.setObject(new KHTMLPageCache);
    00125   return _self;
    00126 }
    00127
    00128 KHTMLPageCache::KHTMLPageCache()
    00129 {
    00130   d = new KHTMLPageCachePrivate;
    00131   d->newId = 1;
    00132   d->deliveryActive = false;
    00133 }
    00134
    00135 KHTMLPageCache::~KHTMLPageCache()
    00136 {
    00137   d->delivery.setAutoDelete(true);
    00138   d->dict.setAutoDelete(true);
    00139   delete d;
    00140 }
    00141
    00142 long
    00143 KHTMLPageCache::createCacheEntry()
    00144 {
    00145   KHTMLPageCacheEntry *entry = new KHTMLPageCacheEntry(d->newId);
    00146   d->dict.insert(d->newId, entry);
    00147   d->expireQueue.append(entry);
    00148   if (d->expireQueue.count() > KHTML_PAGE_CACHE_SIZE)
    00149   {
    00150      KHTMLPageCacheEntry *entry = d->expireQueue.take(0);
    00151      d->dict.remove(entry->m_id);
    00152      delete entry;
    00153   }
    00154   return (d->newId++);
    00155 }
    00156
    00157 void
    00158 KHTMLPageCache::addData(long id, const QByteArray &data)
    00159 {
    00160   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00161   if (entry)
    00162      entry->addData(data);
    00163 }
    00164
    00165 void
    00166 KHTMLPageCache::endData(long id)
    00167 {
    00168   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00169   if (entry)
    00170      entry->endData();
    00171 }
    00172
    00173 void
    00174 KHTMLPageCache::cancelEntry(long id)
    00175 {
    00176   KHTMLPageCacheEntry *entry = d->dict.take(id);
    00177   if (entry)
    00178   {
    00179      d->expireQueue.removeRef(entry);
    00180      delete entry;
    00181   }
    00182 }
    00183
    00184 bool
    00185 KHTMLPageCache::isValid(long id)
    00186 {
    00187   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00188   if (entry)
    00189      return entry->isValid();
    00190   return false;
    00191 }
    00192
    00193 void
    00194 KHTMLPageCache::fetchData(long id, QObject *recvObj, const char *recvSlot)
    00195 {
    00196   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00197   if (!entry) return;
    00198
    00199   // Make this entry the most recent entry.
    00200   d->expireQueue.removeRef(entry);
    00201   d->expireQueue.append(entry);
    00202
    00203   d->delivery.append( entry->fetchData(recvObj, recvSlot) );
    00204   if (!d->deliveryActive)
    00205   {
    00206      d->deliveryActive = true;
    00207      QTimer::singleShot(20, this, SLOT(sendData()));
    00208   }
    00209 }
    00210
    00211 void
    00212 KHTMLPageCache::cancelFetch(QObject *recvObj)
    00213 {
    00214   KHTMLPageCacheDelivery *next;
    00215   for(KHTMLPageCacheDelivery* delivery = d->delivery.first();
    00216       delivery;
    00217       delivery = next)
    00218   {
    00219       next = d->delivery.next();
    00220       if (delivery->recvObj == recvObj)
    00221       {
    00222          d->delivery.removeRef(delivery);
    00223          delete delivery;
    00224       }
    00225   }
    00226 }
    00227
    00228 void
    00229 KHTMLPageCache::sendData()
    00230 {
    00231   if (d->delivery.isEmpty())
    00232   {
    00233      d->deliveryActive = false;
    00234      return;
    00235   }
    00236   KHTMLPageCacheDelivery *delivery = d->delivery.take(0);
    00237   assert(delivery);
    00238
    00239   char buf[8192];
    00240   QByteArray byteArray;
    00241
    00242   int n = read(delivery->fd, buf, 8192);
    00243
    00244   if ((n < 0) && (errno == EINTR))
    00245   {
    00246      // try again later
    00247      d->delivery.append( delivery );
    00248   }
    00249   else if (n <= 0)
    00250   {
    00251      // done.
    00252      delivery->emitData(byteArray); // Empty array
    00253      delete delivery;
    00254   }
    00255   else
    00256   {
    00257      byteArray.setRawData(buf, n);
    00258      delivery->emitData(byteArray);
    00259      byteArray.resetRawData(buf, n);
    00260      d->delivery.append( delivery );
    00261   }
    00262   QTimer::singleShot(20, this, SLOT(sendData()));
    00263 }
    00264
    00265 void
    00266 KHTMLPageCache::saveData(long id, QDataStream *str)
    00267 {
    00268   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00269   assert(entry);
    00270
    00271   int fd = entry->m_file->handle();
    00272   if ( fd < 0 ) return;
    00273
    00274   lseek(fd, 0, SEEK_SET);
    00275
    00276   char buf[8192];
    00277
    00278   while(true)
    00279   {
    00280      int n = read(fd, buf, 8192);
    00281      if ((n < 0) && (errno == EINTR))
    00282      {
    00283         // try again
    00284         continue;
    00285      }
    00286      else if (n <= 0)
    00287      {
    00288         // done.
    00289         break;
    00290      }
    00291      else
    00292      {
    00293         str->writeRawBytes(buf, n);
    00294      }
    00295   }
    00296 }
    00297
    00298 KHTMLPageCacheDelivery::~KHTMLPageCacheDelivery()
    00299 {
    00300   close(fd);
    00301 }
    00302
    00303 #include "khtml_pagecache.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:01 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001