attempt to purge low level cache on out of memory during fetch

This commit is contained in:
Vincent Sanders 2014-05-29 14:00:13 +01:00
parent 4acfda898b
commit 644fc616b3
3 changed files with 68 additions and 46 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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