8000 [WIP][HttpKernel] PSR6 Store for HttpCache by jakzal · Pull Request #20061 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[WIP][HttpKernel] PSR6 Store for HttpCache #20061

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 242 additions & 0 deletions src/Symfony/Component/HttpKernel/HttpCache/Psr6Store.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
<?php

namespace Symfony\Component\HttpKernel\HttpCache;

use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

final class Psr6Store implements StoreInterface
{
/**
* @var CacheItemPoolInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed, already hinted in the constructor

*/
private $cachePool;

/**
* List of locks acquired by the current process.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure this adds value

*
* @var array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nor that

*/
private $locks = array();

/**
* @param CacheItemPoolInterface $cachePool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already in the constructor

*/
public function __construct(CacheItemPoolInterface $cachePool)
{
$this->cachePool = $cachePool;
}

/**
* Locates a cached Response for the Request provided.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{@inheritdoc}

*
* @param Request $request A Request instance
*
* @return Response|null A Response instance, or null if no cache entry was found
*/
public function lookup(Request $request)
{
// TODO: Implement lookup() method.
}

/**
* Writes a cache entry to the store for the given Request and Response.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{@inheritdoc}

*
* Existing entries are read and any that match the response are removed. This
* method calls write with the new list of cache entries.
*
* @param Request $request A Request instance
* @param Response $response A Response instance
*
* @return string The key under which the response is stored
*/
public function write(Request $request, Response $response)
{
if (!$response->headers->has('X-Content-Digest')) {
$contentDigest = $this->generateContentDigest($response);

if (false === $this->save($contentDigest, $response->getContent())) {
throw new \RuntimeException('Unable to store the entity.');
}

$response->headers->set('X-Content-Digest', $contentDigest);

if (!$response->headers->has('Transfer-Encoding')) {
$response->headers->set('Content-Length', strlen($response->getContent()));
}
}

$key = $this->getCacheKey($request);
$headers = $response->headers->all();
unset($headers['age']);

$this->save($key, serialize(array(array($request->headers->all(), $headers))));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serializing is already done by the cache pool

}

/**
* Invalidates all cache entries that match the request.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{@inheritdoc}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same below :) )

*
* @param Request $request A Request instance
*/
public function invalidate(Request $request)
{
// TODO: Implement invalidate() method.
}

/**
* Locks the cache for a given Request.
*
* @param Request $request A Request instance
*
* @return bool|string true if the lock is acquired, the path to the current lock otherwise
*/
public function lock(Request $request)
{
$lockKey = $this->getLockKey($request);

if (isset($this->locks[$lockKey])) {
return true;
}

$item = $this->cachePool->getItem($lockKey);

if ($item->isHit()) {
return false;
}

$this->cachePool->save($item);

$this->locks[$lockKey] = true;

return true;
}

/**
* Releases the lock for the given Request.
*
* @param Request $request A Request instance
*
* @return bool False if the lock file does not exist or cannot be unlocked, true otherwise
*/
public function unlock(Request $request)
{
$lockKey = $this->getLockKey($request);

if (!isset($this->locks[$lockKey])) {
return false;
}

$this->cachePool->deleteItem($lockKey);

unset($this->locks[$lockKey]);

return true;
}

/**
* Returns whether or not a lock exists.
*
* @param Request $request A Request instance
*
* @return bool true if lock exists, false otherwise
*/
public function isLocked(Request $request)
{
$lockKey = $this->getLockKey($request);

if (isset($this->locks[$lockKey])) {
return true;
}

return $this->cachePool->hasItem($this->getLockKey($request));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use $lockKey

}

/**
* Purges data for the given URL.
*
* @param string $url A URL
*
* @return bool true if the URL exists and has been purged, false otherwise
*/
public function purge($url)
{
// TODO: Implement purge() method.
}

/**
* Cleanups storage.
*/
public function cleanup()
{
$this->cachePool->deleteItems(array_keys($this->locks));
$this->locks = array();
}

/**
* @param Request $request
*
* @return string
*/
private function getCacheKey(Request $request)
{
return 'md'.hash('sha256', $request->getUri());
}

/**
* @param Request $request
*
* @return string
*/
private function getLockKey(Request $request)
{
return $this->getCacheKey($request).'.lock';
}

/**
* @param Response $response
*
* @return string
*/
private function generateContentDigest(Response $response)
{
return 'en'.hash('sha256', $response->getContent());
}

/**
* @param string $key
* @param string $data
*
* @return bool
*/
private function save($key, $data)
{
return $this->cachePool->save($this->createCacheItem($key, $data));
}

/**
* @param string $key
* @param mixed $value
* @param bool $isHit
*
* @return CacheItem
*/
private function createCacheItem($key, $value, $isHit = false)
Copy link
Member
@nicolas-grekas nicolas-grekas Sep 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the implementation work only with Symfony's Cache components: cache items aren't interoperable.
You must get the item from the pool first (and maybe keep this as an optimization when Symfony Cache is used, another idea being to keep track of fetched C943 items in this storage object to use them here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of feedback i wanted to get (ignore comments etc, i left them there for my reference until I'm done and replace them with inheritdoc) ;)

You must get the item from the pool first

I did it first, perhaps I tried to optimise too early and replaced a call to pool with this. I'll revert back. Once it's all working we can run tests and see if it needs improving.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the optimization is OK if you keep the non-optimized version for other pools

{
$f = \Closure::bind(
function ($key, $value, $isHit) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;

return $item;
},
null,
CacheItem::class
);

return $f($key, $value, $isHit);
}
}
Loading
0