Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TMemCache class file
4
 *
5
 * @author Qiang Xue <qiang.xue@gmail.com>
6
 * @author Carl G. Mathisen <carlgmathisen@gmail.com>
7
 * @link http://www.pradosoft.com/
8
 * @copyright Copyright &copy; 2005-2008 PradoSoft
9
 * @license http://www.pradosoft.com/license/
10
 * @version $Id: TMemCache.php 2541 2008-10-21 15:05:13Z qiang.xue $
11
 * @package System.Caching
12
 */
13
 
14
/**
15
 * TMemCache class
16
 *
17
 * TMemCache implements a cache application module based on {@link http://www.danga.com/memcached/ memcached}.
18
 *
19
 * TMemCache can be configured with the Host and Port properties, which
20
 * specify the host and port of the memcache server to be used.
21
 * By default, they take the value 'localhost' and 11211, respectively.
22
 * These properties must be set before {@link init} is invoked.
23
 *
24
 * The following basic cache operations are implemented:
25
 * - {@link get} : retrieve the value with a key (if any) from cache
26
 * - {@link set} : store the value with a key into cache
27
 * - {@link add} : store the value only if cache does not have this key
28
 * - {@link delete} : delete the value with the specified key from cache
29
 * - {@link flush} : delete all values from cache
30
 *
31
 * Each value is associated with an expiration time. The {@link get} operation
32
 * ensures that any expired value will not be returned. The expiration time can
33
 * be specified by the number of seconds (maximum 60*60*24*30)
34
 * or a UNIX timestamp. A expiration time 0 represents never expire.
35
 *
36
 * By definition, cache does not ensure the existence of a value
37
 * even if it never expires. Cache is not meant to be an persistent storage.
38
 *
39
 * Also note, there is no security measure to protected data in memcache.
40
 * All data in memcache can be accessed by any process running in the system.
41
 *
42
 * To use this module, the memcache PHP extension must be loaded.
43
 *
44
 * Some usage examples of TMemCache are as follows,
45
 * <code>
46
 * $cache=new TMemCache;  // TMemCache may also be loaded as a Prado application module
47
 * $cache->init(null);
48
 * $cache->add('object',$object);
49
 * $object2=$cache->get('object');
50
 * </code>
51
 *
52
 * You can configure TMemCache two different ways. If you only need one memcache server
53
 * you may use the method as follows.
54
 * <code>
55
 * <module id="cache" class="System.Caching.TMemCache" Host="localhost" Port="11211" />
56
 * </code>
57
 *
58
 * If you want a more complex configuration, you may use the method as follows.
59
 * <code>
60
 * <module id="cache" classs="System.Caching.TMemCache">
61
 *     <server Host="localhost" Port="11211" Weight="1" Timeout="300" RetryInterval="15" />
62
 *     <server Host="anotherhost" Port="11211" Weight="1" Timeout="300" RetryInterval="15" />
63
 * </module>
64
 * </code>
65
 *
66
 * If loaded, TMemCache will register itself with {@link TApplication} as the
67
 * cache module. It can be accessed via {@link TApplication::getCache()}.
68
 *
69
 * TMemCache may be configured in application configuration file as follows
70
 * <code>
71
 * <module id="cache" class="System.Caching.TMemCache" Host="localhost" Port="11211" />
72
 * </code>
73
 * where {@link getHost Host} and {@link getPort Port} are configurable properties
74
 * of TMemCache.
75
 *
76
 * @author Qiang Xue <qiang.xue@gmail.com>
77
 * @version $Id: TMemCache.php 2541 2008-10-21 15:05:13Z qiang.xue $
78
 * @package System.Caching
79
 * @since 3.0
80
 */
81
class TMemCache extends TCache
82
{
83
	/**
84
	 * @var boolean if the module is initialized
85
	 */
86
	private $_initialized=false;
87
	/**
88
	 * @var Memcache the Memcache instance
89
	 */
90
	private $_cache=null;
91
	/**
92
	 * @var string a unique prefix used to identify this cache instance from the others
93
	 */
94
	private $_prefix=null;
95
	/**
96
	 * @var string host name of the memcache server
97
	 */
98
	private $_host='localhost';
99
	/**
100
	 * @var integer the port number of the memcache server
101
	 */
102
	private $_port=11211;
103
	/**
104
	 * @var boolean controls the use of a persistent connection. Default to true.
105
	 */
106
    private $_persistence = true;
107
    /**
108
     * @var integer number of buckets to create for this server which in turn control its
109
     * probability of it being selected. The probability is relative to the total weight
110
     * of all servers.
111
     */
112
    private $_weight = 1;
113
 
114
    private $_timeout = 360;
115
 
116
    private $_retryInterval = 15;
117
 
118
    private $_status = true;
119
 
120
    private $_failureCallback = null;
121
 
122
	/**
123
	 * @var array list of servers available
124
	 */
125
	private $_servers=array();
126
 
127
	/**
128
	 * Destructor.
129
	 * Disconnect the memcache server.
130
	 */
131
	public function __destruct()
132
	{
133
		if($this->_cache!==null)
134
			$this->_cache->close();
135
	}
136
 
137
	/**
138
	 * Initializes this module.
139
	 * This method is required by the IModule interface. It makes sure that
140
	 * UniquePrefix has been set, creates a Memcache instance and connects
141
	 * to the memcache server.
142
	 * @param TApplication Prado application, can be null
143
	 * @param TXmlElement configuration for this module, can be null
144
	 * @throws TConfigurationException if memcache extension is not installed or memcache sever connection fails
145
	 */
146
	public function init($config)
147
	{
148
		if(!extension_loaded('memcache'))
149
			throw new TConfigurationException('memcache_extension_required');
150
		$this->_cache=new Memcache;
151
		$this->loadConfig($config);
152
		if(count($this->_servers))
153
        {
154
            foreach($this->_servers as $server)
155
            {
156
                Prado::trace('Adding server '.$server['Host'].' from serverlist', 'System.Caching.TMemCache');
157
                if($this->_cache->addServer($server['Host'],$server['Port'],$server['Persistent'],
158
                    $server['Weight'],$server['Timeout'],$server['RetryInterval'])===false)
159
                    throw new TConfigurationException('memcache_connection_failed',$server['Host'],$server['Port']);
160
            }
161
        }
162
        else
163
        {
164
            Prado::trace('Adding server '.$this->_host, 'System.Caching.TMemCache');
165
            if($this->_cache->addServer($this->_host,$this->_port)===false)
166
                throw new TConfigurationException('memcache_connection_failed',$this->_host,$this->_port);
167
        }
168
		$this->_initialized=true;
169
		parent::init($config);
170
	}
171
 
172
    /**
173
	 * Loads configuration from an XML element
174
	 * @param TXmlElement configuration node
175
	 * @throws TConfigurationException if log route class or type is not specified
176
	 */
177
	private function loadConfig($xml)
178
	{
179
	    if($xml instanceof TXmlElement)
180
		{
181
    		foreach($xml->getElementsByTagName('server') as $serverConfig)
182
    		{
183
    			$properties=$serverConfig->getAttributes();
184
    			if(($host=$properties->remove('Host'))===null)
185
    				throw new TConfigurationException('memcache_serverhost_required');
186
    			if(($port=$properties->remove('Port'))===null)
187
        			throw new TConfigurationException('memcache_serverport_required');
188
        		if(!is_numeric($port))
189
        		    throw new TConfigurationException('memcache_serverport_invalid');
190
        		$server = array('Host'=>$host,'Port'=>$port,'Weight'=>1,'Timeout'=>1800,'RetryInterval'=>15,'Persistent'=>true);
191
        		$checks = array(
192
        		    'Weight'=>'memcache_serverweight_invalid',
193
        		    'Timeout'=>'memcache_servertimeout_invalid',
194
        		    'RetryInterval'=>'memcach_serverretryinterval_invalid'
195
        		);
196
        		foreach($checks as $property=>$exception)
197
        		{
198
        		    $value=$properties->remove($property);
199
        		    if($value!==null && is_numeric($value))
200
        		        $server[$property]=$value;
201
        		    else if($value!==null)
202
        		        throw new TConfigurationException($exception);
203
        		}
204
        		$server['Persistent']= TPropertyValue::ensureBoolean($properties->remove('Persistent'));
205
    			$this->_servers[]=$server;
206
    		}
207
	    }
208
	}
209
 
210
	/**
211
	 * @return string host name of the memcache server
212
	 */
213
	public function getHost()
214
	{
215
		return $this->_host;
216
	}
217
 
218
	/**
219
	 * @param string host name of the memcache server
220
	 * @throws TInvalidOperationException if the module is already initialized
221
	 */
222
	public function setHost($value)
223
	{
224
		if($this->_initialized)
225
			throw new TInvalidOperationException('memcache_host_unchangeable');
226
		else
227
			$this->_host=$value;
228
	}
229
 
230
	/**
231
	 * @return integer port number of the memcache server
232
	 */
233
	public function getPort()
234
	{
235
		return $this->_port;
236
	}
237
 
238
	/**
239
	 * @param integer port number of the memcache server
240
	 * @throws TInvalidOperationException if the module is already initialized
241
	 */
242
	public function setPort($value)
243
	{
244
		if($this->_initialized)
245
			throw new TInvalidOperationException('memcache_port_unchangeable');
246
		else
247
			$this->_port=TPropertyValue::ensureInteger($value);
248
	}
249
 
250
	/**
251
	 * Retrieves a value from cache with a specified key.
252
	 * This is the implementation of the method declared in the parent class.
253
	 * @param string a unique key identifying the cached value
254
	 * @return string the value stored in cache, false if the value is not in the cache or expired.
255
	 */
256
	protected function getValue($key)
257
	{
258
		return $this->_cache->get($key);
259
	}
260
 
261
	/**
262
	 * Stores a value identified by a key in cache.
263
	 * This is the implementation of the method declared in the parent class.
264
	 *
265
	 * @param string the key identifying the value to be cached
266
	 * @param string the value to be cached
267
	 * @param integer the number of seconds in which the cached value will expire. 0 means never expire.
268
	 * @return boolean true if the value is successfully stored into cache, false otherwise
269
	 */
270
	protected function setValue($key,$value,$expire)
271
	{
272
		return $this->_cache->set($key,$value,0,$expire);
273
	}
274
 
275
	/**
276
	 * Stores a value identified by a key into cache if the cache does not contain this key.
277
	 * This is the implementation of the method declared in the parent class.
278
	 *
279
	 * @param string the key identifying the value to be cached
280
	 * @param string the value to be cached
281
	 * @param integer the number of seconds in which the cached value will expire. 0 means never expire.
282
	 * @return boolean true if the value is successfully stored into cache, false otherwise
283
	 */
284
	protected function addValue($key,$value,$expire)
285
	{
286
		return $this->_cache->add($key,$value,0,$expire);
287
	}
288
 
289
	/**
290
	 * Deletes a value with the specified key from cache
291
	 * This is the implementation of the method declared in the parent class.
292
	 * @param string the key of the value to be deleted
293
	 * @return boolean if no error happens during deletion
294
	 */
295
	protected function deleteValue($key)
296
	{
297
		return $this->_cache->delete($key);
298
	}
299
 
300
	/**
301
	 * Deletes all values from cache.
302
	 * Be careful of performing this operation if the cache is shared by multiple applications.
303
	 */
304
	public function flush()
305
	{
306
		return $this->_cache->flush();
307
	}
308
}
309