Path: blob/master/src/applications/cache/PhabricatorKeyValueDatabaseCache.php
12242 views
<?php12final class PhabricatorKeyValueDatabaseCache3extends PhutilKeyValueCache {45const CACHE_FORMAT_RAW = 'raw';6const CACHE_FORMAT_DEFLATE = 'deflate';78public function setKeys(array $keys, $ttl = null) {9if (PhabricatorEnv::isReadOnly()) {10return;11}1213if ($keys) {14$map = $this->digestKeys(array_keys($keys));15$conn_w = $this->establishConnection('w');1617$sql = array();18foreach ($map as $key => $hash) {19$value = $keys[$key];2021list($format, $storage_value) = $this->willWriteValue($key, $value);2223$sql[] = qsprintf(24$conn_w,25'(%s, %s, %s, %B, %d, %nd)',26$hash,27$key,28$format,29$storage_value,30time(),31$ttl ? (time() + $ttl) : null);32}3334$guard = AphrontWriteGuard::beginScopedUnguardedWrites();35foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {36queryfx(37$conn_w,38'INSERT INTO %T39(cacheKeyHash, cacheKey, cacheFormat, cacheData,40cacheCreated, cacheExpires) VALUES %LQ41ON DUPLICATE KEY UPDATE42cacheKey = VALUES(cacheKey),43cacheFormat = VALUES(cacheFormat),44cacheData = VALUES(cacheData),45cacheCreated = VALUES(cacheCreated),46cacheExpires = VALUES(cacheExpires)',47$this->getTableName(),48$chunk);49}50unset($guard);51}5253return $this;54}5556public function getKeys(array $keys) {57$results = array();58if ($keys) {59$map = $this->digestKeys($keys);6061$rows = queryfx_all(62$this->establishConnection('r'),63'SELECT * FROM %T WHERE cacheKeyHash IN (%Ls)',64$this->getTableName(),65$map);66$rows = ipull($rows, null, 'cacheKey');6768foreach ($keys as $key) {69if (empty($rows[$key])) {70continue;71}7273$row = $rows[$key];7475if ($row['cacheExpires'] && ($row['cacheExpires'] < time())) {76continue;77}7879try {80$results[$key] = $this->didReadValue(81$row['cacheFormat'],82$row['cacheData']);83} catch (Exception $ex) {84// Treat this as a cache miss.85phlog($ex);86}87}88}8990return $results;91}9293public function deleteKeys(array $keys) {94if ($keys) {95$map = $this->digestKeys($keys);96queryfx(97$this->establishConnection('w'),98'DELETE FROM %T WHERE cacheKeyHash IN (%Ls)',99$this->getTableName(),100$map);101}102103return $this;104}105106public function destroyCache() {107queryfx(108$this->establishConnection('w'),109'DELETE FROM %T',110$this->getTableName());111return $this;112}113114115/* -( Raw Cache Access )--------------------------------------------------- */116117118public function establishConnection($mode) {119// TODO: This is the only concrete table we have on the database right120// now.121return id(new PhabricatorMarkupCache())->establishConnection($mode);122}123124public function getTableName() {125return 'cache_general';126}127128129/* -( Implementation )----------------------------------------------------- */130131132private function digestKeys(array $keys) {133$map = array();134foreach ($keys as $key) {135$map[$key] = PhabricatorHash::digestForIndex($key);136}137return $map;138}139140private function willWriteValue($key, $value) {141if (!is_string($value)) {142throw new Exception(pht('Only strings may be written to the DB cache!'));143}144145static $can_deflate;146if ($can_deflate === null) {147$can_deflate = function_exists('gzdeflate');148}149150if ($can_deflate) {151$deflated = PhabricatorCaches::maybeDeflateData($value);152if ($deflated !== null) {153return array(self::CACHE_FORMAT_DEFLATE, $deflated);154}155}156157return array(self::CACHE_FORMAT_RAW, $value);158}159160private function didReadValue($format, $value) {161switch ($format) {162case self::CACHE_FORMAT_RAW:163return $value;164case self::CACHE_FORMAT_DEFLATE:165return PhabricatorCaches::inflateData($value);166default:167throw new Exception(pht('Unknown cache format.'));168}169}170171172}173174175