Skip to content

[Cache] Implement PSR-16 SimpleCache #20636

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
wants to merge 1 commit into from

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Nov 25, 2016

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? (not yet, and many are missing anyway)
Fixed tickets -
License MIT
Doc PR -

Let's review PSR-16 by looking at a possible actual implementation of it, helping @Seldaek in his quest to pass it to the FIG.
See also:

@Seldaek
Copy link
Member

Seldaek commented Nov 25, 2016

I'm kinda confused here, I don't know the cache component in depth but it looks like you implemented CounterInterface in the adapters, but then to actually use the new CacheInterface you have to use the simple cache adapter on top of the PSR-6 cache pool, therefore losing the natively implemented CounterInterface?! Maybe you're just not finished yet :)

@Seldaek
Copy link
Member

Seldaek commented Nov 25, 2016

Ah no I missed this..

 +        if ($this->pool instanceof CounterInterface) {
 +            return $this->pool->increment($key, $step);
 +        }

All is well :)

@nicolas-grekas
Copy link
Member Author

nicolas-grekas commented Nov 25, 2016

Questions sent to the FIG:

On CounterInterface:

  • the draft doesn't say what happens when $key is invalid => the same exception as PSR-6?
  • nor does it say what happens when $step is not an integer => return false? throw something?
  • what should happen when $key already exists in the storage but is not "incrementable"? (Redis INCR fails, I didn't check apcu) => return false? throw? erase and store $step? other?

On CacheInterface:

  • doesn't say what happens when $key is invalid => the same exception as PSR-6?
  • the fact that getMultiple returns all keys, even cache misses, makes it impossible to (efficiently) implement a PSR-16 to PSR-6 bridge, because it makes it impossible to detect cache misses. When given an array, apcu_fetch for example has this other behavior of returning only the "hit", so it doesn't suffer from this. Could this be worth considering?

@dragoonis
Copy link

Thanks you @nicolas-grekas for creating this PR. Saved me some time :-)

}
}

$e = $this->doSave(array($id => $step), 0);
Copy link
Member

Choose a reason for hiding this comment

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

this implementation in the base adapter is suspicious. The spec asks for atomicity, but atomicity requires to overwrite this method in each child adapter. An adapter not overwriting it would not provide atomicity, thus breaking the spec.

Copy link
Member Author

Choose a reason for hiding this comment

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

public function getMultiple($keys)
{
foreach ($this->pool->getItems($keys) as $key => $item) {
yield $key => $item->get();
Copy link
Member

Choose a reason for hiding this comment

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

The spec says @return array, which excludes generators

Copy link
Member Author

Choose a reason for hiding this comment

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

on purpose @Seldaek?

Copy link
Member

Choose a reason for hiding this comment

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

Not really on purpose. Please email on fig ML to keep everything centralized there because otherwise stuff will get lost.. Not sure if I like generators here though, if you get multiple keys you most likely want to have them in an array where you access every result by key, and not have to loop over it.. But it's also kinda easy to wrap iterator_to_array so not huge deal either way.

*/
public function getMultiple($keys)
{
foreach ($this->pool->getItems($keys) as $key => $item) {
Copy link
Member

Choose a reason for hiding this comment

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

this call would be done only when starting to iterate the generator, which is too late

if (is_numeric($value = $item->get())) {
$step += $value;
}
$item->set($step);
Copy link
Member

Choose a reason for hiding this comment

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

this fallback logic does not respect the spec, as it is not atomic

Copy link
Member Author

@nicolas-grekas nicolas-grekas Nov 25, 2016

Choose a reason for hiding this comment

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

@Seldaek shouldn't the spec use a normative MUST or SHOULD on this topic? (SHOULD would be my pref so that fallback implems are kind of OK, it'd then be up to the user to chose an implem+backend that provides real atomicity when required).

Copy link
Member

Choose a reason for hiding this comment

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

there is only the phpdoc here in the spec, and it says Increment atomically so it looks like a MUST for now (at least I understand it this way when reading it)

Copy link
Member

Choose a reason for hiding this comment

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

yeah people complained about it being part of the CacheInterface initially because it wasn't possible to guarantee it can be implemented atomically.. So we split it, to keep it MUST, because otherwise it's kinda useless really IMO. I think it's still fine for implementors to provide non-atomic if they want, but at least violating the spec means you should warn people and make them aware that non-atomic ones are a bad idea if you do anything related to security or just overall don't want to lose data in high-concurrency settings.

@nicolas-grekas
Copy link
Member Author

nicolas-grekas commented Nov 25, 2016

New unresolved issues with PSR-16 draft:

  • accepting Traversable for *Multiple methods is not consistent with PSR-6 which only takes arrays as arguments
  • returning array for getMultiple is not consistent with PSR-6 getItems which returns array|Traversable
  • atomicity in CounterInterface misses a normative MUST or SHOULD

if (is_numeric($result = $this->doIncrement($id, (int) $step))) {
return $result;
}
CacheItem::log($this->logger, 'Failed to increment key "{key}"', array('key' => $key));
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you call this code also from decrement, this message may be misleading in some cases

@nicolas-grekas
Copy link
Member Author

This PR achieved its goal to spot edge cases in PSR-16.
Closing to keep this version in the github history.
New PR to come when the next iteration of PSR-16 is ready.
Thank you all for the feedback.

@nicolas-grekas nicolas-grekas deleted the simple-cache branch November 29, 2016 21:54
fabpot added a commit that referenced this pull request Jan 23, 2017
…kas)

This PR was squashed before being merged into the 3.3-dev branch (closes #20694).

Discussion
----------

[Cache] Implement PSR-16 SimpleCache v1.0

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | not yet
| Fixed tickets | -
| License       | MIT
| Doc PR        | symfony/symfony-docs#7409

Second iteration on the topic after #20636 raised some issues.

Please don't squash while merging.

Commits
-------

6219dd6 [Cache] Create PSR-16 variants of all PSR-6 adapters
99ae9d6 [Cache] Move adapter implementations to traits
848a33e [Cache] Implement PSR-16 SimpleCache v1.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants