Qt 4.8
qnetworkaccesscache.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qnetworkaccesscache_p.h"
43 #include "QtCore/qpointer.h"
44 #include "QtCore/qdatetime.h"
45 #include "QtCore/qqueue.h"
47 #include "qnetworkreply_p.h"
48 #include "qnetworkrequest.h"
49 
51 
53  ExpiryTime = 120
54 };
55 
56 namespace {
57  struct Receiver
58  {
59  QPointer<QObject> object;
60  const char *member;
61  };
62 }
63 
64 // idea copied from qcache.h
66 {
70 
71  Node *older, *newer;
73 
74  int useCount;
75 
76  Node()
77  : older(0), newer(0), object(0), useCount(0)
78  { }
79 };
80 
82 {
83  // leave the members uninitialized
84  // they must be initialized by the derived class's constructor
85 }
86 
88 {
89 #if 0 //def QT_DEBUG
90  if (!key.isEmpty() && Ptr()->hasEntry(key))
91  qWarning() << "QNetworkAccessCache: object" << (void*)this << "key" << key
92  << "destroyed without being removed from cache first!";
93 #endif
94 }
95 
97 {
98  expires = enable;
99 }
100 
102 {
103  shareable = enable;
104 }
105 
107  : oldest(0), newest(0)
108 {
109 }
110 
112 {
113  clear();
114 }
115 
117 {
118  NodeHash hashCopy = hash;
119  hash.clear();
120 
121  // remove all entries
122  NodeHash::Iterator it = hashCopy.begin();
123  NodeHash::Iterator end = hashCopy.end();
124  for ( ; it != end; ++it) {
125  it->object->key.clear();
126  it->object->dispose();
127  }
128 
129  // now delete:
130  hashCopy.clear();
131 
132  timer.stop();
133 
134  oldest = newest = 0;
135 }
136 
142 {
144  if (it == hash.end())
145  return;
146 
147  Node *const node = &it.value();
148  Q_ASSERT(node != oldest && node != newest);
149  Q_ASSERT(node->older == 0 && node->newer == 0);
150  Q_ASSERT(node->useCount == 0);
151 
152  if (newest) {
153  Q_ASSERT(newest->newer == 0);
154  newest->newer = node;
155  node->older = newest;
156  }
157  if (!oldest) {
158  // there are no entries, so this is the oldest one too
159  oldest = node;
160  }
161 
163  newest = node;
164 }
165 
171 {
173  if (it == hash.end())
174  return false;
175 
176  Node *const node = &it.value();
177 
178  bool wasOldest = false;
179  if (node == oldest) {
180  oldest = node->newer;
181  wasOldest = true;
182  }
183  if (node == newest)
184  newest = node->older;
185  if (node->older)
186  node->older->newer = node->newer;
187  if (node->newer)
188  node->newer->older = node->older;
189 
190  node->newer = node->older = 0;
191  return wasOldest;
192 }
193 
195 {
196  timer.stop();
197 
198  if (!oldest)
199  return;
200 
202  if (interval <= 0) {
203  interval = 0;
204  } else {
205  // round up the interval
206  interval = (interval + 15) & ~16;
207  }
208 
209  timer.start(interval * 1000, this);
210 }
211 
212 bool QNetworkAccessCache::emitEntryReady(Node *node, QObject *target, const char *member)
213 {
215  target, member, Qt::QueuedConnection))
216  return false;
217 
218  emit entryReady(node->object);
220 
221  return true;
222 }
223 
225 {
226  // expire old items
228 
229  while (oldest && oldest->timestamp < now) {
230  Node *next = oldest->newer;
231  oldest->object->dispose();
232 
233  hash.remove(oldest->key); // oldest gets deleted
234  oldest = next;
235  }
236 
237  // fixup the list
238  if (oldest)
239  oldest->older = 0;
240  else
241  newest = 0;
242 
243  updateTimer();
244 }
245 
247 {
248  Q_ASSERT(!key.isEmpty());
249 
250  if (unlinkEntry(key))
251  updateTimer();
252 
253  Node &node = hash[key]; // create the entry in the hash if it didn't exist
254  if (node.useCount)
255  qWarning("QNetworkAccessCache::addEntry: overriding active cache entry '%s'",
256  key.constData());
257  if (node.object)
258  node.object->dispose();
259  node.object = entry;
260  node.object->key = key;
261  node.key = key;
262  node.useCount = 1;
263 }
264 
266 {
267  return hash.contains(key);
268 }
269 
270 bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, const char *member)
271 {
273  if (it == hash.end())
274  return false; // no such entry
275 
276  Node *node = &it.value();
277 
278  if (node->useCount > 0 && !node->object->shareable) {
279  // object is not shareable and is in use
280  // queue for later use
281  Q_ASSERT(node->older == 0 && node->newer == 0);
282  Receiver receiver;
283  receiver.object = target;
284  receiver.member = member;
285  node->receiverQueue.enqueue(receiver);
286 
287  // request queued
288  return true;
289  } else {
290  // node not in use or is shareable
291  if (unlinkEntry(key))
292  updateTimer();
293 
294  ++node->useCount;
295  return emitEntryReady(node, target, member);
296  }
297 }
298 
300 {
302  if (it == hash.end())
303  return 0;
304  if (it->useCount > 0) {
305  if (it->object->shareable) {
306  ++it->useCount;
307  return it->object;
308  }
309 
310  // object in use and not shareable
311  return 0;
312  }
313 
314  // entry not in use, let the caller have it
315  bool wasOldest = unlinkEntry(key);
316  ++it->useCount;
317 
318  if (wasOldest)
319  updateTimer();
320  return it->object;
321 }
322 
324 {
326  if (it == hash.end()) {
327  qWarning("QNetworkAccessCache::releaseEntry: trying to release key '%s' that is not in cache",
328  key.constData());
329  return;
330  }
331 
332  Node *node = &it.value();
333  Q_ASSERT(node->useCount > 0);
334 
335  // are there other objects waiting?
336  if (!node->receiverQueue.isEmpty()) {
337  // queue another activation
338  Receiver receiver;
339  do {
340  receiver = node->receiverQueue.dequeue();
341  } while (receiver.object.isNull() && !node->receiverQueue.isEmpty());
342 
343  if (!receiver.object.isNull()) {
344  emitEntryReady(node, receiver.object, receiver.member);
345  return;
346  }
347  }
348 
349  if (!--node->useCount) {
350  // no objects waiting; add it back to the expiry list
351  if (node->object->expires)
352  linkEntry(key);
353 
354  if (oldest == node)
355  updateTimer();
356  }
357 }
358 
360 {
362  if (it == hash.end()) {
363  qWarning("QNetworkAccessCache::removeEntry: trying to remove key '%s' that is not in cache",
364  key.constData());
365  return;
366  }
367 
368  Node *node = &it.value();
369  if (unlinkEntry(key))
370  updateTimer();
371  if (node->useCount > 1)
372  qWarning("QNetworkAccessCache::removeEntry: removing active cache entry '%s'",
373  key.constData());
374 
375  node->object->key.clear();
376  hash.remove(node->key);
377 }
378 
QDateTime addSecs(int secs) const
Returns a QDateTime object containing a datetime s seconds later than the datetime of this object (or...
Definition: qdatetime.cpp:2869
bool requestEntry(const QByteArray &key, QObject *target, const char *member)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void timerEvent(QTimerEvent *)
This event handler can be reimplemented in a subclass to receive timer events for the object...
void clear()
Removes all items from the hash.
Definition: qhash.h:574
int remove(const Key &key)
Removes all the items that have the key from the hash.
Definition: qhash.h:784
#define it(className, varName)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void entryReady(QNetworkAccessCache::CacheableObject *)
CacheableObject * requestEntryNow(const QByteArray &key)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
QQueue< Receiver > receiverQueue
#define SIGNAL(a)
Definition: qobjectdefs.h:227
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void addEntry(const QByteArray &key, CacheableObject *entry)
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
#define emit
Definition: qobjectdefs.h:76
int secsTo(const QDateTime &) const
Returns the number of seconds from this datetime to the other datetime.
Definition: qdatetime.cpp:2914
Q_CORE_EXPORT void qWarning(const char *,...)
bool unlinkEntry(const QByteArray &key)
Removes the entry pointed by key from the linked list.
bool emitEntryReady(Node *node, QObject *target, const char *member)
void stop()
Stops the timer.
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition: qqueue.h:60
bool hasEntry(const QByteArray &key) const
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:467
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
void linkEntry(const QByteArray &key)
Appens the entry given by key to the end of the linked list.
int key
static QDateTime currentDateTime()
Returns the current datetime, as reported by the system clock, in the local time zone.
Definition: qdatetime.cpp:3138
iterator begin()
Returns an STL-style iterator pointing to the first item in the hash.
Definition: qhash.h:464
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
void releaseEntry(const QByteArray &key)
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition: qhash.h:865
T dequeue()
Removes the head item in the queue and returns it.
Definition: qqueue.h:61
static const KeyPair *const end
void removeEntry(const QByteArray &key)
void clear()
Clears the contents of the byte array and makes it empty.
iterator Iterator
Qt-style synonym for QHash::iterator.
Definition: qhash.h:473
void start(int msec, QObject *obj)
Starts (or restarts) the timer with a msec milliseconds timeout.