From 7dc182a2e6633e07e2d68e9b20518624726b74d6 Mon Sep 17 00:00:00 2001 From: Tim <162806658+timotei-litespeed@users.noreply.github.com> Date: Fri, 31 May 2024 21:39:02 +0300 Subject: [PATCH 1/2] Object cache - improvements Improve object cache debug Multiple Actions: add/set/get/delete - Redis + Memcache Co-Authored-By: Timotei --- src/activation.cls.php | 3 +- src/object-cache.cls.php | 235 ++++++++++++++++++++++++++++----- src/object.lib.php | 273 ++++++++++++++++++++++++++++++++------- 3 files changed, 430 insertions(+), 81 deletions(-) diff --git a/src/activation.cls.php b/src/activation.cls.php index b3d0177aa..f7ec0c089 100644 --- a/src/activation.cls.php +++ b/src/activation.cls.php @@ -352,6 +352,7 @@ private function _update_conf_data_file($options) $ids = array(); if ($options[self::O_OBJECT]) { $this_ids = array( + self::O_DEBUG, self::O_OBJECT_KIND, self::O_OBJECT_HOST, self::O_OBJECT_PORT, @@ -369,7 +370,7 @@ private function _update_conf_data_file($options) } if ($options[self::O_GUEST]) { - $this_ids = array(self::HASH, self::O_CACHE_LOGIN_COOKIE, self::O_DEBUG, self::O_DEBUG_IPS, self::O_UTIL_NO_HTTPS_VARY, self::O_GUEST_UAS, self::O_GUEST_IPS); + $this_ids = array(self::HASH, self::O_CACHE_LOGIN_COOKIE, self::O_DEBUG_IPS, self::O_UTIL_NO_HTTPS_VARY, self::O_GUEST_UAS, self::O_GUEST_IPS); $ids = array_merge($ids, $this_ids); } diff --git a/src/object-cache.cls.php b/src/object-cache.cls.php index e55b62b13..c76305a81 100644 --- a/src/object-cache.cls.php +++ b/src/object-cache.cls.php @@ -14,6 +14,7 @@ class Object_Cache extends Root { + const O_DEBUG = 'debug'; const O_OBJECT = 'object'; const O_OBJECT_KIND = 'object-kind'; const O_OBJECT_HOST = 'object-host'; @@ -29,6 +30,7 @@ class Object_Cache extends Root const O_OBJECT_NON_PERSISTENT_GROUPS = 'object-non_persistent_groups'; private $_conn; + private $_cfg_debug; private $_cfg_enabled; private $_cfg_method; private $_cfg_host; @@ -56,7 +58,8 @@ class Object_Cache extends Root */ public function __construct($cfg = false) { - defined('LSCWP_LOG') && Debug2::debug2('[Object] init'); + $this->debug_oc('-------------'); + $this->debug_oc('init'); if ($cfg) { if (!is_array($cfg[Base::O_OBJECT_GLOBAL_GROUPS])) { @@ -65,6 +68,7 @@ public function __construct($cfg = false) if (!is_array($cfg[Base::O_OBJECT_NON_PERSISTENT_GROUPS])) { $cfg[Base::O_OBJECT_NON_PERSISTENT_GROUPS] = explode("\n", $cfg[Base::O_OBJECT_NON_PERSISTENT_GROUPS]); } + $this->_cfg_debug = $cfg[Base::O_DEBUG] ? $cfg[Base::O_DEBUG] : false; $this->_cfg_method = $cfg[Base::O_OBJECT_KIND] ? true : false; $this->_cfg_host = $cfg[Base::O_OBJECT_HOST]; $this->_cfg_port = $cfg[Base::O_OBJECT_PORT]; @@ -83,10 +87,12 @@ public function __construct($cfg = false) } $this->_cfg_enabled = $cfg[Base::O_OBJECT] && class_exists($this->_oc_driver) && $this->_cfg_host; - defined('LSCWP_LOG') && Debug2::debug('[Object] init with cfg result : ', $this->_cfg_enabled); + $this->debug_oc('init with cfg result : ', $this->_cfg_enabled); } // If OC is OFF, will hit here to init OC after conf initialized elseif (defined('LITESPEED_CONF_LOADED')) { + + $this->_cfg_debug = $this->conf(Base::O_DEBUG) ? $this->conf(Base::O_DEBUG) : false; $this->_cfg_method = $this->conf(Base::O_OBJECT_KIND) ? true : false; $this->_cfg_host = $this->conf(Base::O_OBJECT_HOST); $this->_cfg_port = $this->conf(Base::O_OBJECT_PORT); @@ -109,6 +115,7 @@ public function __construct($cfg = false) // Use self::const to avoid loading more classes $cfg = json_decode(file_get_contents(WP_CONTENT_DIR . '/' . self::CONF_FILE), true); if (!empty($cfg[self::O_OBJECT_HOST])) { + $this->_cfg_debug = !empty($cfg[Base::O_DEBUG]) ? $cfg[Base::O_DEBUG] : false; $this->_cfg_method = !empty($cfg[self::O_OBJECT_KIND]) ? $cfg[self::O_OBJECT_KIND] : false; $this->_cfg_host = $cfg[self::O_OBJECT_HOST]; $this->_cfg_port = $cfg[self::O_OBJECT_PORT]; @@ -133,6 +140,25 @@ public function __construct($cfg = false) $this->_cfg_enabled = false; } } + + /** + * Add debug. + * + * @since 6.3 + * @access private + */ + private function debug_oc( $text, $show_error = false ){ + if( defined('LSCWP_LOG') ){ + Debug2::debug( $text ); + + return; + } + + if (!$show_error && !$this->_cfg_debug) return; + + + error_log( gmdate('m/d/y H:i:s') . ' - ' . $text . PHP_EOL, 3, WP_CONTENT_DIR . '/debug.log' ); + } /** * Get `Store Transients` setting value @@ -172,7 +198,7 @@ public function update_file($options) // Update cls file if (!file_exists($_oc_wp_file) || md5_file($_oc_wp_file) !== md5_file($_oc_ori_file)) { - defined('LSCWP_LOG') && Debug2::debug('[Object] copying object-cache.php file to ' . $_oc_wp_file); + $this->debug_oc('copying object-cache.php file to ' . $_oc_wp_file); copy($_oc_ori_file, $_oc_wp_file); $changed = true; @@ -199,7 +225,7 @@ public function del_file() $_oc_wp_file = WP_CONTENT_DIR . '/object-cache.php'; if (file_exists($_oc_wp_file) && md5_file($_oc_wp_file) === md5_file($_oc_ori_file)) { - defined('LSCWP_LOG') && Debug2::debug('[Object] removing ' . $_oc_wp_file); + $this->debug_oc('removing ' . $_oc_wp_file); unlink($_oc_wp_file); } } @@ -223,11 +249,9 @@ public function test_connection() */ private function _reconnect($cfg) { - defined('LSCWP_LOG') && Debug2::debug('[Object] Reconnecting'); - // error_log( 'Object: reconnect !' ); + $this->debug_oc('Reconnecting'); if (isset($this->_conn)) { - // error_log( 'Object: Quiting existing connection!' ); - defined('LSCWP_LOG') && Debug2::debug('[Object] Quiting existing connection'); + $this->debug_oc('Quiting existing connection'); $this->flush(); $this->_conn = null; $this->cls(false, true); @@ -261,7 +285,8 @@ private function _connect() return false; } - defined('LSCWP_LOG') && Debug2::debug('[Object] connecting to ' . $this->_cfg_host . ':' . $this->_cfg_port); + $this->debug_oc('Init ' . $this->_oc_driver . ' connection'); + $this->debug_oc('connecting to ' . $this->_cfg_host . ':' . $this->_cfg_port); $failed = false; /** @@ -271,8 +296,6 @@ private function _connect() * @see https://github.com/phpredis/phpredis/#example-1 */ if ($this->_oc_driver == 'Redis') { - defined('LSCWP_LOG') && Debug2::debug('[Object] Init ' . $this->_oc_driver . ' connection'); - set_error_handler('litespeed_exception_handler'); try { $this->_conn = new \Redis(); @@ -310,28 +333,27 @@ private function _connect() $failed = true; } } catch (\Exception $e) { - error_log($e->getMessage()); + $this->debug_oc( 'Redis connect exception: ' . $e->getMessage(), true ); $failed = true; } catch (\ErrorException $e) { - error_log($e->getMessage()); + $this->debug_oc( 'Redis connect error: ' . $e->getMessage(), true ); $failed = true; } restore_error_handler(); } /** * Connect to Memcached */ else { - defined('LSCWP_LOG') && Debug2::debug('[Object] Init ' . $this->_oc_driver . ' connection'); if ($this->_cfg_persistent) { $this->_conn = new \Memcached($this->_get_mem_id()); // Check memcached persistent connection if ($this->_validate_mem_server()) { // error_log( 'Object: _validate_mem_server' ); - defined('LSCWP_LOG') && Debug2::debug('[Object] Got persistent ' . $this->_oc_driver . ' connection'); + $this->debug_oc('Got persistent ' . $this->_oc_driver . ' connection'); return true; } - defined('LSCWP_LOG') && Debug2::debug('[Object] No persistent ' . $this->_oc_driver . ' server list!'); + $this->debug_oc('No persistent ' . $this->_oc_driver . ' server list!'); } else { // error_log( 'Object: new memcached!' ); $this->_conn = new \Memcached(); @@ -358,7 +380,7 @@ private function _connect() // If failed to connect if ($failed) { - defined('LSCWP_LOG') && Debug2::debug('[Object] Failed to connect ' . $this->_oc_driver . ' server!'); + $this->debug_oc('❌ Failed to connect ' . $this->_oc_driver . ' server!', true); $this->_conn = null; $this->_cfg_enabled = false; !defined('LITESPEED_OC_FAILURE') && define('LITESPEED_OC_FAILURE', true); @@ -366,7 +388,7 @@ private function _connect() return false; } - defined('LSCWP_LOG') && Debug2::debug2('[Object] Connected'); + $this->debug_oc('Connected'); return true; } @@ -432,12 +454,44 @@ public function get($key) return null; } - // defined( 'LSCWP_LOG' ) && Debug2::debug2( '[Object] get ' . $key ); - $res = $this->_conn->get($key); return $res; } + + /** + * Get cache, multiple keys at once + * + * @since 6.3 + * @access public + */ + public function get_multiple($keys) + { + if (count($keys)<1) { + return array(); + } + + if (!$this->_cfg_enabled) { + return array(); + } + + if (!$this->_can_cache()) { + return array(); + } + + if (!$this->_connect()) { + return array(); + } + + if ($this->_oc_driver == 'Redis') { + $res = $this->_conn->mGet($keys); + } + else{ + $res = $this->_conn->getMulti($keys, \Memcached::GET_PRESERVE_ORDER); + } + + return $res; + } /** * Set cache @@ -462,11 +516,6 @@ public function set($key, $data, $expire) if (!$this->_connect()) { return null; } - - // defined( 'LSCWP_LOG' ) && Debug2::debug2( '[Object] set ' . $key ); - - // error_log( 'Object: set ' . $key ); - $ttl = $expire ?: $this->_cfg_life; if ($this->_oc_driver == 'Redis') { @@ -475,7 +524,7 @@ public function set($key, $data, $expire) } catch (\RedisException $ex) { $res = false; $msg = sprintf(__('Redis encountered a fatal error: %s (code: %d)', 'litespeed-cache'), $ex->getMessage(), $ex->getCode()); - Debug2::debug('[Object] ' . $msg); + $this->debug_oc($msg); Admin_Display::error($msg); } } else { @@ -485,6 +534,78 @@ public function set($key, $data, $expire) return $res; } + /** + * Test if Redis has Pipeline enabled + * + * @since 6.3 + * @access private + */ + private function redis_has_pipeline(){ + return method_exists( $this->_conn, 'pipeline' ); + } + + /** + * Set multiple cache + * + * @since 6.3 + * @access public + */ + public function set_multiple($data, $group, $expire) + { + $res = array(); + + if (!$this->_cfg_enabled) { + return null; + } + + if (!$this->_connect()) { + return null; + } + + $ttl = $expire ?: $this->_cfg_life; + $keys = array_keys($data); + + if ( + $this->_oc_driver == 'Redis' && + $this->redis_has_pipeline() && + ! $this->is_non_persistent($group) + ) { + try { + // Create pipeline. + $pipeline = $this->_conn->pipeline(); + // Add action to pipeline. + foreach($data as $key=>$value){ + if ( $expire ) { + $pipeline->setex( $key, $ttl, $value ); + } else { + $pipeline->set( $key, $value ); + } + } + // Run the pipeline and get values. + $exec = $pipeline->exec(); + + // Prepare return + foreach ( $exec as $i => $result) { + $res[$keys[$i]] = $result; + } + + return $res; + } catch (\Exception $ex) { + return false; + } + } + elseif ($this->_oc_driver == 'Memcached') { + return $this->_conn->setMulti($data, $ttl); + } + + // Fallback: Do normal set in case of error. + foreach($data as $key => $value){ + $res[$key] = $this->set($key, $value, $ttl); + } + + return $res; + } + /** * Check if can cache or not * @@ -515,8 +636,6 @@ public function delete($key) return null; } - // defined( 'LSCWP_LOG' ) && Debug2::debug2( '[Object] delete ' . $key ); - if ($this->_oc_driver == 'Redis') { $res = $this->_conn->del($key); } else { @@ -526,6 +645,51 @@ public function delete($key) return (bool) $res; } + /** + * Delete multiple cache at once + * + * @since 6.3 + * @access public + */ + public function delete_multiple($keys, $group) + { + if (!$this->_cfg_enabled) { + return null; + } + + if (!$this->_connect()) { + return null; + } + + if ( + $this->_oc_driver == 'Redis' && + $this->redis_has_pipeline() && + ! $this->is_non_persistent($group) + ) { + try { + // Create pipeline. + $pipeline = $this->_conn->pipeline(); + // Add action to pipeline. + foreach($keys as $key){ + $pipeline->del($key); + } + + // Run the pipeline and get status. + $exec = $pipeline->exec(); + foreach ($exec as $i => $result) { + $res[$keys[$i]] = $result; + } + + return $res; + } catch (\Exception $ex) { + return false; + } + } + elseif ($this->_oc_driver == 'Memcached') { + return $this->_conn->deleteMulti($keys); + } + } + /** * Clear all cache * @@ -535,7 +699,7 @@ public function delete($key) public function flush() { if (!$this->_cfg_enabled) { - defined('LSCWP_LOG') && Debug2::debug('[Object] bypass flushing'); + $this->debug_oc('bypass flushing'); return null; } @@ -543,7 +707,7 @@ public function flush() return null; } - defined('LSCWP_LOG') && Debug2::debug('[Object] flush!'); + $this->debug_oc('flush!'); if ($this->_oc_driver == 'Redis') { $res = $this->_conn->flushDb(); @@ -555,6 +719,17 @@ public function flush() return $res; } + /** + * Closes the cache. + * + * @since 6.3 + * @access public + */ + public function close() + { + return true; + } + /** * Add global groups * diff --git a/src/object.lib.php b/src/object.lib.php index eba7608d1..f3c1de766 100644 --- a/src/object.lib.php +++ b/src/object.lib.php @@ -27,7 +27,10 @@ function litespeed_exception_handler($errno, $errstr, $errfile, $errline) */ function wp_cache_init() { + global $wp_object_cache; $GLOBALS['wp_object_cache'] = WP_Object_Cache::get_instance(); + + \register_shutdown_function([$GLOBALS['wp_object_cache'], 'close']); } /** @@ -46,11 +49,11 @@ function wp_cache_init() * Default 0 (no expiration). * @return bool True on success, false if cache key and group already exist. */ -function wp_cache_add($key, $data, $group = '', $expire = 0) +function wp_cache_add($key, $data, $group = 'default', $expire = 0) { global $wp_object_cache; - return $wp_object_cache->add($key, $data, $group, (int) $expire); + return $wp_object_cache->add($key, $data, trim((string) $group), (int) $expire); } /** @@ -68,11 +71,11 @@ function wp_cache_add($key, $data, $group = '', $expire = 0) * @return bool[] Array of return values, grouped by key. Each value is either * true on success, or false if cache key and group already exist. */ -function wp_cache_add_multiple(array $data, $group = '', $expire = 0) +function wp_cache_add_multiple(array $data, $group = 'default', $expire = 0) { global $wp_object_cache; - return $wp_object_cache->add_multiple($data, $group, $expire); + return $wp_object_cache->add_multiple($data, trim((string) $group), (int) $expire); } /** @@ -91,11 +94,11 @@ function wp_cache_add_multiple(array $data, $group = '', $expire = 0) * Default 0 (no expiration). * @return bool True if contents were replaced, false if original value does not exist. */ -function wp_cache_replace($key, $data, $group = '', $expire = 0) +function wp_cache_replace($key, $data, $group = 'default', $expire = 0) { global $wp_object_cache; - return $wp_object_cache->replace($key, $data, $group, (int) $expire); + return $wp_object_cache->replace($key, $data, trim((string) $group), (int) $expire); } /** @@ -116,11 +119,11 @@ function wp_cache_replace($key, $data, $group = '', $expire = 0) * Default 0 (no expiration). * @return bool True on success, false on failure. */ -function wp_cache_set($key, $data, $group = '', $expire = 0) +function wp_cache_set($key, $data, $group = 'default', $expire = 0) { global $wp_object_cache; - return $wp_object_cache->set($key, $data, $group, (int) $expire); + return $wp_object_cache->set($key, $data, trim((string) $group), (int) $expire); } /** @@ -138,11 +141,11 @@ function wp_cache_set($key, $data, $group = '', $expire = 0) * @return bool[] Array of return values, grouped by key. Each value is either * true on success, or false on failure. */ -function wp_cache_set_multiple(array $data, $group = '', $expire = 0) +function wp_cache_set_multiple(array $data, $group = 'default', $expire = 0) { global $wp_object_cache; - return $wp_object_cache->set_multiple($data, $group, $expire); + return $wp_object_cache->set_multiple($data, trim((string) $group), (int) $expire); } /** @@ -161,11 +164,11 @@ function wp_cache_set_multiple(array $data, $group = '', $expire = 0) * Disambiguates a return of false, a storable value. Default null. * @return mixed|false The cache contents on success, false on failure to retrieve contents. */ -function wp_cache_get($key, $group = '', $force = false, &$found = null) +function wp_cache_get($key, $group = 'default', $force = false, &$found = null) { global $wp_object_cache; - return $wp_object_cache->get($key, $group, $force, $found); + return $wp_object_cache->get($key, trim((string) $group), $force, $found); } /** @@ -183,11 +186,11 @@ function wp_cache_get($key, $group = '', $force = false, &$found = null) * @return array Array of return values, grouped by key. Each value is either * the cache contents on success, or false on failure. */ -function wp_cache_get_multiple($keys, $group = '', $force = false) +function wp_cache_get_multiple($keys, $group = 'default', $force = false) { global $wp_object_cache; - - return $wp_object_cache->get_multiple($keys, $group, $force); + + return $wp_object_cache->get_multiple($keys, trim((string) $group), $force); } /** @@ -202,11 +205,11 @@ function wp_cache_get_multiple($keys, $group = '', $force = false) * @param string $group Optional. Where the cache contents are grouped. Default empty. * @return bool True on successful removal, false on failure. */ -function wp_cache_delete($key, $group = '') +function wp_cache_delete($key, $group = 'default') { global $wp_object_cache; - return $wp_object_cache->delete($key, $group); + return $wp_object_cache->delete($key, trim((string) $group)); } /** @@ -222,11 +225,11 @@ function wp_cache_delete($key, $group = '') * @return bool[] Array of return values, grouped by key. Each value is either * true on success, or false if the contents were not deleted. */ -function wp_cache_delete_multiple(array $keys, $group = '') +function wp_cache_delete_multiple(array $keys, $group = 'default') { global $wp_object_cache; - return $wp_object_cache->delete_multiple($keys, $group); + return $wp_object_cache->delete_multiple($keys, trim((string) $group)); } /** @@ -243,11 +246,11 @@ function wp_cache_delete_multiple(array $keys, $group = '') * @param string $group Optional. The group the key is in. Default empty. * @return int|false The item's new value on success, false on failure. */ -function wp_cache_incr($key, $offset = 1, $group = '') +function wp_cache_incr($key, $offset = 1, $group = 'default') { global $wp_object_cache; - return $wp_object_cache->incr($key, $offset, $group); + return $wp_object_cache->incr($key, $offset, trim((string) $group)); } /** @@ -264,11 +267,11 @@ function wp_cache_incr($key, $offset = 1, $group = '') * @param string $group Optional. The group the key is in. Default empty. * @return int|false The item's new value on success, false on failure. */ -function wp_cache_decr($key, $offset = 1, $group = '') +function wp_cache_decr($key, $offset = 1, $group = 'default') { global $wp_object_cache; - return $wp_object_cache->decr($key, $offset, $group); + return $wp_object_cache->decr($key, $offset, trim((string) $group)); } /** @@ -318,13 +321,40 @@ function wp_cache_flush_runtime() * @param string $group Name of group to remove from cache. * @return bool True if group was flushed, false otherwise. */ -function wp_cache_flush_group($group) +function wp_cache_flush_group($group = 'default') { - global $wp_object_cache; + global $wp_object_cache, $wp_object_cache_flushlog; + + $group = trim((string) $group); + $backtrace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5); + + if (\function_exists('\apply_filters')) { + $should_flush = (bool) \apply_filters('lts_oc_flush_group', true, $group, $backtrace); + + if (! $should_flush) { + return false; + } + } + + $wp_object_cache_flushlog[] = [ + 'type' => 'group-flush', + 'group' => $group, + 'backtrace' => $backtrace, + ]; return $wp_object_cache->flush_group($group); } +/** + * Determines whether the object cache implementation supports flushing individual cache groups. + * + * @return bool True if group flushing is supported, false otherwise. + */ +function wp_cache_supports_group_flush() +{ + return true; +} + /** * Determines whether the object cache implementation supports a particular feature. * @@ -549,6 +579,32 @@ protected function is_valid_key($key) return false; } + /** + * Serves as a utility function to determine whether a array of keys are valid. + * + * @since 6.3 + * + * @param int|string $key Cache keys to check for validity. + * @return bool If one of the key is invalid will invalidate all the keys. + */ + protected function is_valid_keys($keys) + { + if(!is_array($keys)){ + return false; + } + + $status = true; + + foreach($keys as $key){ + if(!$this->is_valid_key($key)){ + $status = false; + break; + } + } + + return $status; + } + /** * Get the final key. * @@ -565,6 +621,30 @@ private function _key($key, $group = 'default') return LSOC_PREFIX . $prefix . $group . '.' . $key; } + + /** + * Get array with ids as array keys and internal IDS as values. + * + * @since 6.3 + * + * @param array $keys List of keys to get. + * @param string $group Group used. + * @return array + */ + public function _keys_to_ids($keys, $group){ + $ids = []; + + foreach($keys as $key){ + $ids[$key] = $this->_key((string) $key, $group); + } + + return $ids; + } + + public function close() + { + return true; + } /** * Output debug info. @@ -745,26 +825,38 @@ public function set($key, $data, $group = 'default', $expire = 0) } /** - * Sets multiple values to the cache in one call. + * Sets array of data contents into the cache. * - * @since 5.4 + * @since 6.3 * @access public * - * @param array $data Array of key and value to be set. - * @param string $group Optional. Where the cache contents are grouped. Default empty. - * @param int $expire Optional. When to expire the cache contents, in seconds. - * Default 0 (no expiration). - * @return bool[] Array of return values, grouped by key. Each value is always true. + * @param mixed $data The contents to store in the cache. + * @param string $group Optional. Where to group the cache contents. Default 'default'. + * @param int $expire Optional. When to expire the cache contents, in seconds. + * Default 0 (no expiration). + * @return bool True if contents were set, false if key is invalid. */ - public function set_multiple(array $data, $group = '', $expire = 0) + public function set_multiple($data, $group = 'default', $expire = 0) { - $values = array(); + if (!$this->is_valid_keys(array_keys($data))) { + return false; + } + if (empty($group)) { + $group = 'default'; + } + if( $this->_object_cache->is_non_persistent($group)) { + return false; + } - foreach ($data as $key => $value) { - $values[$key] = $this->set($key, $value, $group, $expire); + // Convert ids to object keys. + $ids = $this->_keys_to_ids(array_keys($data), $group); + foreach($data as &$d){ + $d = serialize(array('data' => $d)); } + // Create data with OC keys to send. + $set_data = array_combine(array_values($ids), array_values($data)); - return $values; + return $this->_object_cache->set_multiple($set_data, $group, $expire); } /** @@ -855,7 +947,7 @@ public function get($key, $group = 'default', $force = false, &$found = null) /** * Retrieves multiple values from the cache in one call. * - * @since 5.4 + * @since 6.3 * @access public * * @param array $keys Array of keys under which the cache contents are stored. @@ -867,13 +959,90 @@ public function get($key, $group = 'default', $force = false, &$found = null) */ public function get_multiple($keys, $group = 'default', $force = false) { - $values = array(); + if (!$this->is_valid_keys($keys)) { + return false; + } + if (empty($group)) { + $group = 'default'; + } + if ( ! is_array( $keys ) ) { + return array(); + } + + $cache_values = array(); + $ids = $this->_keys_to_ids($keys, $group); + $ids_to_get = $ids; + // get from local cache + is force foreach ($keys as $key) { - $values[$key] = $this->get($key, $group, $force); + $id = $ids[ $key ]; + if (array_key_exists($id, $this->_cache) && !$force) { + $cache_values[ $key ] = $this->_cache[$id]; + $this->count_hit_incall++; + unset($ids_to_get[$key]); + } } - return $values; + // No ids to get, return values. + if ( empty( $ids_to_get ) ) { + return $cache_values; + } + + // Get cache from server. + $results_srv = array(); + try { + // Get values and keep order. + $results_tmp = $this->_object_cache->get_multiple( array_values($ids) ); + $results_srv = array_combine( + array_keys($ids), + $results_tmp ? : array_fill( 0, count( $ids ), false ) + ); + } catch ( Exception $exception ) { + // Get values and keep order. + $results_srv = array_combine( + $ids, + array_fill( 0, count( $ids ), false ) + ); + } + $this->cache_total++; + + // Assign it to return variable. + foreach($results_srv as $key => $result){ + if(isset($ids_to_get[ $key ])){ + $found = false; + + if (!array_key_exists( $ids_to_get[ $key ], $this->_cache_404) && !$this->_object_cache->is_non_persistent($group)) { + if ($result !== null) { + $result = @maybe_unserialize($result); + } + + if (is_array($result) && array_key_exists('data', $result)) { + $this->count_hit++; + $cache_values[ $key ] = $result['data']; + $this->_cache[ $ids_to_get[ $key ] ] = $result['data']; + $found = true; + } else { + // If not found but has `Store Transients` cfg on, still need to follow WP's get_transient() logic + if (!$found && $this->_object_cache->store_transients($group)) { + $result = $this->_transient_get($key, $group); + $cache_values[ $key ] = $result; + $this->_cache[ $ids_to_get[ $key ] ] = $result; + } + else{ + $cache_values[ $key ] = false; + $this->_cache_404[$ids_to_get[ $key ]] = 1; + $this->count_miss++; + } + } + } + else{ + $cache_values[ $key ] = false; + $this->count_miss_incall++; + } + } + } + + return $cache_values; } /** @@ -928,15 +1097,21 @@ public function delete($key, $group = 'default', $deprecated = false) * @return bool[] Array of return values, grouped by key. Each value is either * true on success, or false if the contents were not deleted. */ - public function delete_multiple(array $keys, $group = '') + public function delete_multiple(array $keys, $group = 'default') { - $values = array(); - - foreach ($keys as $key) { - $values[$key] = $this->delete($key, $group); + if (!$this->is_valid_keys($keys)) { + return false; + } + if ( ! is_array( $keys ) ) { + return array(); + } + if (empty($group)) { + $group = 'default'; } - return $values; + $ids = $this->_keys_to_ids($keys, $group); + + return $this->_object_cache->delete_multiple(array_values($ids), $group); } /** @@ -1026,9 +1201,7 @@ public function flush() { $this->flush_runtime(); - $this->_object_cache->flush(); - - return true; + return $this->_object_cache->flush(); } /** From 57b98ab48609fe9ad369669e755e9eb74a4ae7e0 Mon Sep 17 00:00:00 2001 From: Timotei Date: Wed, 21 Aug 2024 19:16:19 +0300 Subject: [PATCH 2/2] remove double function --- src/object-cache.cls.php | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/object-cache.cls.php b/src/object-cache.cls.php index d8e7786c2..993f7fc90 100644 --- a/src/object-cache.cls.php +++ b/src/object-cache.cls.php @@ -139,25 +139,6 @@ public function __construct($cfg = false) $this->_cfg_enabled = false; } } - - /** - * Add debug. - * - * @since 6.3 - * @access private - */ - private function debug_oc( $text, $show_error = false ){ - if( defined('LSCWP_LOG') ){ - Debug2::debug( $text ); - - return; - } - - if (!$show_error && !$this->_cfg_debug) return; - - - error_log( gmdate('m/d/y H:i:s') . ' - ' . $text . PHP_EOL, 3, WP_CONTENT_DIR . '/debug.log' ); - } /** * Add debug.