3
* Copyright 2013 Horde LLC (http://www.horde.org/)
5
* See the enclosed file COPYING for license information (LGPL). If you
6
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
9
* @copyright 2013 Horde LLC
10
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
15
* Cache storage in a MongoDB database.
17
* @author Michael Slusarz <slusarz@horde.org>
19
* @copyright 2013 Horde LLC
20
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
23
class Horde_Cache_Storage_Mongo extends Horde_Cache_Storage_Base
28
const EXPIRE = 'expire';
29
const TIMESTAMP = 'ts';
32
* The MongoDB Collection object for the cache data.
34
* @var MongoCollection
41
* @param array $params Parameters:
42
* - collection: (string) The collection name.
43
* - mongo_db: [REQUIRED] (Horde_Mongo_Client) A MongoDB client object.
45
public function __construct(array $params = array())
47
if (!isset($params['mongo_db'])) {
48
throw new InvalidArgumentException('Missing mongo_db parameter.');
51
parent::__construct(array_merge(array(
52
'collection' => 'horde_cache'
59
public function __destruct()
61
/* Only do garbage collection 0.1% of the time we create an object. */
62
if (rand(0, 999) == 0) {
64
$this->_db->remove(array(
65
self::EXPIRE => array(
70
} catch (MongoException $e) {
71
$this->_logger->log($e->getMessage(), 'DEBUG');
78
protected function _initOb()
80
$this->_db = $this->_params['mongo_db']->selectCollection(null, $this->_params['collection']);
85
public function get($key, $lifetime = 0)
88
$key = $this->_getCid($key);
90
/* Build SQL query. */
95
// 0 lifetime checks for objects which have no expiration
97
$query[self::TIMESTAMP] = array('$gte' => time() - $lifetime);
101
$result = $this->_db->findOne($query, array(self::DATA));
102
} catch (MongoException $e) {
103
$this->_logger->log($e->getMessage(), 'DEBUG');
107
if (empty($result)) {
108
/* No rows were found - cache miss */
109
if ($this->_logger) {
110
$this->_logger->log(sprintf('Cache miss: %s (cache ID %s)', $okey, $key), 'DEBUG');
115
if ($this->_logger) {
116
$this->_logger->log(sprintf('Cache hit: %s (cache ID %s)', $okey, $key), 'DEBUG');
119
return $result[self::DATA]->bin;
124
public function set($key, $data, $lifetime = 0)
127
$key = $this->_getCid($key);
132
self::DATA => new MongoBinData($data, MongoBinData::BYTE_ARRAY),
133
self::TIMESTAMP => $curr
136
// 0 lifetime indicates the object should not be GC'd.
137
if (!empty($lifetime)) {
138
$data[self::EXPIRE] = intval($lifetime) + $curr;
141
if ($this->_logger) {
142
$this->_logger->log(sprintf(
143
'Cache set: %s (id %s set at %s%s)',
147
(isset($data[self::EXPIRE]) ? ' expires at ' . date('r', $data[self::EXPIRE]) : '')
151
// Remove any old cache data and prevent duplicate keys
153
$this->_db->update(array(
161
} catch (MongoException $e) {
162
$this->_logger->log($e->getMessage(), 'DEBUG');
169
public function exists($key, $lifetime = 0)
172
$key = $this->_getCid($key);
174
/* Build SQL query. */
179
// 0 lifetime checks for objects which have no expiration
180
if ($lifetime != 0) {
181
$query[self::TIMESTAMP] = array('$gte' => time() - $lifetime);
185
$result = $this->_db->findOne($query);
186
} catch (MongoException $e) {
187
$this->_logger->log($e->getMessage(), 'DEBUG');
191
if (is_null($result)) {
192
if ($this->_logger) {
193
$this->_logger->log(sprintf('Cache exists() miss: %s (cache ID %s)', $okey, $key), 'DEBUG');
198
if ($this->_logger) {
199
$this->_logger->log(sprintf('Cache exists() hit: %s (cache ID %s)', $okey, $key), 'DEBUG');
207
public function expire($key)
210
$this->_db->remove(array(
211
self::CID => $this->_getCid($key)
214
} catch (MongoException $e) {
221
public function clear()
227
* Gets the cache ID for a key.
229
* @param string $key The key.
231
* @return string The cache ID.
233
protected function _getCid($key)
235
return hash('md5', $key);