Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 anikendra 1
<?php
2
/**
3
 * Memcache storage engine for cache
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://cakephp.org CakePHP(tm) Project
14
 * @package       Cake.Cache.Engine
15
 * @since         CakePHP(tm) v 1.2.0.4933
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
/**
20
 * Memcache storage engine for cache. Memcache has some limitations in the amount of
21
 * control you have over expire times far in the future. See MemcacheEngine::write() for
22
 * more information.
23
 *
24
 * @package       Cake.Cache.Engine
25
 */
26
class MemcacheEngine extends CacheEngine {
27
 
28
/**
29
 * Contains the compiled group names
30
 * (prefixed with the global configuration prefix)
31
 *
32
 * @var array
33
 */
34
	protected $_compiledGroupNames = array();
35
 
36
/**
37
 * Memcache wrapper.
38
 *
39
 * @var Memcache
40
 */
41
	protected $_Memcache = null;
42
 
43
/**
44
 * Settings
45
 *
46
 *  - servers = string or array of memcache servers, default => 127.0.0.1. If an
47
 *    array MemcacheEngine will use them as a pool.
48
 *  - compress = boolean, default => false
49
 *
50
 * @var array
51
 */
52
	public $settings = array();
53
 
54
/**
55
 * Initialize the Cache Engine
56
 *
57
 * Called automatically by the cache frontend
58
 * To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
59
 *
60
 * @param array $settings array of setting for the engine
61
 * @return boolean True if the engine has been successfully initialized, false if not
62
 */
63
	public function init($settings = array()) {
64
		if (!class_exists('Memcache')) {
65
			return false;
66
		}
67
		if (!isset($settings['prefix'])) {
68
			$settings['prefix'] = Inflector::slug(APP_DIR) . '_';
69
		}
70
		$settings += array(
71
			'engine' => 'Memcache',
72
			'servers' => array('127.0.0.1'),
73
			'compress' => false,
74
			'persistent' => true
75
		);
76
		parent::init($settings);
77
 
78
		if ($this->settings['compress']) {
79
			$this->settings['compress'] = MEMCACHE_COMPRESSED;
80
		}
81
		if (is_string($this->settings['servers'])) {
82
			$this->settings['servers'] = array($this->settings['servers']);
83
		}
84
		if (!isset($this->_Memcache)) {
85
			$return = false;
86
			$this->_Memcache = new Memcache();
87
			foreach ($this->settings['servers'] as $server) {
88
				list($host, $port) = $this->_parseServerString($server);
89
				if ($this->_Memcache->addServer($host, $port, $this->settings['persistent'])) {
90
					$return = true;
91
				}
92
			}
93
			return $return;
94
		}
95
		return true;
96
	}
97
 
98
/**
99
 * Parses the server address into the host/port. Handles both IPv6 and IPv4
100
 * addresses and Unix sockets
101
 *
102
 * @param string $server The server address string.
103
 * @return array Array containing host, port
104
 */
105
	protected function _parseServerString($server) {
106
		if ($server[0] === 'u') {
107
			return array($server, 0);
108
		}
109
		if (substr($server, 0, 1) === '[') {
110
			$position = strpos($server, ']:');
111
			if ($position !== false) {
112
				$position++;
113
			}
114
		} else {
115
			$position = strpos($server, ':');
116
		}
117
		$port = 11211;
118
		$host = $server;
119
		if ($position !== false) {
120
			$host = substr($server, 0, $position);
121
			$port = substr($server, $position + 1);
122
		}
123
		return array($host, $port);
124
	}
125
 
126
/**
127
 * Write data for key into cache. When using memcache as your cache engine
128
 * remember that the Memcache pecl extension does not support cache expiry times greater
129
 * than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
130
 *
131
 * @param string $key Identifier for the data
132
 * @param mixed $value Data to be cached
133
 * @param integer $duration How long to cache the data, in seconds
134
 * @return boolean True if the data was successfully cached, false on failure
135
 * @see http://php.net/manual/en/memcache.set.php
136
 */
137
	public function write($key, $value, $duration) {
138
		if ($duration > 30 * DAY) {
139
			$duration = 0;
140
		}
141
		return $this->_Memcache->set($key, $value, $this->settings['compress'], $duration);
142
	}
143
 
144
/**
145
 * Read a key from the cache
146
 *
147
 * @param string $key Identifier for the data
148
 * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
149
 */
150
	public function read($key) {
151
		return $this->_Memcache->get($key);
152
	}
153
 
154
/**
155
 * Increments the value of an integer cached key
156
 *
157
 * @param string $key Identifier for the data
158
 * @param integer $offset How much to increment
159
 * @return New incremented value, false otherwise
160
 * @throws CacheException when you try to increment with compress = true
161
 */
162
	public function increment($key, $offset = 1) {
163
		if ($this->settings['compress']) {
164
			throw new CacheException(
165
				__d('cake_dev', 'Method %s not implemented for compressed cache in %s', 'increment()', __CLASS__)
166
			);
167
		}
168
		return $this->_Memcache->increment($key, $offset);
169
	}
170
 
171
/**
172
 * Decrements the value of an integer cached key
173
 *
174
 * @param string $key Identifier for the data
175
 * @param integer $offset How much to subtract
176
 * @return New decremented value, false otherwise
177
 * @throws CacheException when you try to decrement with compress = true
178
 */
179
	public function decrement($key, $offset = 1) {
180
		if ($this->settings['compress']) {
181
			throw new CacheException(
182
				__d('cake_dev', 'Method %s not implemented for compressed cache in %s', 'decrement()', __CLASS__)
183
			);
184
		}
185
		return $this->_Memcache->decrement($key, $offset);
186
	}
187
 
188
/**
189
 * Delete a key from the cache
190
 *
191
 * @param string $key Identifier for the data
192
 * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
193
 */
194
	public function delete($key) {
195
		return $this->_Memcache->delete($key);
196
	}
197
 
198
/**
199
 * Delete all keys from the cache
200
 *
201
 * @param boolean $check
202
 * @return boolean True if the cache was successfully cleared, false otherwise
203
 */
204
	public function clear($check) {
205
		if ($check) {
206
			return true;
207
		}
208
		foreach ($this->_Memcache->getExtendedStats('slabs') as $slabs) {
209
			foreach (array_keys($slabs) as $slabId) {
210
				if (!is_numeric($slabId)) {
211
					continue;
212
				}
213
 
214
				foreach ($this->_Memcache->getExtendedStats('cachedump', $slabId) as $stats) {
215
					if (!is_array($stats)) {
216
						continue;
217
					}
218
					foreach (array_keys($stats) as $key) {
219
						if (strpos($key, $this->settings['prefix']) === 0) {
220
							$this->_Memcache->delete($key);
221
						}
222
					}
223
				}
224
			}
225
		}
226
		return true;
227
	}
228
 
229
/**
230
 * Connects to a server in connection pool
231
 *
232
 * @param string $host host ip address or name
233
 * @param integer $port Server port
234
 * @return boolean True if memcache server was connected
235
 */
236
	public function connect($host, $port = 11211) {
237
		if ($this->_Memcache->getServerStatus($host, $port) === 0) {
238
			if ($this->_Memcache->connect($host, $port)) {
239
				return true;
240
			}
241
			return false;
242
		}
243
		return true;
244
	}
245
 
246
/**
247
 * Returns the `group value` for each of the configured groups
248
 * If the group initial value was not found, then it initializes
249
 * the group accordingly.
250
 *
251
 * @return array
252
 */
253
	public function groups() {
254
		if (empty($this->_compiledGroupNames)) {
255
			foreach ($this->settings['groups'] as $group) {
256
				$this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
257
			}
258
		}
259
 
260
		$groups = $this->_Memcache->get($this->_compiledGroupNames);
261
		if (count($groups) !== count($this->settings['groups'])) {
262
			foreach ($this->_compiledGroupNames as $group) {
263
				if (!isset($groups[$group])) {
264
					$this->_Memcache->set($group, 1, false, 0);
265
					$groups[$group] = 1;
266
				}
267
			}
268
			ksort($groups);
269
		}
270
 
271
		$result = array();
272
		$groups = array_values($groups);
273
		foreach ($this->settings['groups'] as $i => $group) {
274
			$result[] = $group . $groups[$i];
275
		}
276
 
277
		return $result;
278
	}
279
 
280
/**
281
 * Increments the group value to simulate deletion of all keys under a group
282
 * old values will remain in storage until they expire.
283
 *
284
 * @return boolean success
285
 */
286
	public function clearGroup($group) {
287
		return (bool)$this->_Memcache->increment($this->settings['prefix'] . $group);
288
	}
289
}