FRiCKLE/ngx_cache_purge

After purging a specific variant, that variant may still be present in the cache

sharpobject opened this issue · 4 comments

If you are using Vary, you might purge a specific variant, but that variant may still be present in the cache and served to clients.

In this example, the following sequence of requests is made for the Waifu: Mokou variant:

GET (MISS)
GET (HIT)
PURGE (404)
GET (HIT)

In this example, the following sequence of requests is made for the Waifu: Mokou variant:

GET (MISS)
GET (HIT)
GET (MISS)
PURGE (200)
GET (HIT)

Both of these tests "pass" over here on OSX 10.12.1 with nginx 1.9.15 and ngx_cache_purge 2.3.

taosx commented

Exactly same problem. I just found https://github.com/nginx-modules/ngx_cache_purge, maybe it's fixed.

@taosx My impression is that this issue is pretty fundamental to the way nginx's cache's Vary support works. So I would be surprised and impressed if someone fixed it from the module side.

I guess I should take this to the nginx mailing list. The issue is much less severe in the absence of ngx_cache_purge though, because the worst that can happen is like... you can MISS for some variant when you should HIT after some other variant gets deleted by LRU. Then you will store 2 copies of the same variant for a while.

Ok, I had a look and you can definitely successfully purge all variants of a resource if you use ngx_walk_tree. I think this will be linear in the number of files in your entire cache. I don't really want that.

99th edit: The fork linked by taosx above will have the same behavior for purging a single file, but will purge all variants if you use partial key purge.

I investigated this, and decided that just as @sharpobject says, ngx_walk_tree will look at every file in the cache, and worse, the plugin will (in ngx_http_purge_file_cache_delete_partial_file) read each of those files to find the cache_key stored inside to decide if it matches the partial key.

Worse, it will then delete the file from disk, but if you have another layer of cache, like the file_open cache, the cache entry will not be invalidated, so it's possible that it can still be served from memory. You'd need to set fcn->exists = 0; for the relevant ngx_http_file_cache_node_t *fcn, I guess, but how do you find that?

Disclaimer: This is the first time I've looked at NGINX sources. Don't trust anything I speculate about.