store.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include <assert.h>
  24. #include <limits.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. typedef struct fz_item
  28. {
  29. void *key;
  30. fz_storable *val;
  31. size_t size;
  32. struct fz_item *next;
  33. struct fz_item *prev;
  34. fz_store *store;
  35. const fz_store_type *type;
  36. } fz_item;
  37. /* Every entry in fz_store is protected by the alloc lock */
  38. struct fz_store
  39. {
  40. int refs;
  41. /* Every item in the store is kept in a doubly linked list, ordered
  42. * by usage (so LRU entries are at the end). */
  43. fz_item *head;
  44. fz_item *tail;
  45. /* We have a hash table that allows to quickly find a subset of the
  46. * entries (those whose keys are indirect objects). */
  47. fz_hash_table *hash;
  48. /* We keep track of the size of the store, and keep it below max. */
  49. size_t max;
  50. size_t size;
  51. int defer_reap_count;
  52. int needs_reaping;
  53. int scavenging;
  54. };
  55. void
  56. fz_new_store_context(fz_context *ctx, size_t max)
  57. {
  58. fz_store *store;
  59. store = fz_malloc_struct(ctx, fz_store);
  60. fz_try(ctx)
  61. {
  62. store->hash = fz_new_hash_table(ctx, 4096, sizeof(fz_store_hash), FZ_LOCK_ALLOC, NULL);
  63. }
  64. fz_catch(ctx)
  65. {
  66. fz_free(ctx, store);
  67. fz_rethrow(ctx);
  68. }
  69. store->refs = 1;
  70. store->head = NULL;
  71. store->tail = NULL;
  72. store->size = 0;
  73. store->max = max;
  74. store->defer_reap_count = 0;
  75. store->needs_reaping = 0;
  76. ctx->store = store;
  77. }
  78. void *
  79. fz_keep_storable(fz_context *ctx, const fz_storable *sc)
  80. {
  81. /* Explicitly drop const to allow us to use const
  82. * sanely throughout the code. */
  83. fz_storable *s = (fz_storable *)sc;
  84. return fz_keep_imp(ctx, s, &s->refs);
  85. }
  86. void *fz_keep_key_storable(fz_context *ctx, const fz_key_storable *sc)
  87. {
  88. return fz_keep_storable(ctx, &sc->storable);
  89. }
  90. /*
  91. Entered with FZ_LOCK_ALLOC held.
  92. Drops FZ_LOCK_ALLOC.
  93. */
  94. static void
  95. do_reap(fz_context *ctx)
  96. {
  97. fz_store *store = ctx->store;
  98. fz_item *item, *prev, *remove;
  99. if (store == NULL)
  100. {
  101. fz_unlock(ctx, FZ_LOCK_ALLOC);
  102. return;
  103. }
  104. fz_assert_lock_held(ctx, FZ_LOCK_ALLOC);
  105. ctx->store->needs_reaping = 0;
  106. FZ_LOG_DUMP_STORE(ctx, "Before reaping store:\n");
  107. /* Reap the items */
  108. remove = NULL;
  109. for (item = store->tail; item; item = prev)
  110. {
  111. prev = item->prev;
  112. if (item->type->needs_reap == NULL || item->type->needs_reap(ctx, item->key) == 0)
  113. continue;
  114. /* We have to drop it */
  115. store->size -= item->size;
  116. /* Unlink from the linked list */
  117. if (item->next)
  118. item->next->prev = item->prev;
  119. else
  120. store->tail = item->prev;
  121. if (item->prev)
  122. item->prev->next = item->next;
  123. else
  124. store->head = item->next;
  125. /* Remove from the hash table */
  126. if (item->type->make_hash_key)
  127. {
  128. fz_store_hash hash = { NULL };
  129. hash.drop = item->val->drop;
  130. if (item->type->make_hash_key(ctx, &hash, item->key))
  131. fz_hash_remove(ctx, store->hash, &hash);
  132. }
  133. /* Store whether to drop this value or not in 'prev' */
  134. if (item->val->refs > 0)
  135. (void)Memento_dropRef(item->val);
  136. item->prev = (item->val->refs > 0 && --item->val->refs == 0) ? item : NULL;
  137. /* Store it in our removal chain - just singly linked */
  138. item->next = remove;
  139. remove = item;
  140. }
  141. fz_unlock(ctx, FZ_LOCK_ALLOC);
  142. /* Now drop the remove chain */
  143. for (item = remove; item != NULL; item = remove)
  144. {
  145. remove = item->next;
  146. /* Drop a reference to the value (freeing if required) */
  147. if (item->prev)
  148. item->val->drop(ctx, item->val);
  149. /* Always drops the key and drop the item */
  150. item->type->drop_key(ctx, item->key);
  151. fz_free(ctx, item);
  152. }
  153. FZ_LOG_DUMP_STORE(ctx, "After reaping store:\n");
  154. }
  155. void fz_drop_key_storable(fz_context *ctx, const fz_key_storable *sc)
  156. {
  157. /* Explicitly drop const to allow us to use const
  158. * sanely throughout the code. */
  159. fz_key_storable *s = (fz_key_storable *)sc;
  160. int drop;
  161. int unlock = 1;
  162. if (s == NULL)
  163. return;
  164. fz_lock(ctx, FZ_LOCK_ALLOC);
  165. assert(s->storable.refs != 0);
  166. if (s->storable.refs > 0)
  167. {
  168. (void)Memento_dropRef(s);
  169. drop = --s->storable.refs == 0;
  170. if (!drop && s->storable.refs == s->store_key_refs)
  171. {
  172. if (ctx->store->defer_reap_count > 0)
  173. {
  174. ctx->store->needs_reaping = 1;
  175. }
  176. else
  177. {
  178. do_reap(ctx);
  179. unlock = 0;
  180. }
  181. }
  182. }
  183. else
  184. drop = 0;
  185. if (unlock)
  186. fz_unlock(ctx, FZ_LOCK_ALLOC);
  187. /*
  188. If we are dropping the last reference to an object, then
  189. it cannot possibly be in the store (as the store always
  190. keeps a ref to everything in it, and doesn't drop via
  191. this method. So we can simply drop the storable object
  192. itself without any operations on the fz_store.
  193. */
  194. if (drop)
  195. s->storable.drop(ctx, &s->storable);
  196. }
  197. void *fz_keep_key_storable_key(fz_context *ctx, const fz_key_storable *sc)
  198. {
  199. /* Explicitly drop const to allow us to use const
  200. * sanely throughout the code. */
  201. fz_key_storable *s = (fz_key_storable *)sc;
  202. if (s == NULL)
  203. return NULL;
  204. fz_lock(ctx, FZ_LOCK_ALLOC);
  205. if (s->storable.refs > 0)
  206. {
  207. (void)Memento_takeRef(s);
  208. ++s->storable.refs;
  209. ++s->store_key_refs;
  210. }
  211. fz_unlock(ctx, FZ_LOCK_ALLOC);
  212. return s;
  213. }
  214. void fz_drop_key_storable_key(fz_context *ctx, const fz_key_storable *sc)
  215. {
  216. /* Explicitly drop const to allow us to use const
  217. * sanely throughout the code. */
  218. fz_key_storable *s = (fz_key_storable *)sc;
  219. int drop;
  220. if (s == NULL)
  221. return;
  222. fz_lock(ctx, FZ_LOCK_ALLOC);
  223. assert(s->store_key_refs > 0 && s->storable.refs >= s->store_key_refs);
  224. (void)Memento_dropRef(s);
  225. drop = --s->storable.refs == 0;
  226. --s->store_key_refs;
  227. fz_unlock(ctx, FZ_LOCK_ALLOC);
  228. /*
  229. If we are dropping the last reference to an object, then
  230. it cannot possibly be in the store (as the store always
  231. keeps a ref to everything in it, and doesn't drop via
  232. this method. So we can simply drop the storable object
  233. itself without any operations on the fz_store.
  234. */
  235. if (drop)
  236. s->storable.drop(ctx, &s->storable);
  237. }
  238. static void
  239. evict(fz_context *ctx, fz_item *item)
  240. {
  241. fz_store *store = ctx->store;
  242. int drop;
  243. store->size -= item->size;
  244. /* Unlink from the linked list */
  245. if (item->next)
  246. item->next->prev = item->prev;
  247. else
  248. store->tail = item->prev;
  249. if (item->prev)
  250. item->prev->next = item->next;
  251. else
  252. store->head = item->next;
  253. /* Drop a reference to the value (freeing if required) */
  254. if (item->val->refs > 0)
  255. (void)Memento_dropRef(item->val);
  256. drop = (item->val->refs > 0 && --item->val->refs == 0);
  257. /* Remove from the hash table */
  258. if (item->type->make_hash_key)
  259. {
  260. fz_store_hash hash = { NULL };
  261. hash.drop = item->val->drop;
  262. if (item->type->make_hash_key(ctx, &hash, item->key))
  263. fz_hash_remove(ctx, store->hash, &hash);
  264. }
  265. fz_unlock(ctx, FZ_LOCK_ALLOC);
  266. if (drop)
  267. item->val->drop(ctx, item->val);
  268. /* Always drops the key and drop the item */
  269. item->type->drop_key(ctx, item->key);
  270. fz_free(ctx, item);
  271. fz_lock(ctx, FZ_LOCK_ALLOC);
  272. }
  273. static size_t
  274. ensure_space(fz_context *ctx, size_t tofree)
  275. {
  276. fz_item *item, *prev;
  277. size_t count;
  278. fz_store *store = ctx->store;
  279. fz_item *to_be_freed = NULL;
  280. fz_assert_lock_held(ctx, FZ_LOCK_ALLOC);
  281. /* First check that we *can* free tofree; if not, we'd rather not
  282. * cache this. */
  283. count = 0;
  284. for (item = store->tail; item; item = item->prev)
  285. {
  286. if (item->val->refs == 1)
  287. {
  288. count += item->size;
  289. if (count >= tofree)
  290. break;
  291. }
  292. }
  293. /* If we ran out of items to search, then we can never free enough */
  294. if (item == NULL)
  295. {
  296. return 0;
  297. }
  298. /* Now move all the items to be freed onto 'to_be_freed' */
  299. count = 0;
  300. for (item = store->tail; item; item = prev)
  301. {
  302. prev = item->prev;
  303. if (item->val->refs != 1)
  304. continue;
  305. store->size -= item->size;
  306. /* Unlink from the linked list */
  307. if (item->next)
  308. item->next->prev = item->prev;
  309. else
  310. store->tail = item->prev;
  311. if (item->prev)
  312. item->prev->next = item->next;
  313. else
  314. store->head = item->next;
  315. /* Remove from the hash table */
  316. if (item->type->make_hash_key)
  317. {
  318. fz_store_hash hash = { NULL };
  319. hash.drop = item->val->drop;
  320. if (item->type->make_hash_key(ctx, &hash, item->key))
  321. fz_hash_remove(ctx, store->hash, &hash);
  322. }
  323. /* Link into to_be_freed */
  324. item->next = to_be_freed;
  325. to_be_freed = item;
  326. count += item->size;
  327. if (count >= tofree)
  328. break;
  329. }
  330. /* Now we can safely drop the lock and free our pending items. These
  331. * have all been removed from both the store list, and the hash table,
  332. * so they can't be 'found' by anyone else in the meantime. */
  333. while (to_be_freed)
  334. {
  335. int drop;
  336. item = to_be_freed;
  337. to_be_freed = to_be_freed->next;
  338. /* Drop a reference to the value (freeing if required) */
  339. if (item->val->refs > 0)
  340. (void)Memento_dropRef(item->val);
  341. drop = (item->val->refs > 0 && --item->val->refs == 0);
  342. fz_unlock(ctx, FZ_LOCK_ALLOC);
  343. if (drop)
  344. item->val->drop(ctx, item->val);
  345. /* Always drops the key and drop the item */
  346. item->type->drop_key(ctx, item->key);
  347. fz_free(ctx, item);
  348. fz_lock(ctx, FZ_LOCK_ALLOC);
  349. }
  350. return count;
  351. }
  352. static void
  353. touch(fz_store *store, fz_item *item)
  354. {
  355. if (item->next != item)
  356. {
  357. /* Already in the list - unlink it */
  358. if (item->next)
  359. item->next->prev = item->prev;
  360. else
  361. store->tail = item->prev;
  362. if (item->prev)
  363. item->prev->next = item->next;
  364. else
  365. store->head = item->next;
  366. }
  367. /* Now relink it at the start of the LRU chain */
  368. item->next = store->head;
  369. if (item->next)
  370. item->next->prev = item;
  371. else
  372. store->tail = item;
  373. store->head = item;
  374. item->prev = NULL;
  375. }
  376. void *
  377. fz_store_item(fz_context *ctx, void *key, void *val_, size_t itemsize, const fz_store_type *type)
  378. {
  379. fz_item *item = NULL;
  380. size_t size;
  381. fz_storable *val = (fz_storable *)val_;
  382. fz_store *store = ctx->store;
  383. fz_store_hash hash = { NULL };
  384. int use_hash = 0;
  385. if (!store)
  386. return NULL;
  387. /* If we fail for any reason, we swallow the exception and continue.
  388. * All that the above program will see is that we failed to store
  389. * the item. */
  390. item = Memento_label(fz_malloc_no_throw(ctx, sizeof (fz_item)), "fz_item");
  391. if (!item)
  392. return NULL;
  393. memset(item, 0, sizeof (fz_item));
  394. if (type->make_hash_key)
  395. {
  396. hash.drop = val->drop;
  397. use_hash = type->make_hash_key(ctx, &hash, key);
  398. }
  399. type->keep_key(ctx, key);
  400. fz_lock(ctx, FZ_LOCK_ALLOC);
  401. /* Fill out the item. To start with, we always set item->next == item
  402. * and item->prev == item. This is so that we can spot items that have
  403. * been put into the hash table without having made it into the linked
  404. * list yet. */
  405. item->key = key;
  406. item->val = val;
  407. item->size = itemsize;
  408. item->next = item;
  409. item->prev = item;
  410. item->type = type;
  411. /* If we can index it fast, put it into the hash table. This serves
  412. * to check whether we have one there already. */
  413. if (use_hash)
  414. {
  415. fz_item *existing = NULL;
  416. fz_try(ctx)
  417. {
  418. /* May drop and retake the lock */
  419. existing = fz_hash_insert(ctx, store->hash, &hash, item);
  420. }
  421. fz_catch(ctx)
  422. {
  423. /* Any error here means that item never made it into the
  424. * hash - so no one else can have a reference. */
  425. fz_unlock(ctx, FZ_LOCK_ALLOC);
  426. fz_free(ctx, item);
  427. type->drop_key(ctx, key);
  428. return NULL;
  429. }
  430. if (existing)
  431. {
  432. /* There was one there already! Take a new reference
  433. * to the existing one, and drop our current one. */
  434. fz_warn(ctx, "found duplicate %s in the store", type->name);
  435. touch(store, existing);
  436. if (existing->val->refs > 0)
  437. {
  438. (void)Memento_takeRef(existing->val);
  439. existing->val->refs++;
  440. }
  441. fz_unlock(ctx, FZ_LOCK_ALLOC);
  442. fz_free(ctx, item);
  443. type->drop_key(ctx, key);
  444. return existing->val;
  445. }
  446. }
  447. /* Now bump the ref */
  448. if (val->refs > 0)
  449. {
  450. (void)Memento_takeRef(val);
  451. val->refs++;
  452. }
  453. /* If we haven't got an infinite store, check for space within it */
  454. if (store->max != FZ_STORE_UNLIMITED)
  455. {
  456. /* FIXME: Overflow? */
  457. size = store->size + itemsize;
  458. if (size > store->max)
  459. {
  460. FZ_LOG_STORE(ctx, "Store size exceeded: item=%zu, size=%zu, max=%zu\n",
  461. itemsize, store->size, store->max);
  462. while (size > store->max)
  463. {
  464. size_t saved;
  465. /* First, do any outstanding reaping, even if defer_reap_count > 0 */
  466. if (store->needs_reaping)
  467. {
  468. do_reap(ctx); /* Drops alloc lock */
  469. fz_lock(ctx, FZ_LOCK_ALLOC);
  470. }
  471. size = store->size + itemsize;
  472. if (size <= store->max)
  473. break;
  474. /* ensure_space may drop, then retake the lock */
  475. saved = ensure_space(ctx, size - store->max);
  476. size -= saved;
  477. if (saved == 0)
  478. {
  479. /* Failed to free any space. */
  480. /* We used to 'unstore' it here, but that's wrong.
  481. * If we've already spent the memory to malloc it
  482. * then not putting it in the store just means that
  483. * a resource used multiple times will just be malloced
  484. * again. Better to put it in the store, have the
  485. * store account for it, and for it to potentially be reused.
  486. * When the caller drops the reference to it, it can then
  487. * be dropped from the store on the next attempt to store
  488. * anything else. */
  489. break;
  490. }
  491. }
  492. FZ_LOG_DUMP_STORE(ctx, "After eviction:\n");
  493. }
  494. }
  495. store->size += itemsize;
  496. /* Regardless of whether it's indexed, it goes into the linked list */
  497. touch(store, item);
  498. fz_unlock(ctx, FZ_LOCK_ALLOC);
  499. return NULL;
  500. }
  501. void *
  502. fz_find_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_store_type *type)
  503. {
  504. fz_item *item;
  505. fz_store *store = ctx->store;
  506. fz_store_hash hash = { NULL };
  507. int use_hash = 0;
  508. if (!store)
  509. return NULL;
  510. if (!key)
  511. return NULL;
  512. if (type->make_hash_key)
  513. {
  514. hash.drop = drop;
  515. use_hash = type->make_hash_key(ctx, &hash, key);
  516. }
  517. fz_lock(ctx, FZ_LOCK_ALLOC);
  518. if (use_hash)
  519. {
  520. /* We can find objects keyed on indirected objects quickly */
  521. item = fz_hash_find(ctx, store->hash, &hash);
  522. }
  523. else
  524. {
  525. /* Others we have to hunt for slowly */
  526. for (item = store->head; item; item = item->next)
  527. {
  528. if (item->val->drop == drop && !type->cmp_key(ctx, item->key, key))
  529. break;
  530. }
  531. }
  532. if (item)
  533. {
  534. /* LRU the block. This also serves to ensure that any item
  535. * picked up from the hash before it has made it into the
  536. * linked list does not get whipped out again due to the
  537. * store being full. */
  538. touch(store, item);
  539. /* And bump the refcount before returning */
  540. if (item->val->refs > 0)
  541. {
  542. (void)Memento_takeRef(item->val);
  543. item->val->refs++;
  544. }
  545. fz_unlock(ctx, FZ_LOCK_ALLOC);
  546. return (void *)item->val;
  547. }
  548. fz_unlock(ctx, FZ_LOCK_ALLOC);
  549. return NULL;
  550. }
  551. void
  552. fz_remove_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_store_type *type)
  553. {
  554. fz_item *item;
  555. fz_store *store = ctx->store;
  556. int dodrop;
  557. fz_store_hash hash = { NULL };
  558. int use_hash = 0;
  559. if (type->make_hash_key)
  560. {
  561. hash.drop = drop;
  562. use_hash = type->make_hash_key(ctx, &hash, key);
  563. }
  564. fz_lock(ctx, FZ_LOCK_ALLOC);
  565. if (use_hash)
  566. {
  567. /* We can find objects keyed on indirect objects quickly */
  568. item = fz_hash_find(ctx, store->hash, &hash);
  569. if (item)
  570. fz_hash_remove(ctx, store->hash, &hash);
  571. }
  572. else
  573. {
  574. /* Others we have to hunt for slowly */
  575. for (item = store->head; item; item = item->next)
  576. if (item->val->drop == drop && !type->cmp_key(ctx, item->key, key))
  577. break;
  578. }
  579. if (item)
  580. {
  581. /* Momentarily things can be in the hash table without being
  582. * in the list. Don't attempt to unlink these. We indicate
  583. * such items by setting item->next == item. */
  584. if (item->next != item)
  585. {
  586. if (item->next)
  587. item->next->prev = item->prev;
  588. else
  589. store->tail = item->prev;
  590. if (item->prev)
  591. item->prev->next = item->next;
  592. else
  593. store->head = item->next;
  594. }
  595. if (item->val->refs > 0)
  596. (void)Memento_dropRef(item->val);
  597. dodrop = (item->val->refs > 0 && --item->val->refs == 0);
  598. fz_unlock(ctx, FZ_LOCK_ALLOC);
  599. if (dodrop)
  600. item->val->drop(ctx, item->val);
  601. type->drop_key(ctx, item->key);
  602. fz_free(ctx, item);
  603. }
  604. else
  605. fz_unlock(ctx, FZ_LOCK_ALLOC);
  606. }
  607. void
  608. fz_empty_store(fz_context *ctx)
  609. {
  610. fz_store *store = ctx->store;
  611. if (store == NULL)
  612. return;
  613. fz_lock(ctx, FZ_LOCK_ALLOC);
  614. /* Run through all the items in the store */
  615. while (store->head)
  616. evict(ctx, store->head); /* Drops then retakes lock */
  617. fz_unlock(ctx, FZ_LOCK_ALLOC);
  618. }
  619. fz_store *
  620. fz_keep_store_context(fz_context *ctx)
  621. {
  622. if (ctx == NULL || ctx->store == NULL)
  623. return NULL;
  624. return fz_keep_imp(ctx, ctx->store, &ctx->store->refs);
  625. }
  626. void
  627. fz_drop_store_context(fz_context *ctx)
  628. {
  629. if (!ctx)
  630. return;
  631. if (fz_drop_imp(ctx, ctx->store, &ctx->store->refs))
  632. {
  633. fz_empty_store(ctx);
  634. fz_drop_hash_table(ctx, ctx->store->hash);
  635. fz_free(ctx, ctx->store);
  636. ctx->store = NULL;
  637. }
  638. }
  639. static void
  640. fz_debug_store_item(fz_context *ctx, void *state, void *key_, int keylen, void *item_)
  641. {
  642. unsigned char *key = key_;
  643. fz_item *item = item_;
  644. int i;
  645. char buf[256];
  646. fz_output *out = (fz_output *)state;
  647. fz_unlock(ctx, FZ_LOCK_ALLOC);
  648. item->type->format_key(ctx, buf, sizeof buf, item->key);
  649. fz_lock(ctx, FZ_LOCK_ALLOC);
  650. fz_write_printf(ctx, out, "STORE\thash[");
  651. for (i=0; i < keylen; ++i)
  652. fz_write_printf(ctx, out,"%02x", key[i]);
  653. fz_write_printf(ctx, out, "][refs=%d][size=%d] key=%s val=%p\n", item->val->refs, (int)item->size, buf, (void *)item->val);
  654. }
  655. static void
  656. fz_debug_store_locked(fz_context *ctx, fz_output *out)
  657. {
  658. fz_item *item, *next;
  659. char buf[256];
  660. fz_store *store = ctx->store;
  661. size_t list_total = 0;
  662. fz_write_printf(ctx, out, "STORE\t-- resource store contents --\n");
  663. for (item = store->head; item; item = next)
  664. {
  665. next = item->next;
  666. if (next)
  667. {
  668. (void)Memento_takeRef(next->val);
  669. next->val->refs++;
  670. }
  671. fz_unlock(ctx, FZ_LOCK_ALLOC);
  672. item->type->format_key(ctx, buf, sizeof buf, item->key);
  673. fz_lock(ctx, FZ_LOCK_ALLOC);
  674. fz_write_printf(ctx, out, "STORE\tstore[*][refs=%d][size=%d] key=%s val=%p\n",
  675. item->val->refs, (int)item->size, buf, (void *)item->val);
  676. list_total += item->size;
  677. if (next)
  678. {
  679. (void)Memento_dropRef(next->val);
  680. next->val->refs--;
  681. }
  682. }
  683. fz_write_printf(ctx, out, "STORE\t-- resource store hash contents --\n");
  684. fz_hash_for_each(ctx, store->hash, out, fz_debug_store_item);
  685. fz_write_printf(ctx, out, "STORE\t-- end --\n");
  686. fz_write_printf(ctx, out, "STORE\tmax=%zu, size=%zu, actual size=%zu\n", store->max, store->size, list_total);
  687. }
  688. void
  689. fz_debug_store(fz_context *ctx, fz_output *out)
  690. {
  691. fz_lock(ctx, FZ_LOCK_ALLOC);
  692. fz_debug_store_locked(ctx, out);
  693. fz_unlock(ctx, FZ_LOCK_ALLOC);
  694. }
  695. /*
  696. Consider if we have blocks of the following sizes in the store, from oldest
  697. to newest:
  698. A 32
  699. B 64
  700. C 128
  701. D 256
  702. Further suppose we need to free 97 bytes. Naively freeing blocks until we have
  703. freed enough would mean we'd free A, B and C, when we could have freed just C.
  704. We are forced into an n^2 algorithm by the need to drop the lock as part of the
  705. eviction, so we might as well embrace it and go for a solution that properly
  706. drops just C.
  707. The algorithm used is to scan the list of blocks from oldest to newest, counting
  708. how many bytes we can free in the blocks we pass. We stop this scan when we have
  709. found enough blocks. We then free the largest block. This releases the lock
  710. momentarily, which means we have to start the scan process all over again, so
  711. we repeat. This guarantees we only evict a minimum of blocks, but does mean we
  712. scan more blocks than we'd ideally like.
  713. */
  714. static int
  715. scavenge(fz_context *ctx, size_t tofree)
  716. {
  717. fz_store *store = ctx->store;
  718. size_t freed = 0;
  719. fz_item *item;
  720. if (store->scavenging)
  721. return 0;
  722. store->scavenging = 1;
  723. do
  724. {
  725. /* Count through a suffix of objects in the store until
  726. * we find enough to give us what we need to evict. */
  727. size_t suffix_size = 0;
  728. fz_item *largest = NULL;
  729. for (item = store->tail; item; item = item->prev)
  730. {
  731. if (item->val->refs == 1 && (item->val->droppable == NULL || item->val->droppable(ctx, item->val)))
  732. {
  733. /* This one is evictable */
  734. suffix_size += item->size;
  735. if (largest == NULL || item->size > largest->size)
  736. largest = item;
  737. if (suffix_size >= tofree - freed)
  738. break;
  739. }
  740. }
  741. /* If there are no evictable blocks, we can't find anything to free. */
  742. if (largest == NULL)
  743. break;
  744. /* Free largest. */
  745. if (freed == 0) {
  746. FZ_LOG_DUMP_STORE(ctx, "Before scavenge:\n");
  747. }
  748. freed += largest->size;
  749. evict(ctx, largest); /* Drops then retakes lock */
  750. }
  751. while (freed < tofree);
  752. if (freed != 0) {
  753. FZ_LOG_DUMP_STORE(ctx, "After scavenge:\n");
  754. }
  755. store->scavenging = 0;
  756. /* Success is managing to evict any blocks */
  757. return freed != 0;
  758. }
  759. void
  760. fz_drop_storable(fz_context *ctx, const fz_storable *sc)
  761. {
  762. /* Explicitly drop const to allow us to use const
  763. * sanely throughout the code. */
  764. fz_storable *s = (fz_storable *)sc;
  765. int num;
  766. if (s == NULL)
  767. return;
  768. fz_lock(ctx, FZ_LOCK_ALLOC);
  769. /* Drop the ref, and leave num as being the number of
  770. * refs left (-1 meaning, "statically allocated"). */
  771. if (s->refs > 0)
  772. {
  773. (void)Memento_dropIntRef(s);
  774. num = --s->refs;
  775. }
  776. else
  777. num = -1;
  778. /* If we have just 1 ref left, it's possible that
  779. * this ref is held by the store. If the store is
  780. * oversized, we ought to throw any such references
  781. * away to try to bring the store down to a "legal"
  782. * size. Run a scavenge to check for this case. */
  783. if (ctx->store->max != FZ_STORE_UNLIMITED)
  784. if (num == 1 && ctx->store->size > ctx->store->max)
  785. scavenge(ctx, ctx->store->size - ctx->store->max);
  786. fz_unlock(ctx, FZ_LOCK_ALLOC);
  787. /* If we have no references to an object left, then
  788. * it cannot possibly be in the store (as the store always
  789. * keeps a ref to everything in it, and doesn't drop via
  790. * this method). So we can simply drop the storable object
  791. * itself without any operations on the fz_store.
  792. */
  793. if (num == 0)
  794. s->drop(ctx, s);
  795. }
  796. int fz_store_scavenge_external(fz_context *ctx, size_t size, int *phase)
  797. {
  798. int ret;
  799. fz_lock(ctx, FZ_LOCK_ALLOC);
  800. ret = fz_store_scavenge(ctx, size, phase);
  801. fz_unlock(ctx, FZ_LOCK_ALLOC);
  802. return ret;
  803. }
  804. int fz_store_scavenge(fz_context *ctx, size_t size, int *phase)
  805. {
  806. fz_store *store;
  807. size_t max;
  808. store = ctx->store;
  809. if (store == NULL)
  810. return 0;
  811. #ifdef DEBUG_SCAVENGING
  812. fz_write_printf(ctx, fz_stdout(ctx), "Scavenging: store=%zu size=%zu phase=%d\n", store->size, size, *phase);
  813. fz_debug_store_locked(ctx, fz_stdout(ctx));
  814. Memento_stats();
  815. #endif
  816. do
  817. {
  818. size_t tofree;
  819. /* Calculate 'max' as the maximum size of the store for this phase */
  820. if (*phase >= 16)
  821. max = 0;
  822. else if (store->max != FZ_STORE_UNLIMITED)
  823. max = store->max / 16 * (16 - *phase);
  824. else
  825. max = store->size / (16 - *phase) * (15 - *phase);
  826. (*phase)++;
  827. /* Slightly baroque calculations to avoid overflow */
  828. if (size > SIZE_MAX - store->size)
  829. tofree = SIZE_MAX - max;
  830. else if (size + store->size > max)
  831. continue;
  832. else
  833. tofree = size + store->size - max;
  834. if (scavenge(ctx, tofree))
  835. {
  836. #ifdef DEBUG_SCAVENGING
  837. fz_write_printf(ctx, fz_stdout(ctx), "scavenged: store=%zu\n", store->size);
  838. fz_debug_store(ctx, fz_stdout(ctx));
  839. Memento_stats();
  840. #endif
  841. return 1;
  842. }
  843. }
  844. while (max > 0);
  845. #ifdef DEBUG_SCAVENGING
  846. fz_write_printf(ctx, fz_stdout(ctx), "scavenging failed\n");
  847. fz_debug_store(ctx, fz_stdout(ctx));
  848. Memento_listBlocks();
  849. #endif
  850. return 0;
  851. }
  852. int
  853. fz_shrink_store(fz_context *ctx, unsigned int percent)
  854. {
  855. int success;
  856. fz_store *store;
  857. size_t new_size;
  858. if (percent >= 100)
  859. return 1;
  860. store = ctx->store;
  861. if (store == NULL)
  862. return 0;
  863. #ifdef DEBUG_SCAVENGING
  864. fz_write_printf(ctx, fz_stdout(ctx), "fz_shrink_store: %zu\n", store->size/(1024*1024));
  865. #endif
  866. fz_lock(ctx, FZ_LOCK_ALLOC);
  867. new_size = (size_t)(((uint64_t)store->size * percent) / 100);
  868. if (store->size > new_size)
  869. scavenge(ctx, store->size - new_size);
  870. success = (store->size <= new_size) ? 1 : 0;
  871. fz_unlock(ctx, FZ_LOCK_ALLOC);
  872. #ifdef DEBUG_SCAVENGING
  873. fz_write_printf(ctx, fz_stdout(ctx), "fz_shrink_store after: %zu\n", store->size/(1024*1024));
  874. #endif
  875. return success;
  876. }
  877. void fz_filter_store(fz_context *ctx, fz_store_filter_fn *fn, void *arg, const fz_store_type *type)
  878. {
  879. fz_store *store;
  880. fz_item *item, *prev, *remove;
  881. store = ctx->store;
  882. if (store == NULL)
  883. return;
  884. fz_lock(ctx, FZ_LOCK_ALLOC);
  885. /* Filter the items */
  886. remove = NULL;
  887. for (item = store->tail; item; item = prev)
  888. {
  889. prev = item->prev;
  890. if (item->type != type)
  891. continue;
  892. if (fn(ctx, arg, item->key) == 0)
  893. continue;
  894. /* We have to drop it */
  895. store->size -= item->size;
  896. /* Unlink from the linked list */
  897. if (item->next)
  898. item->next->prev = item->prev;
  899. else
  900. store->tail = item->prev;
  901. if (item->prev)
  902. item->prev->next = item->next;
  903. else
  904. store->head = item->next;
  905. /* Remove from the hash table */
  906. if (item->type->make_hash_key)
  907. {
  908. fz_store_hash hash = { NULL };
  909. hash.drop = item->val->drop;
  910. if (item->type->make_hash_key(ctx, &hash, item->key))
  911. fz_hash_remove(ctx, store->hash, &hash);
  912. }
  913. /* Store whether to drop this value or not in 'prev' */
  914. if (item->val->refs > 0)
  915. (void)Memento_dropRef(item->val);
  916. item->prev = (item->val->refs > 0 && --item->val->refs == 0) ? item : NULL;
  917. /* Store it in our removal chain - just singly linked */
  918. item->next = remove;
  919. remove = item;
  920. }
  921. fz_unlock(ctx, FZ_LOCK_ALLOC);
  922. /* Now drop the remove chain */
  923. for (item = remove; item != NULL; item = remove)
  924. {
  925. remove = item->next;
  926. /* Drop a reference to the value (freeing if required) */
  927. if (item->prev) /* See above for our abuse of prev here */
  928. item->val->drop(ctx, item->val);
  929. /* Always drops the key and drop the item */
  930. item->type->drop_key(ctx, item->key);
  931. fz_free(ctx, item);
  932. }
  933. }
  934. void fz_defer_reap_start(fz_context *ctx)
  935. {
  936. if (ctx->store == NULL)
  937. return;
  938. fz_lock(ctx, FZ_LOCK_ALLOC);
  939. ctx->store->defer_reap_count++;
  940. fz_unlock(ctx, FZ_LOCK_ALLOC);
  941. }
  942. void fz_defer_reap_end(fz_context *ctx)
  943. {
  944. int reap;
  945. if (ctx->store == NULL)
  946. return;
  947. fz_lock(ctx, FZ_LOCK_ALLOC);
  948. --ctx->store->defer_reap_count;
  949. reap = ctx->store->defer_reap_count == 0 && ctx->store->needs_reaping;
  950. if (reap)
  951. do_reap(ctx); /* Drops FZ_LOCK_ALLOC */
  952. else
  953. fz_unlock(ctx, FZ_LOCK_ALLOC);
  954. }
  955. #ifdef ENABLE_STORE_LOGGING
  956. void fz_log_dump_store(fz_context *ctx, const char *fmt, ...)
  957. {
  958. fz_output *out;
  959. va_list args;
  960. va_start(args, fmt);
  961. out = fz_new_log_for_module(ctx, "STORE");
  962. fz_write_vprintf(ctx, out, fmt, args);
  963. va_end(args);
  964. fz_debug_store(ctx, out);
  965. fz_write_printf(ctx, out, "STORE\tEND\n");
  966. fz_close_output(ctx, out);
  967. fz_drop_output(ctx, out);
  968. }
  969. #endif