| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | 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 isComplete()
    00053    { return m_complete; }
    00054
    00055   KHTMLPageCacheDelivery *fetchData(QObject *recvObj, const char *recvSlot);
    00056 private:
    00057   long m_id;
    00058   bool m_complete;
    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_complete(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_complete = 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(_self, 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   return (d->dict.find(id) != 0);
    00188 }
    00189
    00190 bool
    00191 KHTMLPageCache::isComplete(long id)
    00192 {
    00193   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00194   if (entry)
    00195      return entry->isComplete();
    00196   return false;
    00197 }
    00198
    00199 void
    00200 KHTMLPageCache::fetchData(long id, QObject *recvObj, const char *recvSlot)
    00201 {
    00202   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00203   if (!entry || !entry->isComplete()) return;
    00204
    00205   // Make this entry the most recent entry.
    00206   d->expireQueue.removeRef(entry);
    00207   d->expireQueue.append(entry);
    00208
    00209   d->delivery.append( entry->fetchData(recvObj, recvSlot) );
    00210   if (!d->deliveryActive)
    00211   {
    00212      d->deliveryActive = true;
    00213      QTimer::singleShot(20, this, SLOT(sendData()));
    00214   }
    00215 }
    00216
    00217 void
    00218 KHTMLPageCache::cancelFetch(QObject *recvObj)
    00219 {
    00220   KHTMLPageCacheDelivery *next;
    00221   for(KHTMLPageCacheDelivery* delivery = d->delivery.first();
    00222       delivery;
    00223       delivery = next)
    00224   {
    00225       next = d->delivery.next();
    00226       if (delivery->recvObj == recvObj)
    00227       {
    00228          d->delivery.removeRef(delivery);
    00229          delete delivery;
    00230       }
    00231   }
    00232 }
    00233
    00234 void
    00235 KHTMLPageCache::sendData()
    00236 {
    00237   if (d->delivery.isEmpty())
    00238   {
    00239      d->deliveryActive = false;
    00240      return;
    00241   }
    00242   KHTMLPageCacheDelivery *delivery = d->delivery.take(0);
    00243   assert(delivery);
    00244
    00245   char buf[8192];
    00246   QByteArray byteArray;
    00247
    00248   int n = read(delivery->fd, buf, 8192);
    00249
    00250   if ((n < 0) && (errno == EINTR))
    00251   {
    00252      // try again later
    00253      d->delivery.append( delivery );
    00254   }
    00255   else if (n <= 0)
    00256   {
    00257      // done.
    00258      delivery->emitData(byteArray); // Empty array
    00259      delete delivery;
    00260   }
    00261   else
    00262   {
    00263      byteArray.setRawData(buf, n);
    00264      delivery->emitData(byteArray);
    00265      byteArray.resetRawData(buf, n);
    00266      d->delivery.append( delivery );
    00267   }
    00268   QTimer::singleShot(0, this, SLOT(sendData()));
    00269 }
    00270
    00271 void
    00272 KHTMLPageCache::saveData(long id, QDataStream *str)
    00273 {
    00274   KHTMLPageCacheEntry *entry = d->dict.find(id);
    00275   assert(entry);
    00276
    00277   int fd = entry->m_file->handle();
    00278   if ( fd < 0 ) return;
    00279
    00280   off_t pos = lseek(fd, 0, SEEK_CUR);
    00281   lseek(fd, 0, SEEK_SET);
    00282
    00283   char buf[8192];
    00284
    00285   while(true)
    00286   {
    00287      int n = read(fd, buf, 8192);
    00288      if ((n < 0) && (errno == EINTR))
    00289      {
    00290         // try again
    00291         continue;
    00292      }
    00293      else if (n <= 0)
    00294      {
    00295         // done.
    00296         break;
    00297      }
    00298      else
    00299      {
    00300         str->writeRawBytes(buf, n);
    00301      }
    00302   }
    00303
    00304   if (pos != (off_t)-1)
    00305     lseek(fd, pos, SEEK_SET);
    00306 }
    00307
    00308 KHTMLPageCacheDelivery::~KHTMLPageCacheDelivery()
    00309 {
    00310   close(fd);
    00311 }
    00312
    00313 #include "khtml_pagecache.moc"

This file is part of the documentation for khtml Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:33:12 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003