Skip to content

Commit c17ea6d

Browse files
committed
Fix race condition on flushByTag function
1 parent bc718cf commit c17ea6d

File tree

7 files changed

+33
-82
lines changed

7 files changed

+33
-82
lines changed

Classes/Cache/Backend/SsiIncludeCacheBackend.php

Lines changed: 18 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,15 @@
66

77
use AUS\SsiInclude\Utility\FilenameUtility;
88
use InvalidArgumentException;
9-
use TYPO3\CMS\Core\Cache\Backend\AbstractBackend;
10-
use TYPO3\CMS\Core\Cache\Backend\BackendInterface;
11-
use TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface;
12-
use TYPO3\CMS\Core\Cache\CacheManager;
9+
use TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend;
1310
use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
14-
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
1511
use TYPO3\CMS\Core\Core\Environment;
1612
use TYPO3\CMS\Core\Utility\GeneralUtility;
1713
use Webimpress\SafeWriter\Exception\ExceptionInterface;
1814
use Webimpress\SafeWriter\FileWriter;
1915

20-
class SsiIncludeCacheBackend extends AbstractBackend implements TaggableBackendInterface
16+
class SsiIncludeCacheBackend extends Typo3DatabaseBackend
2117
{
22-
private readonly TaggableBackendInterface $concrete;
23-
24-
private string $concreteCache = 'aus_ssi_include_concrete_cache';
25-
2618
private readonly FilenameUtility $filenameUtility;
2719

2820
/**
@@ -35,30 +27,26 @@ class SsiIncludeCacheBackend extends AbstractBackend implements TaggableBackendI
3527
/**
3628
* @inheritdoc
3729
* @param array<string, mixed> $options
38-
* @throws NoSuchCacheException
3930
*/
4031
public function __construct($context, array $options = [])
4132
{
4233
parent::__construct($context, $options);
4334

4435
$this->filenameUtility = GeneralUtility::makeInstance(FilenameUtility::class);
36+
}
4537

46-
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
47-
assert($cacheManager instanceof CacheManager);
48-
$concrete = $cacheManager->getCache($this->concreteCache)->getBackend();
49-
assert($concrete instanceof BackendInterface);
50-
assert($concrete instanceof TaggableBackendInterface);
51-
$this->concrete = $concrete;
38+
public function getSsiIncludeDir(): string
39+
{
40+
return $this->ssiIncludeDir;
5241
}
5342

5443
/**
55-
* The cache identifier of the concrete cache which is used to save
56-
* the data. If storeData is false, it also creates an empty cache entry
57-
* to include with caching framework and have the identifier tied to the cache tags and lifetime
44+
* @return list<string>
5845
*/
59-
public function setConcreteCache(string $concreteCache): void
46+
private function getSsiIncludeDirFiles(): array
6047
{
61-
$this->concreteCache = $concreteCache;
48+
$publicIncludeDir = Environment::getPublicPath() . $this->ssiIncludeDir;
49+
return glob($publicIncludeDir . '*.html') ?: [];
6250
}
6351

6452
/**
@@ -78,19 +66,6 @@ public function setStoreData(bool $storeData): void
7866
$this->storeData = $storeData;
7967
}
8068

81-
public function getSsiIncludeDir(): string
82-
{
83-
return $this->ssiIncludeDir;
84-
}
85-
86-
/**
87-
* @inheritdoc
88-
*/
89-
public function setCache(FrontendInterface $cache): void
90-
{
91-
$this->cache = $cache;
92-
}
93-
9469
/**
9570
* @inheritdoc
9671
* @param array<string> $tags
@@ -102,23 +77,15 @@ public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
10277
throw new InvalidArgumentException('Data must be a string', 1616420133);
10378
}
10479

80+
parent::set($entryIdentifier, $this->storeData ? $data : '', $tags, $lifetime);
81+
10582
$absolutePath = $this->filenameUtility->getAbsoluteFilename($entryIdentifier);
10683

10784
GeneralUtility::mkdir_deep(dirname($absolutePath));
10885
GeneralUtility::fixPermissions(dirname($absolutePath));
10986

11087
FileWriter::writeFile($absolutePath, $data);
11188
GeneralUtility::fixPermissions($absolutePath);
112-
113-
$this->concrete->set($entryIdentifier, $this->storeData ? $data : '', $tags, $lifetime);
114-
}
115-
116-
/**
117-
* @inheritdoc
118-
*/
119-
public function get($entryIdentifier): false|string
120-
{
121-
return $this->concrete->get($entryIdentifier);
12289
}
12390

12491
/**
@@ -127,7 +94,7 @@ public function get($entryIdentifier): false|string
12794
*/
12895
public function has($entryIdentifier): bool
12996
{
130-
$data = $this->concrete->has($entryIdentifier);
97+
$data = parent::has($entryIdentifier);
13198
if (!$data) {
13299
return false;
133100
}
@@ -147,7 +114,7 @@ public function remove($entryIdentifier): bool
147114
unlink($absoluteFile);
148115
}
149116

150-
return $this->concrete->remove($entryIdentifier);
117+
return parent::remove($entryIdentifier);
151118
}
152119

153120
/**
@@ -159,7 +126,7 @@ public function flush(): void
159126
unlink($file);
160127
}
161128

162-
$this->concrete->flush();
129+
parent::flush();
163130
}
164131

165132
/**
@@ -169,7 +136,7 @@ public function flush(): void
169136
public function collectGarbage(): void
170137
{
171138
// remove outdated things
172-
$this->concrete->collectGarbage();
139+
parent::collectGarbage();
173140

174141
// get all files, and the file that has no entry remove them
175142
$files = $this->getSsiIncludeDirFiles();
@@ -200,7 +167,7 @@ public function flushByTag($tag): void
200167
*/
201168
public function flushByTags(array $tags): void
202169
{
203-
$this->concrete->flushByTags($tags);
170+
parent::flushByTags($tags);
204171
foreach ($tags as $tag) {
205172
$this->flushByTag($tag);
206173
}
@@ -213,15 +180,6 @@ public function flushByTags(array $tags): void
213180
*/
214181
public function findIdentifiersByTag($tag): array
215182
{
216-
return $this->concrete->findIdentifiersByTag($tag);
217-
}
218-
219-
/**
220-
* @return list<string>
221-
*/
222-
private function getSsiIncludeDirFiles(): array
223-
{
224-
$publicIncludeDir = Environment::getPublicPath() . $this->ssiIncludeDir;
225-
return glob($publicIncludeDir . '*.html') ?: [];
183+
return parent::findIdentifiersByTag($tag);
226184
}
227185
}

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,6 @@ This defaults to on, but if you want to spare some space you can disable it.
101101

102102
Public directory where the SSI files are stored.
103103

104-
#### concreteCache
105-
106-
An configured taggable cache to use as the cache backends backbone
107-
108104
### Using the LazyDataProcessor to increase the Performance even more.
109105

110106
#### before:

Tests/Classes/SsiIncludeCacheBackendTest.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ private function initializeCacheFramework(): void
6464
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
6565
assert($cacheManager instanceof CacheManager);
6666
$cacheManager->setCacheConfigurations([
67-
'aus_ssi_include_concrete_cache' => [
68-
'frontend' => VariableFrontend::class,
69-
'backend' => Typo3DatabaseBackend::class,
70-
],
7167
'aus_ssi_include_cache' => [
7268
'frontend' => SsiIncludeCacheFrontend::class,
7369
'backend' => SsiIncludeCacheBackend::class,
@@ -84,11 +80,11 @@ private function initializeCacheFramework(): void
8480
*/
8581
public function cacheTableExists(): void
8682
{
87-
$connection = $this->getConnectionPool()->getConnectionForTable('cache_aus_ssi_include_concrete_cache');
88-
$query = $connection->executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='cache_aus_ssi_include_concrete_cache'");
83+
$connection = $this->getConnectionPool()->getConnectionForTable('cache_aus_ssi_include_cache');
84+
$query = $connection->executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='cache_aus_ssi_include_cache'");
8985
$result = $query->fetchAssociative();
9086

91-
self::assertNotEmpty($result, 'The cache_ssi_cache table was not created.');
87+
self::assertNotEmpty($result, 'The cache_aus_ssi_include_cache table was not created.');
9288
}
9389

9490
/**

Tests/Classes/SsiIncludeCacheFrontendTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
class SsiIncludeCacheFrontendTest extends UnitTestCase
1111
{
12+
protected bool $resetSingletonInstances = true;
13+
1214
/**
1315
* @test
1416
*/

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
],
1313
"require": {
1414
"php": "~8.1.0 || ~8.2.0 || ~8.3.0",
15-
"typo3/cms-fluid": "^10.4.0 || ^11.5.0 || ^12.4.0",
16-
"typo3/cms-frontend": "^10.4.0 || ^11.5.0 || ^12.4.0",
15+
"typo3/cms-fluid": "^11.5.0 || ^12.4.0",
16+
"typo3/cms-frontend": "^11.5.0 || ^12.4.0",
1717
"webimpress/safe-writer": "^2.2.0"
1818
},
1919
"require-dev": {

ext_localconf.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313

1414
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'][] = ClearCache::class . '->clearCache';
1515

16-
// we might want to have a default concrete cache if not already defined in another way
17-
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['aus_ssi_include_cache']['options']['concreteCache'])) {
18-
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['aus_ssi_include_concrete_cache'] = [
19-
'frontend' => VariableFrontend::class,
20-
'backend' => Typo3DatabaseBackend::class,
21-
];
22-
}
23-
24-
// TODO nochmal testen wie die ergebnisse sind jenachdem was ich im projekt hinterlege
2516
// define the main cache with the possibility to have a partial configuration already
2617
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['aus_ssi_include_cache'] = array_merge([
2718
'frontend' => SsiIncludeCacheFrontend::class,

runTest.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
3+
docker run -u1000 -v ./:/app -w /app ghcr.io/pluswerk/php-dev:nginx-8.1-alpine sh -c 'git config --global --add safe.directory /app && composer require typo3/testing-framework typo3/minimal="^11" -q -n -W --dev && composer test'
4+
docker run -u1000 -v ./:/app -w /app ghcr.io/pluswerk/php-dev:nginx-8.1-alpine sh -c 'git config --global --add safe.directory /app && composer require typo3/testing-framework typo3/minimal="^12" -q -n -W --dev && composer test'
5+
docker run -u1000 -v ./:/app -w /app ghcr.io/pluswerk/php-dev:nginx-8.2-alpine sh -c 'git config --global --add safe.directory /app && composer require typo3/testing-framework typo3/minimal="^11" -q -n -W --dev && composer test'
6+
docker run -u1000 -v ./:/app -w /app ghcr.io/pluswerk/php-dev:nginx-8.2-alpine sh -c 'git config --global --add safe.directory /app && composer require typo3/testing-framework typo3/minimal="^12" -q -n -W --dev && composer test'
7+
docker run -u1000 -v ./:/app -w /app ghcr.io/pluswerk/php-dev:nginx-8.3-alpine sh -c 'git config --global --add safe.directory /app && composer require typo3/testing-framework typo3/minimal="^11" -q -n -W --dev && composer test'
8+
docker run -u1000 -v ./:/app -w /app ghcr.io/pluswerk/php-dev:nginx-8.3-alpine sh -c 'git config --global --add safe.directory /app && composer require typo3/testing-framework typo3/minimal="^12" -q -n -W --dev && composer test'

0 commit comments

Comments
 (0)