## Apache Zeta Components Manual :: File Source for memory.php

## Source for file memory.php

Documentation is available at memory.php

1. <?php
2. /**
3. * File containing the ezcCacheStorageMemory class.
4. *
5. * Licensed to the Apache Software Foundation (ASF) under one
6. * or more contributor license agreements. See the NOTICE file
7. * distributed with this work for additional information
8. * regarding copyright ownership. The ASF licenses this file
9. * to you under the Apache License, Version 2.0 (the
10. * "License"); you may not use this file except in compliance
11. * with the License. You may obtain a copy of the License at
12. *
13. * http://www.apache.org/licenses/LICENSE-2.0
14. *
15. * Unless required by applicable law or agreed to in writing,
16. * software distributed under the License is distributed on an
17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18. * KIND, either express or implied. See the License for the
19. * specific language governing permissions and limitations
20. * under the License.
21. *
22. * @package Cache
23. * @version //autogentag//
24. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
25. * @filesource
26. */
28. /**
29. * Base abstract class for all memory storage classes.
30. *
31. * Abstract classes extending this class:
32. * - {@link ezcCacheStorageMemcache}
33. * - {@link ezcCacheStorageApc}
34. *
35. * Implementations derived from this class and its descendants:
36. * - {@link ezcCacheStorageMemcachePlain}
37. * - {@link ezcCacheStorageApcPlain}
38. * - {@link ezcCacheStorageFileApcArray}
39. *
40. * @package Cache
41. * @version //autogentag//
42. */
43. abstract class ezcCacheStorageMemory extends ezcCacheStorage implements ezcCacheStackableStorage , ezcCacheStackMetaDataStorage
44. {
45. /**
46. * Holds the memory backend object which communicates with the memory handler
47. * (Memcache, APC).
48. *
49. * @var ezcCacheMemoryBackend
50. */
51. protected $backend ;
53. /**
54. * Holds the name of the memory backend.
55. *
56. * @var string
57. */
58. protected $backendName ;
60. /**
61. * Holds the name of the registry.
62. *
63. * @var string
64. */
65. protected $registryName ;
67. /**
68. * Holds the registry.
69. *
70. * @var array(mixed)
71. */
72. protected $registry = array();
74. /**
75. * Holds the search registry.
76. *
77. * @var array(mixed)
78. */
79. protected $searchRegistry = array();
81. /**
82. * Wether this storage holds a lock.
83. *
84. * @var bool
85. */
86. private $lock = false;
88. /**
89. * Creates a new cache storage in the given location.
90. *
91. * Options can contain the 'ttl' (Time-To-Live). Specific implementations
92. * can have additional options.
93. *
94. * @throws ezcBasePropertyNotFoundException
95. * If you tried to set a non-existent option value. The accepted
96. * options depend on the ezcCacheStorage implementation and may
97. * vary.
98. *
99. * @param string $location Path to the cache location. Null for
100. * memory-based storage and an existing
101. * writeable path for file or memory/file
102. * storage.
103. * @param array(string=>string) $options Options for the cache
104. */
105. public function __construct ( $location, array $options = array() )
106. {
107. parent:: __construct ( $location, array() );
108. }
110. /**
111. * Stores data to the cache storage under the key $id.
112. *
113. * The type of cache data which is expected by an ezcCacheStorageMemory
114. * implementation depends on the backend. In most cases strings and arrays
115. * will be accepted, in some rare cases only strings might be accepted.
116. *
117. * Using attributes you can describe your cache data further. This allows
118. * you to deal with multiple cache data at once later. Some
119. * ezcCacheStorageMemory implementations also use the attributes for storage
120. * purposes. Attributes form some kind of "extended ID".
121. *
122. * @return string The ID string of the newly cached data
123. *
124. * @param string $id Unique identifier for the data
125. * @param mixed $data The data to store
126. * @param array(string=>string) $attributes Attributes describing the cached data
127. */
128. public function store ( $id, $data, $attributes = array() )
129. {
130. // Generate the Identifier
131. $identifier = $this-> generateIdentifier ( $id, $attributes );
132. $location = $this-> properties ['location'];
134. if ( isset( $this-> registry [$location][$id][$identifier] ) )
135. {
136. unset( $this-> registry [$location][$id][$identifier] );
137. }
139. // Prepare the data
140. $dataStr = $this->prepareData( $data );
142. // Store the data
143. $this-> registerIdentifier ( $id, $attributes, $identifier );
144. if ( !$this-> backend -> store ( $identifier, $dataStr, $this-> properties ['options']['ttl'] ) )
145. {
146. $exceptionClass = "ezcCache{$this-> backendName }Exception

";
- throw new $exceptionClass( "{$this-> backendName } store failed." );
- }
- return $id;
- }
- /**
- * Restores the data from the cache.
- *
- * During access to cached data the caches are automatically
- * expired. This means, that the ezcCacheStorageMemory object checks
- * before returning the data if it's still actual. If the cache
- * has expired, data will be deleted and false is returned.
- *
- * You should always provide the attributes you assigned, although
- * the cache storages must be able to find a cache ID even without
- * them. BEWARE: Finding cache data only by ID can be much
- * slower than finding it by ID and attributes.
- *
- * @param string $id The item ID to restore
- * @param array(string=>string) $attributes Attributes describing the data to restore
- * @param bool $search Whether to search for items if not found directly
- * @return mixed The cached data on success, otherwise false
- */
- public function restore( $id, $attributes = array(), $search = false )
- {
- // Generate the Identifier
- $identifier = $this-> generateIdentifier ( $id, $attributes );
- $location = $this-> properties ['location'];
- // Creates a registry object
- if ( !isset( $this-> registry [$location][$id][$identifier] ) )
- {
- if ( !isset( $this-> registry [$location] ) )
- {
- $this-> registry [$location] = array();
- }
- if ( !isset( $this-> registry [$location][$id] ) )
- {
- $this-> registry [$location][$id] = array();
- }
- $this-> registry [$location][$id][$identifier] = $this->fetchData( $identifier, true );
- }
- // Makes sure a cache exists
- if ( $this-> registry [$location][$id][$identifier] === false )
- {
- if ( $search === true
- && count( $identifiers = $this-> search ( $id, $attributes ) ) === 1 )
- {
- $identifier = $identifiers[0][2];
- $this-> registry [$location][$id][$identifier] = $this->fetchData( $identifier, true );
- }
- else
- {
- // There are more elements found during search, so false is returned
- return false;
- }
- }
- // Make sure the data is not supposed to be expired
- if ( $this-> properties ['options']['ttl'] !== false
- && $this-> calcLifetime ( $identifier, $this-> registry [$location][$id][$identifier] ) == 0 )
- {
- $this-> delete ( $id, $attributes, false );
- return false;
- }
- // Return the data
- $data = is_object( $this-> registry [$location][$id][$identifier] ) ? $this-> registry [$location][$id][$identifier]->data : false;
- if ( $data !== false )
- {
- return $data;
- }
- else
- {
- return false;
- }
- }
- /**
- * Deletes the data associated with $id or $attributes from the cache.
- *
- * Additional attributes provided will matched additionally. This can give
- * you an immense speed improvement against just searching for ID (see
- * {@link ezcCacheStorage::restore()}).
- *
- * If you only provide attributes for deletion of cache data, all cache
- * data matching these attributes will be purged.
- *
- * @throws ezcBaseFilePermissionException
- * If an already existsing cache file could not be unlinked.
- * This exception means most likely that your cache directory
- * has been corrupted by external influences (file permission
- * change).
- *
- * @param string $id The item ID to purge
- * @param array(string=>string) $attributes Attributes describing the data to restore
- * @param bool $search Whether to search for items if not found directly
- */
- public function delete( $id = null, $attributes = array(), $search = false )
- {
- // Generate the Identifier
- $identifier = $this-> generateIdentifier ( $id, $attributes );
- $location = $this-> properties ['location'];
- // Finds the caches that require deletion
- $delCaches = array();
- if ( $this->fetchData( $identifier ) !== false )
- {
- $delCaches[] = array( $id, $attributes, $identifier );
- }
- else if ( $search === true )
- {
- $delCaches = $this-> search ( $id, $attributes );
- }
- $deletedIds = array();
- // Process the caches to delete
- $identifiers = array();
- foreach ( $delCaches as $cache )
- {
- $this-> backend -> delete ( $cache[2] );
- $deletedIds[] = $cache[0];
- $this-> unRegisterIdentifier ( $cache[0], $cache[1], $cache[2], true );
- if ( isset( $this-> registry [$location][$cache[0]][$cache[2]] ) )
- {
- unset( $this-> registry [$location][$cache[0]][$cache[2]] );
- }
- }
- $this-> storeSearchRegistry ();
- return $deletedIds;
- }
- /**
- * Returns the number of items in the cache matching a certain criteria.
- *
- * This method determines if cache data described by the given ID and/or
- * attributes exists. It returns the number of cache data items found.
- *
- * @param string $id The item ID
- * @param array(string=>string) $attributes Attributes describing the data
- * @return int Number of data items matching the criteria
- */
- public function countDataItems( $id = null, $attributes = array() )
- {
- return count( $this-> search ( $id, $attributes ) );
- }
- /**
- * Returns the time in seconds which remains for a cache object, before it
- * gets outdated. In case the cache object is already outdated or does not
- * exists, this method returns 0.
- *
- * @param string $id The item ID
- * @param array(string=>string) $attributes Attributes describing the data
- * @return int The remaining lifetime (0 if it does not exist or outdated)
- */
- public function getRemainingLifetime( $id, $attributes = array() )
- {
- if ( count( $found = $this-> search ( $id, $attributes ) ) > 0 )
- {
- $identifier = $found[0][2];
- return $this-> calcLifetime ( $identifier );
- }
- return 0;
- }
- /**
- * Generates the storage internal identifier from ID and attributes.
- *
- * @param string $id The ID
- * @param array(string=>string) $attributes Attributes describing the data
- * @return string The generated identifier
- */
- public function generateIdentifier( $id, $attributes = null )
- {
- $identifier = strtolower( $this-> backendName )
- . $this-> properties ['location']
- . $id
- . (
- ( $attributes !== null && !empty( $attributes ) )
- ? md5( serialize( $attributes ) )
- : ''
- );
- return urlencode( $identifier );
- }
- /**
- * Purge outdated data from the storage.
- *
- * This method purges outdated data from the cache. If $limit is given, a
- * maximum of $limit items is purged. Otherwise all outdated items are
- * purged. The method returns an array containing the IDs of all cache
- * items that have been purged.
- *
- * @param int $limit
- * @return array(string)
- */
- public function purge( $limit = null )
- {
- $this-> fetchSearchRegistry ( true );
- $purgedIds = array();
- $ttl = $this-> properties ['options']->ttl;
- foreach ( $this-> searchRegistry [$this-> properties ['location']] as $id => $identifiers )
- {
- $deleted = false;
- foreach( $identifiers as $identifier => $data )
- {
- if ( $ttl !== false && $this-> calcLifetime ( $identifier ) == 0 )
- {
- // Since ID <-> identifier mapping is ambigious, this does
- // not ensure that all data for an ID is deleted. However,
- // this should work if used properly
- $this-> backend -> delete ( $identifier );
- $this-> unRegisterIdentifier ( null, null, $identifiers, true );
- // Avoid adding an ID twice to the returned array
- $deleted = true;
- }
- }
- if ( $deleted === true )
- {
- $purgedIds[] = $id;
- }
- if ( $limit !== null && count( $purgedIds ) >= $limit )
- {
- break;
- }
- }
- $this-> storeSearchRegistry ();
- return $purgedIds;
- }
- /**
- * Reset the complete storage.
- *
- * This method resets the complete cache storage. All content (including
- * content stored with the {@link ezcCacheStackMetaDataStorage} interfacer) must
- * be deleted and the cache storage must appear as if it has just newly
- * been created.
- *
- * @return void
- */
- public function reset()
- {
- $this-> backend ->reset();
- $this-> registry = array();
- $this-> searchRegistry = array( $this-> properties ['location'] => null );
- $this-> storeSearchRegistry ();
- }
- /**
- * Restores and returns the meta data struct.
- *
- * This method fetches the meta data stored in the storage and returns the
- * according struct of type {@link ezcCacheStackMetaData}. The meta data
- * must be stored inside the storage, but should not be visible as normal
- * cache items to the user.
- *
- * @return ezcCacheStackMetaData
- */
- public function restoreMetaData()
- {
- $metaDataKey = urlencode( $this-> properties ['location'] ) . '_'
- . $this-> properties ['options']->metaDataKey;
- if ( ( $data = $this-> backend -> fetch ( $metaDataKey ) ) === false )
- {
- $data = null;
- }
- return $data;
- }
- /**
- * Stores the given meta data struct.
- *
- * This method stores the given $metaData inside the storage. The data must
- * be stored with the same mechanism that the storage itself uses. However,
- * it should not be stored as a normal cache item, if possible, to avoid
- * accedental user manipulation.
- *
- * @param ezcCacheStackMetaData $metaData
- * @return void
- */
- public function storeMetaData( ezcCacheStackMetaData $metaData )
- {
- $metaDataKey = urlencode( $this-> properties ['location'] ) . '_'
- . $this-> properties ['options']->metaDataKey;
- $this-> backend -> store (
- $metaDataKey,
- $metaData
- );
- }
- /**
- * Acquire a lock on the storage.
- *
- * This method acquires a lock on the storage. If locked, the storage must
- * block all other method calls until the lock is freed again using {@link
- * ezcCacheStackMetaDataStorage::unlock()}. Methods that are called within
- * the request that successfully acquired the lock must succeed as usual.
- *
- * @return void
- */
- public function lock()
- {
- $lockKey = urlencode( $this-> properties ['location'] ) . '_'
- . $this-> properties ['options']->lockKey;
- $this-> backend ->acquireLock(
- $lockKey,
- $this-> properties ['options']->lockWaitTime,
- $this-> properties ['options']->maxLockTime
- );
- $this->lock = true;
- }
- /**
- * Release a lock on the storage.
- *
- * This method releases the lock of the storage, that has been acquired via
- * {@link ezcCacheStackMetaDataStorage::lock()}. After this method has been
- * called, blocked method calls (including calls to lock()) can suceed
- * again.
- *
- * @return void
- */
- public function unlock()
- {
- if ( $this->lock !== false )
- {
- $lockKey = urlencode( $this-> properties ['location'] ) . '_'
- . $this-> properties ['options']->lockKey;
- $this-> backend ->releaseLock(
- $lockKey
- );
- $this->lock = false;
- }
- }
- /**
- * Calculates the lifetime remaining for a cache object.
- *
- * In case the TTL options is set to true, this method always returns 1.
- *
- * @param string $identifier The memcache identifier
- * @param bool $dataObject The optional data object for which to calculate the lifetime
- * @return int The remaining lifetime in seconds (0 if no time remaining)
- */
- protected function calcLifetime( $identifier, $dataObject = false )
- {
- $ttl = $this->options->ttl;
- $dataObject = is_object( $dataObject ) ? $dataObject : $this->fetchData ( $identifier, true );
- if ( is_object( $dataObject ) )
- {
- if ( $ttl === false )
- {
- return 1;
- }
- return (
- ( $lifeTime = ( time() - $dataObject->time ) < $ttl )
- ? $ttl - $lifeTime
- : 0
- );
- }
- else
- {
- return 0;
- }
- }
- /**
- * Registers an identifier to facilitate searching.
- *
- * @param string $id ID for the cache item
- * @param array $attributes Attributes for the cache item
- * @param string $identifier Identifier generated for the cache item
- */
- protected function registerIdentifier( $id = null, $attributes = array(), $identifier = null )
- {
- $identifier = ( $identifier !== null ) ? $identifier : $this-> generateIdentifier ( $id, $attributes );
- $location = $this-> properties ['location'];
- $this-> fetchSearchRegistry ();
- // Makes sure the identifier exists
- if ( !isset( $this-> searchRegistry [$location][$id][$identifier] ) )
- {
- // Makes sure the id exists
- if ( !isset( $this-> searchRegistry [$location][$id] )
- || !is_array( $this-> searchRegistry [$location][$id] ) )
- {
- $this-> searchRegistry [$location][$id] = array();
- }
- $this-> searchRegistry [$location][$id][$identifier] = new ezcCacheStorageMemoryRegisterStruct( $id, $attributes, $identifier, $location );
- $this-> storeSearchRegistry ();
- }
- }
- /**
- * Un-registers a previously registered identifier.
- *
- * @param string $id ID for the cache item
- * @param array $attributes Attributes for the cache item
- * @param string $identifier Identifier generated for the cache item
- * @param bool $delayStore Delays the storing of the updated search registry
- */
- protected function unRegisterIdentifier( $id = null, $attributes = array(), $identifier = null, $delayStore = false )
- {
- $identifier = ( $identifier !== null ) ? $identifier : $this-> generateIdentifier ( $id, $attributes );
- $location = $this-> properties ['location'];
- $this-> fetchSearchRegistry ( !$delayStore );
- if ( $this-> searchRegistry === false )
- {
- $this-> searchRegistry = array();
- }
- if ( isset( $this-> searchRegistry [$location][$id][$identifier] ) )
- {
- unset( $this-> searchRegistry [$location][$id][$identifier], $this-> registry [$location][$id][$identifier] );
- if ( $delayStore === false )
- {
- $this-> storeSearchRegistry ();
- }
- }
- }
- /**
- * Fetches the search registry from the backend or creates it if empty.
- *
- * @param bool $requireFresh To create a new search registry or not
- */
- protected function fetchSearchRegistry( $requireFresh = false )
- {
- $location = $this-> properties ['location'];
- if ( !is_array( $this-> searchRegistry ) )
- {
- $this-> searchRegistry = array();
- }
- if ( !isset( $this-> searchRegistry [$location] )
- || !is_array( $this-> searchRegistry [$location] ) )
- {
- $this-> searchRegistry [$location] = array();
- }
- // Makes sure the registry exists
- if ( empty( $this-> searchRegistry [$location] )
- || $requireFresh === true )
- {
- $this-> searchRegistry [$location] = $this-> backend -> fetch ( $this-> registryName . '_' . urlencode( $location ) );
- }
- }
- /**
- * Stores the search registry in the backend.
- */
- protected function storeSearchRegistry()
- {
- $location = $this-> properties ['location'];
- $this-> backend -> store ( $this-> registryName . '_' . urlencode( $location ), $this-> searchRegistry [$location] );
- $this-> searchRegistry [$location] = null;
- $this-> fetchSearchRegistry ( true );
- }
- /**
- * Generates a string from the $attributes array.
- *
- * @param array(string=>string) $attributes Attributes describing the data
- * @return string
- *
- * @apichange Was only used to generate "pseudo-regex". Attribute arrays
- * are compared directly now.
- */
- protected function generateAttrStr( $attributes = array() )
- {
- ksort( $attributes );
- $attrStr = '';
- foreach ( $attributes as $key => $val )
- {
- $attrStr .= '-' . $key . '=' .$val;
- }
- return $attrStr;
- }
- /**
- * Checks if the location property is valid.
- */
- protected function validateLocation()
- {
- return;
- }
- /**
- * Searches the storage for data defined by ID and/or attributes.
- *
- * @param string $id The item ID
- * @param array(string=>string) $attributes Attributes describing the data
- * @return array(mixed)
- */
- protected function search( $id = null, $attributes = array() )
- {
- // Grabs the identifier registry
- $this-> fetchSearchRegistry ();
- // Grabs the $location
- $location = $this-> properties ['location'];
- // Finds all in case of empty $id and $attributes
- if ( $id === null
- && empty( $attributes )
- && isset( $this-> searchRegistry [$location] )
- && is_array( $this-> searchRegistry [$location] ) )
- {
- $itemArr = array();
- foreach ( $this-> searchRegistry [$location] as $idArr )
- {
- foreach ( $idArr as $registryObj )
- {
- if ( !is_null( $registryObj->id ) )
- {
- $itemArr[] = array( $registryObj->id, $registryObj->attributes, $registryObj->identifier );
- }
- }
- }
- return $itemArr;
- }
- $itemArr = array();
- // Makes sure we've seen this ID before
- if ( isset( $this-> searchRegistry [$location][$id] )
- && is_array( $this-> searchRegistry [$location][$id] ) )
- {
- foreach ( $this-> searchRegistry [$location][$id] as $identifier => $dataArr )
- {
- if ( $this->fetchData( $identifier ) !== false )
- {
- $itemArr[] = array( $id, $attributes, $identifier );
- }
- }
- }
- else
- {
- // Finds cache items that fit our description
- if ( isset( $this-> searchRegistry [$location] )
- && is_array( $this-> searchRegistry [$location] ) )
- {
- foreach ( $this-> searchRegistry [$location] as $id => $arr )
- {
- foreach ( $arr as $identifier => $registryObj )
- {
- if ( count( array_diff_assoc( $attributes, $registryObj->attributes ) ) === 0 )
- {
- $itemArr[] = array(
- $registryObj->id,
- $registryObj->attributes,
- $registryObj->identifier
- );
- }
- }
- }
- }
- }
- return $itemArr;
- }
- }
Documentation generated by phpDocumentor 1.4.3