Skip to content

Commit 416ae6a

Browse files
[Cache] improve perf of pruning for fs-based adapters
1 parent fbf55c2 commit 416ae6a

File tree

4 files changed

+56
-24
lines changed

4 files changed

+56
-24
lines changed

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

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\Cache\Adapter;
1313

14-
use Symfony\Component\Cache\Exception\LogicException;
1514
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
1615
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
1716
use Symfony\Component\Cache\PruneableInterface;
@@ -27,8 +26,9 @@
2726
class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface
2827
{
2928
use FilesystemTrait {
30-
doSave as doSaveCache;
31-
doDelete as doDeleteCache;
29+
doClear as private doClearCache;
30+
doSave as private doSaveCache;
31+
doDelete as private doDeleteCache;
3232
}
3333

3434
/**
@@ -48,6 +48,24 @@ public function __construct(string $namespace = '', int $defaultLifetime = 0, st
4848
$this->init($namespace, $directory);
4949
}
5050

51+
/**
52+
* {@inheritdoc}
53+
*/
54+
protected function doClear($namespace)
55+
{
56+
$ok = true;
57+
58+
if ('' === $namespace) {
59+
foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) {
60+
foreach ($this->scanHashDir($dir.\DIRECTORY_SEPARATOR) as $link) {
61+
$ok = ($this->doUnlink($link) || !file_exists($link)) && $ok;
62+
}
63+
}
64+
}
65+
66+
return $this->doClearCache($namespace) && $ok;
67+
}
68+
5169
/**
5270
* {@inheritdoc}
5371
*/
@@ -113,22 +131,9 @@ protected function doDelete(array $ids, array $tagData = []): bool
113131
protected function doInvalidate(array $tagIds): bool
114132
{
115133
foreach ($tagIds as $tagId) {
116-
$tagsFolder = $this->getTagFolder($tagId);
117-
if (!file_exists($tagsFolder)) {
118-
continue;
119-
}
120-
121-
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS)) as $itemLink) {
122-
if (!$itemLink->isLink()) {
123-
throw new LogicException('Expected a (sym)link when iterating over tag folder, non link found: '.$itemLink);
124-
}
125-
126-
$valueFile = $itemLink->getRealPath();
127-
if ($valueFile && file_exists($valueFile)) {
128-
@unlink($valueFile);
129-
}
130-
131-
@unlink((string) $itemLink);
134+
foreach ($this->scanHashDir($this->getTagFolder($tagId)) as $itemLink) {
135+
@unlink(realpath($itemLink) ?: $itemLink);
136+
@unlink($itemLink);
132137
}
133138
}
134139

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ trait FilesystemCommonTrait
2626
private function init(string $namespace, ?string $directory)
2727
{
2828
if (!isset($directory[0])) {
29-
$directory = sys_get_temp_dir().'/symfony-cache';
29+
$directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache';
3030
} else {
3131
$directory = realpath($directory) ?: $directory;
3232
}
@@ -55,12 +55,12 @@ protected function doClear($namespace)
5555
{
5656
$ok = true;
5757

58-
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
58+
foreach ($this->scanHashDir($this->directory) as $file) {
5959
if ('' !== $namespace && 0 !== strpos($this->getFileKey($file), $namespace)) {
6060
continue;
6161
}
6262

63-
$ok = ($file->isDir() || $this->doUnlink($file) || !file_exists($file)) && $ok;
63+
$ok = ($this->doUnlink($file) || !file_exists($file)) && $ok;
6464
}
6565

6666
return $ok;
@@ -123,6 +123,33 @@ private function getFileKey(string $file): string
123123
return '';
124124
}
125125

126+
private function scanHashDir(string $directory): \Generator
127+
{
128+
if (!file_exists($directory)) {
129+
return;
130+
}
131+
132+
$chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
133+
134+
for ($i = 0; $i < 38; ++$i) {
135+
if (!file_exists($directory.$chars[$i])) {
136+
continue;
137+
}
138+
139+
for ($j = 0; $j < 38; ++$j) {
140+
if (!file_exists($dir = $directory.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) {
141+
continue;
142+
}
143+
144+
foreach (@scandir($dir, SCANDIR_SORT_NONE) ?: [] as $file) {
145+
if ('.' !== $file && '..' !== $file) {
146+
yield $dir.\DIRECTORY_SEPARATOR.$file;
147+
}
148+
}
149+
}
150+
}
151+
}
152+
126153
/**
127154
* @internal
128155
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function prune()
3333
$time = time();
3434
$pruned = true;
3535

36-
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
36+
foreach ($this->scanHashDir($this->directory) as $file) {
3737
if (!$h = @fopen($file, 'rb')) {
3838
continue;
3939
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function prune()
5454

5555
set_error_handler($this->includeHandler);
5656
try {
57-
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
57+
foreach ($this->scanHashDir($this->directory) as $file) {
5858
try {
5959
if (\is_array($expiresAt = include $file)) {
6060
$expiresAt = $expiresAt[0];

0 commit comments

Comments
 (0)