From d69412a6f521876430dc513f3d734872b3ea7cd5 Mon Sep 17 00:00:00 2001 From: javier-villatoro Date: Thu, 8 Aug 2024 16:33:35 -0600 Subject: [PATCH] Optimize memory management to prevent leaks --- src/Http/Middleware/LeverRateStore.php | 70 ++++++++++++++++++++------ 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/src/Http/Middleware/LeverRateStore.php b/src/Http/Middleware/LeverRateStore.php index fe0a24a..fe42aa4 100644 --- a/src/Http/Middleware/LeverRateStore.php +++ b/src/Http/Middleware/LeverRateStore.php @@ -25,14 +25,14 @@ public function __construct() public function get(): array { - $data = Cache::get($this->cacheKey, []); + $data = []; + $part = 1; - // Check the size of the data in the cache - if ($this->getCacheSize($data) > $this->maxCacheSize) { - // If the data is too large, clear the cache - Cache::forget($this->cacheKey); - - return []; + // Retrieve and merge all parts + while (Cache::has($this->getCacheKey($part))) { // Check if the part exists + $partData = Cache::get($this->getCacheKey($part), []); // Retrieve the part data + $data = array_merge($data, $partData); // Merge the part data with the main data + $part++; // Move to the next part } return $data; @@ -40,20 +40,58 @@ public function get(): array public function push(int $timestamp, int $limit) { - $data = array_merge($this->get(), [$timestamp]); - - // Check the size of the data before saving it - if ($this->getCacheSize($data) <= $this->maxCacheSize) { - Cache::put($this->cacheKey, $data, $this->cacheTtl); - } else { - // If the data is too large, clear the cache and save only the new data - Cache::forget($this->cacheKey); - Cache::put($this->cacheKey, [$timestamp], $this->cacheTtl); + // Retrieve current data + $data = $this->get(); + $data[] = $timestamp; + + // Split data into parts and store each part separately + $parts = $this->splitDataIntoParts($data); + + // Store each part in the cache with separate keys + foreach ($parts as $index => $partData) { + Cache::put($this->getCacheKey($index + 1), $partData, $this->cacheTtl); } + + // Remove any leftover parts that may have been left from previous larger dataset + $this->cleanupExtraParts(count($parts) + 1); + } + + private function splitDataIntoParts(array $data): array + { + $parts = []; + $currentPart = []; + + foreach ($data as $item) { + $currentPart[] = $item; + if ($this->getCacheSize($currentPart) > $this->maxCacheSize) { + array_pop($currentPart); // Remove the last item that caused the size to exceed + $parts[] = $currentPart; // Store the current part in the parts array + $currentPart = [$item]; // Start a new part with the last item that was removed + } + } + + if (! empty($currentPart)) { + $parts[] = $currentPart; // Store the current part in the parts array + } + + return $parts; + } + + private function getCacheKey(int $part): string + { + return $this->cacheKey.':'.$part; } private function getCacheSize(array $data): int { return strlen(serialize($data)); } + + private function cleanupExtraParts(int $startPart) + { + while (Cache::has($this->getCacheKey($startPart))) { + Cache::forget($this->getCacheKey($startPart)); + $startPart++; + } + } }