FS#12216 - Dircache shuts down when closing a file that was opened prior to reloading the dircache
The dircache shuts down (resets dircache_initialized to false) when it encounters files it does not know about, assuming a dircache inconsistency. One of the reasons for shutting down the dircache is when it encounters a file handle it doesn't know about. To prevent this from happening, the dircache maintains a mapping between file handles and file names, which is maintained even when the dircache is not fully operating yet during the boot phase (by way of a small temporary cache array).
The problem is that this scheme has a few holes that allow files to be open without the dircache knowing about it:
1. When dircache_initializing is not set, the temporary cache is not maintained and newly opened files will slip through.
2. When the dircache is disabled and later re-enabled, open-file mappings that were active during the first dircache instance are not carried over to the new instance.
Both cases occur frequently when reloading the dircache after updating the database, which defaults to disabling the dircache and using the dircache buffer for its commit phase, and then reloading the dircache.
The most common case I see is when playback is active during the automatic DB update (Resume Playback is my startup screen). When I wait for the DB update and dircache reload to complete and then start a new playlist from the database, the playlist-control file (I believe) is closed. The new dircache instance does not know that this file was open before and shuts down (in update_filesize). (With current SVN, this later causes the DB browser to crash, but that's a different story.)
I'm wondering what the best way to keep the dircache online would be. Some ideas:
* When the dircache shuts down, save the current list of bindings to the temporary cache, to be reloaded when the new instance starts up. Also set dircache_initializing = true, and reset it only when the temporary cache overflows). This would require a few more entries in the temporary cache than the current two.
* Recover the bindings from the FAT filesystem layer, or maybe even generally store them there. This layer already has a list of open files, but currently does not store a file-descriptor binding. Unfortunately, this solution does not work for hosted platforms.
* Make the dircache resilient against unknown file-descriptor bindings. It's somewhat unclear to me how that could work, as each handle-based update that we ignore and just pass through to the filesystem creates a dircache inconsistency.