[ Avaa Bypassed ]




Upload:

Command:

www-data@3.15.34.228: ~ $
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Cache\Adapter;

use Predis;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Response\Status;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\LogicException;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\Traits\RedisTrait;

/**
 * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using sPOP.
 *
 * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even
 * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache
 * relationship survives eviction (cache cleanup when Redis runs out of memory).
 *
 * Requirements:
 *  - Server: Redis 3.2+
 *  - Client: PHP Redis 3.1.3+ OR Predis
 *  - Redis Server(s) configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory
 *
 * Design limitations:
 *  - Max 2 billion cache keys per cache tag
 *    E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 2 billion cache items as well
 *
 * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies.
 * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype.
 * @see https://redis.io/commands/spop Documentation for sPOP operation, capable of retriving AND emptying a Set at once.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 * @author André Rømcke <andre.romcke+symfony@gmail.com>
 *
 * @experimental in 4.3
 */
class RedisTagAwareAdapter extends AbstractTagAwareAdapter
{
    use RedisTrait;

    /**
     * Redis "Set" can hold more than 4 billion members, here we limit ourselves to PHP's > 2 billion max int (32Bit).
     */
    private const POP_MAX_LIMIT = 2147483647 - 1;

    /**
     * Limits for how many keys are deleted in batch.
     */
    private const BULK_DELETE_LIMIT = 10000;

    /**
     * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are
     * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements.
     */
    private const DEFAULT_CACHE_TTL = 8640000;

    /**
     * @var bool|null
     */
    private $redisServerSupportSPOP = null;

    /**
     * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redisClient     The redis client
     * @param string                                                   $namespace       The default namespace
     * @param int                                                      $defaultLifetime The default lifetime
     *
     * @throws \Symfony\Component\Cache\Exception\LogicException If phpredis with version lower than 3.1.3.
     */
    public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
    {
        $this->init($redisClient, $namespace, $defaultLifetime, $marshaller);

        // Make sure php-redis is 3.1.3 or higher configured for Redis classes
        if (!$this->redis instanceof \Predis\ClientInterface && version_compare(phpversion('redis'), '3.1.3', '<')) {
            throw new LogicException('RedisTagAwareAdapter requires php-redis 3.1.3 or higher, alternatively use predis/predis');
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $delTagData = []): array
    {
        // serialize values
        if (!$serialized = $this->marshaller->marshall($values, $failed)) {
            return $failed;
        }

        // While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op
        $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData, $failed) {
            // Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one
            foreach ($serialized as $id => $value) {
                yield 'setEx' => [
                    $id,
                    0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime,
                    $value,
                ];
            }

            // Add and Remove Tags
            foreach ($addTagData as $tagId => $ids) {
                if (!$failed || $ids = array_diff($ids, $failed)) {
                    yield 'sAdd' => array_merge([$tagId], $ids);
                }
            }

            foreach ($delTagData as $tagId => $ids) {
                if (!$failed || $ids = array_diff($ids, $failed)) {
                    yield 'sRem' => array_merge([$tagId], $ids);
                }
            }
        });

        foreach ($results as $id => $result) {
            // Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not
            if (is_numeric($result)) {
                continue;
            }
            // setEx results
            if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) {
                $failed[] = $id;
            }
        }

        return $failed;
    }

    /**
     * {@inheritdoc}
     */
    protected function doDelete(array $ids, array $tagData = []): bool
    {
        if (!$ids) {
            return true;
        }

        $predisCluster = $this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface;
        $this->pipeline(static function () use ($ids, $tagData, $predisCluster) {
            if ($predisCluster) {
                foreach ($ids as $id) {
                    yield 'del' => [$id];
                }
            } else {
                yield 'del' => $ids;
            }

            foreach ($tagData as $tagId => $idList) {
                yield 'sRem' => array_merge([$tagId], $idList);
            }
        })->rewind();

        return true;
    }

    /**
     * {@inheritdoc}
     */
    protected function doInvalidate(array $tagIds): bool
    {
        if (!$this->redisServerSupportSPOP()) {
            return false;
        }

        // Pop all tag info at once to avoid race conditions
        $tagIdSets = $this->pipeline(static function () use ($tagIds) {
            foreach ($tagIds as $tagId) {
                // Client: Predis or PHP Redis 3.1.3+ (https://github.com/phpredis/phpredis/commit/d2e203a6)
                // Server: Redis 3.2 or higher (https://redis.io/commands/spop)
                yield 'sPop' => [$tagId, self::POP_MAX_LIMIT];
            }
        });

        // Flatten generator result from pipeline, ignore keys (tag ids)
        $ids = array_unique(array_merge(...iterator_to_array($tagIdSets, false)));

        // Delete cache in chunks to avoid overloading the connection
        foreach (array_chunk($ids, self::BULK_DELETE_LIMIT) as $chunkIds) {
            $this->doDelete($chunkIds);
        }

        return true;
    }

    private function redisServerSupportSPOP(): bool
    {
        if (null !== $this->redisServerSupportSPOP) {
            return $this->redisServerSupportSPOP;
        }

        foreach ($this->getHosts() as $host) {
            $info = $host->info('Server');
            $info = isset($info['Server']) ? $info['Server'] : $info;
            if (version_compare($info['redis_version'], '3.2', '<')) {
                CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as '.$info['redis_version']);

                return $this->redisServerSupportSPOP = false;
            }
        }

        return $this->redisServerSupportSPOP = true;
    }
}

Filemanager

Name Type Size Permission Actions
AbstractAdapter.php File 7.99 KB 0644
AbstractTagAwareAdapter.php File 11.81 KB 0644
AdapterInterface.php File 785 B 0644
ApcuAdapter.php File 643 B 0644
ArrayAdapter.php File 4.08 KB 0644
ChainAdapter.php File 8.02 KB 0644
DoctrineAdapter.php File 700 B 0644
FilesystemAdapter.php File 933 B 0644
FilesystemTagAwareAdapter.php File 4.51 KB 0644
MemcachedAdapter.php File 1.27 KB 0644
NullAdapter.php File 2.47 KB 0644
PdoAdapter.php File 2.31 KB 0644
PhpArrayAdapter.php File 9.23 KB 0644
PhpFilesAdapter.php File 1.32 KB 0644
ProxyAdapter.php File 7.71 KB 0644
Psr16Adapter.php File 1.84 KB 0644
RedisAdapter.php File 1 KB 0644
RedisTagAwareAdapter.php File 7.77 KB 0644
SimpleCacheAdapter.php File 552 B 0644
TagAwareAdapter.php File 10.79 KB 0644
TagAwareAdapterInterface.php File 785 B 0644
TraceableAdapter.php File 6.57 KB 0644
TraceableTagAwareAdapter.php File 926 B 0644