Skip to main content
Topic: File-based cache and the old problem with corrupted files (Read 3336 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

File-based cache and the old problem with corrupted files

I'm not sure if it is relevant for Elk at that time (even more because IIRC there is the intention to drop the file-based cache from 1.1), but recently I got some reports that SMF 2.0.9 still presents the "old" cache corruption problem that leads to a crash of the forum.

SMF 2.0.9 incorporates basically the same "safety mechanisms" that Elk has in order to try to avoid the race condition when writing the modSettings cache to the disk, see:
http://custom.simplemachines.org/upgrades/index.php?action=upgrade;file=smf_patch_2.0.7.tar.gz;smf_version=2.0.6
Code: [Select]
				// Write the file.
if (function_exists('file_put_contents'))
{
$cache_bytes = @file_put_contents($cachedir . '/data_' . $key . '.php', $cache_data, LOCK_EX);
if ($cache_bytes != strlen($cache_data))
@unlink($cachedir . '/data_' . $key . '.php');
}
else
{
$fh = @fopen($cachedir . '/data_' . $key . '.php', 'w');
if ($fh)
{
// Write the file.
set_file_buffer($fh, 0);
flock($fh, LOCK_EX);
$cache_bytes = fwrite($fh, $cache_data);
flock($fh, LOCK_UN);
fclose($fh);

// Check that the cache write was successful; all the data should be written
// If it fails due to low diskspace, remove the cache file
if ($cache_bytes != strlen($cache_data))
@unlink($cachedir . '/data_' . $key . '.php');
}
}

while Elk's code is:
Code: [Select]
				if (@file_put_contents(CACHEDIR . '/data_' . $key . '.php', $cache_data, LOCK_EX) !== strlen($cache_data))
@unlink(CACHEDIR . '/data_' . $key . '.php');

The only difference (looking at the file_put_contents branch) is that in Elk there is no variable getting the result of file_put_content.

So, apparently all this is not enough to avoid the issue. It still appears from time to time.

While writing this post, I decided to try to find a way to do some testing, and I think I discovered something odd.
I found:
http://jakarta.apache.org/jmeter/
a software that may be used to simulate load on the server.
I think I set it up to simulate 200 users requesting the home page in a loop "for a while".
Then I started monitoring in particular the modSettings cache file.
In my tests, everything seems to be fine for about 50 seconds, then the cache file is regenerated, even though it should last 90 seconds. Then, from that point on, the regenerations are mostly random: from 1 to 30 seconds, but never 90 as expected.
I'm not sure what is happening.
I'm pretty sure Load.php is not changed/touched during that period (otherwise the key would change and the cache file deleted, and anyway ls -l confirms it was last changed before the experiments).
And if there is no concurrent page loads (i.e. simple ctrl+r every few seconds) the file is replaced exactly when expected.

Soooo.... no idea.
Should I continue debug the issue?
Do you have any suggestion?
Should I just give up and think to something quite more important? :P
Bugs creator.
Features destroyer.
Template killer.

Re: File-based cache and the old problem with corrupted files

Reply #1

Give up. Not an issue. Use Tedvim\Stash in 1.1.

Re: File-based cache and the old problem with corrupted files

Reply #2

You mean this? https://github.com/tedious/Stash/

Interesting.
And even more interesting:
https://github.com/tedious/Stash/blob/master/src/Stash/Driver/FileSystem.php#L247
that could explain some of the "too early" refreshes of the cache: maybe even if the file is written, the OP cache still returns the old one and so the file is replaced (again).
Bugs creator.
Features destroyer.
Template killer.

Re: File-based cache and the old problem with corrupted files

Reply #3

Yup that could be a problem, the cache dir should be in the OpCache blacklist to avoid problems.  I did add this at some point

Code: [Select]
		// Let them know if they may have problems
if ($cache_accelerator === 'filebased' && !empty($modSettings['cache_enable']) && extension_loaded('Zend OPcache'))
{
// The opcache will cache the filebased user data files, updating them based on opcache.revalidate_freq
// which can cause delays (or prevent) the invalidation of file cache files
$opcache_config = @opcache_get_configuration();
if (!empty($opcache_config['directives']['opcache.enable']))
$context['settings_message'] = $txt['cache_conflict'];
}

The fix you linked is probably needed as well since its not always obvious that the opcache is enabled in the newer versions of php (5.5+), and not everyone is going to configure it past the defaults anyway.