Skip to content

Commit 43a651b

Browse files
authored
Do not delete a container that another process has not journaled yet (#6797)
1 parent 95c1b80 commit 43a651b

2 files changed

Lines changed: 66 additions & 2 deletions

File tree

‎src/DependencyInjection/Configurator.php‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ private function journal(string $currentContainerClassName): void
145145
$linesToWrite = [];
146146
$usedInTheLastWeek = [];
147147
$now = time();
148+
$week = 3600 * 24 * 7;
148149
$currentAlreadyInTheJournal = false;
149150
foreach ($journalLines as $journalLine) {
150151
if ($journalLine === '') {
@@ -157,8 +158,6 @@ private function journal(string $currentContainerClassName): void
157158
$className = $journalLineParts[0];
158159
$containerLastUsedTime = (int) $journalLineParts[1];
159160

160-
$week = 3600 * 24 * 7;
161-
162161
if ($containerLastUsedTime + $week < $now) {
163162
continue;
164163
}
@@ -200,6 +199,11 @@ private function journal(string $currentContainerClassName): void
200199
if (in_array($fileClassName, $usedInTheLastWeek, true)) {
201200
continue;
202201
}
202+
// another PHPStan process sharing this directory writes a new container before it is
203+
// journaled, so a file missing from the journal is deleted only once it is a week old
204+
if ($fileInfo->getMTime() + $week >= $now) {
205+
continue;
206+
}
203207
$basePathname = $fileInfo->getPathname();
204208
@unlink($basePathname);
205209
@unlink($basePathname . '.lock');
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\DependencyInjection;
4+
5+
use Nette\Utils\FileSystem;
6+
use Override;
7+
use PHPStan\File\FileHelper;
8+
use PHPUnit\Framework\TestCase;
9+
use function file_put_contents;
10+
use function is_file;
11+
use function sprintf;
12+
use function sys_get_temp_dir;
13+
use function time;
14+
use function touch;
15+
use function uniqid;
16+
17+
final class ConfiguratorJournalTest extends TestCase
18+
{
19+
20+
private string $tempDirectory;
21+
22+
#[Override]
23+
protected function setUp(): void
24+
{
25+
$this->tempDirectory = sys_get_temp_dir() . '/' . uniqid('phpstan-configurator-journal-', true);
26+
}
27+
28+
#[Override]
29+
protected function tearDown(): void
30+
{
31+
FileSystem::delete($this->tempDirectory);
32+
}
33+
34+
public function testKeepsAContainerThatAnotherProcessHasNotJournaledYet(): void
35+
{
36+
$configurator = new Configurator(new LoaderFactory(new FileHelper(__DIR__), __DIR__, __DIR__, null, []), true);
37+
$configurator->setTempDirectory($this->tempDirectory);
38+
$directory = $configurator->getContainerCacheDirectory();
39+
FileSystem::createDir($directory);
40+
41+
$now = time();
42+
$eightDaysAgo = $now - 3600 * 24 * 8;
43+
file_put_contents($directory . '/container.journal', sprintf("Container_used:%d\nContainer_expired:%d\n", $now, $eightDaysAgo));
44+
foreach (['Container_used', 'Container_expired', 'Container_current', 'Container_unjournaled'] as $className) {
45+
file_put_contents($directory . '/' . $className . '.php', '<?php');
46+
touch($directory . '/' . $className . '.php', $eightDaysAgo);
47+
}
48+
// written by another process that has not journaled it yet
49+
file_put_contents($directory . '/Container_fresh.php', '<?php');
50+
51+
(fn () => $this->journal('Container_current'))->call($configurator);
52+
53+
$this->assertFileExists($directory . '/Container_used.php');
54+
$this->assertFileExists($directory . '/Container_current.php');
55+
$this->assertFileExists($directory . '/Container_fresh.php');
56+
$this->assertFalse(is_file($directory . '/Container_expired.php'));
57+
$this->assertFalse(is_file($directory . '/Container_unjournaled.php'));
58+
}
59+
60+
}

0 commit comments

Comments
 (0)