@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

Introduce a serializing key-value cache proxy

Summary:
Ref T11954. I want to store some lists/arrays in the mutable (database) cache, but it only supports string storage.

Provide a serializing wrapper which flattens when values are written and expands them when they're read.

Test Plan: Used by D16997. See that revision.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11954

Differential Revision: https://secure.phabricator.com/D16999

+75
+2
src/__phutil_library_map__.php
··· 2813 2813 'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php', 2814 2814 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 2815 2815 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', 2816 + 'PhabricatorKeyValueSerializingCacheProxy' => 'applications/cache/PhabricatorKeyValueSerializingCacheProxy.php', 2816 2817 'PhabricatorKeyboardRemarkupRule' => 'infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php', 2817 2818 'PhabricatorKeyring' => 'applications/files/keyring/PhabricatorKeyring.php', 2818 2819 'PhabricatorKeyringConfigOptionType' => 'applications/files/keyring/PhabricatorKeyringConfigOptionType.php', ··· 7798 7799 'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType', 7799 7800 'PhabricatorJumpNavHandler' => 'Phobject', 7800 7801 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 7802 + 'PhabricatorKeyValueSerializingCacheProxy' => 'PhutilKeyValueCacheProxy', 7801 7803 'PhabricatorKeyboardRemarkupRule' => 'PhutilRemarkupRule', 7802 7804 'PhabricatorKeyring' => 'Phobject', 7803 7805 'PhabricatorKeyringConfigOptionType' => 'PhabricatorConfigJSONOptionType',
+18
src/applications/cache/PhabricatorCaches.php
··· 116 116 return $caches; 117 117 } 118 118 119 + public static function getMutableStructureCache() { 120 + static $cache; 121 + if (!$cache) { 122 + $caches = self::buildMutableStructureCaches(); 123 + $cache = self::newStackFromCaches($caches); 124 + } 125 + return $cache; 126 + } 127 + 128 + private static function buildMutableStructureCaches() { 129 + $caches = array(); 130 + 131 + $cache = new PhabricatorKeyValueDatabaseCache(); 132 + $cache = new PhabricatorKeyValueSerializingCacheProxy($cache); 133 + $caches[] = $cache; 134 + 135 + return $caches; 136 + } 119 137 120 138 /* -( Runtime Cache )------------------------------------------------------ */ 121 139
+55
src/applications/cache/PhabricatorKeyValueSerializingCacheProxy.php
··· 1 + <?php 2 + 3 + /** 4 + * Proxies another cache and serializes values. 5 + * 6 + * This allows more complex data to be stored in a cache which can only store 7 + * strings. 8 + */ 9 + final class PhabricatorKeyValueSerializingCacheProxy 10 + extends PhutilKeyValueCacheProxy { 11 + 12 + public function getKeys(array $keys) { 13 + $results = parent::getKeys($keys); 14 + 15 + $reads = array(); 16 + foreach ($results as $key => $result) { 17 + $structure = @unserialize($result); 18 + 19 + // The unserialize() function returns false when unserializing a 20 + // literal `false`, and also when it fails. If we get a literal 21 + // `false`, test if the serialized form is the same as the 22 + // serialization of `false` and miss the cache otherwise. 23 + if ($structure === false) { 24 + static $serialized_false; 25 + if ($serialized_false === null) { 26 + $serialized_false = serialize(false); 27 + } 28 + if ($result !== $serialized_false) { 29 + continue; 30 + } 31 + } 32 + 33 + $reads[$key] = $structure; 34 + } 35 + 36 + return $reads; 37 + } 38 + 39 + public function setKeys(array $keys, $ttl = null) { 40 + $writes = array(); 41 + foreach ($keys as $key => $value) { 42 + if (is_object($value)) { 43 + throw new Exception( 44 + pht( 45 + 'Serializing cache can not write objects (for key "%s")!', 46 + $key)); 47 + } 48 + $writes[$key] = serialize($value); 49 + } 50 + 51 + return parent::setKeys($writes, $ttl); 52 + } 53 + 54 + 55 + }