Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Optimized TagAware Symfony Cache File & Redis Adapters #4

Merged
merged 33 commits into from Mar 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e1b1371
Initial version of native TagAware File & Redis cache
andrerom Jan 28, 2019
26632d2
CS
andrerom Feb 1, 2019
7e6be16
Adjust invalidation logic to be in batches and fix merge logic
andrerom Feb 4, 2019
00950da
[CS]
andrerom Feb 8, 2019
01985f3
Fix Redis adapter after batch invalidatation change
andrerom Feb 12, 2019
2f42296
Simplify & align with Symfony 4
andrerom Feb 17, 2019
991eede
Update to align with Symfony PR
andrerom Feb 25, 2019
18e8b2a
[composer.json] Add conflict on kernel ranges for versions the cache …
andrerom Feb 27, 2019
df07cb3
PHPdoc
andrerom Feb 28, 2019
562b16e
Add source info on Marshaller
andrerom Feb 28, 2019
9b4ebf2
AbstractAdapater: Change closures to be static when they can
andrerom Mar 5, 2019
463ea3d
Fix never endign loop on invalidation of tags
andrerom Mar 5, 2019
8905744
Bump syfony reqs, make closures static + use Closure::fromCallable li…
andrerom Mar 7, 2019
7081d93
Port over some smaller fixes found while testing Sf PR
andrerom Mar 7, 2019
ea4ceb9
Port tests and changes from Symfony PR
andrerom Mar 10, 2019
56ad3df
Add missing PruneableInterface on FileSystem
andrerom Mar 10, 2019
a2c4e28
Remove non relevant test for Symfony 3.4
andrerom Mar 10, 2019
7ce9cc6
Add phpunit and travis file from Symfony (probably overkill here, and…
andrerom Mar 10, 2019
def9f2c
Simplify travis & gitignore config
andrerom Mar 10, 2019
78718e7
Fix phpunit.xml.dist
andrerom Mar 10, 2019
1dfd20b
[Tests] Fix missing class import
andrerom Mar 10, 2019
4c947cd
[Tests] Add more debug info
andrerom Mar 10, 2019
b4a07a7
[Travis] Add Redis Cluster testing
andrerom Mar 10, 2019
8d5757c
[Tests] Adapt for 3.4
andrerom Mar 10, 2019
353fc1f
Revert "[Tests] Add more debug info"
andrerom Mar 10, 2019
f00c130
Minor fixes
andrerom Mar 10, 2019
56295d0
[Optimization] Assume only cluster on Predis needs to delete one by one
andrerom Mar 11, 2019
f4d9972
Backport removal of versining on RedisCluster (RedisTrait & RedisClus…
andrerom Mar 11, 2019
c9d3c54
Adopt RedisTrait for marshaller use locally
andrerom Mar 11, 2019
3c7c64e
Don't leak key's and tags into adapters
andrerom Mar 11, 2019
03c85b6
Overload PredisTagAwareAdapterTest.php::testCreateConnection() for Re…
andrerom Mar 11, 2019
e443508
[PHPDoc] Add links to source
andrerom Mar 11, 2019
b393815
[PHPDoc] Fix phpdoc for tag expiry info
andrerom Mar 11, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 2 additions & 47 deletions .gitignore
@@ -1,48 +1,3 @@
# Cache and logs (Symfony2)
/app/cache/*
/app/logs/*
!app/cache/.gitkeep
!app/logs/.gitkeep

# Email spool folder
/app/spool/*

# Cache, session files and logs (Symfony3)
/var/cache/*
/var/logs/*
/var/sessions/*
!var/cache/.gitkeep
!var/logs/.gitkeep
!var/sessions/.gitkeep

# Parameters
/app/config/parameters.yml
/app/config/parameters.ini

# Managed by Composer
/app/bootstrap.php.cache
/var/bootstrap.php.cache
/bin/*
!bin/console
!bin/symfony_requirements
/vendor/

# Assets and user uploads
/web/bundles/
/web/uploads/

# PHPUnit
/app/phpunit.xml
/phpunit.xml

# Build data
/build/

# Composer PHAR
/composer.phar

# Backup entities generated with doctrine:generate:entities command
**/Entity/*~

# Embedded web-server pid file
/.web-server-pid
composer.lock
.php_cs.cache
1 change: 1 addition & 0 deletions .php_cs
Expand Up @@ -29,6 +29,7 @@ return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setFinder(
PhpCsFixer\Finder::create()
->exclude('lib/Symfony')
->in(__DIR__ . '/src')
->files()->name('*.php')
)
Expand Down
54 changes: 54 additions & 0 deletions .travis.yml
@@ -0,0 +1,54 @@
dist: xenial
sudo: required

language: php

cache:
directories:
- "$HOME/.composer/cache"

git:
depth: 2

matrix:
fast_finish: true
include:
- php: 7.1
- php: 7.2
env: ENABLE_IGBINARY=true
- php: 7.3
env: CHECK_CS=true

services:
- redis-server
# - memcached
- docker

# test only master + stable (+ Pull requests)
branches:
only:
- master
- /^\d.\d+$/

before_install:
- phpenv config-rm xdebug.ini
- |
# Start Redis cluster
docker pull grokzen/redis-cluster:4.0.12
docker run -d -p 7000:7000 -p 7001:7001 -p 7002:7002 -p 7003:7003 -p 7004:7004 -p 7005:7005 --name redis-cluster grokzen/redis-cluster:4.0.8
export REDIS_CLUSTER_HOSTS='localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005'

install:
# - echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- if [ "$ENABLE_IGBINARY" != "" ] ; then pecl install igbinary ; fi
- if [ "$ENABLE_LZF" != "" ] ; then printf "no\n" | pecl install lzf ; fi
- travis_retry composer install --prefer-dist --no-interaction

script:
- composer test
- if [ "$CHECK_CS" != "" ]; then ./vendor/bin/php-cs-fixer fix -v --dry-run --diff --show-progress=estimating; fi


notifications:
email: false
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 eZ Systems
Copyright (c) 2019 eZ Systems

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
34 changes: 21 additions & 13 deletions README.md
@@ -1,46 +1,54 @@
# ezsystems/symfony-tools
Collection of polyfill (backport) and incubator features for Symfony.
Collection of polyfill (backported) and incubator (proposed) features for Symfony.

Backports Symfony features so they can be used in earlier versions of Symfony, and
aims to serve as incubator for ideas to improve Symfony in the future.
proposed features improving Symfony further.

This bundle is first and foremost aiming to cover needs of [eZ Platform](https://ezplatform.com),
but is placed in own bundle under MIT as we think others can benefit and help collaborate, and
to simplify forward and backport ports to and from Symfony itself.

### Requriments

- Symfony 3.4 _(4.3+ planned spring 2019, 2.8 support might happen if we need it)_
- PHP 7.1+ 3.x branch for Symfony3 _(PHP 5.6+ for 2.x for Symfony2 if we ever add that)_
- Symfony 3.4
- PHP 7.1+ _(due to backported Symfony 4 code being written for PHP 7.1+)_

#### Semantic Versioning exception

Bundle follows [SemVer](https://semver.org/) with one exception:
- Incubator features are allowed to break BC also in Minor versions (x.Y.z), __when__ needed in order to align with changes to the feature when it gets contributed to Symfony.
- Incubator features are allowed to break BC also in Minor versions (x.Y.z), __when__ needed in order to align with
changes to the feature when it gets accepted to Symfony.


!! Tip: As such if you rely on incubator features, make sure to require specific minor versions in composer, like `~1.1.0` or `~1.1.2 || ~1.2.0`
!! Tip: As such if you rely on incubator features, make sure to require specific minor versions in composer, like
`~1.1.0` or `~1.1.2 || ~1.2.0`

### Features

**Polyfill (backport) features:**
- [Redis session handler](doc/RedisSessionHandler.md) _(for Symfony3, native in Symfony4)_

**Incubator features**
-
**Incubator (proposed) features**
- [NativeTagAwareAdapters](doc/NativeTagAwareAdapters.md)


### Contributing

Make sure as much as possible the feature is forward compatible for users, so when they upgrade to Symfony version where it's included, they should ideally not need to adapt their code/config. _(see `Semantic Versioning exception` for how this works for incubators)_
Make sure as much as possible the feature is forward compatible for users, so when they upgrade to Symfony version where
it's included, they should ideally not need to adapt their code/config. _(see `Semantic Versioning exception` for how
this works for incubators)_

**Polyfill (Backports)**
When contributing Symfony backports to this bundle, be aware you commit to help maintain that feature in case there are bug fixes or improvements to that feature in Symfony itself.
When contributing Symfony backports to this bundle, be aware you commit to help maintain that feature in case there are
bug fixes or improvements to that feature in Symfony itself.

**Incubator**
Incubator features should only be proposed here if you intend to contribute this to Symfony itself, and there is at least some certainty it will be accepted. And you also commit to adapt the feature here, if changes are requested once proposed to Symfony. Essentially aiming for the feature here becoming a polyfill/backport feature in the end.
**Incubator (Proposed)**
Incubator features should only be proposed here if also proposed against Symfony itself, and there is at least some
certainty it will be accepted. And you also commit to adapt the feature here, if changes are requested once proposed to
Symfony. Essentially aiming for the feature here becoming a polyfill/backport feature in the end.

As such it's only applicable for smaller features _(e.g. new cache adapter(s))_, not a complete new component or larger changes across Symfony itself for instance.
As such it's only applicable for smaller features _(e.g. new cache adapter(s))_, not a complete new component or larger
changes across Symfony itself for instance.

### License

Expand Down
19 changes: 16 additions & 3 deletions composer.json
Expand Up @@ -23,13 +23,26 @@
},
"require": {
"php": "^7.1",
"symfony/symfony": "^3.4.17"
"symfony/symfony": "^3.4.23"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"friendsofphp/php-cs-fixer": "v2.14.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"phpunit/phpunit": "^7.3",
"friendsofphp/php-cs-fixer": "^2.7"
"predis/predis": "^1.1.0",
"symfony/phpunit-bridge": "~3.4|~4.0"

},
"conflict": {
"ezsystems/ezpublish-kernel": "7.0 - 7.3.4 | 7.4.0 - 7.4.2"
},
"suggest": {
"ext-redis": "For use with RedisSessionHandler & RedisTagAwareAdapter, usage of native redis v3.1.3+ extension is recommended",
"ext-igbinary": "To improve serialization size and speed for cache and sessions, install igbinary extension "
},
"scripts": {
"fix-cs": "@php ./vendor/bin/php-cs-fixer fix -v --show-progress=estimating"
"fix-cs": "@php ./vendor/bin/php-cs-fixer fix -v --show-progress=estimating",
"test": "@php ./vendor/bin/phpunit"
}
}
92 changes: 92 additions & 0 deletions doc/NativeTagAwareAdapters.md
@@ -0,0 +1,92 @@
# NativeTagAwareAdapters

This feature is an Incubator, and as such might change from minor release to the next.

Contains a set of optimized TagAwareAdapters that cuts number of cache lookups down by half
compared to usage of Symfony's TagAwareAdapter. In short, for Filesystem symlinks for tags are used,
and for Redis a Set is used to keep track of ids connected to a tag, and instead of tag lookups to
find expiry info on each request this info is used to do it on-demand when calling invalidation buy tags.
_See Adapters for further details._

It also backports `Marshaller` feature from Symfony 4 in order to support serialization with igbinary.
The `MarshallerInterface` and `DefaultMarshaller` class is taken from the following revision: d2098d7
See: https://github.com/symfony/symfony/commits/master/src/Symfony/Component/Cache/Marshaller

## Requirements
- Symfony 3.4, PHP 7.1+
- For usage eZ Platform v2: `ezsystems/ezpublish-kernel` v7.3.5, v7.4.3 or higher.
- For `RedisTagAwareAdapter` usage:
- [PHP Redis](https://pecl.php.net/package/redis) extension v3.1.3 or higher, _or_ [Predis](https://packagist.org/packages/predis/predis)
- Redis 3.2 or higher, configured with `noeviction` or any `volatile-*` eviction policy

## Configuration
After installing the bundle, you have to configure proper services in order to use this.

**Here is an example on how to do that with eZ Platform:**


### File system cache

In `app/config/cache_pool/app.cache.tagaware.filesystem.yml`, place the following:
```yaml
services:
app.cache.tagaware.filesystem:
class: Symfony\Component\Cache\Adapter\TagAware\FilesystemTagAwareAdapter
parent: cache.adapter.filesystem
tags:
- name: cache.pool
clearer: cache.app_clearer
# Cache namespace prefix overriding the one used by Symfony by default
# This makes sure cache is reliably shared across whole cluster and all Symfony env's
# Can be used for blue/green deployment strategies when changes affect content cache.
# For multi db setup adapt this to be unique per pool (one pool per database)
# If you prefer default behaviour set this to null or comment out, and consider for instance:
# https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed
namespace: '%cache_namespace%'
```

Once that is done you can enable the handler, for instance by setting the following environment variable for PHP:
```bash
export CACHE_POOL="app.cache.tagaware.filesystem"
```

_Then clear cache and restart web server, you'll be able to verify it's in use on Symfony's web debug toolbar._


### Redis cache

In `app/config/cache_pool/app.cache.tagaware.redis.yml`, place the following:
```yaml
services:
app.cache.tagaware.redis:
class: Symfony\Component\Cache\Adapter\TagAware\RedisTagAwareAdapter
parent: cache.adapter.redis
tags:
- name: cache.pool
clearer: cache.app_clearer
# Examples from vendor/symfony/symfony/src/Symfony/Component/Cache/Traits/RedisTrait.php:
# redis://localhost:6379
# redis://secret@example.com:1234/13
# redis://secret@/var/run/redis.sock/13?persistent_id=4&class=Redis&timeout=3&retry_interval=3
# Example using Predis: redis://%cache_dsn%?class=\Predis\Client
provider: 'redis://%cache_dsn%'
# Cache namespace prefix overriding the one used by Symfony by default
# This makes sure cache is reliably shared across whole cluster and all Symfony env's
# Can be used for blue/green deployment strategies when changes affect content cache.
# For multi db setup adapt this to be unique per pool (one pool per database)
# If you prefer default behaviour set this to null or comment out, and consider for instance:
# https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed
namespace: '%cache_namespace%'
```

Once that is done you can enable the handler, for instance by setting the following environment variable for PHP:
```bash
export CACHE_POOL="app.cache.tagaware.redis"
```
If you don't have redis, for testing you can use:
- Run: `docker run --name my-redis -p 6379:6379 -d redis`.
- Stop + Remove: `docker rm -f my-redis`.
- Debug: `printf "PING\r\n" | nc localhost 6379`, should return `+PONG`.


_Then clear cache and restart web server, you'll be able to verify it's in use on Symfony's web debug toolbar._
55 changes: 55 additions & 0 deletions phpunit.xml.dist
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
<env name="REDIS_HOST" value="localhost" />
<env name="MEMCACHED_HOST" value="localhost" />
</php>

<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
<testsuite name="Symfony Test Suites">
<directory>./src/lib/Symfony/Components/*/Tests/</directory>
</testsuite>
</testsuites>

<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./tests</directory>
<directory>./vendor</directory>
<directory>./src/lib/Symfony/Components/*/Tests/</directory>
</exclude>
</whitelist>
</filter>

<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments>
<array>
<element key="time-sensitive">
<array>
<element key="0"><string>Cache\IntegrationTests</string></element>
<element key="1"><string>Symfony\Component\Cache</string></element>
<element key="2"><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
<element key="3"><string>Symfony\Component\Cache\Traits</string></element>
<element key="4"><string>Symfony\Component\Cache\Tests\Adapter</string></element>
<element key="5"><string>Symfony\Component\Cache\Tests\Traits</string></element>
</array>
</element>
</array>
</arguments>
</listener>
</listeners>
</phpunit>