diff options
Diffstat (limited to 'fitz/res_store.c')
-rw-r--r-- | fitz/res_store.c | 100 |
1 files changed, 65 insertions, 35 deletions
diff --git a/fitz/res_store.c b/fitz/res_store.c index 93a7c6e3..bfe7eedb 100644 --- a/fitz/res_store.c +++ b/fitz/res_store.c @@ -188,6 +188,31 @@ ensure_space(fz_context *ctx, unsigned int tofree) return count; } +static void +touch(fz_store *store, fz_item *item) +{ + if (item->next != item) + { + /* Already in the list - unlink it */ + if (item->next) + item->next->prev = item->prev; + else + store->tail = item->prev; + if (item->prev) + item->prev->next = item->next; + else + store->head = item->next; + } + /* Now relink it at the start of the LRU chain */ + item->next = store->head; + if (item->next) + item->next->prev = item; + else + store->tail = item; + store->head = item; + item->prev = NULL; +} + void * fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_store_type *type) { @@ -256,6 +281,8 @@ fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_ } fz_catch(ctx) { + /* Any error here means that item never made it into the + * hash - so no one else can have a reference. */ fz_unlock(ctx, FZ_LOCK_ALLOC); fz_free(ctx, item); type->drop_key(ctx, key); @@ -265,6 +292,7 @@ fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_ { /* There was one there already! Take a new reference * to the existing one, and drop our current one. */ + touch(store, existing); if (existing->val->refs > 0) existing->val->refs++; fz_unlock(ctx, FZ_LOCK_ALLOC); @@ -286,8 +314,16 @@ fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_ if (ensure_space(ctx, size - store->max) == 0) { /* Failed to free any space. */ + /* If we are using the hash table, then we've already + * inserted item - remove it. */ if (use_hash) { + /* If someone else has already picked up a reference + * to item, then we cannot remove it. Leave it in the + * store, and we'll live with being over budget. We + * know this is the case, if it's in the linked list. */ + if (item->next != item) + break; fz_hash_remove_fast(ctx, store->hash, &hash, pos); } fz_unlock(ctx, FZ_LOCK_ALLOC); @@ -302,13 +338,7 @@ fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_ store->size += itemsize; /* Regardless of whether it's indexed, it goes into the linked list */ - item->next = store->head; - if (item->next) - item->next->prev = item; - else - store->tail = item; - store->head = item; - item->prev = NULL; + touch(store, item); fz_unlock(ctx, FZ_LOCK_ALLOC); return NULL; @@ -351,31 +381,11 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type * } if (item) { - /* Momentarily things can be in the hash table (and hence can - * be found) without being in the list. Don't attempt to LRU - * these. We indicate such items by setting - * item->next == item. */ - if (item->next != item) - { - /* LRU: Move the block to the front */ - /* Unlink from present position */ - if (item->next) - item->next->prev = item->prev; - else - store->tail = item->prev; - if (item->prev) - item->prev->next = item->next; - else - store->head = item->next; - /* Insert at head */ - item->next = store->head; - if (item->next) - item->next->prev = item; - else - store->tail = item; - item->prev = NULL; - store->head = item; - } + /* LRU the block. This also serves to ensure that any item + * picked up from the hash before it has made it into the + * linked list does not get whipped out again due to the + * store being full. */ + touch(store, item); /* And bump the refcount before returning */ if (item->val->refs > 0) item->val->refs++; @@ -491,15 +501,23 @@ fz_drop_store_context(fz_context *ctx) } #ifndef NDEBUG +static void +print_item(FILE *out, void *item_) +{ + fz_item *item = (fz_item *)item_; + fprintf(out, " val=%p item=%p\n", item->val, item); + fflush(out); +} + void -fz_print_store(fz_context *ctx, FILE *out) +fz_print_store_locked(fz_context *ctx, FILE *out) { fz_item *item, *next; fz_store *store = ctx->store; fprintf(out, "-- resource store contents --\n"); + fflush(out); - fz_lock(ctx, FZ_LOCK_ALLOC); for (item = store->head; item; item = next) { next = item->next; @@ -509,10 +527,22 @@ fz_print_store(fz_context *ctx, FILE *out) fz_unlock(ctx, FZ_LOCK_ALLOC); item->type->debug(out, item->key); fprintf(out, " = %p\n", item->val); + fflush(out); fz_lock(ctx, FZ_LOCK_ALLOC); if (next) next->val->refs--; } + fprintf(out, "-- resource store hash contents --\n"); + fz_print_hash_details(ctx, out, store->hash, print_item); + fprintf(out, "-- end --\n"); + fflush(out); +} + +void +fz_print_store(fz_context *ctx, FILE *out) +{ + fz_lock(ctx, FZ_LOCK_ALLOC); + fz_print_store_locked(ctx, out); fz_unlock(ctx, FZ_LOCK_ALLOC); } #endif @@ -561,7 +591,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase) #ifdef DEBUG_SCAVENGING printf("Scavenging: store=%d size=%d phase=%d\n", store->size, size, *phase); - fz_print_store(ctx, stderr); + fz_print_store_locked(ctx, stderr); Memento_stats(); #endif do |