569 lines
23 KiB
ReStructuredText
569 lines
23 KiB
ReStructuredText
HTTP Cache
|
||
==========
|
||
|
||
This document describes the **HTTP cache implementation**.
|
||
|
||
The code resides in `/netwerk/cache2 (searchfox)
|
||
<https://searchfox.org/mozilla-central/source/netwerk/cache2>`_
|
||
|
||
API
|
||
---
|
||
|
||
Here is a detailed description of the HTTP cache v2 API, examples
|
||
included. This document only contains what cannot be found or may not
|
||
be clear directly from the `IDL files <https://searchfox.org/mozilla-central/search?q=&path=cache2%2FnsICache&case=false®exp=false>`_ comments.
|
||
|
||
- The cache API is **completely thread-safe** and **non-blocking**.
|
||
- There is **no IPC support**. It's only accessible on the default
|
||
chrome process.
|
||
- When there is no profile the new HTTP cache works, but everything is
|
||
stored only in memory not obeying any particular limits.
|
||
|
||
.. _nsICacheStorageService:
|
||
|
||
nsICacheStorageService
|
||
----------------------
|
||
|
||
- The HTTP cache entry-point. Accessible as a service only, fully
|
||
thread-safe, scriptable.
|
||
|
||
- `nsICacheStorageService.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheStorageService.idl>`_
|
||
|
||
- \ ``"@mozilla.org/netwerk/cache-storage-service;1"``
|
||
|
||
- Provides methods accessing "storage" objects – see `nsICacheStorage` below – giving further access to cache entries – see :ref:`nsICacheEntry <nsICacheEntry>` more below – per specific URL.
|
||
|
||
- Currently we have 3 types of storages, all the access methods return
|
||
an :ref:`nsICacheStorage <nsICacheStorage>` object:
|
||
|
||
- **memory-only** (``memoryCacheStorage``): stores data only in a
|
||
memory cache, data in this storage are never put to disk
|
||
|
||
- **disk** (``diskCacheStorage``): stores data on disk, but for
|
||
existing entries also looks into the memory-only storage; when
|
||
instructed via a special argument also primarily looks into
|
||
application caches
|
||
|
||
.. note::
|
||
|
||
**application cache** (``appCacheStorage``): when a consumer has a
|
||
specific ``nsIApplicationCache`` (i.e. a particular app cache
|
||
version in a group) in hands, this storage will provide read and
|
||
write access to entries in that application cache; when the app
|
||
cache is not specified, this storage will operate over all
|
||
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>`_
|
||
|
||
- The service also provides methods to clear the whole disk and memory
|
||
cache content or purge any intermediate memory structures:
|
||
|
||
- ``clear``– after it returns, all entries are no longer accessible
|
||
through the cache APIs; the method is fast to execute and
|
||
non-blocking in any way; the actual erase happens in background
|
||
|
||
- ``purgeFromMemory``– removes (schedules to remove) any
|
||
intermediate cache data held in memory for faster access (more
|
||
about the :ref:`Intermediate_Memory_Caching <Intermediate_Memory_Caching>` below)
|
||
|
||
.. _nsILoadContextInfo:
|
||
|
||
nsILoadContextInfo
|
||
------------------
|
||
|
||
- Distinguishes the scope of the storage demanded to open.
|
||
|
||
- Mandatory argument to ``*Storage`` methods of :ref:`nsICacheStorageService <nsICacheStorageService>`.
|
||
|
||
- `nsILoadContextInfo.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/base/nsILoadContextInfo.idl>`_
|
||
|
||
|
||
- It is a helper interface wrapping following four arguments into a single one:
|
||
|
||
- **private-browsing** boolean flag
|
||
- **anonymous load** boolean flag
|
||
- **origin attributes** js value
|
||
|
||
.. note::
|
||
|
||
Helper functions to create nsILoadContextInfo objects:
|
||
|
||
- C++ consumers: functions at ``LoadContextInfo.h`` exported
|
||
header
|
||
|
||
- JS consumers: ``Services.loadContextInfo`` which is an instance of ``nsILoadContextInfoFactory``.
|
||
|
||
- Two storage objects created with the same set of
|
||
``nsILoadContextInfo``\ arguments are identical, containing the same
|
||
cache entries.
|
||
|
||
- Two storage objects created with in any way different
|
||
``nsILoadContextInfo``\ arguments are strictly and completely
|
||
distinct and cache entries in them do not overlap even when having
|
||
the same URIs.
|
||
|
||
.. _nsICacheStorage:
|
||
|
||
nsICacheStorage
|
||
---------------
|
||
|
||
- `nsICacheStorage.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheStorage.idl>`_
|
||
|
||
- Obtained from call to one of the ``*Storage`` methods on
|
||
:ref:`nsICacheStorageService <nsICacheStorageService>`.
|
||
|
||
- Represents a distinct storage area (or scope) to put and get cache
|
||
entries mapped by URLs into and from it.
|
||
|
||
- *Similarity with the old cache*\ : this interface may be with some
|
||
limitations considered as a mirror to ``nsICacheSession``, but less
|
||
generic and not inclining to abuse.
|
||
|
||
nsICacheEntryOpenCallback
|
||
-------------------------
|
||
|
||
- `nsICacheEntryOpenCallback.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheEntryOpenCallback.idl>`_
|
||
|
||
- The result of ``nsICacheStorage.asyncOpenURI`` is always and only
|
||
sent to callbacks on this interface.
|
||
|
||
- These callbacks are ensured to be invoked when ``asyncOpenURI``
|
||
returns ``NS_OK``.
|
||
|
||
-
|
||
|
||
.. note::
|
||
|
||
When the
|
||
cache entry object is already present in memory or open as
|
||
"force-new" (a.k.a "open-truncate") this callback is invoked
|
||
sooner then the ``asyncOpenURI``\ method returns (i.e.
|
||
immediately); there is currently no way to opt out of this feature
|
||
(see `bug
|
||
938186 <https://bugzilla.mozilla.org/show_bug.cgi?id=938186>`__).
|
||
|
||
.. _nsICacheEntry:
|
||
|
||
nsICacheEntry
|
||
-------------
|
||
|
||
- `nsICacheEntry.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheEntry.idl>`_
|
||
|
||
- Obtained asynchronously or pseudo-asynchronously by a call to
|
||
``nsICacheStorage.asyncOpenURI``.
|
||
|
||
- Provides access to a cached entry data and meta data for reading or
|
||
writing or in some cases both, see below.
|
||
|
||
Lifetime of a new entry
|
||
-----------------------
|
||
|
||
- Such entry is initially empty (no data or meta data is stored in it).
|
||
|
||
- The ``aNew``\ argument in ``onCacheEntryAvailable`` is ``true`` for
|
||
and only for new entries.
|
||
|
||
- Only one consumer (the so called "*writer*") may have such an entry
|
||
available (obtained via ``onCacheEntryAvailable``).
|
||
|
||
- Other parallel openers of the same cache entry are blocked (wait) for
|
||
invocation of their ``onCacheEntryAvailable`` until one of the
|
||
following occurs:
|
||
|
||
- The *writer* simply throws the entry away: other waiting opener in
|
||
line gets the entry again as "*new*", the cycle repeats.
|
||
|
||
.. note::
|
||
|
||
This applies in general, writers throwing away the cache entry
|
||
means a failure to write the cache entry and a new writer is
|
||
being looked for again, the cache entry remains empty (a.k.a.
|
||
"new").
|
||
|
||
- The *writer* stored all necessary meta data in the cache entry and
|
||
called ``metaDataReady`` on it: other consumers now get the entry
|
||
and may examine and potentially modify the meta data and read the
|
||
data (if any) of the cache entry.
|
||
- When the *writer* has data (i.e. the response payload) to write to
|
||
the cache entry, it **must** open the output stream on it
|
||
**before** it calls ``metaDataReady``.
|
||
|
||
- When the *writer* still keeps the cache entry and has open and keeps
|
||
open the output stream on it, other consumers may open input streams
|
||
on the entry. The data will be available as the *writer* writes data
|
||
to the cache entry's output stream immediately, even before the
|
||
output stream is closed. This is called :ref:`concurrent
|
||
read/write <Concurrent_read_and_write>`.
|
||
|
||
.. _Concurrent_read_and_write:
|
||
|
||
Concurrent read and write
|
||
-------------------------
|
||
|
||
The cache supports reading a cache entry data while it is still being
|
||
written by the first consumer - the *writer*.
|
||
This can only be engaged for resumable responses that (`bug
|
||
960902 <https://bugzilla.mozilla.org/show_bug.cgi?id=960902#c17>`__)
|
||
don't need revalidation. Reason is that when the writer is interrupted
|
||
(by e.g. external canceling of the loading channel) concurrent readers
|
||
would not be able to reach the remaining unread content.
|
||
|
||
.. note::
|
||
|
||
This could be improved by keeping the network load running and being
|
||
stored to the cache entry even after the writing channel has been
|
||
canceled.
|
||
|
||
When the *writer* is interrupted, the first concurrent *reader* in line
|
||
does a range request for the rest of the data - and becomes that way a
|
||
new *writer*. The rest of the *readers* are still concurrently reading
|
||
the content since output stream for the cache entry is again open and
|
||
kept by the current *writer*.
|
||
|
||
Lifetime of an existing entry with only a partial content
|
||
---------------------------------------------------------
|
||
|
||
- Such a cache entry is first examined in the
|
||
``nsICacheEntryOpenCallback.onCacheEntryCheck`` callback, where it
|
||
has to be checked for completeness.
|
||
- In this case, the ``Content-Length`` (or different indicator) header
|
||
doesn't equal to the data size reported by the cache entry.
|
||
- The consumer then indicates the cache entry needs to be revalidated
|
||
by returning ``ENTRY_NEEDS_REVALIDATION``\ from
|
||
``onCacheEntryCheck``.
|
||
- This consumer, from the point of view the cache, takes a role of the
|
||
*writer*.
|
||
- Other parallel consumers, if any, are blocked until the *writer*
|
||
calls ``setValid`` on the cache entry.
|
||
- The consumer is then responsible to validate the partial content
|
||
cache entry with the network server and attempt to load the rest of
|
||
the data.
|
||
- When the server responds positively (in case of an HTTP server with a
|
||
206 response code) the *writer* (in this order) opens the output
|
||
stream on the cache entry and calls ``setValid`` to unblock other
|
||
pending openers.
|
||
- Concurrent read/write is engaged.
|
||
|
||
Lifetime of an existing entry that doesn't pass server revalidation
|
||
-------------------------------------------------------------------
|
||
|
||
- Such a cache entry is first examined in the
|
||
``nsICacheEntryOpenCallback.onCacheEntryCheck`` callback, where the
|
||
consumer finds out it must be revalidated with the server before use.
|
||
- The consumer then indicates the cache entry needs to be revalidated
|
||
by returning ``ENTRY_NEEDS_REVALIDATION``\ from
|
||
``onCacheEntryCheck``.
|
||
- This consumer, from the point of view the cache, takes a role of the
|
||
*writer*.
|
||
- Other parallel consumers, if any, are blocked until the *writer*
|
||
calls ``setValid`` on the cache entry.
|
||
- The consumer is then responsible to validate the partial content
|
||
cache entry with the network server.
|
||
- The server responses with a 200 response which means the cached
|
||
content is no longer valid and a new version must be loaded from the
|
||
network.
|
||
- The *writer* then calls ``recreate``\ on the cache entry. This
|
||
returns a new empty entry to write the meta data and data to, the
|
||
*writer* exchanges its cache entry by this new one and handles it as
|
||
a new one.
|
||
- The *writer* then (in this order) fills the necessary meta data of
|
||
the cache entry, opens the output stream on it and calls
|
||
``metaDataReady`` on it.
|
||
- Any other pending openers, if any, are now given this new entry to
|
||
examine and read as an existing entry.
|
||
|
||
Adding a new storage
|
||
--------------------
|
||
|
||
Should there be a need to add a new distinct storage for which the
|
||
current scoping model would not be sufficient - use one of the two
|
||
following ways:
|
||
|
||
#. *[preferred]* Add a new ``<Your>Storage`` method on
|
||
:ref:`nsICacheStorageService <nsICacheStorageService>` and if needed give it any arguments to
|
||
specify the storage scope even more. Implementation only should need
|
||
to enhance the context key generation and parsing code and enhance
|
||
current - or create new when needed - :ref:`nsICacheStorage <nsICacheStorage>`
|
||
implementations to carry any additional information down to the cache
|
||
service.
|
||
#. *[*\ **not**\ *preferred]* Add a new argument to
|
||
:ref:`nsILoadContextInfo <nsILoadContextInfo>`; **be careful
|
||
here**, since some arguments on the context may not be known during
|
||
the load time, what may lead to inter-context data leaking or
|
||
implementation problems. Adding more distinction to
|
||
:ref:`nsILoadContextInfo <nsILoadContextInfo>` also affects all existing storages which may
|
||
not be always desirable.
|
||
|
||
See context keying details for more information.
|
||
|
||
Threading
|
||
---------
|
||
|
||
The cache API is fully thread-safe.
|
||
|
||
The cache is using a single background thread where any IO operations
|
||
like opening, reading, writing and erasing happen. Also memory pool
|
||
management, eviction, visiting loops happen on this thread.
|
||
|
||
The thread supports several priority levels. Dispatching to a level with
|
||
a lower number is executed sooner then dispatching to higher number
|
||
layers; also any loop on lower levels yields to higher levels so that
|
||
scheduled deletion of 1000 files will not block opening cache entries.
|
||
|
||
#. **OPEN_PRIORITY:** except opening priority cache files also file
|
||
dooming happens here to prevent races
|
||
#. **READ_PRIORITY:** top level documents and head blocking script cache
|
||
files are open and read as the first
|
||
#. **OPEN**
|
||
#. **READ:** any normal priority content, such as images are open and
|
||
read here
|
||
#. **WRITE:** writes are processed as last, we cache data in memory in
|
||
the mean time
|
||
#. **MANAGEMENT:** level for the memory pool and CacheEntry background
|
||
operations
|
||
#. **CLOSE:** file closing level
|
||
#. **INDEX:** index is being rebuild here
|
||
#. **EVICT:** files overreaching the disk space consumption limit are
|
||
being evicted here
|
||
|
||
NOTE: Special case for eviction - when an eviction is scheduled on the
|
||
IO thread, all operations pending on the OPEN level are first merged to
|
||
the OPEN_PRIORITY level. The eviction preparation operation - i.e.
|
||
clearing of the internal IO state - is then put to the end of the
|
||
OPEN_PRIORITY level. All this happens atomically.
|
||
|
||
Storage and entries scopes
|
||
--------------------------
|
||
|
||
A *scope key* string used to map the storage scope is based on the
|
||
arguments of :ref:`nsILoadContextInfo <nsILoadContextInfo>`. The form is following (currently
|
||
pending in `bug
|
||
968593 <https://bugzilla.mozilla.org/show_bug.cgi?id=968593>`__):
|
||
|
||
.. code:: JavaScript
|
||
|
||
a,b,i1009,p,
|
||
|
||
- Regular expression: ``(.([-,]+)?,)*``
|
||
- The first letter is an identifier, identifiers are to be
|
||
alphabetically sorted and always terminate with ','
|
||
- a - when present the scope is belonging to an **anonymous** load
|
||
- b - when present the scope is **in browser element** load
|
||
- i - when present must have a decimal integer value that represents an
|
||
app ID the scope belongs to, otherwise there is no app (app ID is
|
||
considered ``0``)
|
||
- p - when present the scope is of a **private browsing** load, this
|
||
never persists
|
||
|
||
``CacheStorageService``\ keeps a global hashtable mapped by the *scope
|
||
key*. Elements in this global hashtable are hashtables of cache entries.
|
||
The cache entries are mapped by concantation of Enhance ID and URI
|
||
passed to ``nsICacheStorage.asyncOpenURI``. So that when an entry is
|
||
being looked up, first the global hashtable is searched using the
|
||
*scope key*. An entries hashtable is found. Then this entries hashtable
|
||
is searched using <enhance-id:><uri> string. The elements in this
|
||
hashtable are CacheEntry classes, see below.
|
||
|
||
The hash tables keep a strong reference to ``CacheEntry`` objects. The
|
||
only way to remove ``CacheEntry`` objects from memory is by exhausting a
|
||
memory limit for :ref:`Intermediate_Memory_Caching <Intermediate_Memory_Caching>`, what triggers a background
|
||
process of purging expired and then least used entries from memory.
|
||
Another way is to directly call the
|
||
``nsICacheStorageService.purge``\ method. That method is also called
|
||
automatically on the ``"memory-pressure"`` indication.
|
||
|
||
Access to the hashtables is protected by a global lock. We also - in a
|
||
thread-safe manner - count the number of consumers keeping a reference
|
||
on each entry. The open callback actually doesn't give the consumer
|
||
directly the ``CacheEntry`` object but a small wrapper class that
|
||
manages the 'consumer reference counter' on its cache entry. This both
|
||
mechanisms ensure thread-safe access and also inability to have more
|
||
then a single instance of a ``CacheEntry`` for a single
|
||
<scope+enhanceID+URL> key.
|
||
|
||
``CacheStorage``, implementing the :ref:`nsICacheStorage <nsICacheStorage>` interface, is
|
||
forwarding all calls to internal methods of ``CacheStorageService``
|
||
passing itself as an argument. ``CacheStorageService`` then generates
|
||
the *scope key* using the ``nsILoadContextInfo`` of the storage. Note:
|
||
CacheStorage keeps a thread-safe copy of ``nsILoadContextInfo`` passed
|
||
to a ``*Storage`` method on ``nsICacheStorageService``.
|
||
|
||
Invoking open callbacks
|
||
-----------------------
|
||
|
||
``CacheEntry``, implementing the ``nsICacheEntry`` interface, is
|
||
responsible for managing the cache entry internal state and to properly
|
||
invoke ``onCacheEntryCheck`` and ``onCacheEntryAvaiable`` callbacks to
|
||
all callers of ``nsICacheStorage.asyncOpenURI``.
|
||
|
||
- Keeps a FIFO of all openers.
|
||
- Keeps its internal state like NOTLOADED, LOADING, EMPTY, WRITING,
|
||
READY, REVALIDATING.
|
||
- Keeps the number of consumers keeping a reference to it.
|
||
- Refers a ``CacheFile`` object that holds actual data and meta data
|
||
and, when told to, persists it to the disk.
|
||
|
||
The openers FIFO is an array of ``CacheEntry::Callback`` objects.
|
||
``CacheEntry::Callback`` keeps a strong reference to the opener plus the
|
||
opening flags. ``nsICacheStorage.asyncOpenURI`` forwards to
|
||
``CacheEntry::AsyncOpen`` and triggers the following pseudo-code:
|
||
|
||
**CacheStorage::AsyncOpenURI** - the API entry point:
|
||
|
||
- globally atomic:
|
||
|
||
- look a given ``CacheEntry`` in ``CacheStorageService`` hash tables
|
||
up
|
||
- if not found: create a new one, add it to the proper hash table
|
||
and set its state to NOTLOADED
|
||
- consumer reference ++
|
||
|
||
- call to `CacheEntry::AsyncOpen`
|
||
- consumer reference --
|
||
|
||
**CacheEntry::AsyncOpen** (entry atomic):
|
||
|
||
- the opener is added to FIFO, consumer reference ++ (dropped back
|
||
after an opener is removed from the FIFO)
|
||
- state == NOTLOADED:
|
||
|
||
- state = LOADING
|
||
- when OPEN_TRUNCATE flag was used:
|
||
|
||
- ``CacheFile`` is created as 'new', state = EMPTY
|
||
|
||
- otherwise:
|
||
|
||
- ``CacheFile`` is created and load on it started
|
||
- ``CacheEntry::OnFileReady`` notification is now expected
|
||
|
||
- state == LOADING: just do nothing and exit
|
||
- call to `CacheEntry::InvokeCallbacks`
|
||
|
||
**CacheEntry::InvokeCallbacks** (entry atomic):
|
||
|
||
- called on:
|
||
|
||
- a new opener has been added to the FIFO via an ``AsyncOpen`` call
|
||
- asynchronous result of CacheFile open ``CacheEntry::OnFileReady>``
|
||
- the writer throws the entry away - ``CacheEntry::OnHandleClosed``
|
||
- the **output stream** of the entry has been **opened** or
|
||
**closed**
|
||
- ``metaDataReady``\ or ``setValid``\ on the entry has been called
|
||
- the entry has been **doomed**
|
||
|
||
- state == EMPTY:
|
||
|
||
- on OPER_READONLY flag use: onCacheEntryAvailable with
|
||
``null``\ for the cache entry
|
||
- otherwise:
|
||
|
||
- state = WRITING
|
||
- opener is removed from the FIFO and remembered as the current
|
||
'*writer*'
|
||
- onCacheEntryAvailable with ``aNew = true``\ and this entry is
|
||
invoked (on the caller thread) for the *writer*
|
||
|
||
- state == READY:
|
||
|
||
- onCacheEntryCheck with the entry is invoked on the first opener in
|
||
FIFO - on the caller thread if demanded
|
||
- result == RECHECK_AFTER_WRITE_FINISHED:
|
||
|
||
- opener is left in the FIFO with a flag ``RecheckAfterWrite``
|
||
- such openers are skipped until the output stream on the entry
|
||
is closed, then ``onCacheEntryCheck`` is re-invoked on them
|
||
- Note: here is a potential for endless looping when
|
||
RECHECK_AFTER_WRITE_FINISHED is abused
|
||
|
||
- result == ENTRY_NEEDS_REVALIDATION:
|
||
|
||
- state = REVALIDATING, this prevents invocation of any callback
|
||
until ``CacheEntry::SetValid`` is called
|
||
- continue as in state ENTRY_WANTED (just below)
|
||
|
||
- result == ENTRY_WANTED:
|
||
|
||
- consumer reference ++ (dropped back when the consumer releases
|
||
the entry)
|
||
- onCacheEntryAvailable is invoked on the opener with
|
||
``aNew = false``\ and the entry
|
||
- opener is removed from the FIFO
|
||
|
||
- result == ENTRY_NOT_WANTED:
|
||
|
||
- ``onCacheEntryAvailable`` is invoked on the opener with
|
||
``null``\ for the entry
|
||
- opener is removed from the FIFO
|
||
|
||
- state == WRITING or REVALIDATING:
|
||
|
||
- do nothing and exit
|
||
|
||
- any other value of state is unexpected here (assertion failure)
|
||
- loop this process while there are openers in the FIFO
|
||
|
||
**CacheEntry::OnFileReady** (entry atomic):
|
||
|
||
- load result == failure or the file has not been found on disk (is
|
||
new): state = EMPTY
|
||
- otherwise: state = READY since the cache file has been found and is
|
||
usable containing meta data and data of the entry
|
||
- call to ``CacheEntry::InvokeCallbacks``
|
||
|
||
**CacheEntry::OnHandleClosed** (entry atomic):
|
||
|
||
- Called when any consumer throws the cache entry away
|
||
- If the handle is not the handle given to the current *writer*, then
|
||
exit
|
||
- state == WRITING: the writer failed to call ``metaDataReady`` on the
|
||
entry - state = EMPTY
|
||
- state == REVALIDATING: the writer failed the re-validation process
|
||
and failed to call ``setValid`` on the entry - state = READY
|
||
- call to ``CacheEntry::InvokeCallbacks``
|
||
|
||
**All consumers release the reference:**
|
||
|
||
- the entry may now be purged (removed) from memory when found expired
|
||
or least used on overrun of the :ref:`memory
|
||
pool <Intermediate_Memory_Caching>` limit
|
||
- when this is a disk cache entry, its cached data chunks are released
|
||
from memory and only meta data is kept
|
||
|
||
.. _Intermediate_Memory_Caching:
|
||
|
||
Intermediate memory caching
|
||
---------------------------
|
||
|
||
Intermediate memory caching of frequently used metadata (a.k.a. disk cache memory pool).
|
||
|
||
For the disk cache entries we keep some of the most recent and most used
|
||
cache entries' meta data in memory for immediate zero-thread-loop
|
||
opening. The default size of this meta data memory pool is only 250kB
|
||
and is controlled by a new ``browser.cache.disk.metadata_memory_limit``
|
||
preference. When the limit is exceeded, we purge (throw away) first
|
||
**expired** and then **least used** entries to free up memory again.
|
||
|
||
Only ``CacheEntry`` objects that are already loaded and filled with data
|
||
and having the 'consumer reference == 0' (`bug
|
||
942835 <https://bugzilla.mozilla.org/show_bug.cgi?id=942835#c3>`__) can
|
||
be purged.
|
||
|
||
The 'least used' entries are recognized by the lowest value of
|
||
`frecency <https://wiki.mozilla.org/User:Jesse/NewFrecency?title=User:Jesse/NewFrecency>`__
|
||
we re-compute for each entry on its every access. The decay time is
|
||
controlled by the ``browser.cache.frecency_half_life_hours`` preference
|
||
and defaults to 6 hours. The best decay time will be based on results of
|
||
`an experiment <https://bugzilla.mozilla.org/show_bug.cgi?id=986728>`__.
|
||
|
||
The memory pool is represented by two lists (strong referring ordered
|
||
arrays) of ``CacheEntry`` objects:
|
||
|
||
#. Sorted by expiration time (that default to 0xFFFFFFFF)
|
||
#. Sorted by frecency (defaults to 0)
|
||
|
||
We have two such pools, one for memory-only entries actually
|
||
representing the memory-only cache and one for disk cache entries for
|
||
which we only keep the meta data. Each pool has a different limit
|
||
checking - the memory cache pool is controlled by
|
||
``browser.cache.memory.capacity``, the disk entries pool is already
|
||
described above. The pool can be accessed and modified only on the cache
|
||
background thread.
|