Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix for CacheProvider serious performance issue #125

Merged
merged 3 commits into from

6 participants

@sobstel

Prior implementation for CacheProvider was seriously flawed from performance point of view as each fetch() call results in 2 additional cache storage calls due to $this->getNamespaceId(), which always checks for $namespaceCacheKey (and fetches it if exists, which will be the case for 2nd and next calls).

It is big overhead (3 calls instead just one for each fetch), and actually can be easily solved by memoizing namespace version value.

sobstel and others added some commits
@sobstel sobstel CacheProvider: memoize namespace version value.
Prior implementation for CacheProvider was seriously flawed
from performance point of view as each fetch() call results
in 2 additional cache storage calls due to $this->getNamespaceId(),
which always checks for $namespaceCacheKey (and fetches it if
exists, which will be the case for 2nd and next calls).
7bad040
@florin-innobyte florin-innobyte CacheProvider: avoid double call to fetch $namespaceVersion. 6d05190
lib/Doctrine/Common/Cache/CacheProvider.php
((17 lines not shown))
+ {
+ return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
+ }
+
+ /**
+ * Namespace version
+ *
+ * @return string $namespaceVersion
+ */
+ private function getNamespaceVersion()
+ {
+ if (NULL === $this->namespaceVersion)
+ {
+ $namespaceCacheKey = $this->getNamespaceCacheKey();
+ $namespaceVersion = $this->doFetch($namespaceCacheKey);
+ if (false === $namespaceVersion) {
@beberlei Owner

can you guarantee this for all cache drivers? or is false == the better condition here? Since its definately not 1 its a sufficient check.

Since @sobstel did the change on my recommendation I'd like to jump in on this one.

As mentioned on #122, "if the documentation here, https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Cache/CacheProvider.php#L144 , is right, then fetch will return FALSE in case the value is not found so I don't see a point in doing a trip to the caching server, ask if it has the value in it's cache, if it has fetch it, if not then" we should change the function documentation as it's wrong.

@beberlei what's your input on this?

I've also created some tests in #127 which should help with that but I couldn't test all the cache drivers. Memcache(d), APC, Array pass this condition, Zend should too since it's based on APC and I'm clueless about the rest.

@sobstel
sobstel added a note

"== condition" will also work as we're expecting integer here. We could even do ($namespaceVersion < 1) condition. But as doFetch($id) is supposed to return false, it should be ok as well. And if it's not case for some cache driver, then it should be fixed there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/Common/Cache/CacheProvider.php
@@ -117,10 +122,11 @@ public function flushAll()
*/
public function deleteAll()
{
- $namespaceCacheKey = sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
- $namespaceVersion = ($this->doContains($namespaceCacheKey)) ? $this->doFetch($namespaceCacheKey) : 1;
+ $namespaceCacheKey = $this->getNamespaceCacheKey();
+ $namespaceVersion = $this->getNamespaceVersion() + 1;
+ $this->namespaceVersion = $namespaceVersion;
@guilhermeblanco Owner

Add a line space before this line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/Common/Cache/CacheProvider.php
((13 lines not shown))
+ *
+ * @return string $namespaceCacheKey
+ */
+ private function getNamespaceCacheKey()
+ {
+ return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
+ }
+
+ /**
+ * Namespace version
+ *
+ * @return string $namespaceVersion
+ */
+ private function getNamespaceVersion()
+ {
+ if (NULL === $this->namespaceVersion)
@guilhermeblanco Owner

Use "null" (lowercased) here

@stof Collaborator
stof added a note

and the curly brace should be on the same line than the if

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@guilhermeblanco guilhermeblanco commented on the diff
lib/Doctrine/Common/Cache/CacheProvider.php
((7 lines not shown))
return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
}
/**
+ * Namespace cache key
+ *
+ * @return string $namespaceCacheKey
+ */
+ private function getNamespaceCacheKey()
+ {
+ return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
+ }
+
+ /**
+ * Namespace version
+ *
+ * @return string $namespaceVersion
+ */
+ private function getNamespaceVersion()
@guilhermeblanco Owner

Ok, this whole code needs to be refactored.
It breaks the rule #1 of Object Calisthenics: "Only one level of indentation per method".
You can rewrite this one using early returns

private function getNamespaceVersion()
{
    if (null !== $this->namespaceVersion) {
        return $this->namespaceVersion;
    }

    $namespaceCacheKey = $this->getNamespaceCacheKey();
    $namespaceVersion  = $this->doFetch($namespaceCacheKey);

    if (false === $namespaceVersion) {
        $namespaceVersion = 1;

        $this->doSave($namespaceCacheKey, $namespaceVersion);
    }

    $this->namespaceVersion = $namespaceVersion;

    return $this->namespaceVersion;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/Common/Cache/CacheProvider.php
@@ -40,6 +40,11 @@
private $namespace = '';
/**
+ * @var string The namespace version
+ */
+ private $namespaceVersion = NULL;
@stof Collaborator
stof added a note

remove the = null. It is useless as it is already the default in PHP when omitting it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dlsniper

Hi,

What's needed in order for this to be merged?

Thanks.

@stof
Collaborator
@guilhermeblanco guilhermeblanco merged commit 4f78640 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 28, 2012
  1. @sobstel

    CacheProvider: memoize namespace version value.

    sobstel authored
    Prior implementation for CacheProvider was seriously flawed
    from performance point of view as each fetch() call results
    in 2 additional cache storage calls due to $this->getNamespaceId(),
    which always checks for $namespaceCacheKey (and fetches it if
    exists, which will be the case for 2nd and next calls).
Commits on Mar 29, 2012
  1. @florin-innobyte @sobstel
Commits on Mar 31, 2012
  1. @sobstel
This page is out of date. Refresh to see the latest.
Showing with 46 additions and 5 deletions.
  1. +46 −5 lib/Doctrine/Common/Cache/CacheProvider.php
View
51 lib/Doctrine/Common/Cache/CacheProvider.php
@@ -40,6 +40,11 @@
private $namespace = '';
/**
+ * @var string The namespace version
+ */
+ private $namespaceVersion;
+
+ /**
* Set the namespace to prefix all cache ids with.
*
* @param string $namespace
@@ -117,10 +122,12 @@ public function flushAll()
*/
public function deleteAll()
{
- $namespaceCacheKey = sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
- $namespaceVersion = ($this->doContains($namespaceCacheKey)) ? $this->doFetch($namespaceCacheKey) : 1;
+ $namespaceCacheKey = $this->getNamespaceCacheKey();
+ $namespaceVersion = $this->getNamespaceVersion() + 1;
- return $this->doSave($namespaceCacheKey, $namespaceVersion + 1);
+ $this->namespaceVersion = $namespaceVersion;
+
+ return $this->doSave($namespaceCacheKey, $namespaceVersion);
}
/**
@@ -131,13 +138,47 @@ public function deleteAll()
*/
private function getNamespacedId($id)
{
- $namespaceCacheKey = sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
- $namespaceVersion = ($this->doContains($namespaceCacheKey)) ? $this->doFetch($namespaceCacheKey) : 1;
+ $namespaceVersion = $this->getNamespaceVersion();
return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
}
/**
+ * Namespace cache key
+ *
+ * @return string $namespaceCacheKey
+ */
+ private function getNamespaceCacheKey()
+ {
+ return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
+ }
+
+ /**
+ * Namespace version
+ *
+ * @return string $namespaceVersion
+ */
+ private function getNamespaceVersion()
@guilhermeblanco Owner

Ok, this whole code needs to be refactored.
It breaks the rule #1 of Object Calisthenics: "Only one level of indentation per method".
You can rewrite this one using early returns

private function getNamespaceVersion()
{
    if (null !== $this->namespaceVersion) {
        return $this->namespaceVersion;
    }

    $namespaceCacheKey = $this->getNamespaceCacheKey();
    $namespaceVersion  = $this->doFetch($namespaceCacheKey);

    if (false === $namespaceVersion) {
        $namespaceVersion = 1;

        $this->doSave($namespaceCacheKey, $namespaceVersion);
    }

    $this->namespaceVersion = $namespaceVersion;

    return $this->namespaceVersion;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ if (null !== $this->namespaceVersion) {
+ return $this->namespaceVersion;
+ }
+
+ $namespaceCacheKey = $this->getNamespaceCacheKey();
+ $namespaceVersion = $this->doFetch($namespaceCacheKey);
+
+ if (false === $namespaceVersion) {
+ $namespaceVersion = 1;
+
+ $this->doSave($namespaceCacheKey, $namespaceVersion);
+ }
+
+ $this->namespaceVersion = $namespaceVersion;
+
+ return $this->namespaceVersion;
+ }
+
+ /**
* Fetches an entry from the cache.
*
* @param string $id cache id The id of the cache entry to fetch.
Something went wrong with that request. Please try again.