Graham Leggett wrote:
Niklas Edmundsson wrote:

However, I don't see how you can do a lockless design with multiple files and an index that can do:

* Clients read from the cache as files are being cached.
* Only one session caches the same file.
* Header/Body updates.
* No index/files out-of-sync issues. Ever.

Thinking about this some more I do see a race during purging - a cache thread could read the header, the purge deletes header and body, and then the cache thread reads the body, and interprets the missing body as "the body is still coming".

One possible (and reasonably simple) solution would be to cache the header and body in a unique directory - the directory name becomes the key, and the entry is either cached completely / still being cached if the directory exists. This assumes it's possible to atomically delete directories.

I don't understand why bother getting so complex. Touch/truncate the body file when storing the header, and then a missing body means things have gone amok - retry the request. Conversely, a zero-length, or < C-L body length means another thread is working on the body.

Another option is to version the filename of the body based on a key in the header. In other words, in the header, called <key>.header, is a version number <timestamp>, meaning there should be a body called <key>.<timestamp>.body. A replacement cached entry therefore cannot stomp on what pre existing threads are doing. If the body file is created first, before the header file, then a non existent body file means "this entry has been invalidated, try the request again".

There is an assumption that <timestamp> is fine grained enough to be unique.

You're right, this is a tricky one, but there is a solution out there.
Maybe we're attacking the problem from the wrong angle. Rather than modifying mod_cache, modify the garbage-collector (e.g., htcacheclean). Do a two pass cleanup. The first pass is a data-store transversal pass which decides what to remove. It immediately purges the header file, and stores the entity key (or filename, or whatever it needs to re-access the entity) in a list. Once the first pass finishes, a second pass is made leisurely cleaning up all of the entities that are still missing their header files (that way, if a mod_cache thread re-caches the entity, we won't purge it).

That should be a safe solution, provided that the time taken to perform the first pass is shorter than the time between opening the header and body files. That should normally be the case, unless someone can come up with a reasonable case where it wouldn't be so?

 Issac

Reply via email to