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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy