125 if (!extension_loaded(
'redis')) {
126 throw new \TYPO3\CMS\Core\Cache\Exception(
'The PHP extension "redis" must be installed and loaded in order to use the redis backend.', 1279462933);
128 parent::__construct(
$context, $options);
138 $this->redis = new \Redis();
140 $this->connected = $this->redis->connect($this->hostname, $this->port);
144 if ($this->connected) {
145 if (strlen($this->password)) {
146 $success = $this->redis->auth($this->password);
148 throw new \TYPO3\CMS\Core\Cache\Exception(
'The given password was not accepted by the redis server.', 1279765134);
151 if ($this->database > 0) {
152 $success = $this->redis->select($this->database);
154 throw new \TYPO3\CMS\Core\Cache\Exception(
'The given database "' . $this->database .
'" could not be selected.', 1279765144);
192 throw new \InvalidArgumentException(
'The specified database number is of type "' . gettype(
$database) .
'" but an integer is expected.', 1279763057);
195 throw new \InvalidArgumentException(
'The specified database "' .
$database .
'" must be greater or equal than zero.', 1279763534);
221 throw new \InvalidArgumentException(
'The specified compression of type "' . gettype(
$compression) .
'" but a boolean is expected.', 1289679153);
238 throw new \InvalidArgumentException(
'The specified compression of type "' . gettype(
$compressionLevel) .
'" but an integer is expected.', 1289679154);
243 throw new \InvalidArgumentException(
'The specified compression level must be an integer between -1 and 9.', 1289679155);
262 public function set($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
263 if (!is_string($entryIdentifier)) {
264 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" but a string is expected.', 1279470252);
266 if (!is_string($data)) {
267 throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException(
'The specified data is of type "' . gettype($data) .
'" but a string is expected.', 1279469941);
269 $lifetime = $lifetime === NULL ? $this->defaultLifetime : $lifetime;
270 if (!is_integer($lifetime)) {
271 throw new \InvalidArgumentException(
'The specified lifetime is of type "' . gettype($lifetime) .
'" but an integer or NULL is expected.', 1279488008);
274 throw new \InvalidArgumentException(
'The specified lifetime "' . $lifetime .
'" must be greater or equal than zero.', 1279487573);
276 if ($this->connected) {
277 $expiration = $lifetime === 0 ? self::FAKED_UNLIMITED_LIFETIME : $lifetime;
278 if ($this->compression) {
279 $data = gzcompress($data, $this->compressionLevel);
281 $this->redis->setex(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier, $expiration, $data);
283 $removeTags = array();
284 $existingTags = $this->redis->sMembers(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier);
285 if (!empty($existingTags)) {
286 $addTags = array_diff($tags, $existingTags);
287 $removeTags = array_diff($existingTags, $tags);
289 if (count($removeTags) > 0 || count($addTags) > 0) {
290 $queue = $this->redis->multi(\Redis::PIPELINE);
291 foreach ($removeTags as $tag) {
292 $queue->sRemove(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier, $tag);
293 $queue->sRemove(self::TAG_IDENTIFIERS_PREFIX . $tag, $entryIdentifier);
295 foreach ($addTags as $tag) {
296 $queue->sAdd(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier, $tag);
297 $queue->sAdd(self::TAG_IDENTIFIERS_PREFIX . $tag, $entryIdentifier);
314 public function get($entryIdentifier) {
315 if (!is_string($entryIdentifier)) {
316 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" but a string is expected.', 1279470253);
318 $storedEntry = FALSE;
319 if ($this->connected) {
320 $storedEntry = $this->redis->get(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier);
322 if ($this->compression && strlen($storedEntry) > 0) {
323 $storedEntry = gzuncompress($storedEntry);
338 public function has($entryIdentifier) {
339 if (!is_string($entryIdentifier)) {
340 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" but a string is expected.', 1279470254);
342 return $this->connected && $this->redis->exists(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier);
356 public function remove($entryIdentifier) {
357 if (!is_string($entryIdentifier)) {
358 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" but a string is expected.', 1279470255);
360 $elementsDeleted = FALSE;
361 if ($this->connected) {
362 if ($this->redis->exists(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier)) {
363 $assignedTags = $this->redis->sMembers(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier);
364 $queue = $this->redis->multi(\Redis::PIPELINE);
365 foreach ($assignedTags as $tag) {
366 $queue->sRemove(self::TAG_IDENTIFIERS_PREFIX . $tag, $entryIdentifier);
368 $queue->delete(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier, self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier);
370 $elementsDeleted = TRUE;
373 return $elementsDeleted;
389 if (!is_string($tag)) {
390 throw new \InvalidArgumentException(
'The specified tag is of type "' . gettype($tag) .
'" but a string is expected.', 1279569759);
392 $foundIdentifiers = array();
393 if ($this->connected) {
394 $foundIdentifiers = $this->redis->sMembers(self::TAG_IDENTIFIERS_PREFIX . $tag);
396 return $foundIdentifiers;
408 if ($this->connected) {
409 $this->redis->flushdb();
425 if (!is_string($tag)) {
426 throw new \InvalidArgumentException(
'The specified tag is of type "' . gettype($tag) .
'" but a string is expected.', 1279578078);
428 if ($this->connected) {
429 $identifiers = $this->redis->sMembers(self::TAG_IDENTIFIERS_PREFIX . $tag);
430 if (count($identifiers) > 0) {
448 $identifierToTagsKeys = $this->redis->getKeys(self::IDENTIFIER_TAGS_PREFIX .
'*');
449 foreach ($identifierToTagsKeys as $identifierToTagsKey) {
450 list(, $identifier) = explode(
':', $identifierToTagsKey);
452 if (!$this->redis->exists((self::IDENTIFIER_DATA_PREFIX . $identifier))) {
453 $tagsToRemoveIdentifierFrom = $this->redis->sMembers($identifierToTagsKey);
454 $queue = $this->redis->multi(\Redis::PIPELINE);
455 $queue->delete($identifierToTagsKey);
456 foreach ($tagsToRemoveIdentifierFrom as $tag) {
457 $queue->sRemove(self::TAG_IDENTIFIERS_PREFIX . $tag, $identifier);
478 $uniqueTempKey =
'temp:' . uniqid(
'', TRUE);
479 $prefixedKeysToDelete = array($uniqueTempKey);
480 $prefixedIdentifierToTagsKeysToDelete = array();
481 foreach ($identifiers as $identifier) {
482 $prefixedKeysToDelete[] = self::IDENTIFIER_DATA_PREFIX . $identifier;
483 $prefixedIdentifierToTagsKeysToDelete[] = self::IDENTIFIER_TAGS_PREFIX . $identifier;
485 foreach ($tags as $tag) {
486 $prefixedKeysToDelete[] = self::TAG_IDENTIFIERS_PREFIX . $tag;
488 $tagToIdentifiersSetsToRemoveIdentifiersFrom = $this->redis->sUnion($prefixedIdentifierToTagsKeysToDelete);
490 $tagToIdentifiersSetsToRemoveIdentifiersFrom = array_diff($tagToIdentifiersSetsToRemoveIdentifiersFrom, $tags);
493 $queue = $this->redis->multi(\Redis::PIPELINE);
494 foreach ($identifiers as $identifier) {
495 $queue->sAdd($uniqueTempKey, $identifier);
497 foreach ($tagToIdentifiersSetsToRemoveIdentifiersFrom as $tagToIdentifiersSet) {
498 $queue->sDiffStore(self::TAG_IDENTIFIERS_PREFIX . $tagToIdentifiersSet, self::TAG_IDENTIFIERS_PREFIX . $tagToIdentifiersSet, $uniqueTempKey);
500 $queue->delete(array_merge($prefixedKeysToDelete, $prefixedIdentifierToTagsKeysToDelete));
const IDENTIFIER_DATA_PREFIX
const IDENTIFIER_TAGS_PREFIX
findIdentifiersByTag($tag)
removeIdentifierEntriesAndRelations(array $identifiers, array $tags)
const FAKED_UNLIMITED_LIFETIME
const TAG_IDENTIFIERS_PREFIX
const SYSLOG_SEVERITY_ERROR
setCompressionLevel($compressionLevel)
__construct($context, array $options=array())
setCompression($compression)