diff options
Diffstat (limited to 'fitz')
-rw-r--r-- | fitz/base_hash.c | 19 | ||||
-rw-r--r-- | fitz/fitz-internal.h | 2 | ||||
-rw-r--r-- | fitz/res_store.c | 100 |
3 files changed, 81 insertions, 40 deletions
diff --git a/fitz/base_hash.c b/fitz/base_hash.c index 037988cb..1da8cac9 100644 --- a/fitz/base_hash.c +++ b/fitz/base_hash.c @@ -311,11 +311,11 @@ fz_hash_remove_fast(fz_context *ctx, fz_hash_table *table, void *key, unsigned p { fz_hash_entry *ents = table->ents; - if (memcmp(key, ents[pos].key, table->keylen) != 0) + if (ents[pos].val == NULL || memcmp(key, ents[pos].key, table->keylen) != 0) { - /* The key didn't match! The table must have been rebuilt - * (or the contents moved) in the meantime. Do the removal - * the slow way. */ + /* The value isn't there, or the key didn't match! The table + * must have been rebuilt (or the contents moved) in the + * meantime. Do the removal the slow way. */ fz_hash_remove(ctx, table, key); } else @@ -326,6 +326,12 @@ fz_hash_remove_fast(fz_context *ctx, fz_hash_table *table, void *key, unsigned p void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table) { + fz_print_hash_details(ctx, out, table, NULL); +} + +void +fz_print_hash_details(fz_context *ctx, FILE *out, fz_hash_table *table, void (*details)(FILE *,void*)) +{ int i, k; fprintf(out, "cache load %d / %d\n", table->load, table->size); @@ -339,7 +345,10 @@ fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table) fprintf(out, "table % 4d: key=", i); for (k = 0; k < MAX_KEY_LEN; k++) fprintf(out, "%02x", ((char*)table->ents[i].key)[k]); - fprintf(out, " val=$%p\n", table->ents[i].val); + if (details) + details(out, table->ents[i].val); + else + fprintf(out, " val=$%p\n", table->ents[i].val); } } } diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index 7193301a..bf7d2873 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -271,6 +271,7 @@ void *fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx); #ifndef NDEBUG void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table); +void fz_print_hash_details(fz_context *ctx, FILE *out, fz_hash_table *table, void (*details)(FILE *, void *)); #endif /* @@ -587,6 +588,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase); */ #ifndef NDEBUG void fz_print_store(fz_context *ctx, FILE *out); +void fz_print_store_locked(fz_context *ctx, FILE *out); #endif struct fz_buffer_s 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 |