Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fee5714

Browse files
committed
feature #47352 [HttpKernel] FileProfilerStorage remove expired profiles mechanism (alamirault)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [HttpKernel] FileProfilerStorage remove expired profiles mechanism | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | Fix #45831 <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead --> | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> This is a first attempt for limit number of profiles saved (discussed in #45831). When we save new profile, all expired profiles are removed. Expiration is one day for the moment. Questions: - Not sure how to deal, profiles with time `0`, like an unexpired profile ? - I assume profiles are sorted and oldest profile is on firstline. -> avoid readind all index file if first profile is not expired - Is there a best way ? (cpu/memory, io efficient) (I'm not sure I have the necessary skills, changes are welcome :)) TODOS: - [x] Changelog - [x] Complete tests - [ ] Symfony docs PR Commits ------- 58d0662 [HttpKernel] FileProfilerStorage remove expired profiles mechanism
2 parents 1923f8c + 58d0662 commit fee5714

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Deprecate parameters `container.dumper.inline_factories` and `container.dumper.inline_class_loader`, use `.container.dumper.inline_factories` and `.container.dumper.inline_class_loader` instead
8+
* `FileProfilerStorage` removes profiles automatically after two days
89

910
6.2
1011
---

src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,15 @@ public function write(Profile $profile): bool
165165
$profile->getIp(),
166166
$profile->getMethod(),
167167
$profile->getUrl(),
168-
$profile->getTime(),
168+
$profile->getTime() ?: time(),
169169
$profile->getParentToken(),
170170
$profile->getStatusCode(),
171171
]);
172172
fclose($file);
173+
174+
if (1 === mt_rand(1, 10)) {
175+
$this->removeExpiredProfiles();
176+
}
173177
}
174178

175179
return true;
@@ -289,4 +293,29 @@ private function doRead($token, Profile $profile = null): ?Profile
289293

290294
return $this->createProfileFromData($token, $data, $profile);
291295
}
296+
297+
private function removeExpiredProfiles()
298+
{
299+
$minimalProfileTimestamp = time() - 2 * 86400;
300+
$file = $this->getIndexFilename();
301+
$handle = fopen($file, 'r');
302+
303+
if ($offset = is_file($file.'.offset') ? (int) file_get_contents($file.'.offset') : 0) {
304+
fseek($handle, $offset);
305+
}
306+
307+
while ($line = fgets($handle)) {
308+
[$csvToken, , , , $csvTime] = str_getcsv($line);
309+
310+
if ($csvTime >= $minimalProfileTimestamp) {
311+
break;
312+
}
313+
314+
@unlink($this->getFilename($csvToken));
315+
$offset += \strlen($line);
316+
}
317+
fclose($handle);
318+
319+
file_put_contents($file.'.offset', $offset);
320+
}
292321
}

src/Symfony/Component/HttpKernel/Tests/Profiler/FileProfilerStorageTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,57 @@ public function testMultiRowIndexFile()
344344
$this->assertFalse(fgetcsv($handle));
345345
}
346346

347+
/**
348+
* @dataProvider provideExpiredProfiles
349+
*/
350+
public function testRemoveExpiredProfiles(string $index, string $expectedOffset)
351+
{
352+
$file = $this->tmpDir.'/index.csv';
353+
file_put_contents($file, $index);
354+
355+
$r = new \ReflectionMethod($this->storage, 'removeExpiredProfiles');
356+
$r->invoke($this->storage);
357+
358+
$this->assertSame($expectedOffset, file_get_contents($this->tmpDir.'/index.csv.offset'));
359+
}
360+
361+
public static function provideExpiredProfiles()
362+
{
363+
$oneHourAgo = new \DateTimeImmutable('-1 hour');
364+
365+
yield 'One unexpired profile' => [
366+
<<<CSV
367+
token0,127.0.0.0,,http://foo.bar/0,{$oneHourAgo->getTimestamp()},,
368+
369+
CSV,
370+
'0',
371+
];
372+
373+
$threeDaysAgo = new \DateTimeImmutable('-3 days');
374+
375+
yield 'One expired profile' => [
376+
<<<CSV
377+
token0,127.0.0.0,,http://foo.bar/0,{$threeDaysAgo->getTimestamp()},,
378+
379+
CSV,
380+
'48',
381+
];
382+
383+
$fourDaysAgo = new \DateTimeImmutable('-4 days');
384+
$threeDaysAgo = new \DateTimeImmutable('-3 days');
385+
$oneHourAgo = new \DateTimeImmutable('-1 hour');
386+
387+
yield 'Multiple expired profiles' => [
388+
<<<CSV
389+
token0,127.0.0.0,,http://foo.bar/0,{$fourDaysAgo->getTimestamp()},,
390+
token1,127.0.0.1,,http://foo.bar/1,{$threeDaysAgo->getTimestamp()},,
391+
token2,127.0.0.2,,http://foo.bar/2,{$oneHourAgo->getTimestamp()},,
392+
393+
CSV,
394+
'96',
395+
];
396+
}
397+
347398
public function testReadLineFromFile()
348399
{
349400
$r = new \ReflectionMethod($this->storage, 'readLineFromFile');

0 commit comments

Comments
 (0)