New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 782869 link

Starred by 4 users

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 2
Type: Bug

Blocked on:
issue 902488



Sign in to add a comment

Non GC'ed caches keep them from being closed (and also deleted).

Project Member Reported by cmumford@chromium.org, Nov 8 2017

Issue description

A CacheStorage cache that is deleted in JavaScript, via a call to caches.delete() will not result in the cache actually being deleted if there is a prior JavaScript object reference to that cache that has not yet been GC'ed. For example:

caches.open(CACHE_NAME).then(function(cache) { // <= JS reference here.
  cache.put(url, response);
});

caches.delete(CACHE_NAME);

In the above code the cache will still exist on disk until a GC happens, the tab is closed, or (if in a Service Worker) the browser is restarted.
 
index.html
3.4 KB View Download

Comment 1 by bke...@mozilla.com, Nov 8 2017

AFAIK keeping the Cache and matched Response objects functional even after a delete() has occurred is intentional.  We spoke about it in spec issues, etc.  We do the same thing in Firefox and I think we have tests that even verify this continues to work.

Whether or not the data lives on disk is kind of orthogonal to the spec, but its hard to envision how an implementation could make this work without keeping the files on disk until the last reference is dropped.
bkelly@ Yes, you're correct, and we do have tests to verify that a cache isn't deleted until the last reference is closed. However, I think an unfortunate side effect is what is described above. With a service worker many MB's, or even GB's of data can be written to disk without creating enough JS heap use to cause a GC.

Comment 3 by bke...@mozilla.com, Nov 8 2017

Ok.  If this is about not running GC enough, then sure.  I just wanted to make sure we didn't remove the feature of live objects continuing to work after delete() while referenced.  Sorry for my confusion.
Any update on this bug? It's relatively straightforward to get into a bad situation in Google Docs that prevents docs from getting synced offline due to quota issues.

Comment 5 by bke...@mozilla.com, Mar 16 2018

We could consider adding a new method to the spec that immediately invalidates the job wrapper.  Something like Cache.disconnect(), etc.  This would let you avoid having to wait for GC if your particular site happens to hit this kind of issue.

One question, though.  How is your site observing that the disk resources are still in use.  Storage API?  This may be a GC observability issue that needs to be addressed as well.

Comment 6 by ralp...@google.com, Mar 16 2018

If the mechanism of requiring the data to be stored until the reference is GC'ed is justified, then adding an explicit method would definitely help here. Alternatively, is it also possible for Chrome to schedule a GC run shortly after a delete call happens?

We use queryUsageAndQuota() from a page context to figure out the usage.

Comment 7 by bke...@mozilla.com, Mar 16 2018

Hmm, ok.  That is a non-standard API, but its pretty much the same as Storage API's estimate() for this purpose, though.

I filed a spec issue about the GC observability:

https://github.com/whatwg/storage/issues/60

I also filed a spec issue for some kind of explicit detach or immediate deletion:

https://github.com/w3c/ServiceWorker/issues/1287

Comment 8 by ralp...@google.com, Mar 16 2018

Would the workaround mentioned in https://bugs.chromium.org/p/chromium/issues/detail?id=777462#c17, also work for this issue? i.e. if we delete all keys before we delete the Cache?

Also curious about the motivation for the spec behavior i.e. why should the Cache references still be accessible after a CacheStorage.delete()?
https://w3c.github.io/ServiceWorker/#cache-storage-delete
It sounds like this might be the same issue as  https://crbug.com/795701 ?

Comment 10 by bke...@mozilla.com, Mar 19 2018

> Also curious about the motivation for the spec behavior i.e. why should the Cache references still be accessible after a CacheStorage.delete()?

Since Cache API does not have transaction support it would be difficult to use any delete operation without this behavior.  Separate asynchronous operations (like multiple fetch events) could step on each other.

In addition, you really need to hold it alive as long as one of the response bodies is still unconsumed.  Consider the case where a `Cache.match()` has resolved a `Response` and passed it to the browser via `FetchEvent.respondWith()`.  If deletion was immediate and forceful, then content would not have any idea when it was safe to perform the deletion since it can't tell when the browser finishes consuming the body.

Comment 11 by ralp...@google.com, Mar 20 2018

Thanks for the explanation.

Anyone able to confirm if the workaround mentioned in crbug.com/777462#c17 would work here? Wouldn't deleting the individual entries also be susceptible to the same garbage collection issues?

Comment 12 by aaronsn@google.com, Mar 23 2018

Couldn't you impose a reasonable time-limit (say, an hour?) on leaving a resource around, and then garbage collect it? As long as deleting prevents new reads from cache, then after a time limit you'd expect nobody to still be using a resource unless they're holding onto it in memory for a long time, and then it would be reasonably safe to delete it.
Cc: jimmyshen@google.com
We've decided to mitigate this in the interim by deleting the entries ahead of the cache. Of course, it is likely that this workaround will break again once we fix the behavior here, so it would be ideal to implement some mechanism to release this memory eventually (i.e. comment 12) so when that does get fixed we don't end up in this state again.

Comment 14 by aaronsn@google.com, Apr 10 2018

I think we might have misunderstood this bug. Holding a JS reference to a cache prevents it from being garbage collected which prevents it from being deleted from disk.

Can anyone clarify:
- what it means to "have a JS reference" to a cache? Do local variables count or would you have to have a more permanent reference?
- When does the garbage collector run? Will it run while the service worker is still running?

To summarize, if you only access cache through local variables, when after deletion can you expect the cache to actually be deleted from disk?
Blockedon: 902488
This could be worse than expected due to this code:

https://cs.chromium.org/chromium/src/content/browser/cache_storage/cache_storage_dispatcher_host.cc?l=364-368&rcl=85f78938e304061d5dea7a5455ffaab5d7881adb

Which was added in  bug 558427 .  I'm planning to remove this timer in  bug 902488 .

Sign in to add a comment