10000 feature #27549 [Cache] Unconditionally use PhpFilesAdapter for system… · symfony/symfony@d4f5d46 · GitHub
[go: up one dir, main page]

Skip to content

Commit d4f5d46

Browse files
committed
feature #27549 [Cache] Unconditionally use PhpFilesAdapter for system pools (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- [Cache] Unconditionally use PhpFilesAdapter for system pools | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Now that we're about to leverage OPCache shared memory even for objects (see #27543), there's no reason anymore to use APCu for system caches. Let's remove some complexity here. As a bonus, this makes system caches pruneable using the `cache:pool:prune` command. Commits ------- 51381e5 [Cache] Unconditionally use PhpFilesAdapter for system pools
2 parents 7e3b7b0 + 51381e5 commit d4f5d46

15 files changed

+51
-58
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1538,7 +1538,6 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
15381538
{
15391539
$version = new Parameter('container.build_id');
15401540
$container->getDefinition('cache.adapter.apcu')->replaceArgument(2, $version);
1541-
$container->getDefinition('cache.adapter.system')->replaceArgument(2, $version);
15421541
$container->getDefinition('cache.adapter.filesystem')->replaceArgument(2, $config['directory']);
15431542

15441543
if (isset($config['prefix_seed'])) {

src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@
3535
<tag name="cache.pool" />
3636
</service>
3737

38-
<service id="cache.adapter.system" class="Symfony\Component\Cache\Adapter\AdapterInterface" abstract="true">
39-
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache" />
38+
<service id="cache.adapter.system" class="Symfony\Component\Cache\Adapter\PhpFilesAdapter" abstract="true">
4039
<tag name="cache.pool" clearer="cache.system_clearer" />
4140
<tag name="monolog.logger" channel="cache" />
4241
<argument /> <!-- namespace -->
4342
<argument>0</argument> <!-- default lifetime -->
44-
<argument /> <!-- version -->
4543
<argument>%kernel.cache_dir%/pools</argument>
46-
<argument type="service" id="logger" on-invalid="ignore" />
44+
<call method="setLogger">
45+
<argument type="service" id="logger" on-invalid="ignore" />
46+
</call>
4747
</service>
4848

4949
<service id="cache.adapter.apcu" class="Symfony\Component\Cache\Adapter\ApcuAdapter" abstract="true">

src/Symfony/Component/Cache/Adapter/AbstractAdapter.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ function ($deferred, $namespace, &$expiredIds) use ($getId) {
102102
* @param LoggerInterface|null $logger
103103
*
104104
* @return AdapterInterface
105+
*
106+
* @deprecated since Symfony 4.2
105107
*/
106108
public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
107109
{
110+
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
111+
108112
if (null === self::$apcuSupported) {
109113
self::$apcuSupported = ApcuAdapter::isSupported();
110114
}

src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public function __construct(string $file, AdapterInterface $fallbackPool)
4343
{
4444
$this->file = $file;
4545
$this->pool = $fallbackPool;
46-
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
4746
$this->createCacheItem = \Closure::bind(
4847
function ($key, $value, $isHit) {
4948
$item = new CacheItem();

src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,11 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
2424
*/
2525
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
2626
{
27-
if (!static::isSupported()) {
28-
throw new CacheException('OPcache is not enabled');
29-
}
27+
self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
3028
parent::__construct('', $defaultLifetime);
3129
$this->init($namespace, $directory);
3230

3331
$e = new \Exception();
3432
$this->includeHandler = function () use ($e) { throw $e; };
35-
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
3633
}
3734
}

src/Symfony/Component/Cache/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* added `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache
88
* throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool
99
* deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead
10+
* deprecated the `AbstractAdapter::createSystemCache()` method
1011

1112
3.4.0
1213
-----

src/Symfony/Component/Cache/Simple/PhpArrayCache.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ public function __construct(string $file, CacheInterface $fallbackPool)
3636
{
3737
$this->file = $file;
3838
$this->pool = $fallbackPool;
39-
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
4039
}
4140

4241
/**

src/Symfony/Component/Cache/Simple/PhpFilesCache.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,11 @@ class PhpFilesCache extends AbstractCache implements PruneableInterface
2424
*/
2525
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null)
2626
{
27-
if (!static::isSupported()) {
28-
throw new CacheException('OPcache is not enabled');
29-
}
27+
self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
3028
parent::__construct('', $defaultLifetime);
3129
$this->init($namespace, $directory);
3230

3331
$e = new \Exception();
3432
$this->includeHandler = function () use ($e) { throw $e; };
35-
$this->zendDetectUnicode = ini_get('zend.detect_unicode');
3633
}
3734
}

src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function testLongKey()
2626
$cache->expects($this->exactly(2))
2727
->method('doHave')
2828
->withConsecutive(
29-
array($this->equalTo('----------:0GTYWa9n4ed8vqNlOT2iEr:')),
29+
array($this->equalTo('----------:nWfzGiCgLczv3SSUzXL3kg:')),
3030
array($this->equalTo('----------:---------------------------------------'))
3131
);
3232

src/Symfony/Component/Cache/Tests/Adapter/PhpFilesAdapterTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ class PhpFilesAdapterTest extends AdapterTestCase
2525

2626
public function createCachePool()
2727
{
28-
if (!PhpFilesAdapter::isSupported()) {
29-
$this->markTestSkipped('OPcache extension is not enabled.');
30-
}
31-
3228
return new PhpFilesAdapter('sf-cache');
3329
}
3430

src/Symfony/Component/Cache/Tests/Simple/PhpFilesCacheTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ class PhpFilesCacheTest extends CacheTestCase
2525

2626
public function createSimpleCache()
2727
{
28-
if (!PhpFilesCache::isSupported()) {
29-
$this->markTestSkipped('OPcache extension is not enabled.');
30-
}
31-
3228
return new PhpFilesCache('sf-cache');
3329
}
3430

src/Symfony/Component/Cache/Traits/AbstractTrait.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ trait AbstractTrait
2727
private $namespaceVersion = '';
2828
private $versioningIsEnabled = false;
2929
private $deferred = array();
30+
private $ids = array();
3031

3132
/**
3233
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
@@ -198,6 +199,7 @@ public function reset()
198199
$this->commit();
199200
}
200201
$this->namespaceVersion = '';
202+
$this->ids = array();
201203
}
202204

203205
/**
@@ -229,20 +231,26 @@ protected static function unserialize($value)
229231

230232
private function getId($key)
231233
{
232-
CacheItem::validateKey($key);
233-
234234
if ($this->versioningIsEnabled && '' === $this->namespaceVersion) {
235235
$this->namespaceVersion = '1:';
236236
foreach ($this->doFetch(array('@'.$this->namespace)) as $v) {
237237
$this->namespaceVersion = $v;
238238
}
239239
}
240240

241+
if (\is_string($key) && isset($this->ids[$key])) {
242+
return $this->namespace.$this->namespaceVersion.$this->ids[$key];
243+
}
244+
CacheItem::validateKey($key);
245+
$this->ids[$key] = $key;
246+
241247
if (null === $this->maxIdLength) {
242248
return $this->namespace.$this->namespaceVersion.$key;
243249
}
244250
if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) {
245-
$id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -22);
251+
// Use MD5 to favor speed over security, which is not an issue here
252+
$this->ids[$key] = $id = substr_replace(base64_encode(hash('md5', $key, true)), ':', -2);
253+
$id = $this->namespace.$this->namespaceVersion.$id;
246254
}
247255

248256
return $id;

src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected function doClear($namespace)
5656
$ok = true;
5757

5858
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
59-
$ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok;
59+
$ok = ($file->isDir() || $this->doUnlink($file) || !file_exists($file)) && $ok;
6060
}
6161

6262
return $ok;
@@ -71,12 +71,17 @@ protected function doDelete(array $ids)
7171

7272
foreach ($ids as $id) {
7373
$file = $this->getFile($id);
74-
$ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok;
74+
$ok = (!file_exists($file) || $this->doUnlink($file) || !file_exists($file)) && $ok;
7575
}
7676

7777
return $ok;
7878
}
7979

80+
protected function doUnlink($file)
81+
{
82+
return @unlink($file);
83+
}
84+
8085
private function write($file, $data, $expiresAt = null)
8186
{
8287
set_error_handler(__CLASS__.'::throwError');
@@ -98,7 +103,8 @@ private function write($file, $data, $expiresAt = null)
98103

99104
private function getFile($id, $mkdir = false)
100105
{
101-
$hash = str_replace('/', '-', base64_encode(hash('sha256', static::class.$id, true)));
106+
// Use MD5 to favor speed over security, which is not an issue here
107+
$hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true)));
102108
$dir = $this->directory.strtoupper($hash[0].DIRECTORY_SEPARATOR.$hash[1].DIRECTORY_SEPARATOR);
103109

104110
if ($mkdir && !file_exists($dir)) {

src/Symfony/Component/Cache/Traits/PhpArrayTrait.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ trait PhpArrayTrait
2626

2727
private $file;
2828
private $values;
29-
private $zendDetectUnicode;
3029

3130
/**
3231
* Store an array of cached values.
@@ -98,7 +97,6 @@ public function warmUp(array $values)
9897
}
9998

10099
$dump .= "\n);\n";
101-
$dump = str_replace("' . \"\\0\" . '", "\0", $dump);
102100

103101
$tmpFile = uniqid($this->file, true);
104102

@@ -128,15 +126,6 @@ public function clear()
128126
*/
129127
private function initialize()
130128
{
131-
if ($this->zendDetectUnicode) {
132-
$zmb = ini_set('zend.detect_unicode', 0);
133-
}
134-
try {
135-
$this->values = file_exists($this->file) ? (include $this->file ?: array()) : array();
136-
} finally {
137-
if ($this->zendDetectUnicode) {
138-
ini_set('zend.detect_unicode', $zmb);
139-
}
140-
}
129+
$this->values = file_exists($this->file) ? (include $this->file ?: array()) : array();
141130
}
142131
}

src/Symfony/Component/Cache/Traits/PhpFilesTrait.php

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ trait PhpFilesTrait
2626
use FilesystemCommonTrait;
2727

2828
private $includeHandler;
29-
private $zendDetectUnicode;
29+
30+
private static $startTime;
3031

3132
public static function isSupported()
3233
{
33-
return function_exists('opcache_invalidate') && ini_get('opcache.enable');
34+
self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time();
35+
36+
return \function_exists('opcache_invalidate') && ini_get('opcache.enable') && ('cli' !== \PHP_SAPI || ini_get('opcache.enable_cli'));
3437
}
3538

3639
/**
@@ -40,19 +43,14 @@ public function prune()
4043
{
4144
$time = time();
4245
$pruned = true;
43-
$allowCompile = 'cli' !== PHP_SAPI || ini_get('opcache.enable_cli');
4446

4547
set_error_handler($this->includeHandler);
4648
try {
4749
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
4850
list($expiresAt) = include $file;
4951

5052
if ($time >= $expiresAt) {
51-
$pruned = @unlink($file) && !file_exists($file) && $pruned;
52-
53-
if ($allowCompile) {
54-
@opcache_invalidate($file, true);
55-
}
53+
$pruned = $this->doUnlink($file) && !file_exists($file) && $pruned;
5654
}
5755
}
5856
} finally {
@@ -70,9 +68,6 @@ protected function doFetch(array $ids)
7068
$values = array();
7169
$now = time();
7270

73-
if ($this->zendDetectUnicode) {
74-
$zmb = ini_set('zend.detect_unicode', 0);
75-
}
7671
set_error_handler($this->includeHandler);
7772
try {
7873
foreach ($ids as $id) {
@@ -88,9 +83,6 @@ protected function doFetch(array $ids)
8883
}
8984
} finally {
9085
restore_error_handler();
91-
if ($this->zendDetectUnicode) {
92-
ini_set('zend.detect_unicode', $zmb);
93-
}
9486
}
9587

9688
foreach ($values as $id => $value) {
@@ -119,7 +111,7 @@ protected function doSave(array $values, $lifetime)
119111
{
120112
$ok = true;
121113
$data = array($lifetime ? time() + $lifetime : PHP_INT_MAX, '');
122-
$allowCompile = 'cli' !== PHP_SAPI || ini_get('opcache.enable_cli');
114+
$allowCompile = self::isSupported();
123115

124116
foreach ($values as $key => $value) {
125117
if (null === $value || \is_object($value)) {
@@ -142,7 +134,8 @@ protected function doSave(array $values, $lifetime)
142134

143135
$data[1] = $value;
144136
$file = $this->getFile($key, true);
145-
$ok = $this->write($file, '<?php return '.var_export($data, true).';') && $ok;
137+
// Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
138+
$ok = $this->write($file, '<?php return '.var_export($data, true).';', self::$startTime - 10) && $ok;
146139

147140
if ($allowCompile) {
148141
@opcache_invalidate($file, true);
@@ -155,4 +148,13 @@ protected function doSave(array $values, $lifetime)
155148

156149
return $ok;
157150
}
151+
152+
protected function doUnlink($file)
153+
{
154+
if (self::isSupported()) {
155+
@opcache_invalidate($file, true);
156+
}
157+
158+
return @unlink($file);
159+
}
158160
}

0 commit comments

Comments
 (0)
0