Backed out changeset 4b2edb2c26d4 (bug 1880582) for causing mochitest failures on...
[gecko.git] / netwerk / docs / cache2 / doc.rst
blobb9be70abc8822bc06982d39fd754863ea7a1c450
1 HTTP Cache
2 ==========
4 This document describes the **HTTP cache implementation**.
6 The code resides in `/netwerk/cache2 (searchfox)
7 <https://searchfox.org/mozilla-central/source/netwerk/cache2>`_
9 API
10 ---
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.
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 new HTTP cache works, but everything is
20    stored only in memory not obeying any particular limits.
22 .. _nsICacheStorageService:
24 nsICacheStorageService
25 ----------------------
27 -  The HTTP cache entry-point. Accessible as a service only, fully
28    thread-safe, scriptable.
30 -  `nsICacheStorageService.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheStorageService.idl>`_
32 -   \ ``"@mozilla.org/netwerk/cache-storage-service;1"``
34 -  Provides methods accessing "storage" objects – see `nsICacheStorage` below – giving further access to cache entries – see :ref:`nsICacheEntry <nsICacheEntry>` more below – per specific URL.
36 -  Currently we have 3 types of storages, all the access methods return
37    an :ref:`nsICacheStorage <nsICacheStorage>` object:
39    -  **memory-only** (``memoryCacheStorage``): stores data only in a
40       memory cache, data in this storage are never put to disk
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
47    .. note::
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>`_
56 -  The service also provides methods to clear the whole disk and memory
57    cache content or purge any intermediate memory structures:
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
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)
67 .. _nsILoadContextInfo:
69 nsILoadContextInfo
70 ------------------
72 -  Distinguishes the scope of the storage demanded to open.
74 -  Mandatory argument to ``*Storage`` methods of :ref:`nsICacheStorageService <nsICacheStorageService>`.
76 -  `nsILoadContextInfo.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/base/nsILoadContextInfo.idl>`_
79 -  It is a helper interface wrapping following four arguments into a single one:
81    -  **private-browsing** boolean flag
82    -  **anonymous load** boolean flag
83    -  **origin attributes** js value
85    .. note::
87       Helper functions to create nsILoadContextInfo objects:
89       -  C++ consumers: functions at ``LoadContextInfo.h`` exported
90          header
92       -  JS consumers: ``Services.loadContextInfo`` which is an instance of ``nsILoadContextInfoFactory``.
94 -  Two storage objects created with the same set of
95    ``nsILoadContextInfo``\ arguments are identical, containing the same
96    cache entries.
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.
103 .. _nsICacheStorage:
105 nsICacheStorage
106 ---------------
108 -  `nsICacheStorage.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheStorage.idl>`_
110 -  Obtained from call to one of the ``*Storage`` methods on
111    :ref:`nsICacheStorageService <nsICacheStorageService>`.
113 -  Represents a distinct storage area (or scope) to put and get cache
114    entries mapped by URLs into and from it.
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.
120 nsICacheEntryOpenCallback
121 -------------------------
123 -  `nsICacheEntryOpenCallback.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheEntryOpenCallback.idl>`_
125 -  The result of ``nsICacheStorage.asyncOpenURI`` is always and only
126    sent to callbacks on this interface.
128 -  These callbacks are ensured to be invoked when ``asyncOpenURI``
129    returns ``NS_OK``.
133    .. note::
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>`__).
143 .. _nsICacheEntry:
145 nsICacheEntry
146 -------------
148 -  `nsICacheEntry.idl (searchfox) <https://searchfox.org/mozilla-central/source/netwerk/cache2/nsICacheEntry.idl>`_
150 -  Obtained asynchronously or pseudo-asynchronously by a call to
151    ``nsICacheStorage.asyncOpenURI``.
153 -  Provides access to a cached entry data and meta data for reading or
154    writing or in some cases both, see below.
156 Lifetime of a new entry
157 -----------------------
159 -  Such entry is initially empty (no data or meta data is stored in it).
161 -  The ``aNew``\ argument in ``onCacheEntryAvailable`` is ``true`` for
162    and only for new entries.
164 -  Only one consumer (the so called "*writer*") may have such an entry
165    available (obtained via ``onCacheEntryAvailable``).
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:
171    -  The *writer* simply throws the entry away: other waiting opener in
172       line gets the entry again as "*new*", the cycle repeats.
174       .. note::
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").
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``.
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>`.
196 .. _Concurrent_read_and_write:
198 Concurrent read and write
199 -------------------------
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.
209 .. note::
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.
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*.
221 Lifetime of an existing entry with only a partial content
222 ---------------------------------------------------------
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.
245 Lifetime of an existing entry that doesn't pass server revalidation
246 -------------------------------------------------------------------
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.
273 Adding a new storage
274 --------------------
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:
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.
295 See context keying details for more information.
297 Threading
298 ---------
300 The cache API is fully thread-safe.
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.
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.
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
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.
333 Storage and entries scopes
334 --------------------------
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>`__):
341 .. code:: JavaScript
343    a,b,i1009,p,
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
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.
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.
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.
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``.
389 Invoking open callbacks
390 -----------------------
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``.
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.
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:
409 **CacheStorage::AsyncOpenURI** - the API entry point:
411 -  globally atomic:
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 ++
419 -  call to `CacheEntry::AsyncOpen`
420 -  consumer reference --
422 **CacheEntry::AsyncOpen** (entry atomic):
424 -  the opener is added to FIFO, consumer reference ++ (dropped back
425    after an opener is removed from the FIFO)
426 -  state == NOTLOADED:
428    -  state = LOADING
429    -  when OPEN_TRUNCATE flag was used:
431       -  ``CacheFile`` is created as 'new', state = EMPTY
433    -  otherwise:
435       -  ``CacheFile`` is created and load on it started
436       -  ``CacheEntry::OnFileReady`` notification is now expected
438 -  state == LOADING: just do nothing and exit
439 -  call to `CacheEntry::InvokeCallbacks`
441 **CacheEntry::InvokeCallbacks** (entry atomic):
443 -  called on:
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**
453 -  state == EMPTY:
455    -  on OPER_READONLY flag use: onCacheEntryAvailable with
456       ``null``\ for the cache entry
457    -  otherwise:
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*
465 -  state == READY:
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:
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
477    -  result == ENTRY_NEEDS_REVALIDATION:
479       -  state = REVALIDATING, this prevents invocation of any callback
480          until ``CacheEntry::SetValid`` is called
481       -  continue as in state ENTRY_WANTED (just below)
483    -  result == ENTRY_WANTED:
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
491    -  result == ENTRY_NOT_WANTED:
493       -  ``onCacheEntryAvailable`` is invoked on the opener with
494          ``null``\ for the entry
495       -  opener is removed from the FIFO
497 -  state == WRITING or REVALIDATING:
499    -  do nothing and exit
501 -  any other value of state is unexpected here (assertion failure)
502 -  loop this process while there are openers in the FIFO
504 **CacheEntry::OnFileReady** (entry atomic):
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``
512 **CacheEntry::OnHandleClosed** (entry atomic):
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``
523 **All consumers release the reference:**
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
531 .. _Intermediate_Memory_Caching:
533 Intermediate memory caching
534 ---------------------------
536 Intermediate memory caching of frequently used metadata (a.k.a. disk cache memory pool).
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.
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.
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>`__.
557 The memory pool is represented by two lists (strong referring ordered
558 arrays) of ``CacheEntry`` objects:
560 #. Sorted by expiration time (that default to 0xFFFFFFFF)
561 #. Sorted by frecency (defaults to 0)
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.