From e61ed35aa06c633db93903d64244a3f82221586f Mon Sep 17 00:00:00 2001 From: Zankaria Date: Fri, 16 Feb 2024 15:18:17 +0100 Subject: [PATCH] Refactor queue.php --- inc/functions.php | 12 ++++- inc/queue.php | 121 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 95 insertions(+), 38 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 50e0ca38..5890da8a 100755 --- a/inc/functions.php +++ b/inc/functions.php @@ -2918,8 +2918,16 @@ function generation_strategy($fun, $array=array()) { global $config; return 'rebuild'; case 'defer': // Ok, it gets interesting here :) - get_queue('generate')->push(serialize(array('build', $fun, $array, $action))); - return 'ignore'; + $queue = Queues::get_queue($config, 'generate'); + if ($queue === false) { + if ($config['syslog']) { + _syslog(LOG_ERR, "Could not initialize generate queue, falling back to immediate rebuild strategy"); + } + return 'rebuild'; + } else { + $queue->push(serialize(array('build', $fun, $array, $action))); + return 'ignore'; + } case 'build_on_load': return 'delete'; } diff --git a/inc/queue.php b/inc/queue.php index 2801170e..0ecd1e3c 100644 --- a/inc/queue.php +++ b/inc/queue.php @@ -1,49 +1,98 @@ lock = Locks::get_lock($config, $key); - $key = str_replace('/', '::', $key); - $key = str_replace("\0", '', $key); - $this->key = "tmp/queue/$key/"; - } +class Queues { + private static $queues = array(); + + + /** + * This queue implementation isn't actually ordered, so it works more as a "bag". + */ + private static function filesystem(string $key, Lock $lock): Queue { + $key = str_replace('/', '::', $key); + $key = str_replace("\0", '', $key); + $key = "tmp/queue/$key/"; + + return new class($key, $lock) implements Queue { + private Lock $lock; + private string $key; + + + function __construct(string $key, Lock $lock) { + $this->lock = $lock; + $this->key = $key; + } + + public function push(string $str): Queue { + $this->lock->get_ex(); + file_put_contents($this->key . microtime(true), $str); + $this->lock->free(); + return $this; + } + + public function pop(int $n = 1): array { + $this->lock->get_ex(); + $dir = opendir($this->key); + $paths = array(); + + while ($n > 0) { + $path = readdir($dir); + if ($path === false) { + break; + } elseif ($path == '.' || $path == '..') { + continue; + } else { + $paths[] = $path; + $n--; + } + } + + $out = array(); + foreach ($paths as $v) { + $out[] = file_get_contents($this->key . $v); + unlink($this->key . $v); + } + + $this->lock->free(); + return $out; + } + }; } - function push($str) { global $config; - if ($config['queue']['enabled'] == 'fs') { - $this->lock->get_ex(); - file_put_contents($this->key.microtime(true), $str); - $this->lock->free(); - } - return $this; + /** + * No-op. Can be used for mocking. + */ + public static function none(): Queue { + return new class() implements Queue { + public function push(string $str): Queue { + return $this; + } + + public function pop(int $n = 1): array { + return array(); + } + }; } - function pop($n = 1) { global $config; - if ($config['queue']['enabled'] == 'fs') { - $this->lock->get_ex(); - $dir = opendir($this->key); - $paths = array(); - while ($n > 0) { - $path = readdir($dir); - if ($path === FALSE) break; - elseif ($path == '.' || $path == '..') continue; - else { $paths[] = $path; $n--; } + public static function get_queue(array $config, string $name): Queue|false { + if (!isset(self::$queues[$name])) { + if ($config['queue']['enabled'] == 'fs') { + $lock = Locks::get_lock($config, $name); + if ($lock === false) { + return false; + } + self::$queues[$name] = self::filesystem($name, $lock); + } else { + self::$queues[$name] = self::none(); } - $out = array(); - foreach ($paths as $v) { - $out []= file_get_contents($this->key.$v); - unlink($this->key.$v); - } - $this->lock->free(); - return $out; } + return self::$queues[$name]; } } -// Don't use the constructor. Use the get_queue function. -$queues = array(); +interface Queue { + // Push a string in the queue. + public function push(string $str): Queue; -function get_queue($name) { global $queues; - return $queues[$name] = isset ($queues[$name]) ? $queues[$name] : new Queue($name); + // Get a string from the queue. + public function pop(int $n = 1): array; }