Skip to content

Commit

Permalink
always use lock when writing/reading cache data to/from file
Browse files Browse the repository at this point in the history
  • Loading branch information
kkmuffme committed Aug 5, 2022
1 parent 1ef3851 commit fd76799
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 112 deletions.
46 changes: 41 additions & 5 deletions src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php
Expand Up @@ -8,10 +8,14 @@

use function array_merge;
use function dirname;
use function fclose;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function filemtime;
use function filesize;
use function flock;
use function fopen;
use function fread;
use function get_class;
use function hash;
use function igbinary_serialize;
Expand All @@ -23,8 +27,11 @@
use function strtolower;
use function unlink;
use function unserialize;
use function usleep;

use const DIRECTORY_SEPARATOR;
use const LOCK_EX;
use const LOCK_SH;
use const PHP_VERSION_ID;

/**
Expand Down Expand Up @@ -72,6 +79,35 @@ public function __construct(Config $config)
$this->modified_timestamps .= $this->config->computeHash();
}

protected function safeFileGetContents(string $path): string
{
// no readable validation as that must be done in the caller
$fp = fopen($path, 'r');
if ($fp === false) {
return '';
}
$max_wait_cycles = 5;
$has_lock = false;
while ($max_wait_cycles > 0) {
if (flock($fp, LOCK_SH)) {
$has_lock = true;
break;
}
$max_wait_cycles--;
usleep(50000);
}

if (!$has_lock) {
fclose($fp);
throw new UnexpectedValueException('Could not aquire lock for ' . $path);
}

$content = (string) fread($fp, filesize($path));
fclose($fp);

return $content;
}

public function writeToCache(ClassLikeStorage $storage, string $file_path, string $file_contents): void
{
$fq_classlike_name_lc = strtolower($storage->name);
Expand All @@ -86,9 +122,9 @@ public function writeToCache(ClassLikeStorage $storage, string $file_path, strin

$cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, true);
if ($this->config->use_igbinary) {
file_put_contents($cache_location, igbinary_serialize($storage));
file_put_contents($cache_location, igbinary_serialize($storage), LOCK_EX);
} else {
file_put_contents($cache_location, serialize($storage));
file_put_contents($cache_location, serialize($storage), LOCK_EX);
}
}

Expand Down Expand Up @@ -132,7 +168,7 @@ private function loadFromCache(string $fq_classlike_name_lc, ?string $file_path)

if (file_exists($cache_location)) {
if ($this->config->use_igbinary) {
$storage = igbinary_unserialize((string)file_get_contents($cache_location));
$storage = igbinary_unserialize($this->safeFileGetContents($cache_location));

if ($storage instanceof ClassLikeStorage) {
return $storage;
Expand All @@ -141,7 +177,7 @@ private function loadFromCache(string $fq_classlike_name_lc, ?string $file_path)
return null;
}

$storage = unserialize((string)file_get_contents($cache_location));
$storage = unserialize($this->safeFileGetContents($cache_location));

if ($storage instanceof ClassLikeStorage) {
return $storage;
Expand Down

0 comments on commit fd76799

Please sign in to comment.