tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

doc.rst (26452B)


      1 HTTP Cache
      2 ==========
      3 
      4 This document describes the **HTTP cache implementation**.
      5 
      6 The code resides in `/netwerk/cache2 (searchfox)
      7 <https://searchfox.org/mozilla-central/source/netwerk/cache2>`_
      8 
      9 API
     10 ---
     11 
     12 Here is a detailed description of the HTTP cache v2 API, examples
     13 included.  This document only contains what cannot be found or may not
     14 be clear directly from the `IDL files <https://searchfox.org/mozilla-central/search?q=&path=cache2%2FnsICache&case=false&regexp=false>`_ comments.
     15 
     16 -  The cache API is **completely thread-safe** and **non-blocking**.
     17 -  There is **no IPC support**.  It's only accessible on the default
     18   chrome process.
     19 -  When there is no profile the HTTP cache works, but everything is
     20   stored only in memory not obeying any particular limits.
     21 
     22 .. _nsICacheStorageService:
     23 
     24 nsICacheStorageService
     25 ----------------------
     26 
     27 -  The HTTP cache entry-point. Accessible as a service only, fully
     28   thread-safe, scriptable.
     29 
     30 -  `nsICacheStorageService.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheStorageService.idl>`_
     31 
     32 -   \ ``"@mozilla.org/netwerk/cache-storage-service;1"``
     33 
     34 -  Provides methods accessing "storage" objects – see `nsICacheStorage` below – giving further access to cache entries – see :ref:`nsICacheEntry <nsICacheEntry>` more below – per specific URL.
     35 
     36 -  Currently we have 3 types of storages, all the access methods return
     37   an :ref:`nsICacheStorage <nsICacheStorage>` object:
     38 
     39   -  **memory-only** (``memoryCacheStorage``): stores data only in a
     40      memory cache, data in this storage are never put to disk
     41 
     42   -  **disk** (``diskCacheStorage``): stores data on disk, but for
     43      existing entries also looks into the memory-only storage; when
     44      instructed via a special argument also primarily looks into
     45      application caches
     46 
     47   .. note::
     48 
     49      **application cache** (``appCacheStorage``): when a consumer has a
     50      specific ``nsIApplicationCache`` (i.e. a particular app cache
     51      version in a group) in hands, this storage will provide read and
     52      write access to entries in that application cache; when the app
     53      cache is not specified, this storage will operate over all
     54      existing app caches. **This kind of storage is deprecated and will be removed** in `bug 1694662 <https://bugzilla.mozilla.org/show_bug.cgi?id=1694662>`_
     55 
     56 -  The service also provides methods to clear the whole disk and memory
     57   cache content or purge any intermediate memory structures:
     58 
     59   -  ``clear``– after it returns, all entries are no longer accessible
     60      through the cache APIs; the method is fast to execute and
     61      non-blocking in any way; the actual erase happens in background
     62 
     63   -  ``purgeFromMemory``– removes (schedules to remove) any
     64      intermediate cache data held in memory for faster access (more
     65      about the :ref:`Intermediate_Memory_Caching <Intermediate_Memory_Caching>` below)
     66 
     67 .. _nsILoadContextInfo:
     68 
     69 nsILoadContextInfo
     70 ------------------
     71 
     72 -  Distinguishes the scope of the storage demanded to open.
     73 
     74 -  Mandatory argument to ``*Storage`` methods of :ref:`nsICacheStorageService <nsICacheStorageService>`.
     75 
     76 -  `nsILoadContextInfo.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/base/nsILoadContextInfo.idl>`_
     77 
     78 
     79 -  It is a helper interface wrapping following four arguments into a single one:
     80 
     81   -  **private-browsing** boolean flag
     82   -  **anonymous load** boolean flag
     83   -  **origin attributes** js value
     84 
     85   .. note::
     86 
     87      Helper functions to create nsILoadContextInfo objects:
     88 
     89      -  C++ consumers: functions at ``LoadContextInfo.h`` exported
     90         header
     91 
     92      -  JS consumers: ``Services.loadContextInfo`` which is an instance of ``nsILoadContextInfoFactory``.
     93 
     94 -  Two storage objects created with the same set of
     95   ``nsILoadContextInfo``\ arguments are identical, containing the same
     96   cache entries.
     97 
     98 -  Two storage objects created with in any way different
     99   ``nsILoadContextInfo``\ arguments are strictly and completely
    100   distinct and cache entries in them do not overlap even when having
    101   the same URIs.
    102 
    103 .. _nsICacheStorage:
    104 
    105 nsICacheStorage
    106 ---------------
    107 
    108 -  `nsICacheStorage.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheStorage.idl>`_
    109 
    110 -  Obtained from call to one of the ``*Storage`` methods on
    111   :ref:`nsICacheStorageService <nsICacheStorageService>`.
    112 
    113 -  Represents a distinct storage area (or scope) to put and get cache
    114   entries mapped by URLs into and from it.
    115 
    116 -  *Similarity with the old cache*\ : this interface may be with some
    117   limitations considered as a mirror to ``nsICacheSession``, but less
    118   generic and not inclining to abuse.
    119 
    120 nsICacheEntryOpenCallback
    121 -------------------------
    122 
    123 -  `nsICacheEntryOpenCallback.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheEntryOpenCallback.idl>`_
    124 
    125 -  The result of ``nsICacheStorage.asyncOpenURI`` is always and only
    126   sent to callbacks on this interface.
    127 
    128 -  These callbacks are ensured to be invoked when ``asyncOpenURI``
    129   returns ``NS_OK``.
    130 
    131 -
    132 
    133   .. note::
    134 
    135      When the
    136      cache entry object is already present in memory or open as
    137      "force-new" (a.k.a "open-truncate") this callback is invoked
    138      sooner then the ``asyncOpenURI``\ method returns (i.e.
    139      immediately); there is currently no way to opt out of this feature
    140      (see `bug
    141      938186 <https://bugzilla.mozilla.org/show_bug.cgi?id=938186>`__).
    142 
    143 .. _nsICacheEntry:
    144 
    145 nsICacheEntry
    146 -------------
    147 
    148 -  `nsICacheEntry.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheEntry.idl>`_
    149 
    150 -  Obtained asynchronously or pseudo-asynchronously by a call to
    151   ``nsICacheStorage.asyncOpenURI``.
    152 
    153 -  Provides access to a cached entry data and meta data for reading or
    154   writing or in some cases both, see below.
    155 
    156 Lifetime of a new entry
    157 -----------------------
    158 
    159 -  Such entry is initially empty (no data or meta data is stored in it).
    160 
    161 -  The ``aNew``\ argument in ``onCacheEntryAvailable`` is ``true`` for
    162   and only for new entries.
    163 
    164 -  Only one consumer (the so called "*writer*") may have such an entry
    165   available (obtained via ``onCacheEntryAvailable``).
    166 
    167 -  Other parallel openers of the same cache entry are blocked (wait) for
    168   invocation of their ``onCacheEntryAvailable`` until one of the
    169   following occurs:
    170 
    171   -  The *writer* simply throws the entry away: other waiting opener in
    172      line gets the entry again as "*new*", the cycle repeats.
    173 
    174      .. note::
    175 
    176         This applies in general, writers throwing away the cache entry
    177         means a failure to write the cache entry and a new writer is
    178         being looked for again, the cache entry remains empty (a.k.a.
    179         "new").
    180 
    181   -  The *writer* stored all necessary meta data in the cache entry and
    182      called ``metaDataReady`` on it: other consumers now get the entry
    183      and may examine and potentially modify the meta data and read the
    184      data (if any) of the cache entry.
    185   -  When the *writer* has data (i.e. the response payload) to write to
    186      the cache entry, it **must** open the output stream on it
    187      **before** it calls ``metaDataReady``.
    188 
    189 -  When the *writer* still keeps the cache entry and has open and keeps
    190   open the output stream on it, other consumers may open input streams
    191   on the entry. The data will be available as the *writer* writes data
    192   to the cache entry's output stream immediately, even before the
    193   output stream is closed. This is called :ref:`concurrent
    194   read/write <Concurrent_read_and_write>`.
    195 
    196 .. _Concurrent_read_and_write:
    197 
    198 Concurrent read and write
    199 -------------------------
    200 
    201 The cache supports reading a cache entry data while it is still being
    202 written by the first consumer - the *writer*.
    203 This can only be engaged for resumable responses that (`bug
    204 960902 <https://bugzilla.mozilla.org/show_bug.cgi?id=960902#c17>`__)
    205 don't need revalidation. Reason is that when the writer is interrupted
    206 (by e.g. external canceling of the loading channel) concurrent readers
    207 would not be able to reach the remaining unread content.
    208 
    209 .. note::
    210 
    211   This could be improved by keeping the network load running and being
    212   stored to the cache entry even after the writing channel has been
    213   canceled.
    214 
    215 When the *writer* is interrupted, the first concurrent *reader* in line
    216 does a range request for the rest of the data - and becomes that way a
    217 new *writer*. The rest of the *readers* are still concurrently reading
    218 the content since output stream for the cache entry is again open and
    219 kept by the current *writer*.
    220 
    221 Lifetime of an existing entry with only a partial content
    222 ---------------------------------------------------------
    223 
    224 -  Such a cache entry is first examined in the
    225   ``nsICacheEntryOpenCallback.onCacheEntryCheck`` callback, where it
    226   has to be checked for completeness.
    227 -  In this case, the ``Content-Length`` (or different indicator) header
    228   doesn't equal to the data size reported by the cache entry.
    229 -  The consumer then indicates the cache entry needs to be revalidated
    230   by returning ``ENTRY_NEEDS_REVALIDATION``\ from
    231   ``onCacheEntryCheck``.
    232 -  This consumer, from the point of view the cache, takes a role of the
    233   *writer*.
    234 -  Other parallel consumers, if any, are blocked until the *writer*
    235   calls ``setValid`` on the cache entry.
    236 -  The consumer is then responsible to validate the partial content
    237   cache entry with the network server and attempt to load the rest of
    238   the data.
    239 -  When the server responds positively (in case of an HTTP server with a
    240   206 response code) the *writer* (in this order) opens the output
    241   stream on the cache entry and calls ``setValid`` to unblock other
    242   pending openers.
    243 -  Concurrent read/write is engaged.
    244 
    245 Lifetime of an existing entry that doesn't pass server revalidation
    246 -------------------------------------------------------------------
    247 
    248 -  Such a cache entry is first examined in the
    249   ``nsICacheEntryOpenCallback.onCacheEntryCheck`` callback, where the
    250   consumer finds out it must be revalidated with the server before use.
    251 -  The consumer then indicates the cache entry needs to be revalidated
    252   by returning ``ENTRY_NEEDS_REVALIDATION``\ from
    253   ``onCacheEntryCheck``.
    254 -  This consumer, from the point of view the cache, takes a role of the
    255   *writer*.
    256 -  Other parallel consumers, if any, are blocked until the *writer*
    257   calls ``setValid`` on the cache entry.
    258 -  The consumer is then responsible to validate the partial content
    259   cache entry with the network server.
    260 -  The server responses with a 200 response which means the cached
    261   content is no longer valid and a new version must be loaded from the
    262   network.
    263 -  The *writer* then calls ``recreate``\ on the cache entry. This
    264   returns a new empty entry to write the meta data and data to, the
    265   *writer* exchanges its cache entry by this new one and handles it as
    266   a new one.
    267 -  The *writer* then (in this order) fills the necessary meta data of
    268   the cache entry, opens the output stream on it and calls
    269   ``metaDataReady`` on it.
    270 -  Any other pending openers, if any, are now given this new entry to
    271   examine and read as an existing entry.
    272 
    273 Adding a new storage
    274 --------------------
    275 
    276 Should there be a need to add a new distinct storage for which the
    277 current scoping model would not be sufficient - use one of the two
    278 following ways:
    279 
    280 #. *[preferred]* Add a new ``<Your>Storage`` method on
    281   :ref:`nsICacheStorageService <nsICacheStorageService>` and if needed give it any arguments to
    282   specify the storage scope even more.  Implementation only should need
    283   to enhance the context key generation and parsing code and enhance
    284   current - or create new when needed - :ref:`nsICacheStorage <nsICacheStorage>`
    285   implementations to carry any additional information down to the cache
    286   service.
    287 #. *[*\ **not**\ *preferred]* Add a new argument to
    288   :ref:`nsILoadContextInfo <nsILoadContextInfo>`; **be careful
    289   here**, since some arguments on the context may not be known during
    290   the load time, what may lead to inter-context data leaking or
    291   implementation problems. Adding more distinction to
    292   :ref:`nsILoadContextInfo <nsILoadContextInfo>` also affects all existing storages which may
    293   not be always desirable.
    294 
    295 See context keying details for more information.
    296 
    297 Threading
    298 ---------
    299 
    300 The cache API is fully thread-safe.
    301 
    302 The cache is using a single background thread where any IO operations
    303 like opening, reading, writing and erasing happen.  Also memory pool
    304 management, eviction, visiting loops happen on this thread.
    305 
    306 The thread supports several priority levels. Dispatching to a level with
    307 a lower number is executed sooner then dispatching to higher number
    308 layers; also any loop on lower levels yields to higher levels so that
    309 scheduled deletion of 1000 files will not block opening cache entries.
    310 
    311 #. **OPEN_PRIORITY:** except opening priority cache files also file
    312   dooming happens here to prevent races
    313 #. **READ_PRIORITY:** top level documents and head blocking script cache
    314   files are open and read as the first
    315 #. **OPEN**
    316 #. **READ:** any normal priority content, such as images are open and
    317   read here
    318 #. **WRITE:** writes are processed as last, we cache data in memory in
    319   the mean time
    320 #. **MANAGEMENT:** level for the memory pool and CacheEntry background
    321   operations
    322 #. **CLOSE:** file closing level
    323 #. **INDEX:** index is being rebuild here
    324 #. **EVICT:** files overreaching the disk space consumption limit are
    325   being evicted here
    326 
    327 NOTE: Special case for eviction - when an eviction is scheduled on the
    328 IO thread, all operations pending on the OPEN level are first merged to
    329 the OPEN_PRIORITY level. The eviction preparation operation - i.e.
    330 clearing of the internal IO state - is then put to the end of the
    331 OPEN_PRIORITY level.  All this happens atomically.
    332 
    333 Storage and entries scopes
    334 --------------------------
    335 
    336 A *scope key* string used to map the storage scope is based on the
    337 arguments of :ref:`nsILoadContextInfo <nsILoadContextInfo>`. The form is following (currently
    338 pending in `bug
    339 968593 <https://bugzilla.mozilla.org/show_bug.cgi?id=968593>`__):
    340 
    341 .. code:: JavaScript
    342 
    343   a,b,i1009,p,
    344 
    345 -  Regular expression: ``(.([-,]+)?,)*``
    346 -  The first letter is an identifier, identifiers are to be
    347   alphabetically sorted and always terminate with ','
    348 -  a - when present the scope is belonging to an **anonymous** load
    349 -  b - when present the scope is **in browser element** load
    350 -  i - when present must have a decimal integer value that represents an
    351   app ID the scope belongs to, otherwise there is no app (app ID is
    352   considered ``0``)
    353 -  p - when present the scope is of a **private browsing** load, this
    354   never persists
    355 
    356 ``CacheStorageService``\ keeps a global hashtable mapped by the *scope
    357 key*. Elements in this global hashtable are hashtables of cache entries.
    358 The cache entries are mapped by concantation of Enhance ID and URI
    359 passed to ``nsICacheStorage.asyncOpenURI``.  So that when an entry is
    360 being looked up, first the global hashtable is searched using the
    361 *scope key*. An entries hashtable is found. Then this entries hashtable
    362 is searched using <enhance-id:><uri> string. The elements in this
    363 hashtable are CacheEntry classes, see below.
    364 
    365 The hash tables keep a strong reference to ``CacheEntry`` objects. The
    366 only way to remove ``CacheEntry`` objects from memory is by exhausting a
    367 memory limit for :ref:`Intermediate_Memory_Caching <Intermediate_Memory_Caching>`, what triggers a background
    368 process of purging expired and then least used entries from memory.
    369 Another way is to directly call the
    370 ``nsICacheStorageService.purge``\ method. That method is also called
    371 automatically on the ``"memory-pressure"`` indication.
    372 
    373 Access to the hashtables is protected by a global lock. We also - in a
    374 thread-safe manner - count the number of consumers keeping a reference
    375 on each entry. The open callback actually doesn't give the consumer
    376 directly the ``CacheEntry`` object but a small wrapper class that
    377 manages the 'consumer reference counter' on its cache entry. This both
    378 mechanisms ensure thread-safe access and also inability to have more
    379 then a single instance of a ``CacheEntry`` for a single
    380 <scope+enhanceID+URL> key.
    381 
    382 ``CacheStorage``, implementing the :ref:`nsICacheStorage <nsICacheStorage>` interface, is
    383 forwarding all calls to internal methods of ``CacheStorageService``
    384 passing itself as an argument.  ``CacheStorageService`` then generates
    385 the *scope key* using the ``nsILoadContextInfo`` of the storage. Note:
    386 CacheStorage keeps a thread-safe copy of ``nsILoadContextInfo`` passed
    387 to a ``*Storage`` method on ``nsICacheStorageService``.
    388 
    389 Invoking open callbacks
    390 -----------------------
    391 
    392 ``CacheEntry``, implementing the ``nsICacheEntry`` interface, is
    393 responsible for managing the cache entry internal state and to properly
    394 invoke ``onCacheEntryCheck`` and ``onCacheEntryAvaiable`` callbacks to
    395 all callers of ``nsICacheStorage.asyncOpenURI``.
    396 
    397 -  Keeps a FIFO of all openers.
    398 -  Keeps its internal state like NOTLOADED, LOADING, EMPTY, WRITING,
    399   READY, REVALIDATING.
    400 -  Keeps the number of consumers keeping a reference to it.
    401 -  Refers a ``CacheFile`` object that holds actual data and meta data
    402   and, when told to, persists it to the disk.
    403 
    404 The openers FIFO is an array of ``CacheEntry::Callback`` objects.
    405 ``CacheEntry::Callback`` keeps a strong reference to the opener plus the
    406 opening flags.  ``nsICacheStorage.asyncOpenURI`` forwards to
    407 ``CacheEntry::AsyncOpen`` and triggers the following pseudo-code:
    408 
    409 **CacheStorage::AsyncOpenURI** - the API entry point:
    410 
    411 -  globally atomic:
    412 
    413   -  look a given ``CacheEntry`` in ``CacheStorageService`` hash tables
    414      up
    415   -  if not found: create a new one, add it to the proper hash table
    416      and set its state to NOTLOADED
    417   -  consumer reference ++
    418 
    419 -  call to `CacheEntry::AsyncOpen`
    420 -  consumer reference --
    421 
    422 **CacheEntry::AsyncOpen** (entry atomic):
    423 
    424 -  the opener is added to FIFO, consumer reference ++ (dropped back
    425   after an opener is removed from the FIFO)
    426 -  state == NOTLOADED:
    427 
    428   -  state = LOADING
    429   -  when OPEN_TRUNCATE flag was used:
    430 
    431      -  ``CacheFile`` is created as 'new', state = EMPTY
    432 
    433   -  otherwise:
    434 
    435      -  ``CacheFile`` is created and load on it started
    436      -  ``CacheEntry::OnFileReady`` notification is now expected
    437 
    438 -  state == LOADING: just do nothing and exit
    439 -  call to `CacheEntry::InvokeCallbacks`
    440 
    441 **CacheEntry::InvokeCallbacks** (entry atomic):
    442 
    443 -  called on:
    444 
    445   -  a new opener has been added to the FIFO via an ``AsyncOpen`` call
    446   -  asynchronous result of CacheFile open ``CacheEntry::OnFileReady>``
    447   -  the writer throws the entry away - ``CacheEntry::OnHandleClosed``
    448   -  the **output stream** of the entry has been **opened** or
    449      **closed**
    450   -  ``metaDataReady``\ or ``setValid``\ on the entry has been called
    451   -  the entry has been **doomed**
    452 
    453 -  state == EMPTY:
    454 
    455   -  on OPER_READONLY flag use: onCacheEntryAvailable with
    456      ``null``\ for the cache entry
    457   -  otherwise:
    458 
    459      -  state = WRITING
    460      -  opener is removed from the FIFO and remembered as the current
    461         '*writer*'
    462      -  onCacheEntryAvailable with ``aNew = true``\ and this entry is
    463         invoked (on the caller thread) for the *writer*
    464 
    465 -  state == READY:
    466 
    467   -  onCacheEntryCheck with the entry is invoked on the first opener in
    468      FIFO - on the caller thread if demanded
    469   -  result == RECHECK_AFTER_WRITE_FINISHED:
    470 
    471      -  opener is left in the FIFO with a flag ``RecheckAfterWrite``
    472      -  such openers are skipped until the output stream on the entry
    473         is closed, then ``onCacheEntryCheck`` is re-invoked on them
    474      -  Note: here is a potential for endless looping when
    475         RECHECK_AFTER_WRITE_FINISHED is abused
    476 
    477   -  result == ENTRY_NEEDS_REVALIDATION:
    478 
    479      -  state = REVALIDATING, this prevents invocation of any callback
    480         until ``CacheEntry::SetValid`` is called
    481      -  continue as in state ENTRY_WANTED (just below)
    482 
    483   -  result == ENTRY_WANTED:
    484 
    485      -  consumer reference ++ (dropped back when the consumer releases
    486         the entry)
    487      -  onCacheEntryAvailable is invoked on the opener with
    488         ``aNew = false``\ and the entry
    489      -  opener is removed from the FIFO
    490 
    491   -  result == ENTRY_NOT_WANTED:
    492 
    493      -  ``onCacheEntryAvailable`` is invoked on the opener with
    494         ``null``\ for the entry
    495      -  opener is removed from the FIFO
    496 
    497 -  state == WRITING or REVALIDATING:
    498 
    499   -  do nothing and exit
    500 
    501 -  any other value of state is unexpected here (assertion failure)
    502 -  loop this process while there are openers in the FIFO
    503 
    504 **CacheEntry::OnFileReady** (entry atomic):
    505 
    506 -  load result == failure or the file has not been found on disk (is
    507   new): state = EMPTY
    508 -  otherwise: state = READY since the cache file has been found and is
    509   usable containing meta data and data of the entry
    510 -  call to ``CacheEntry::InvokeCallbacks``
    511 
    512 **CacheEntry::OnHandleClosed** (entry atomic):
    513 
    514 -  Called when any consumer throws the cache entry away
    515 -  If the handle is not the handle given to the current *writer*, then
    516   exit
    517 -  state == WRITING: the writer failed to call ``metaDataReady`` on the
    518   entry - state = EMPTY
    519 -  state == REVALIDATING: the writer failed the re-validation process
    520   and failed to call ``setValid`` on the entry - state = READY
    521 -  call to ``CacheEntry::InvokeCallbacks``
    522 
    523 **All consumers release the reference:**
    524 
    525 -  the entry may now be purged (removed) from memory when found expired
    526   or least used on overrun of the :ref:`memory
    527   pool <Intermediate_Memory_Caching>` limit
    528 -  when this is a disk cache entry, its cached data chunks are released
    529   from memory and only meta data is kept
    530 
    531 .. _Intermediate_Memory_Caching:
    532 
    533 Intermediate memory caching
    534 ---------------------------
    535 
    536 Intermediate memory caching of frequently used metadata (a.k.a. disk cache memory pool).
    537 
    538 For the disk cache entries we keep some of the most recent and most used
    539 cache entries' meta data in memory for immediate zero-thread-loop
    540 opening. The default size of this meta data memory pool is only 250kB
    541 and is controlled by a new ``browser.cache.disk.metadata_memory_limit``
    542 preference. When the limit is exceeded, we purge (throw away) first
    543 **expired** and then **least used** entries to free up memory again.
    544 
    545 Only ``CacheEntry`` objects that are already loaded and filled with data
    546 and having the 'consumer reference == 0' (`bug
    547 942835 <https://bugzilla.mozilla.org/show_bug.cgi?id=942835#c3>`__) can
    548 be purged.
    549 
    550 The 'least used' entries are recognized by the lowest value of
    551 `frecency <https://wiki.mozilla.org/User:Jesse/NewFrecency?title=User:Jesse/NewFrecency>`__
    552 we re-compute for each entry on its every access. The decay time is
    553 controlled by the ``browser.cache.frecency_half_life_hours`` preference
    554 and defaults to 6 hours. The best decay time will be based on results of
    555 `an experiment <https://bugzilla.mozilla.org/show_bug.cgi?id=986728>`__.
    556 
    557 The memory pool is represented by two lists (strong referring ordered
    558 arrays) of ``CacheEntry`` objects:
    559 
    560 #. Sorted by expiration time (that default to 0xFFFFFFFF)
    561 #. Sorted by frecency (defaults to 0)
    562 
    563 We have two such pools, one for memory-only entries actually
    564 representing the memory-only cache and one for disk cache entries for
    565 which we only keep the meta data.  Each pool has a different limit
    566 checking - the memory cache pool is controlled by
    567 ``browser.cache.memory.capacity``, the disk entries pool is already
    568 described above. The pool can be accessed and modified only on the cache
    569 background thread.
    570 
    571 Compression Dictionaries
    572 ---------------------------
    573 
    574 Compression Dictionaries are specced by the IETF:
    575 https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/
    576 
    577 See also: https://developer.chrome.com/blog/shared-dictionary-compression
    578 and https://github.com/WICG/compression-dictionary-transport
    579 
    580 Gecko's design for compression dictionary support:
    581 
    582 We have special dict:<origin> entries with a listing of all dictionaries
    583 for that origin, stored in metadata.
    584 
    585 When a fetch is made, we check if there's a dict:<origin> cache entry.  If
    586 not, we know there are no dictionaries.  If there is an entry, and we
    587 haven't previously loaded it into memory, we read and parse the metadata
    588 and create in-memory structures for all dictionaries for <origin>.   This
    589 includes the data needed to match and decide if we want to send a
    590 "Available-Dictionary:" header with the request.
    591 
    592 If a response to any request is received and it has a "Use-As-Dictionary"
    593 header, we create a new dictionary entry in-memory and flag it for saving
    594 to the dict:<origin> metadata.  We set the stream up to decompress before
    595 storing into the cache (see later options for alternatives in the future),
    596 so that we can be ensured to be able to decompress later.   We start
    597 accumulating a hash value for the metadata entry.  Once the resource is
    598 fully received, we finalize the hash value and the metadata can be written.
    599 
    600 When a response is received with dcb or dcz compress (dictionaries), we use
    601 the cache entry for the dictionary that we sent in Available-Dictionary to
    602 decompress the resource.  This means reading it into memory and then
    603 allowing the decompression to occur.
    604 
    605 Several of these actions require a level of asynchronous action (waiting
    606 for a cache entry to be loaded for use as a dictionary, or waiting for a
    607 dict:<origin> entry to be loaded.  This is generally handled via lambdas.
    608 
    609 The metadata and in-memory entries are kept in sync with the cache by
    610 clearing entries out when cache entries are Doomed.  This also interacts
    611 with Clear Site Data and cookie clear headers (see IETF spec).
    612 
    613 Dictionary loading can also be triggered via <link rel="Compression
    614 Dictionary" ...> and link headers.  These will cause prefetches of the
    615 dictionaries.
    616 
    617 Things to watch on landing:
    618 - Cache hitrate
    619 - dictionary utilization
    620 -- Add probes
    621 - pageload metrics
    622 -- Would require OHTTP-based collection
    623 
    624 Future optimizations:
    625 - Compressing dictionaries with zstd in the cache
    626 --  Trades CPU use and some latency decoding dictionary-encoded files for hitrate
    627 -- Perhaps only above some size
    628 - Compressing dictionary-encoded files with zstd in the cache
    629 --  Trades CPU use for hitrate
    630 -- Perhaps only above some size
    631 - Preemptively reading dict:<origin> entries into memory in the background at startup
    632 -- Up to some limit
    633 - LRU-ing dict:<origin> entries and dropping old ones from memory