3 final class PhabricatorKeyValueDatabaseCache
4 extends PhutilKeyValueCache
{
6 const CACHE_FORMAT_RAW
= 'raw';
7 const CACHE_FORMAT_DEFLATE
= 'deflate';
9 public function setKeys(array $keys, $ttl = null) {
10 if (PhabricatorEnv
::isReadOnly()) {
15 $map = $this->digestKeys(array_keys($keys));
16 $conn_w = $this->establishConnection('w');
19 foreach ($map as $key => $hash) {
22 list($format, $storage_value) = $this->willWriteValue($key, $value);
26 '(%s, %s, %s, %B, %d, %nd)',
32 $ttl ?
(time() +
$ttl) : null);
35 $guard = AphrontWriteGuard
::beginScopedUnguardedWrites();
36 foreach (PhabricatorLiskDAO
::chunkSQL($sql) as $chunk) {
40 (cacheKeyHash, cacheKey, cacheFormat, cacheData,
41 cacheCreated, cacheExpires) VALUES %LQ
42 ON DUPLICATE KEY UPDATE
43 cacheKey = VALUES(cacheKey),
44 cacheFormat = VALUES(cacheFormat),
45 cacheData = VALUES(cacheData),
46 cacheCreated = VALUES(cacheCreated),
47 cacheExpires = VALUES(cacheExpires)',
48 $this->getTableName(),
57 public function getKeys(array $keys) {
60 $map = $this->digestKeys($keys);
63 $this->establishConnection('r'),
64 'SELECT * FROM %T WHERE cacheKeyHash IN (%Ls)',
65 $this->getTableName(),
67 $rows = ipull($rows, null, 'cacheKey');
69 foreach ($keys as $key) {
70 if (empty($rows[$key])) {
76 if ($row['cacheExpires'] && ($row['cacheExpires'] < time())) {
81 $results[$key] = $this->didReadValue(
84 } catch (Exception
$ex) {
85 // Treat this as a cache miss.
94 public function deleteKeys(array $keys) {
96 $map = $this->digestKeys($keys);
98 $this->establishConnection('w'),
99 'DELETE FROM %T WHERE cacheKeyHash IN (%Ls)',
100 $this->getTableName(),
107 public function destroyCache() {
109 $this->establishConnection('w'),
111 $this->getTableName());
116 /* -( Raw Cache Access )--------------------------------------------------- */
119 public function establishConnection($mode) {
120 // TODO: This is the only concrete table we have on the database right
122 return id(new PhabricatorMarkupCache())->establishConnection($mode);
125 public function getTableName() {
126 return 'cache_general';
130 /* -( Implementation )----------------------------------------------------- */
133 private function digestKeys(array $keys) {
135 foreach ($keys as $key) {
136 $map[$key] = PhabricatorHash
::digestForIndex($key);
141 private function willWriteValue($key, $value) {
142 if (!is_string($value)) {
143 throw new Exception(pht('Only strings may be written to the DB cache!'));
147 if ($can_deflate === null) {
148 $can_deflate = function_exists('gzdeflate');
152 $deflated = PhabricatorCaches
::maybeDeflateData($value);
153 if ($deflated !== null) {
154 return array(self
::CACHE_FORMAT_DEFLATE
, $deflated);
158 return array(self
::CACHE_FORMAT_RAW
, $value);
161 private function didReadValue($format, $value) {
163 case self
::CACHE_FORMAT_RAW
:
165 case self
::CACHE_FORMAT_DEFLATE
:
166 return PhabricatorCaches
::inflateData($value);
168 throw new Exception(pht('Unknown cache format.'));