Skip to content

Commit 3e4811f

Browse files
APCng storage - avoid worst-case memory usage in buildPermutationTree (#123)
* APCng storage - avoid worst-case memory usage in buildPermutationTree Signed-off-by: Josh Hoffer <[email protected]> * Fix PHPstan errors Signed-off-by: Lukas Kämmerling <[email protected]> --------- Signed-off-by: Josh Hoffer <[email protected]> Signed-off-by: Lukas Kämmerling <[email protected]> Co-authored-by: Lukas Kämmerling <[email protected]>
1 parent 381753d commit 3e4811f

File tree

1 file changed

+14
-24
lines changed

1 file changed

+14
-24
lines changed

src/Prometheus/Storage/APCng.php

+14-24
Original file line numberDiff line numberDiff line change
@@ -430,33 +430,24 @@ private function metaData(array $data): array
430430
* [9] => ['/private', 'get', 'fail'], [10] => ['/private', 'post', 'success'], [11] => ['/private', 'post', 'fail'],
431431
* [12] => ['/metrics', 'put', 'success'], [13] => ['/metrics', 'put', 'fail'], [14] => ['/metrics', 'get', 'success'],
432432
* [15] => ['/metrics', 'get', 'fail'], [16] => ['/metrics', 'post', 'success'], [17] => ['/metrics', 'post', 'fail']
433-
* @param array<string> $labelNames
434433
* @param array<array> $labelValues
435-
* @return array<array>
434+
* @return \Generator<array>
436435
*/
437-
private function buildPermutationTree(array $labelNames, array $labelValues): array /** @phpstan-ignore-line */
438-
{
439-
$treeRowCount = count(array_keys($labelNames));
440-
$numElements = 1;
441-
$treeInfo = [];
442-
for ($i = $treeRowCount - 1; $i >= 0; $i--) {
443-
$treeInfo[$i]['numInRow'] = count($labelValues[$i]);
444-
$numElements *= $treeInfo[$i]['numInRow'];
445-
$treeInfo[$i]['numInTree'] = $numElements;
446-
}
447-
448-
$map = array_fill(0, $numElements, []);
449-
for ($row = 0; $row < $treeRowCount; $row++) {
450-
$col = $i = 0;
451-
while ($i < $numElements) {
452-
$val = $labelValues[$row][$col];
453-
$map[$i] = array_merge($map[$i], array($val));
454-
if (++$i % ($treeInfo[$row]['numInTree'] / $treeInfo[$row]['numInRow']) == 0) {
455-
$col = ++$col % $treeInfo[$row]['numInRow'];
436+
private function buildPermutationTree(array $labelValues): \Generator /** @phpstan-ignore-line */
437+
{
438+
if (count($labelValues) > 0) {
439+
$lastIndex = array_key_last($labelValues);
440+
$currentValue = array_pop($labelValues);
441+
if ($currentValue != null) {
442+
foreach ($this->buildPermutationTree($labelValues) as $prefix) {
443+
foreach ($currentValue as $value) {
444+
yield $prefix + [$lastIndex => $value];
445+
}
456446
}
457447
}
448+
} else {
449+
yield [];
458450
}
459-
return $map;
460451
}
461452

462453
/**
@@ -557,10 +548,9 @@ private function getValues(string $type, array $metaData): array /** @phpstan-ig
557548
if (isset($metaData['buckets'])) {
558549
$metaData['buckets'][] = 'sum';
559550
$labels[] = $metaData['buckets'];
560-
$metaData['labelNames'][] = '__histogram_buckets';
561551
}
562552

563-
$labelValuesList = $this->buildPermutationTree($metaData['labelNames'], $labels);
553+
$labelValuesList = $this->buildPermutationTree($labels);
564554
unset($labels);
565555
$histogramBucket = '';
566556
foreach ($labelValuesList as $labelValues) {

0 commit comments

Comments
 (0)