diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2813,6 +2813,7 @@ 'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', + 'PhabricatorKeyValueSerializingCacheProxy' => 'applications/cache/PhabricatorKeyValueSerializingCacheProxy.php', 'PhabricatorKeyboardRemarkupRule' => 'infrastructure/markup/rule/PhabricatorKeyboardRemarkupRule.php', 'PhabricatorKeyring' => 'applications/files/keyring/PhabricatorKeyring.php', 'PhabricatorKeyringConfigOptionType' => 'applications/files/keyring/PhabricatorKeyringConfigOptionType.php', @@ -7798,6 +7799,7 @@ 'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorJumpNavHandler' => 'Phobject', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', + 'PhabricatorKeyValueSerializingCacheProxy' => 'PhutilKeyValueCacheProxy', 'PhabricatorKeyboardRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorKeyring' => 'Phobject', 'PhabricatorKeyringConfigOptionType' => 'PhabricatorConfigJSONOptionType', diff --git a/src/applications/cache/PhabricatorCaches.php b/src/applications/cache/PhabricatorCaches.php --- a/src/applications/cache/PhabricatorCaches.php +++ b/src/applications/cache/PhabricatorCaches.php @@ -116,6 +116,24 @@ return $caches; } + public static function getMutableStructureCache() { + static $cache; + if (!$cache) { + $caches = self::buildMutableStructureCaches(); + $cache = self::newStackFromCaches($caches); + } + return $cache; + } + + private static function buildMutableStructureCaches() { + $caches = array(); + + $cache = new PhabricatorKeyValueDatabaseCache(); + $cache = new PhabricatorKeyValueSerializingCacheProxy($cache); + $caches[] = $cache; + + return $caches; + } /* -( Runtime Cache )------------------------------------------------------ */ diff --git a/src/applications/cache/PhabricatorKeyValueSerializingCacheProxy.php b/src/applications/cache/PhabricatorKeyValueSerializingCacheProxy.php new file mode 100644 --- /dev/null +++ b/src/applications/cache/PhabricatorKeyValueSerializingCacheProxy.php @@ -0,0 +1,55 @@ + $result) { + $structure = @unserialize($result); + + // The unserialize() function returns false when unserializing a + // literal `false`, and also when it fails. If we get a literal + // `false`, test if the serialized form is the same as the + // serialization of `false` and miss the cache otherwise. + if ($structure === false) { + static $serialized_false; + if ($serialized_false === null) { + $serialized_false = serialize(false); + } + if ($result !== $serialized_false) { + continue; + } + } + + $reads[$key] = $structure; + } + + return $reads; + } + + public function setKeys(array $keys, $ttl = null) { + $writes = array(); + foreach ($keys as $key => $value) { + if (is_object($value)) { + throw new Exception( + pht( + 'Serializing cache can not write objects (for key "%s")!', + $key)); + } + $writes[$key] = serialize($value); + } + + return parent::setKeys($writes, $ttl); + } + + +}