Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/cache/PhutilKeyValueCacheStack.php
12241 views
1
<?php
2
3
/**
4
* Stacks multiple caches on top of each other, with readthrough semantics:
5
*
6
* - For reads, we try each cache in order until we find all the keys.
7
* - For writes, we set the keys in each cache.
8
*
9
* @task config Configuring the Stack
10
*/
11
final class PhutilKeyValueCacheStack extends PhutilKeyValueCache {
12
13
14
/**
15
* Forward list of caches in the stack (from the nearest cache to the farthest
16
* cache).
17
*/
18
private $cachesForward;
19
20
21
/**
22
* Backward list of caches in the stack (from the farthest cache to the
23
* nearest cache).
24
*/
25
private $cachesBackward;
26
27
28
/**
29
* TTL to use for any writes which are side effects of the next read
30
* operation.
31
*/
32
private $nextTTL;
33
34
35
/* -( Configuring the Stack )---------------------------------------------- */
36
37
38
/**
39
* Set the caches which comprise this stack.
40
*
41
* @param list<PhutilKeyValueCache> Ordered list of key-value caches.
42
* @return this
43
* @task config
44
*/
45
public function setCaches(array $caches) {
46
assert_instances_of($caches, 'PhutilKeyValueCache');
47
$this->cachesForward = $caches;
48
$this->cachesBackward = array_reverse($caches);
49
50
return $this;
51
}
52
53
54
/**
55
* Set the readthrough TTL for the next cache operation. The TTL applies to
56
* any keys set by the next call to @{method:getKey} or @{method:getKeys},
57
* and is reset after the call finishes.
58
*
59
* // If this causes any caches to fill, they'll fill with a 15-second TTL.
60
* $stack->setNextTTL(15)->getKey('porcupine');
61
*
62
* // TTL does not persist; this will use no TTL.
63
* $stack->getKey('hedgehog');
64
*
65
* @param int TTL in seconds.
66
* @return this
67
*
68
* @task config
69
*/
70
public function setNextTTL($ttl) {
71
$this->nextTTL = $ttl;
72
return $this;
73
}
74
75
76
/* -( Key-Value Cache Implementation )------------------------------------- */
77
78
79
public function getKeys(array $keys) {
80
81
$remaining = array_fuse($keys);
82
$results = array();
83
$missed = array();
84
85
try {
86
foreach ($this->cachesForward as $cache) {
87
$result = $cache->getKeys($remaining);
88
$remaining = array_diff_key($remaining, $result);
89
$results += $result;
90
if (!$remaining) {
91
while ($cache = array_pop($missed)) {
92
// TODO: This sets too many results in the closer caches, although
93
// it probably isn't a big deal in most cases; normally we're just
94
// filling the request cache.
95
$cache->setKeys($result, $this->nextTTL);
96
}
97
break;
98
}
99
$missed[] = $cache;
100
}
101
$this->nextTTL = null;
102
} catch (Exception $ex) {
103
$this->nextTTL = null;
104
throw $ex;
105
}
106
107
return $results;
108
}
109
110
111
public function setKeys(array $keys, $ttl = null) {
112
foreach ($this->cachesBackward as $cache) {
113
$cache->setKeys($keys, $ttl);
114
}
115
}
116
117
118
public function deleteKeys(array $keys) {
119
foreach ($this->cachesBackward as $cache) {
120
$cache->deleteKeys($keys);
121
}
122
}
123
124
125
public function destroyCache() {
126
foreach ($this->cachesBackward as $cache) {
127
$cache->destroyCache();
128
}
129
}
130
131
}
132
133