Path: blob/master/src/infrastructure/cache/PhutilMemcacheKeyValueCache.php
12241 views
<?php12/**3* @task memcache Managing Memcache4*/5final class PhutilMemcacheKeyValueCache extends PhutilKeyValueCache {67private $servers = array();8private $connections = array();91011/* -( Key-Value Cache Implementation )------------------------------------- */121314public function isAvailable() {15return function_exists('memcache_pconnect');16}1718public function getKeys(array $keys) {19$buckets = $this->bucketKeys($keys);20$results = array();2122foreach ($buckets as $bucket => $bucket_keys) {23$conn = $this->getConnection($bucket);24$result = $conn->get($bucket_keys);25if (!$result) {26// If the call fails, treat it as a miss on all keys.27$result = array();28}2930$results += $result;31}3233return $results;34}3536public function setKeys(array $keys, $ttl = null) {37$buckets = $this->bucketKeys(array_keys($keys));3839// Memcache interprets TTLs as:40//41// - Seconds from now, for values from 1 to 2592000 (30 days).42// - Epoch timestamp, for values larger than 2592000.43//44// We support only relative TTLs, so convert excessively large relative45// TTLs into epoch TTLs.46if ($ttl > 2592000) {47$effective_ttl = time() + $ttl;48} else {49$effective_ttl = $ttl;50}5152foreach ($buckets as $bucket => $bucket_keys) {53$conn = $this->getConnection($bucket);5455foreach ($bucket_keys as $key) {56$conn->set($key, $keys[$key], 0, $effective_ttl);57}58}5960return $this;61}6263public function deleteKeys(array $keys) {64$buckets = $this->bucketKeys($keys);6566foreach ($buckets as $bucket => $bucket_keys) {67$conn = $this->getConnection($bucket);68foreach ($bucket_keys as $key) {69$conn->delete($key);70}71}7273return $this;74}7576public function destroyCache() {77foreach ($this->servers as $key => $spec) {78$this->getConnection($key)->flush();79}80return $this;81}828384/* -( Managing Memcache )-------------------------------------------------- */858687/**88* Set available memcache servers. For example:89*90* $cache->setServers(91* array(92* array(93* 'host' => '10.0.0.20',94* 'port' => 11211,95* ),96* array(97* 'host' => '10.0.0.21',98* 'port' => 11211,99* ),100* ));101*102* @param list<dict> List of server specifications.103* @return this104* @task memcache105*/106public function setServers(array $servers) {107$this->servers = array_values($servers);108return $this;109}110111private function bucketKeys(array $keys) {112$buckets = array();113$n = count($this->servers);114115if (!$n) {116throw new PhutilInvalidStateException('setServers');117}118119foreach ($keys as $key) {120$bucket = (int)((crc32($key) & 0x7FFFFFFF) % $n);121$buckets[$bucket][] = $key;122}123124return $buckets;125}126127128/**129* @phutil-external-symbol function memcache_pconnect130*/131private function getConnection($server) {132if (empty($this->connections[$server])) {133$spec = $this->servers[$server];134$host = $spec['host'];135$port = $spec['port'];136137$conn = memcache_pconnect($host, $spec['port']);138139if (!$conn) {140throw new Exception(141pht(142'Unable to connect to memcache server (%s:%d)!',143$host,144$port));145}146147$this->connections[$server] = $conn;148}149return $this->connections[$server];150}151152}153154155