[Cache] work aroung PHP memory leak

This commit is contained in:
Nicolas Grekas 2019-06-27 23:36:22 +02:00
parent 2fdfa1a8eb
commit 5d55b91fae

View File

@ -50,12 +50,15 @@ trait PhpFilesTrait
{ {
$time = time(); $time = time();
$pruned = true; $pruned = true;
$getExpiry = true;
set_error_handler($this->includeHandler); set_error_handler($this->includeHandler);
try { try {
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
try { try {
list($expiresAt) = include $file; if (\is_array($expiresAt = include $file)) {
$expiresAt = $expiresAt[0];
}
} catch (\ErrorException $e) { } catch (\ErrorException $e) {
$expiresAt = $time; $expiresAt = $time;
} }
@ -87,15 +90,21 @@ trait PhpFilesTrait
$values = []; $values = [];
begin: begin:
$getExpiry = false;
foreach ($ids as $id) { foreach ($ids as $id) {
if (null === $value = $this->values[$id] ?? null) { if (null === $value = $this->values[$id] ?? null) {
$missingIds[] = $id; $missingIds[] = $id;
} elseif ('N;' === $value) { } elseif ('N;' === $value) {
$values[$id] = null; $values[$id] = null;
} elseif ($value instanceof \Closure) { } elseif (!\is_object($value)) {
$values[$id] = $value();
} else {
$values[$id] = $value; $values[$id] = $value;
} elseif (!$value instanceof LazyValue) {
// calling a Closure is for @deprecated BC and should be removed in Symfony 5.0
$values[$id] = $value();
} elseif (false === $values[$id] = include $value->file) {
unset($values[$id], $this->values[$id]);
$missingIds[] = $id;
} }
if (!$this->appendOnly) { if (!$this->appendOnly) {
unset($this->values[$id]); unset($this->values[$id]);
@ -108,10 +117,18 @@ trait PhpFilesTrait
set_error_handler($this->includeHandler); set_error_handler($this->includeHandler);
try { try {
$getExpiry = true;
foreach ($missingIds as $k => $id) { foreach ($missingIds as $k => $id) {
try { try {
$file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id); $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
list($expiresAt, $this->values[$id]) = include $file;
if (\is_array($expiresAt = include $file)) {
[$expiresAt, $this->values[$id]] = $expiresAt;
} elseif ($now < $expiresAt) {
$this->values[$id] = new LazyValue($file);
}
if ($now >= $expiresAt) { if ($now >= $expiresAt) {
unset($this->values[$id], $missingIds[$k]); unset($this->values[$id], $missingIds[$k]);
} }
@ -140,7 +157,13 @@ trait PhpFilesTrait
set_error_handler($this->includeHandler); set_error_handler($this->includeHandler);
try { try {
$file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id); $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
list($expiresAt, $value) = include $file; $getExpiry = true;
if (\is_array($expiresAt = include $file)) {
[$expiresAt, $value] = $expiresAt;
} elseif ($this->appendOnly) {
$value = new LazyValue($file);
}
} catch (\ErrorException $e) { } catch (\ErrorException $e) {
return false; return false;
} finally { } finally {
@ -189,13 +212,16 @@ trait PhpFilesTrait
} }
if (!$isStaticValue) { if (!$isStaticValue) {
$value = str_replace("\n", "\n ", $value); // We cannot use a closure here because of https://bugs.php.net/76982
$value = "static function () {\n\n return {$value};\n\n}"; $value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);
$value = "<?php\n\nnamespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};\n";
} else {
$value = "<?php return [{$expiry}, {$value}];\n";
} }
$file = $this->files[$key] = $this->getFile($key, true); $file = $this->files[$key] = $this->getFile($key, true);
// Since OPcache only compiles files older than the script execution start, set the file's mtime in the past // Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
$ok = $this->write($file, "<?php return [{$expiry}, {$value}];\n", self::$startTime - 10) && $ok; $ok = $this->write($file, $value, self::$startTime - 10) && $ok;
if ($allowCompile) { if ($allowCompile) {
@opcache_invalidate($file, true); @opcache_invalidate($file, true);
@ -241,3 +267,16 @@ trait PhpFilesTrait
return @unlink($file); return @unlink($file);
} }
} }
/**
* @internal
*/
class LazyValue
{
public $file;
public function __construct($file)
{
$this->file = $file;
}
}