Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
system.module
Priority:
Major
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
26 Sep 2015 at 13:51 UTC
Updated:
15 Oct 2015 at 03:44 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
webflo commentedComment #4
webflo commentedComment #5
webflo commentedForgot to add a few files.
Comment #7
daffie commentedQuick look:
This looks wrong
Comment #8
webflo commented@daffie: Can you explain what you mean? Thats the inline php template.
Comment #9
daffie commented@webflo: Then it is my mistake. It looks strange to me, thats why I mentioned it.
Comment #12
webflo commentedComment #13
pfrenssenReviewing.
Comment #14
pfrenssenIf these two switch positions they are alphabetically ordered which is more acceptable for the control freak in me.
It wouldn't hurt to explain why we are generating this class. Perhaps add a line like:
"This class has a method that will return an ID that matches a particular Composer installation. It is used to ensure that PHP opcode caches will be invalidated whenever the Composer dependencies change."
Maybe put a /** @file */ docblock here so that the generated file is compliant with coding standards.
The @see is incomplete, link it to the generator static method.
Use {@inheritdoc} instead.
This also needs a test. We cannot change the composer dependencies in a running test so the only thing we can do is to check that the identifier that is returned by the generated class matches the composer installation.
Comment #15
hussainwebAddressing points in #14.
Comment #16
mile23OK, so hang on... :-)
One of the problems being solved here is that someone just moves the vendor directory to another location, updates the top-level autoload.php, and calls it a day, which breaks APC.
This means that the strategy here fails in two ways:
1) If they never run
composer dumpautoloadthen the script here will never run, and APC will barf.2) Even if they do that, the hash in
composer.lockwill be the same, because it's just a hash of the contents ofcomposer.json, so subsequent changes will not be reflected.So if it's the kernel's job to catch this (which I'm not sure it is), then the Composer script has to use the non-APC autoloader to resolve a class that's in
vendor(like, for instance,Symfony\Component\ClassLoader\ApcClassLoader)for it's file path. Then hash that file path along with thecomposer.lockhash for the unique ID. This way the moved file will have a different hash, and will also reflect the status ofcomposer.json.Also, I'd suggest that we write out the hash as JSON instead of a PHP file, and put it in
vendor/drupal/deployment.json. This way it has a higher probability of being removed for reasons that would change its validity anyway.So that solves the second problem, but now we have to solve the first. Which we can't. People have to run
composer dumpautoload. We should also haveupdate.phpandrebuild.phpcall the same script code to generate thedeployment.json.One downside to this is that the user now has to merge their git pull, because we store vendor in the repo.
But since the goal is to ultimately remove vendor from the repo, then +1.
Comment #17
pfrenssenComment #18
Jaesin commentedBut isn't the goal to be able to remove vendor from the repo, not require it? Or to remove vendor from the do drupal repo?
Comment #19
webflo commentedI try to repsond to the concerns from @Mile23 in #16
1) The dump-autoload event is trigger via
composer install,composer updateand<code>composer dump-autoload. The class will be automatically by one of these commands. The class will be always available, because we will run composer install during Drupal.org Packaging and Drupal CI.2) The hash from
composer.jsonorcomposer.lockmight not change butSettings::getApcuPrefixuses the site root as additional criteria to create unique prefixes for APCu.We generate this class on the fly because its faster than decoding the JSON file. Also the class is auto-discoverable through composers class loader. The JSON file would hard-code the vendor directory to a specific location. Drupal should not know about the location of the vendor directory, because we inject the autoloader in our application.
Comment #20
webflo commentedComment #21
webflo commentedSorry messed up the interdiff in #20.
Comment #24
webflo commentedComment #25
mile23Right, but the point of this issue is that anyone could move vendor at any time anywhere, and that will break APC, so we have to invalidate APC so it can start caching again.
Yes, true, but again: We don't expect the site root to change, we expect vendor/ to change.
Sorry to sound like a broken record (or, uh, skipping CD? or poorly ripped MP3?) but a changed vendor directory is exactly the problem being solved for here, unless I've completely missed the point of https://www.drupal.org/node/2380389#comment-10375583
If the JSON (or PHP or whatever) file isn't present, then we can manage APC and generate a new one.
Comment #28
webflo commentedComment #29
mile23Again, when the vendor directory gets moved, this will result in a fatal error because APC can't load the class. That's why we want JSON, and then to check if it's there, and then load it and compare hashes.
Comment #30
webflo commentedI expect that the composer hash will change because we rebuild the autoloader in #2380389: Use a single vendor directory in the root. It is not supported to just move the autoloader to the root. I tried this in my local installation and i get the following error. The error is in composers autoload before we even try to bootstrap Drupal.
Comment #31
mile23That's the special case of
\Drupalwhich is just file-included by the autoloader.I have an intuition that some of this is compounded by
config.autoload-suffixin bothcomposer.jsonfiles. If we remove that, then the autoloader class changes names with a hash when the autoloader is rebuilt. I have yet to figure out if that's enough to invalidate APC's cache though. It might be a suitable hash for dynamically adding as the prefix in the kernel, though.Also, I've discovered that if you don't manually delete
vendor/autoload.phpit never gets rebuilt, even without the autoload-suffix. I think Composer just gives up too soon in that case.Comment #32
mile23The
composer.lockhash will only change when thecomposer.jsonfile changes *and* you rebuild the lock file:composer update --lockComment #33
webflo commentedI tried this already. Composer autoloader prefix is not related to the APCu key which we use to get the autoload from APCu. Thats why we use a different key after we generated a new autoloader. There are problems with APC afaik, because APC will use the file modification date to invalide the cache. Besides that, APC is not a thing in PHP 5.5.
We could use the content hash as additional information.
Comment #34
mile23Same deal. The content hash just pulls in the JSON, sorts the array, writes it as a file, and then hashes. (So the hash doesn't change when you just re-arrange lines.)
Comment #35
webflo commented@Mile23: I would love to see an alternative patch. I don´t how you want to work around the fatal error from #30.
Comment #36
webflo commentedJust another idea. We could generate the following code.
Comment #37
mile23Somewhat more simple... Not sure how to test it.
Though I did apply #166 from #2380389: Use a single vendor directory in the root, apply this patch, and then reload, and it works. :-)
Comment #38
mile23Might refactor to put this functionality in
Settings::getApcuPrefix().Comment #39
mile23Even more simple. More documentation than code changes. :-)
Still works such that you can apply #166 from #2380389: Use a single vendor directory in the root, apply this patch, and your APC-enabled Drupal installation will simply reload.
Ideas on how to test this are welcome.
Comment #40
webflo commentedI like that Patch in #39 but it does not invalidate the class loader if the vendor stays in the same directory.
Comment #41
alexpottI don't think the recent approach in #39 works for a few reasons:
I do think we need an issue to flush APCu in rebuild.php
I think #36 might offer some protection against moving vendor but it'll need testing.
Comment #42
webflo commentedIntegrated the __DIR__ constant from #36.
Comment #43
webflo commentedChanged to hash algorithm to plain sha256 because its makes no sense to access the class loader at this stage.
Comment #44
mile23@alexpott:
#2380389: Use a single vendor directory in the root Moves the vendor directory and updates the autoloading and so forth. It works fine as long as you don't have APC on.
Agreed.
Let's rescope and add that here, since that's what's happening.
Comment #46
webflo commentedrebuild.php calls 'apc_clear_cache' and 'apcu_clear_cache' already.
Comment #47
mile23Moved the patch in #39 to #2380389: Use a single vendor directory in the root since it solves the immediate problem there.
Comment #48
neclimdulWhere this might help is with symlink deployment.
I don't have a better suggestion but changing this every time we modify composer.json seems like an annoying maintenance hurdle.
Comment #49
mile23The idea is that DeploymentIdentifier.php is generated when you (or a script) type
composer dumpautoload(orinstallorupdate).Comment #50
catchI think in this issue to unblock #2380389: Use a single vendor directory in the root we should use more or less the same logic as https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21DrupalKer...
All of those things are or can be available before the APCu class loader is initialized and don't rely on anything in the vendor directory which is what prompted this issue in the first place.
This will work great if you update between tagged releases.
If you are running the 8.0.x branch and git pull within the timeframe of a tagged release, you might have to update $deployment_identifier in settings.php (or restart apache, call rebuild.php etc.). If you're running dev then that's fine. Same for dev tarballs.
All we need to do here is not break sites between betas or RCs/patch releases.
Also the deployment identifier here has exactly the same name as the one in settings.php already give or take snake casing, that's not great for documentation purposes especially since they're dealing with similar goals albeit the classloader vs. the container.
Also raising priority since the vendor dir change feels like it's RC deadline.
Comment #51
webflo commentedAlright same logic as in DrupalKernel::getContainerCacheKey.
Comment #53
webflo commentedComment #54
timmillwood#51 looks to address everything in #50.
Comment #55
mile23Er, never mind. I guess I just don't get the scope of this issue, especially before coffee.
Comment #56
mile23Comment #57
catchCommitted/pushed to 8.0.x, thanks!
Comment #62
webchick