summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2014-05-29 14:00:13 +0100
committerVincent Sanders <vince@kyllikki.org>2014-05-29 14:00:13 +0100
commit644fc616b3b79d7301aeabb3a86910e10a5606d5 (patch)
treedd6bc438f30745e829e67a608524738ec0966149 /content
parent4acfda898b3ddda29e15318b604d3acf32a93b01 (diff)
downloadnetsurf-644fc616b3b79d7301aeabb3a86910e10a5606d5.tar.gz
netsurf-644fc616b3b79d7301aeabb3a86910e10a5606d5.tar.bz2
attempt to purge low level cache on out of memory during fetch
Diffstat (limited to 'content')
-rw-r--r--content/hlcache.c2
-rw-r--r--content/llcache.c102
-rw-r--r--content/llcache.h10
3 files changed, 68 insertions, 46 deletions
diff --git a/content/hlcache.c b/content/hlcache.c
index 23fb79562..e7c4cd84d 100644
--- a/content/hlcache.c
+++ b/content/hlcache.c
@@ -143,7 +143,7 @@ static void hlcache_clean(void *ignored)
}
/* Attempt to clean the llcache */
- llcache_clean();
+ llcache_clean(false);
/* Re-schedule ourselves */
guit->browser->schedule(hlcache->params.bg_clean_time, hlcache_clean, NULL);
diff --git a/content/llcache.c b/content/llcache.c
index 0c9b865d7..13ef77f3b 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -1916,9 +1916,43 @@ static nserror llcache_fetch_notmodified(llcache_object *object,
* \param len Byte length of data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-static nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
- size_t len)
+static nserror
+llcache_fetch_process_data(llcache_object *object,
+ const uint8_t *data,
+ size_t len)
{
+ if (object->fetch.state != LLCACHE_FETCH_DATA) {
+ /* On entry into this state, check if we need to
+ * invalidate the cache control data. We are guaranteed
+ * to have received all response headers.
+ *
+ * There are two cases in which we want to suppress
+ * cacheing of an object:
+ *
+ * 1) The HTTP response code is not 200 or 203
+ * 2) The request URI had a query string and the
+ * response headers did not provide an explicit
+ * object expiration time.
+ */
+ long http_code = fetch_http_code(object->fetch.fetch);
+
+ if ((http_code != 200 && http_code != 203) ||
+ (nsurl_has_component(object->url, NSURL_QUERY) &&
+ (object->cache.max_age == INVALID_AGE &&
+ object->cache.expires == 0))) {
+ /* Invalidate cache control data */
+ llcache_invalidate_cache_control_data(object);
+ }
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+
+ object->fetch.state = LLCACHE_FETCH_DATA;
+ }
+
/* Resize source buffer if it's too small */
if (object->source_len + len >= object->source_alloc) {
const size_t new_len = object->source_len + len + 64 * 1024;
@@ -2310,38 +2344,6 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
/* Normal 2xx state machine */
case FETCH_DATA:
/* Received some data */
- if (object->fetch.state != LLCACHE_FETCH_DATA) {
- /* On entry into this state, check if we need to
- * invalidate the cache control data. We are guaranteed
- * to have received all response headers.
- *
- * There are two cases in which we want to suppress
- * cacheing of an object:
- *
- * 1) The HTTP response code is not 200 or 203
- * 2) The request URI had a query string and the
- * response headers did not provide an explicit
- * object expiration time.
- */
- long http_code = fetch_http_code(object->fetch.fetch);
-
- if ((http_code != 200 && http_code != 203) ||
- (nsurl_has_component(object->url, NSURL_QUERY) &&
- (object->cache.max_age == INVALID_AGE &&
- object->cache.expires == 0))) {
- /* Invalidate cache control data */
- llcache_invalidate_cache_control_data(object);
- }
-
- /* Release candidate, if any */
- if (object->candidate != NULL) {
- object->candidate->candidate_count--;
- object->candidate = NULL;
- }
- }
-
- object->fetch.state = LLCACHE_FETCH_DATA;
-
error = llcache_fetch_process_data(object,
msg->data.header_or_data.buf,
msg->data.header_or_data.len);
@@ -2445,6 +2447,14 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
/* Deal with any errors reported by event handlers */
if (error != NSERROR_OK) {
+ if (error == NSERROR_NOMEM) {
+ /* attempt to purge the cache to free some
+ * memory. will not help this fetch, but may
+ * allow the UI to report errors etc.
+ */
+ llcache_clean(true);
+ }
+
if (object->fetch.fetch != NULL) {
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
@@ -2454,7 +2464,6 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
object->fetch.state = LLCACHE_FETCH_COMPLETE;
}
- return;
}
}
@@ -2821,20 +2830,29 @@ total_object_size(llcache_object *object)
* Public API *
******************************************************************************/
-/**
+/*
* Attempt to clean the cache
*
* The memory cache cleaning discards objects in order of increasing value.
+ *
+ * Exported interface documented in llcache.h
*/
-/* Exported interface documented in llcache.h */
-void llcache_clean(void)
+void llcache_clean(bool purge)
{
llcache_object *object, *next;
uint32_t llcache_size = 0;
int remaining_lifetime;
+ uint32_t limit;
LLCACHE_LOG(("Attempting cache clean"));
+ /* If the cache is being purged set the size limit to zero. */
+ if (purge) {
+ limit = 0;
+ } else {
+ limit = llcache->limit;
+ }
+
/* Uncacheable objects with no users or fetches */
for (object = llcache->uncached_objects;
object != NULL;
@@ -2892,7 +2910,7 @@ void llcache_clean(void)
* persistant so their RAM can be reclaimed in the next
* step
*/
- if (llcache->limit < llcache_size) {
+ if (limit < llcache_size) {
llcache_persist(NULL);
}
@@ -2901,7 +2919,7 @@ void llcache_clean(void)
* cache exceeds the configured size.
*/
for (object = llcache->cached_objects;
- ((llcache->limit < llcache_size) && (object != NULL));
+ ((limit < llcache_size) && (object != NULL));
object = next) {
next = object->next;
if ((object->users == NULL) &&
@@ -2925,7 +2943,7 @@ void llcache_clean(void)
* the configured size. Efectively just the object metadata.
*/
for (object = llcache->cached_objects;
- ((llcache->limit < llcache_size) && (object != NULL));
+ ((limit < llcache_size) && (object != NULL));
object = next) {
next = object->next;
if ((object->users == NULL) &&
@@ -2955,7 +2973,7 @@ void llcache_clean(void)
* fetch
*/
for (object = llcache->cached_objects;
- ((llcache->limit < llcache_size) && (object != NULL));
+ ((limit < llcache_size) && (object != NULL));
object = next) {
next = object->next;
diff --git a/content/llcache.h b/content/llcache.h
index a9ed1861a..4a3521637 100644
--- a/content/llcache.h
+++ b/content/llcache.h
@@ -246,11 +246,15 @@ void llcache_finalise(void);
nserror llcache_poll(void);
/**
- * Cause the low-level cache to attempt to perform cleanup. No
- * guarantees are made as to whether or not cleanups will take
+ * Cause the low-level cache to attempt to perform cleanup.
+ *
+ * No guarantees are made as to whether or not cleanups will take
* place and what, if any, space savings will be made.
+ *
+ * \param purge Any objects held in the cache that are safely removable will
+ * be freed regardless of the configured size limits.
*/
-void llcache_clean(void);
+void llcache_clean(bool purge);
/**
* Retrieve a handle for a low-level cache object