From 88f9f61e4ed7c2f3fefcc86aba4f4b412372cd77 Mon Sep 17 00:00:00 2001 From: Josh Hoffer Date: Wed, 21 Jun 2023 16:47:26 -0600 Subject: [PATCH 1/2] APCng storage - avoid worst-case memory usage in buildPermutationTree Signed-off-by: Josh Hoffer --- src/Prometheus/Storage/APCng.php | 39 ++++++++++++-------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/Prometheus/Storage/APCng.php b/src/Prometheus/Storage/APCng.php index 6628ef97..9e4ab6c1 100644 --- a/src/Prometheus/Storage/APCng.php +++ b/src/Prometheus/Storage/APCng.php @@ -412,33 +412,23 @@ private function metaData(array $data): array * [9] => ['/private', 'get', 'fail'], [10] => ['/private', 'post', 'success'], [11] => ['/private', 'post', 'fail'], * [12] => ['/metrics', 'put', 'success'], [13] => ['/metrics', 'put', 'fail'], [14] => ['/metrics', 'get', 'success'], * [15] => ['/metrics', 'get', 'fail'], [16] => ['/metrics', 'post', 'success'], [17] => ['/metrics', 'post', 'fail'] - * @param array $labelNames * @param array $labelValues - * @return array + * @return Generator */ - private function buildPermutationTree(array $labelNames, array $labelValues): array /** @phpstan-ignore-line */ - { - $treeRowCount = count(array_keys($labelNames)); - $numElements = 1; - $treeInfo = []; - for ($i = $treeRowCount - 1; $i >= 0; $i--) { - $treeInfo[$i]['numInRow'] = count($labelValues[$i]); - $numElements *= $treeInfo[$i]['numInRow']; - $treeInfo[$i]['numInTree'] = $numElements; - } - - $map = array_fill(0, $numElements, []); - for ($row = 0; $row < $treeRowCount; $row++) { - $col = $i = 0; - while ($i < $numElements) { - $val = $labelValues[$row][$col]; - $map[$i] = array_merge($map[$i], array($val)); - if (++$i % ($treeInfo[$row]['numInTree'] / $treeInfo[$row]['numInRow']) == 0) { - $col = ++$col % $treeInfo[$row]['numInRow']; - } + private function buildPermutationTree(array $labelValues): \Generator /** @phpstan-ignore-line */ + { + if($labelValues){ + $lastIndex = array_key_last($labelValues); + if($currentValue = array_pop($labelValues)){ + foreach($this->buildPermutationTree($labelValues) as $prefix){ + foreach($currentValue as $value){ + yield $prefix + [$lastIndex => $value]; + } } + } + } else { + yield []; } - return $map; } /** @@ -539,10 +529,9 @@ private function getValues(string $type, array $metaData): array /** @phpstan-ig if (isset($metaData['buckets'])) { $metaData['buckets'][] = 'sum'; $labels[] = $metaData['buckets']; - $metaData['labelNames'][] = '__histogram_buckets'; } - $labelValuesList = $this->buildPermutationTree($metaData['labelNames'], $labels); + $labelValuesList = $this->buildPermutationTree($labels); unset($labels); $histogramBucket = ''; foreach ($labelValuesList as $labelValues) { From a1a53f13e65d8d331b8089e56c1328c3a9c52857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20K=C3=A4mmerling?= Date: Wed, 5 Mar 2025 11:08:11 +0100 Subject: [PATCH 2/2] Fix PHPstan errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Kämmerling --- src/Prometheus/Storage/APCng.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Prometheus/Storage/APCng.php b/src/Prometheus/Storage/APCng.php index f1fbd961..b37cffb9 100644 --- a/src/Prometheus/Storage/APCng.php +++ b/src/Prometheus/Storage/APCng.php @@ -431,21 +431,22 @@ private function metaData(array $data): array * [12] => ['/metrics', 'put', 'success'], [13] => ['/metrics', 'put', 'fail'], [14] => ['/metrics', 'get', 'success'], * [15] => ['/metrics', 'get', 'fail'], [16] => ['/metrics', 'post', 'success'], [17] => ['/metrics', 'post', 'fail'] * @param array $labelValues - * @return Generator + * @return \Generator */ private function buildPermutationTree(array $labelValues): \Generator /** @phpstan-ignore-line */ { - if($labelValues){ - $lastIndex = array_key_last($labelValues); - if($currentValue = array_pop($labelValues)){ - foreach($this->buildPermutationTree($labelValues) as $prefix){ - foreach($currentValue as $value){ - yield $prefix + [$lastIndex => $value]; - } + if (count($labelValues) > 0) { + $lastIndex = array_key_last($labelValues); + $currentValue = array_pop($labelValues); + if ($currentValue != null) { + foreach ($this->buildPermutationTree($labelValues) as $prefix) { + foreach ($currentValue as $value) { + yield $prefix + [$lastIndex => $value]; + } + } } - } } else { - yield []; + yield []; } }