summaryrefslogtreecommitdiff
path: root/source/fitz/store.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-04-25 15:09:00 +0100
committerRobin Watts <robin.watts@artifex.com>2016-04-26 10:54:49 +0100
commit1b16995f277aefda88957e31c00d963fc9a59d7a (patch)
tree0f331f9bafcac86f189fca781a3b48f45a0924a7 /source/fitz/store.c
parentf4a365df3f7709192ec6052832e857d2832ae47f (diff)
downloadmupdf-1b16995f277aefda88957e31c00d963fc9a59d7a.tar.xz
Fix fz_store thinko.
Previously, we would refuse to store any object in the store that was larger than the store limits. We'd also refuse to store any object that took the total store size over the limit. This was wrong. Consider the case where we have a store of 1 byte, and a page that repeatedly uses the same font. The first time we meet the font, we look in the store, it isn't there, we load it, and we try to store it. The current code refuses to store it, and we continue, putting that font into the display list. The next time we meet to the font, we look in the store, it still isn't there, we load it, and we try to store it. Again we refuse to store it, and that copy of the font goes into the display list. The net effect of this is that we end up using far more memory in total than we would have done had we stored the first one. The code here, therefore, changes the store to always store objects regardless of their size. Given that we have already loaded the objects into memory before we store them, this doesn't actually cost us any extra memory. If an object is dropped (bringing the reference count down to 1, being the reference for the stores copy), then the object is NOT freed instantly, but will be freed either on the next attempt to store an object, or on the next scavenging malloc.
Diffstat (limited to 'source/fitz/store.c')
-rw-r--r--source/fitz/store.c37
1 files changed, 11 insertions, 26 deletions
diff --git a/source/fitz/store.c b/source/fitz/store.c
index a71fb94d..c80e1087 100644
--- a/source/fitz/store.c
+++ b/source/fitz/store.c
@@ -223,13 +223,6 @@ fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_
fz_var(item);
- if (store->max != FZ_STORE_UNLIMITED && store->max < itemsize)
- {
- /* Our item would take up more room than we can ever
- * possibly have in the store. Just give up now. */
- return NULL;
- }
-
/* If we fail for any reason, we swallow the exception and continue.
* All that the above program will see is that we failed to store
* the item. */
@@ -306,29 +299,21 @@ fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_
{
/* ensure_space may drop, then retake the lock */
int saved = ensure_space(ctx, size - store->max);
+ size -= saved;
if (saved == 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);
- fz_free(ctx, item);
- type->drop_key(ctx, key);
- if (val->refs > 0)
- val->refs--;
- return NULL;
+ /* We used to 'unstore' it here, but that's wrong.
+ * If we've already spent the memory to malloc it
+ * then not putting it in the store just means that
+ * a resource used multiple times will just be malloced
+ * again. Better to put it in the store, have the
+ * store account for it, and for it to potentially be reused.
+ * When the caller drops the reference to it, it can then
+ * be dropped from the store on the next attempt to store
+ * anything else. */
+ break;
}
- size -= saved;
}
}
store->size += itemsize;