Skip to content

Commit

Permalink
added a cache warmer sub-framework
Browse files Browse the repository at this point in the history
Cache warmer will come in the next commits.

To warm up the cache on a production server, you can use
the cache:warmup command:

./app/console_prod cache:warmup
  • Loading branch information
fabpot committed Jan 24, 2011
1 parent 04e16e4 commit d0b4bfc
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 1 deletion.
52 changes: 52 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php
@@ -0,0 +1,52 @@
<?php

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

namespace Symfony\Bundle\FrameworkBundle\Command;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Warmup the cache.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class CacheWarmupCommand extends Command
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('cache:warmup')
->setDescription('Warms up an empty cache')
->setHelp(<<<EOF
The <info>cache:warmup</info> command warms up the cache.
Before running this command, the cache must be empty.
EOF
)
;
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Warming up the cache');

$warmer = $this->container->get('cache_warmer');
$warmer->enableOptionalWarmers();
$warmer->warmUp($this->container->getParameter('kernel.cache_dir'));
}
}
@@ -0,0 +1,45 @@
<?php

namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;

/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

/**
* Registers the cache warmers.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class AddCacheWarmerPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('cache_warmer')) {
return;
}

$warmers = array();
foreach ($container->findTaggedServiceIds('kernel.cache_warmer') as $id => $attributes) {
$warmers[] = new Reference($id);
}

$container->getDefinition('cache_warmer')->setArgument(0, $warmers);

if ('full' === $container->getParameter('kernel.cache_warmup')) {
$container->getDefinition('cache_warmer')->addMethodCall('enableOptionalWarmers', array());
}
}
}
Expand Up @@ -157,6 +157,13 @@ protected function doConfigLoad(array $config, ContainerBuilder $container)
$this->registerEsiConfiguration($config, $container);
}

if (isset($config['cache-warmer'])) {
$config['cache_warmer'] = $config['cache-warmer'];
}

$warmer = isset($config['cache_warmer']) ? $config['cache_warmer'] : !$container->getParameter('kernel.debug');
$container->setParameter('kernel.cache_warmup', $warmer);

$this->addClassesToCompile(array(
'Symfony\\Component\\HttpFoundation\\ParameterBag',
'Symfony\\Component\\HttpFoundation\\HeaderBag',
Expand Down Expand Up @@ -276,7 +283,6 @@ protected function registerTemplatingConfiguration(array $config, ContainerBuild

// compilation
$this->addClassesToCompile(array(
'Symfony\\Component\\Templating\\DelegatingEngine',
'Symfony\\Bundle\\FrameworkBundle\\Templating\\EngineInterface',
'Symfony\\Component\\Templating\\EngineInterface',
));
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Expand Up @@ -21,6 +21,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddClassesToCachePass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\HttpFoundation\File\File;
Expand Down Expand Up @@ -82,6 +83,7 @@ public function registerExtensions(ContainerBuilder $container)
$container->addCompilerPass(new AddFieldFactoryGuessersPass());
$container->addCompilerPass(new AddClassesToCachePass());
$container->addCompilerPass(new TranslatorPass());
$container->addCompilerPass(new AddCacheWarmerPass());
}

/**
Expand Down
Expand Up @@ -23,8 +23,17 @@
<xsd:attribute name="ide" type="xsd:string" />
<xsd:attribute name="charset" type="xsd:string" />
<xsd:attribute name="error-handler" type="xsd:string" />
<xsd:attribute name="cache-warmer" type="cache_warmer" />
</xsd:complexType>

<xsd:simpleType name="cache_warmer">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="false" />
<xsd:enumeration value="true" />
<xsd:enumeration value="full" />
</xsd:restriction>
</xsd:simpleType>

<xsd:complexType name="profiler">
<xsd:all>
<xsd:element name="matcher" type="profiler_matcher" minOccurs="0" maxOccurs="1" />
Expand Down
Expand Up @@ -11,6 +11,7 @@
<parameter key="error_handler.class">Symfony\Component\HttpKernel\Debug\ErrorHandler</parameter>
<parameter key="error_handler.level">null</parameter>
<parameter key="filesystem.class">Symfony\Bundle\FrameworkBundle\Util\Filesystem</parameter>
<parameter key="cache_warmer.class">Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate</parameter>
</parameters>

<services>
Expand All @@ -28,6 +29,10 @@
<call method="setEventDispatcher"><argument type="service" id="event_dispatcher" /></call>
</service>

<service id="cache_warmer" class="%cache_warmer.class%">
<argument type="collection" />
</service>

<!--
If you want to change the Request class, modify the code in
your front controller (app.php) so that it passes an instance of
Expand Down
31 changes: 31 additions & 0 deletions src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php
@@ -0,0 +1,31 @@
<?php

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

namespace Symfony\Component\HttpKernel\CacheWarmer;

/**
*
* @author Fabien Potencier <fabien.potencier@symfony-project.org>
*/
abstract class CacheWarmer implements CacheWarmerInterface
{
protected function writeCacheFile($file, $content)
{
$tmpFile = tempnam(dirname($file), basename($file));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
chmod($file, 0644);

return;
}

throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
}
}
@@ -0,0 +1,72 @@
<?php

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

namespace Symfony\Component\HttpKernel\CacheWarmer;

/**
*
* @author Fabien Potencier <fabien.potencier@symfony-project.org>
*/
class CacheWarmerAggregate implements CacheWarmerInterface
{
protected $warmers;
protected $optionalsEnabled;

public function __construct(array $warmers = array())
{
$this->setWarmers($warmers);
$this->optionalsEnabled = false;
}

public function enableOptionalWarmers()
{
$this->optionalsEnabled = true;
}

/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
*/
public function warmUp($cacheDir)
{
foreach ($this->warmers as $warmer) {
if (!$this->optionalsEnabled && $warmer->isOptional()) {
continue;
}

$warmer->warmUp($cacheDir);
}
}

/**
* Checks whether this warmer is optional or not.
*
* @return Boolean always true

This comment has been minimized.

Copy link
@kossdav

kossdav Jul 10, 2014

I think there is a mistake here, the method returns directly false, not true

This comment has been minimized.

Copy link
@sstok

sstok Jul 12, 2014

Contributor

You can open a PR using https://github.com/symfony/symfony/edit/master/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php#L57

And also correct the spaces before the description (which should be one).

*/
public function isOptional()
{
return false;
}

public function setWarmers(array $warmers)
{
$this->warmers = array();
foreach ($warmers as $warmer) {
$this->add($warmer);
}
}

public function add(CacheWarmerInterface $warmer)
{
$this->warmers[] = $warmer;
}
}
@@ -0,0 +1,38 @@
<?php

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

namespace Symfony\Component\HttpKernel\CacheWarmer;

/**
*
* @author Fabien Potencier <fabien.potencier@symfony-project.org>
*/
interface CacheWarmerInterface
{
/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
*/
function warmUp($cacheDir);

/**
* Checks whether this warmer is optional or not.
*
* Optional warmers can be ignored on certain conditions.
*
* A warmer should return true if the cache can be
* generated incrementally and on-demand.
*
* @return Boolean true if the warmer is optional, false otherwise
*/
function isOptional();
}
7 changes: 7 additions & 0 deletions src/Symfony/Component/HttpKernel/Kernel.php
Expand Up @@ -427,15 +427,22 @@ protected function initializeContainer()
$location = $this->getCacheDir().'/'.$class;
$reload = $this->debug ? $this->needsReload($class, $location) : false;

$fresh = false;
if ($reload || !file_exists($location.'.php')) {
$container = $this->buildContainer();
$this->dumpContainer($container, $class, $location.'.php');

$fresh = true;
}

require_once $location.'.php';

$this->container = new $class();
$this->container->set('kernel', $this);

if ($fresh && 'cli' !== php_sapi_name()) {
$this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
}
}

public function getKernelParameters()
Expand Down

0 comments on commit d0b4bfc

Please sign in to comment.