Skip to content

[DX] Set an unique id to the ApcClassLoader #11307

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
goabonga opened this issue Jul 5, 2014 · 14 comments
Closed

[DX] Set an unique id to the ApcClassLoader #11307

goabonga opened this issue Jul 5, 2014 · 14 comments
Labels
DX DX = Developer eXperience (anything that improves the experience of using Symfony)

Comments

@goabonga
Copy link
Contributor

goabonga commented Jul 5, 2014

What do you think about to set an unique id as prefix by default for the ApcClassLoader to prevent cache key conflicts.

@shoomyth
Copy link

shoomyth commented Jul 5, 2014

What do you mean "unique id"? Unique on every request?

app.php already suggests:

// Use APC for autoloading to improve performance.
// Change 'sf2' to a unique prefix in order to prevent cache key conflicts
// with other applications also using APC.

/*$loader = new ApcClassLoader('sf2', $loader);
$loader->register(true);*/

Of course you can change default prefix sf2

@goabonga
Copy link
Contributor Author

goabonga commented Jul 5, 2014

yes i know but every body dont read it, we can add an unique id (a md5) based on the kernel dir to prevent it.

@shoomyth
Copy link

shoomyth commented Jul 5, 2014

ApcClassLoader is not used by default. Developer understands what he does when enables it. Moreover it's possible to use the same loader for different kernels

@javiereguiluz
Copy link
Member

@shoomyth for professional applications, you must use the ApcClassLoader (or anything equivalent). And it's really annoying to remember that you must choose a unique prefix (unique among all the applications installed in the same directory).

At the end I always use the domain of the application/website, but this could be generated automatically. This idea is similar to generating the name of the forms automatically when you don't care about it, which is most of the times (see related issue: #11185).

So yes, the ApcClassLoader could set the preffix to the md5() of is own __DIR__ value. The big problem is that the preffix is the first argument, so you cannot make it optional:

$loader = new ApcClassLoader('sf2', $loader);

Maybe we could create a new CachedClassLoader that uses APC/OPcache/whatever and makes this preffix optional?

@goabonga
Copy link
Contributor Author

goabonga commented Jul 5, 2014

@javiereguiluz we can set this prefix as a part of the unique id ( like concat the prefix with it )

@shoomyth
Copy link

shoomyth commented Jul 5, 2014

Okay, loader must be created and registered in entry point (app.php):

$loader = new CachedClassLoader($loader);

If I understand right, you suggest:

class CachedClassLoader
{
    public function __construct($loader, $prefix = null)
    {
        if (null === $prefix) {
            $prefix = md5(__DIR__);
        }
    }
}

IMO this solution is less obvious and will cause questions why loader loads incorrect files.

I agree that ApcClassLoader must be used for professional applications when developer understands how loading works.
On the other hand when novice opens app.php and see commented code he could be confused: what the hell? what should I do with this code? Uncomment or what?

So my suggestion is removing all commented code from app.php: ApcClassLoader and AppCache as well and adding cookbook recipe

@goabonga
Copy link
Contributor Author

goabonga commented Jul 5, 2014

that's the idea :
with this case you can't prevent novices error but share the content if it's not unique or have a safe unique version.

public function __construct($prefix, $decorated,$unique = false)
{


    if (!extension_loaded('apc')) {
        throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
    }

    if (!method_exists($decorated, 'findFile')) {
        throw new \InvalidArgumentException('The class finder must implement a "findFile" method.');
    }


    if($unique !== false){
        $this->prefix = sprintf('%s[%s]', $prefix, uniqid($prefix));
    }else{
        $this->prefix = sprintf('%s[%s]', $prefix, md5($prefix));
    }

    $this->decorated = $decorated;
}

@jakzal
Copy link
Contributor

jakzal commented Jul 5, 2014

@goabonga uniqid generates a new value each time you call it. Using it as a prefix effecitvely disables caching. I don't see a point of generating a md5 from the prefix either.

I'm 👎 for this feature. It's better to be explicit in this case. If someone's using the ApcClassLoader, he knows what he's doing. Besides, the prefix is an obligatory argument.

@javiereguiluz
Copy link
Member

@goabonga what I was thinking about was replacing the current constructor:

public function __construct($prefix, $decorated)
{
    if (!extension_loaded('apc')) {
        throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
    }

    if (!method_exists($decorated, 'findFile')) {
        throw new \InvalidArgumentException('The class finder must implement a "findFile" method.');
    }

    $this->prefix = $prefix;
    $this->decorated = $decorated;
}

With this new implementation:

public function __construct($decorated, $prefix = null)
{
    if (!extension_loaded('apc')) {
        throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
    }

    if (!method_exists($decorated, 'findFile')) {
        throw new \InvalidArgumentException('The class finder must implement a "findFile" method.');
    }

    $this->prefix = $prefix ?: md5(__DIR__);
    $this->decorated = $decorated;
}

But obviously we cannot break anything, so this is a no go :(

@goabonga
Copy link
Contributor Author

goabonga commented Jul 5, 2014

@javiereguiluz 👍

@stof
Copy link
Member

stof commented Jul 8, 2014

See symfony/symfony-standard#657 for a PR doing it.

@thunderer
Copy link
Contributor

Out of curiosity, could it be a dynamically generated value in parameters.yml (during composer install or something)? I know that at the time of running app.php nothing exists that could read it, but maybe this idea will inspire you to come with a better solution?

@stof
Copy link
Member

stof commented Jul 9, 2014

@thunderer nope. this value is needed a long time before the container is available (otherwise, you loose half of the benefits of this caching, because you need to load tons of stuff before enabling it).

The solution suggestion in the PR linked above is the best one for a generic setting IMO (a project finding that sha1 is to expensive for this use case can still replace it by an hardcoded string as long as you ensure that you don't deploy 2 apps using the same prefix string on the same server)

@fabpot
Copy link
Member

fabpot commented Jul 11, 2014

Closing in favor of symfony/symfony-standard#657

@fabpot fabpot closed this as completed Jul 11, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DX DX = Developer eXperience (anything that improves the experience of using Symfony)
Projects
None yet
Development

No branches or pull requests

7 participants