8000 [ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files by nicolas-grekas · Pull Request #19276 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files #19276

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 2 commits into from

Conversation

nicolas-grekas
Copy link
Member
@nicolas-grekas nicolas-grekas commented Jul 3, 2016
Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets -
License MIT
Doc PR -

Unfortunately, can't be tested because the method relies too much on side effects.
Coupled with sensiolabs/SensioDistributionBundle#272, allows inlining ClassCollectionLoader itself into the bootstrap.php.cache file.

@nicolas-grekas
Copy link
Member Author
nicolas-grekas commented Jul 4, 2016

Status: needs work
The warm up of the classes.php file is broken: it should inline many more classes but because it excludes currently declared ones, many are excluded.
I'd like to inspect this behavior and it's related to this PR.

* @param string $cacheDir A cache directory
* @param string $name The cache name prefix
* @param bool $autoReload Whether to flush the cache when the cache is stale or not
* @param bool|array $adaptive Whether to remove already declared classes or not, or array of already declared classes
Copy link
Member

Choose a reason for hiding this comment

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

What if someone extended this class?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nobody does that for such a strange and static method 😃
What would be the issue anyway?

Copy link
Member

Choose a reason for hiding this comment

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

There will always be someone doing the not expected things. ;)

The issue is that before they could perform strict comparisons for true and false being passed. This now would fail when an array got passed.

Copy link
Member Author

Choose a reason for hiding this comment

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

@xabbuh please suggest alternatives, or surrender :-) The whole benefit of the PR is worth it, don't you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to split the method in two

@nicolas-grekas
Copy link
Member Author
nicolas-grekas commented Jul 5, 2016

Status: needs review.

This is not finished, yet it's a complex topic. The classes.php file is "broken" on 3.1.
Since #16263, this file is created by a cache warmer, but its generation is affected by the current list of declared classes. This list happens to be quite big when the cache warmer is executed, which means many classes are excluded from inlining.

Without the cache warmer, the file is generated very early in the bootstrapping process, with more classes being inlined.

The outcome of this issue is "only" lower performance of course.

This PR adds mechanisms to compute a very early declared classes list, and inject it later the cache warmer. I'm not sure the implementation is the right one, thus, I'm calling for ideas on the best way to fix this issue (reverting is not possible because that would break read-only containers based on 3.1).

FYI, the list of classes that are re-inlined after using this PR on a SE is the following:

SessionListener, NativeSessionStorage, NativeSessionHandler, NativeFileSessionHandler, SessionHandlerProxy, Session, TemplateNameParser, TemplateNameParser, TemplateLocator, UrlGenerator, RequestContext, Router, UrlMatcher, RedirectableUrlMatcher, Router, FileLocator, Event, EventDispatcher, ContainerAwareEventDispatcher, ResponseListener, RouterListener, ControllerResolver, ArgumentMetadata, KernelEvent, FilterControllerEvent, FilterResponseEvent, GetResponseEvent, GetResponseForControllerResultEvent, GetResponseForExceptionEvent, FileLocator, ControllerNameParser, ControllerResolver, Firewall, AuthenticationProviderManager, TokenStorage, AccessDecisionManager, AuthorizationChecker, FirewallMap, FirewallContext, RequestMatcher, Twig_Environment, Twig_Extension_Core, Twig_Extension_Escaper, Twig_Extension_Optimizer, NormalizerFormatter, LineFormatter, StreamHandler, FilterHandler, TestHandler, Logger, Logger, DebugHandler, ClassUtils, Registry, ControllerListener, ParamConverterListener, TemplateListener, HttpCacheListener, SecurityListener.

@@ -131,6 +131,7 @@ protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = tr
$realKernelClass = substr($realKernelClass, $pos + 1);
}
$tempKernel = $this->getTempKernel($realKernel, $namespace, $realKernelClass, $warmupDir);
$tempKernel->declaredClasses = $realKernel->declaredClasses;
Copy link
Contributor
@tgalopin tgalopin Jul 5, 2016

Choose a reason for hiding this comment

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

What about setting declaredClasses private with only a getter and modifying getTempKernel to set it's value in the code instead of relying on a public argument? It seems better for "backwards compatibiltiy" in the future (even if we are using the internal comment).

@nicolas-grekas nicolas-grekas force-pushed the classcoll branch 3 times, most recently from 885f4d3 to 3225370 Compare July 6, 2016 06:46
@nicolas-grekas
Copy link
Member Author

I think I found the way to go: using get_included_files() combined with get_declared_classes() allows filtering out early-declared classes without "snapshoting" these all the time even when not need, and without changing anything in HttpKernel.

@nicolas-grekas nicolas-grekas force-pushed the classcoll branch 4 times, most recently from 5d2217b to 965e8eb Compare July 6, 2016 08:44
@nicolas-grekas nicolas-grekas changed the title [ClassLoader] Allow injecting declared classes to ClassCollectionLoader::load() [ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files Jul 6, 2016
@nicolas-grekas
Copy link
Member Author

Just added ClassCollectionLoader::inline(), RFR


if ($autoReload) {
// save the resources
self::writeCacheFile($metadata, serialize(array($files, $classes)));
Copy link
Member

Choose a reason for hiding this comment

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

this is broken, because $files is modified into inline.

Savign resources should stay at the same place than saving the main file btw.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, fixed by making inline() return $files. The cache invalidation logic should remain in load() so I kept the general logic as is.

Copy link
Member

Choose a reason for hiding this comment

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

but then, should inline really write the file if it does not write the meta file ?

Copy link
Member Author

Choose a reason for hiding this comment

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

All use cases I saw so far need to write the cache. The metadata-related logic looks fine to me as a decorator thing, handled by ::load().

@nicolas-grekas nicolas-grekas force-pushed the classcoll branch 2 times, most recently from a3356a4 to fc78bb7 Compare July 10, 2016 06:51
@nicolas-grekas
Copy link
Member Author

Much simpler now, magic removed, let's be plain explicit.
Requires sensiolabs/SensioDistributionBundle#272
Status: needs review

<argument>Symfony\Component\HttpKernel\Kernel</argument>
<argument>Symfony\Component\ClassLoader\ClassCollectionLoader</argument>
<argument>Symfony\Component\ClassLoader\ApcClassLoader</argument>
</argument>
Copy link
Member

Choose a reason for hiding this comment

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

This is fragile. We should have tests to ensure that we don't break this at some point.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll see what can do. Btw, would it make sense to move the composer script from distributionbundle to frameworkbundle?

Copy link
Member Author
@nicolas-grekas nicolas-grekas Jul 10, 2016

Choose a reason for hiding this comment

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

Alternatively, what about moving this list in distributionbundle? => not possible, the bundle is not enabled in prod env

@fabpot
Copy link
Member
fabpot commented Jul 10, 2016

I like this approach. Being to have some tests somewhere about this one would be great.

@nicolas-grekas
Copy link
Member Author

I just added unit tests. But for the list of classes given to the cache warmer, this would require an integration test, to be done on the standard edition. Not possible here.

@fabpot
Copy link
Member
fabpot commented Jul 18, 2016

Thank you @nicolas-grekas.

@fabpot fabpot closed this in 583a45d Jul 18, 2016
@nicolas-grekas nicolas-grekas deleted the classcoll branch July 24, 2016 16:48
@fabpot fabpot mentioned this pull request Oct 27, 2016
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
0