Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/cache/PhutilMemcacheKeyValueCache.php
12241 views
1
<?php
2
3
/**
4
* @task memcache Managing Memcache
5
*/
6
final class PhutilMemcacheKeyValueCache extends PhutilKeyValueCache {
7
8
private $servers = array();
9
private $connections = array();
10
11
12
/* -( Key-Value Cache Implementation )------------------------------------- */
13
14
15
public function isAvailable() {
16
return function_exists('memcache_pconnect');
17
}
18
19
public function getKeys(array $keys) {
20
$buckets = $this->bucketKeys($keys);
21
$results = array();
22
23
foreach ($buckets as $bucket => $bucket_keys) {
24
$conn = $this->getConnection($bucket);
25
$result = $conn->get($bucket_keys);
26
if (!$result) {
27
// If the call fails, treat it as a miss on all keys.
28
$result = array();
29
}
30
31
$results += $result;
32
}
33
34
return $results;
35
}
36
37
public function setKeys(array $keys, $ttl = null) {
38
$buckets = $this->bucketKeys(array_keys($keys));
39
40
// Memcache interprets TTLs as:
41
//
42
// - Seconds from now, for values from 1 to 2592000 (30 days).
43
// - Epoch timestamp, for values larger than 2592000.
44
//
45
// We support only relative TTLs, so convert excessively large relative
46
// TTLs into epoch TTLs.
47
if ($ttl > 2592000) {
48
$effective_ttl = time() + $ttl;
49
} else {
50
$effective_ttl = $ttl;
51
}
52
53
foreach ($buckets as $bucket => $bucket_keys) {
54
$conn = $this->getConnection($bucket);
55
56
foreach ($bucket_keys as $key) {
57
$conn->set($key, $keys[$key], 0, $effective_ttl);
58
}
59
}
60
61
return $this;
62
}
63
64
public function deleteKeys(array $keys) {
65
$buckets = $this->bucketKeys($keys);
66
67
foreach ($buckets as $bucket => $bucket_keys) {
68
$conn = $this->getConnection($bucket);
69
foreach ($bucket_keys as $key) {
70
$conn->delete($key);
71
}
72
}
73
74
return $this;
75
}
76
77
public function destroyCache() {
78
foreach ($this->servers as $key => $spec) {
79
$this->getConnection($key)->flush();
80
}
81
return $this;
82
}
83
84
85
/* -( Managing Memcache )-------------------------------------------------- */
86
87
88
/**
89
* Set available memcache servers. For example:
90
*
91
* $cache->setServers(
92
* array(
93
* array(
94
* 'host' => '10.0.0.20',
95
* 'port' => 11211,
96
* ),
97
* array(
98
* 'host' => '10.0.0.21',
99
* 'port' => 11211,
100
* ),
101
* ));
102
*
103
* @param list<dict> List of server specifications.
104
* @return this
105
* @task memcache
106
*/
107
public function setServers(array $servers) {
108
$this->servers = array_values($servers);
109
return $this;
110
}
111
112
private function bucketKeys(array $keys) {
113
$buckets = array();
114
$n = count($this->servers);
115
116
if (!$n) {
117
throw new PhutilInvalidStateException('setServers');
118
}
119
120
foreach ($keys as $key) {
121
$bucket = (int)((crc32($key) & 0x7FFFFFFF) % $n);
122
$buckets[$bucket][] = $key;
123
}
124
125
return $buckets;
126
}
127
128
129
/**
130
* @phutil-external-symbol function memcache_pconnect
131
*/
132
private function getConnection($server) {
133
if (empty($this->connections[$server])) {
134
$spec = $this->servers[$server];
135
$host = $spec['host'];
136
$port = $spec['port'];
137
138
$conn = memcache_pconnect($host, $spec['port']);
139
140
if (!$conn) {
141
throw new Exception(
142
pht(
143
'Unable to connect to memcache server (%s:%d)!',
144
$host,
145
$port));
146
}
147
148
$this->connections[$server] = $conn;
149
}
150
return $this->connections[$server];
151
}
152
153
}
154
155