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