X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=CRM%2FUtils%2FCache.php;h=26bdc6c3b7dd76e68fea0cf846868309ea66f36a;hb=81144b6d222c4c7825e9dcc245937d1120d3c32f;hp=3306f821a73508dfc85f6ed88d3826f75402785f;hpb=d7e0c6a6d10fbd3548bfebb9926a3bf79c91296b;p=civicrm-core.git diff --git a/CRM/Utils/Cache.php b/CRM/Utils/Cache.php index 3306f821a7..26bdc6c3b7 100644 --- a/CRM/Utils/Cache.php +++ b/CRM/Utils/Cache.php @@ -89,18 +89,18 @@ class CRM_Utils_Cache { switch ($cachePlugin) { case 'ArrayCache': case 'NoCache': - $defaults = array(); + $defaults = []; break; case 'Redis': case 'Memcache': case 'Memcached': - $defaults = array( + $defaults = [ 'host' => 'localhost', 'port' => 11211, 'timeout' => 3600, 'prefix' => '', - ); + ]; // Use old constants if needed to ensure backward compatibility if (defined('CIVICRM_MEMCACHE_HOST')) { @@ -139,7 +139,7 @@ class CRM_Utils_Cache { break; case 'APCcache': - $defaults = array(); + $defaults = []; if (defined('CIVICRM_DB_CACHE_TIMEOUT')) { $defaults['timeout'] = CIVICRM_DB_CACHE_TIMEOUT; } @@ -165,11 +165,21 @@ class CRM_Utils_Cache { * should function correctly, but it can be harder to inspect/debug. * - type: array|string, list of acceptable cache types, in order of preference. * - prefetch: bool, whether to prefetch all data in cache (if possible). + * - withArray: bool|null|'fast', whether to setup a thread-local array-cache in front of the cache driver. + * Note that cache-values may be passed to the underlying driver with extra metadata, + * so this will slightly change/enlarge the on-disk format. + * Support varies by driver: + * - For most memory backed caches, this option is meaningful. + * - For SqlGroup, this option is ignored. SqlGroup has equivalent behavior built-in. + * - For ArrayCache, this option is ignored. It's redundant. + * If this is a short-lived process in which TTL's don't matter, you might + * use 'fast' mode. It sacrifices some PSR-16 compliance and cache-coherency + * protections to improve performance. * @return CRM_Utils_Cache_Interface * @throws CRM_Core_Exception * @see Civi::cache() */ - public static function create($params = array()) { + public static function create($params = []) { $types = (array) $params['type']; if (!empty($params['name'])) { @@ -179,26 +189,30 @@ class CRM_Utils_Cache { foreach ($types as $type) { switch ($type) { case '*memory*': - if (defined('CIVICRM_DB_CACHE_CLASS') && in_array(CIVICRM_DB_CACHE_CLASS, array('Memcache', 'Memcached', 'Redis'))) { + if (defined('CIVICRM_DB_CACHE_CLASS') && in_array(CIVICRM_DB_CACHE_CLASS, ['Memcache', 'Memcached', 'Redis'])) { $dbCacheClass = 'CRM_Utils_Cache_' . CIVICRM_DB_CACHE_CLASS; $settings = self::getCacheSettings(CIVICRM_DB_CACHE_CLASS); $settings['prefix'] = CRM_Utils_Array::value('prefix', $settings, '') . self::DELIMITER . $params['name'] . self::DELIMITER; - return new $dbCacheClass($settings); + $cache = new $dbCacheClass($settings); + if (!empty($params['withArray'])) { + $cache = $params['withArray'] === 'fast' ? new CRM_Utils_Cache_FastArrayDecorator($cache) : new CRM_Utils_Cache_ArrayDecorator($cache); + } + return $cache; } break; case 'SqlGroup': if (defined('CIVICRM_DSN') && CIVICRM_DSN) { - return new CRM_Utils_Cache_SqlGroup(array( + return new CRM_Utils_Cache_SqlGroup([ 'group' => $params['name'], 'prefetch' => CRM_Utils_Array::value('prefetch', $params, FALSE), - )); + ]); } break; case 'Arraycache': case 'ArrayCache': - return new CRM_Utils_Cache_ArrayCache(array()); + return new CRM_Utils_Cache_ArrayCache([]); } } @@ -237,7 +251,8 @@ class CRM_Utils_Cache { * Ex: 'ArrayCache', 'Memcache', 'Redis'. */ public static function getCacheDriver() { - $className = 'ArrayCache'; // default to ArrayCache for now + // default to ArrayCache for now + $className = 'ArrayCache'; // Maintain backward compatibility for now. // Setting CIVICRM_USE_MEMCACHE or CIVICRM_USE_ARRAYCACHE will @@ -258,4 +273,33 @@ class CRM_Utils_Cache { return $className; } + /** + * Generate a unique negative-acknowledgement token (NACK). + * + * When using PSR-16 to read a value, the `$cahce->get()` will a return a default + * value on cache-miss, so it's hard to know if you've gotten a geniune value + * from the cache or just a default. If you're in an edge-case where it matters + * (and you want to do has()+get() in a single roundtrip), use the nack() as + * the default: + * + * $nack = CRM_Utils_Cache::nack(); + * $value = $cache->get('foo', $nack); + * echo ($value === $nack) ? "Cache has a value, and we got it" : "Cache has no value". + * + * The value should be unique to avoid accidental matches. + * + * @return string + * Unique nonce value indicating a "negative acknowledgement" (failed read). + * If we need to accurately perform has($key)+get($key), we can + * use `get($key,$nack)`. + */ + public static function nack() { + $st =& Civi::$statics[__CLASS__]; + if (!isset($st['nack-c'])) { + $st['nack-c'] = md5(CRM_Utils_Request::id() . CIVICRM_SITE_KEY . CIVICRM_DSN . mt_rand(0, 10000)); + $st['nack-i'] = 0; + } + return 'NACK:' . $st['nack-c'] . $st['nack-i']++; + } + }