Closed (duplicate)
Project:
Drupal core
Version:
8.0.x-dev
Component:
configuration system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Anonymous (not verified)
Created:
5 Jan 2013 at 06:41 UTC
Updated:
21 Sep 2021 at 20:46 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
Anonymous (not verified) commentedahem, with correct patch.
Comment #3
Anonymous (not verified) commentedhere's the some xhprof data.
aggregate of 40 runs, 1 is head, 2 is the patch.
Comment #5
Anonymous (not verified) commented- fixed preloadCids being altered by getMultiple()
- fixed loadedCids, switch to a count on preloadedCids
new xhprof aggregates coming soon.
Comment #6
Anonymous (not verified) commentedok, this is looking better.
hitting the front page as anonymous 6 standard core blocks enabled, seeing a 7% decrease in wall time and an 8% decrease in function calls.
summary png and zipped xhprof files attached. would love it if someone could confirm these numbers...
Comment #8
sunCan we leverage the existing CacheArray for this?
Also, I'd think that the config names to preload depend on the page/path/route? (Not sure what to do about sub-requests in the long run, but that problem will apply to every route-based CacheArray anyway then.)
Comment #9
berdirNot CacheArray, but maybe #1858616: Extract generic CacheCollector implementation and interface from CacheArray :). CacheArray is slow as it needs to go through ArrayAccess, which was necessary in 7.x but we can define real API's now in 8.x.
Comment #10
Anonymous (not verified) commented#8-path: i've heard the 'load by path' idea a few times now, seems to be popular.
no, i don't want to do that yet. lets do the simplest thing, get some data, then adjust.
on a more generic cache solution - i'd like to use cids and multi-get, rather than cache a list of data. if we can do that with a generic solution, awesome.
lists of data are a recipe for races and cache inconsistency (hello D7 variable cache). storing the cids means we simply don't have to solve the problem of cache invalidation, and introduce no new races writing cache entries.
Comment #11
Anonymous (not verified) commentedfound this gem in ConfigStorageController::buildQuery():
are you kidding me? which part of config()'s contract says "i may return, on occasion, objects that are not, in fact, stored yet. wait, wat?" this reeks of config storage controller knowing (or thinking it knows) something about the innards of config().this comment is full of stupid, please ignore.new patch:
- add a hacky Config::setIsNew(), so that ConfigStorageController trusts config(). wait, wat?
- also, clear the config.factory cache from ConfigStorageController::save()
Comment #12
Anonymous (not verified) commentedComment #13
Anonymous (not verified) commented- get rid of setIsNew(), and use a new function, preload(), which sets isNew to false
Comment #14
sun1) The language/attitude in this issue generally discourages others from commenting.
2) The fact that a
setIsNew()method is required on Config only clarifies even further that we've lost a sane separation between ConfigFactory and Config. Config was the sole and only responsible service that handled the loading and state of config objects previously. ConfigFactory suddenly took over ~50% of that, without a clear definition of which service is responsible for what. This consequence was raised as critical concern for the change proposal that added caching to ConfigFactory, but was brushed away. This patch here tries to advance on that caching, so it's only logical and natural that it is running into the exact architectural problems that were known upfront.3) The caching layer in the config system has to be transparent to all other systems and services. If any external code needs to manually reset or flush the cache of the config factory, then there is a bug in config's caching mechanism itself. There's pre-existing, similar code that manually accounts for renames in the config factory, but that only exists because the issue that introduced the config factory caching did not want to account for the already existing #1739900: Add a rename operation to config storage controllers. Again, known issue, also brushed away. There's a follow-up issue somewhere to fix that. In any case, manual calls into the config factory's cache reset methods are wrong. Renames are the only exception currently.
Comment #15
Anonymous (not verified) commented#14.1 - yeah, sorry about that. i'll tone it down a notch, i'm not being helpful
#14.2 - i took setIsNew() out in #13. i'm trying to avoid re-architecting things here. so far, this patch is small, and i'm trying to keep it that way.
#14.3 - i added
+ drupal_container()->get('config.factory')->reset($prefix . $id);
without knowing if it's really necessary. will take it out once i get this green and see what happens.
sun - i'm not sure what you're proposing. scrap this patch, step back and change Config and ConfigFactory and the way they relate to each other? to me, that feels like a bigger, separate issue.
Comment #16
sunThis patch unintentionally hits some big nails on the broken separation of concerns between Config and ConfigFactory. Ignoring that problem space further and working around it by slapping new, public API methods and behavior onto the system doesn't feel right to me and is guaranteed to make a later, proper refactoring considerably harder.
The architectural problem stems from the fact that this change adds a preload facility to the system, which attempts to inject preloaded data into the system.
One potential way to work around the architectural problems is to cache the actual Config object instead of its data within. In essence, allow a Config object instance to be serialized (in one environment) and deserialized (in another environment).
http://php.net/manual/en/class.serializable.php might help us to achieve that. (I've seen it being actively used in Symfony only recently, which looks really neat.) That way, we can skip the workarounds for isNew entirely and serialize the required properties instead.
Comment #17
Anonymous (not verified) commentedpulling a list of serialized config objects out of cache in ConfigFactory, as opposed to just the data, would simplify this patch a little, but not a lot.
but it won't change the basic idea here at all - front load a bunch of config data with a cache multi-get in the ConfigFactory. unless i'm misunderstanding #16? sun - does the basic idea i'm suggesting work with the refactoring you want to do in the future?
Comment #18
sunYeah, the general idea of preloading is fine I think. We had it for variables already, and due to the bundling of multiple values into larger config objects, it was pretty clear from the beginning that we'll have to (re-)introduce preloading.
That said, I'm not sure whether I didn't expect more performance gains from this change. AFAICS, the patch cuts away ~10-20 minutes from the total testsuite time... although that's comparing the time of two different testbots, so it doesn't really mean anything, and alas, it's also fairly easy to make HEAD faster these days, since HEAD really can't get any slower.
In other words, I'm a little concerned about the net effect of this change. This optimization was (at least in my mind) planned to be one of the last that would happen for the D8 release - considerably improving the overall system performance after fixing all other performance regressions - or in hypothetical numbers: sitting in front of a beta release with a total testsuite time of 25 minutes and cutting it down to 20 with this final optimization. Focus on "final", because after this, there's not much left that can be tweaked. :-/
Comment #19
Anonymous (not verified) commentedi straw-polled #drupal-contribute, and the consensus from xjm, jthorson, EclipseGc etc was that it's worth getting these speedups in sooner rather than later, so i'm going to continue with this patch until it's green.
Comment #20
wim leers#18: I'm intrigued by your third paragraph. Why would we only want to do this optimization very late in the development cycle? Because we'd be less inclined to fix other performance problems, since they'd be less impactful, relatively speaking? But then you say there's not much that can be tweaked after this… which I don't really understand.
Comment #21
catchThere's no value to leaving performance optimizations until the last minute.
Currently the incredibly poor performance of config() is making it very difficult to detect other performance regressions introduced into core. A fixed 5ms slow down might be 1% of the request instead of 5% given a slower system overall.
This means that patches that introduce lots of config() calls alongside other performance regressions are being let in with unknown status on just how bad they are, because it's hard to separate where exactly the regression comes from if it's from multiple places.
Caching per-route sounds worth looking at but not necessarily in this issue.
Where the caching is going to be most likely to be polluted is config entities - i.e. we don't want to load every view on every page, or every field config or instance (although those aren't configuration entities yet anyway but when they are). Also admin pages, since setting/viewing a configuration object doesn't necessarily mean it's needed on runtime.
Comment #22
Anonymous (not verified) commentedi'll try caching by route in the next iteration.
Comment #23
Anonymous (not verified) commentedhmm. so i had a look at trying to cache by path, and at this point i think i'll just use request_path() calls.
current_path() just looks like a hot mess. if you call it early, you get the raw request_path(), if you call it late, you get the system path.
so it's completely useless for a system that wants to get a path early for a read, then get a path late for a write.
Comment #24
Anonymous (not verified) commentedrerolled #13 for head, no new changes.
Comment #26
sunTagging.
Comment #27
andyceo commentedComment #28
gddJust a reroll, but would love to see this moving forward. Will try and do a proper review soon.
Comment #30
Anonymous (not verified) commentedooooook. got this going again once berdir pointed out for me in IRC that error handling during the installer is A BUNCH OF DAMN LIES.
so the only change change needed to get this to install was:
patch attached for the bot's consideration.
Comment #32
Anonymous (not verified) commented#30: 1880766-cmi-preload-30.patch queued for re-testing.
Comment #34
Anonymous (not verified) commentedgrrr, HEAD changes keep breaking this patch.
Comment #35
yched commentedHighly interested in this.
Field API currently maintains its own cache of field and instance definitions (FieldInfo class). These are about to become ConfigEntities, and thus FieldInfo will cache ConfigEntities. Ideally, we'd want to get rid of that extra layer and use the CMI cache instead of caching our own ConfigEntities on top of it.
The thing is, though, that FieldInfo currently goes a long way to implement smart cache strategy - that was #1040790: _field_info_collate_fields() memory usage.
In short : field and instance definitions are cached in separate entries by bundle, and loaded on-demand only for the entity types and bundles that are involved in the current page request.
From a (quick) glance, it seems the current patch would do : "the moment a field definition has been loaded once, it will be preloaded on each subsequent request" ?
Would put us back to "all field and instances definitions for all entity types and bundles are loaded in memory unconditionnally" pretty quick, no ?
Comment #36
catchWe discussed that issue in irc a few weeks ago in respect to both Views and Field API. The outcome of that was to have two pre-load caches:
a. Preloads everything from CMI until there's a route name.
b. Preloads everything between the route name and the end of the request.
This way, (a) is loaded every request, (b) caches based on the route name and only holds items needed in there (and not already in (a)).
The idea being that the same views / entity types / bundles ought to be found for the same routes more or less, while there's also a finite number of route names (except for stuff under admin/ which makes up > 70% on most sites) so should still get a good hit rate (as opposed to caching per-path or similar).
Comment #37
xjmShouldn't this be at least major?
Comment #38
yched commentedThe plan in #36 sounds appealing - cache config by route. Or more precisely, "cache the list of config items names to multiple-pre-load at the beginning of the request, by route", if I get this right ?
If something like this gets in, I guess it would deprecate the smart-but-complex "by bundle" caching strategy in FieldInfo, since two caching strategies on top of each other become hell to predict and debug.
I wonder whether "by route" is going to be granular enough, though. For the same route, the set of config items needed might vary a lot depending on various considerations ? Permissions of the current user comes to mind first, but I guess there are others...
So for example we'd end up loading much more config data than actually needed to serve an anonymous page request ?
Comment #39
Anonymous (not verified) commentedyes, #38 is spot on in terms of the limitations of per-route caching.
you can add cache-clears to the per-user issue - if an anonymous user on a 'light' route happens to be the request that rebuilds some caches, you can see a large number of items cached that are not normally associated with that route.
we have to make sure whatever we implement as the default is easy to override, so we don't force a one-size-fits-all solution on all sites.
Comment #40
yched commentedWhat about maybe just aiming for the ability to do multiple-load on config items, without trying to be too smart for now ?
Comment #41
Anonymous (not verified) commentedhmm. can you elaborate?
are you suggesting building a 'get a list of CMI objects' functionality that this code can use?
or, simplifying the cache loading to store the CMI data as a list? or ... ?
Comment #42
yched commentedI mean just being able to do something like the following would speed Field API quite a bit :
Comment #43
Anonymous (not verified) commentedah, that is a nice idea :-)
Comment #44
berdirRelated: #1971158: Follow-up: Add loadMultiple() and listAll() caching to (cached) config storage, #6, among others :)
Comment #45
Anonymous (not verified) commentedhmm. i don't know how to do this any more. i tried following the context code paths, and failed.
hopefully someone else can figure it out, because it's beyond me.
Comment #46
Anonymous (not verified) commentedok, so #45 was a bit of a whinge.
this patch, and also Berdir's nice patch over in [#1971158:15] can handle multi-load from cache easily. Berdir's patch also includes some nice code to make file scanning more efficient.
but having added a bunch of complexity in order to make this vaguely performant, we then have to do stuff like this per object (from Berdir's patch):
and what do context event listeners to do on 'config.load'? run expensive cache/filesystem code per object.
so, with these optimisations we do expensive stuff (number of 'config.load' listeners * number of config objects) times. without them, we do expensive stuff ((1 + number of 'config.load' listeners) * number of config objects) times.
there are two ways we can go from here.
1. just say "if you use config event listeners to override stuff from your custom .yml files **cough**any multilingual site**cough**, your site will be slow". that sucks, and i bags not having that chat with Gabor.
2. push multi-load down in to the event listener API ('config.load-multiple' something something), so they can add the extra complexity just like we've done here. that sucks.
i'm not sure which i hate the most, so i'll take direction on which way to go.
Comment #47
yched commented[edit: never mind, this comment is irrelevant]
Config listeners are below cache point, right ?So multiple load would still be a win on warm caches (multiple cache reads) even if they're a wash on cold caches ?
Comment #48
Anonymous (not verified) commentedsorry, i didn't follow #47. can you elaborate?
what i'm trying to communicate is
- listeners are called per-object, no matter how we fetch them from cache or file storage
- the most important core listener is locale, which on load, will try to fetch another config object, at which point we're back to 'do expensive stuff per object'
Comment #49
gábor hojtsyIf we push down multiload to this level then we can also rely on multiload in locale speeding up the loading of those overrides somewhat. I'm not sure how faster that is going to be.
Comment #50
catchI'd probably go for pushing the multiple load down to the listeners as well. I never really liked the listeners approach very much and this was the main reason why - having to have a complete layer on top of everything doing stuff twice but we're stuck with that now.
Comment #51
yched commentedre @beejeebus #48: right, sorry, I thought listeners kicked in before data was cached. My bad, scratch #47.
Comment #52
berdirTagging.
Comment #53
jibranTagging.
Comment #54
Anonymous (not verified) commentedgoing to revive this patch. should only be 400% bigger with a config.loadMultiple approach.
Comment #55
Anonymous (not verified) commentedi started working on this, and discussed possible implementations with msonnabaum in IRC.
currently, we fire the config events from a single config object, which makes it impossible to get past the original 'expensive operation per object per listener' pattern here.
to fix that, we'll need to:
- move the 'init' and 'load' events from Config to ConfigFactory
- make the ConfigEvent return an array of Config objects
- remove 'new Config()', and replace it with calls to the factory in ConfigImporter
- port ConfigGlobalOverrideSubscriber and LocaleConfigSubscriber to handle a list of Config objects
optionally, we can convert ConfigFactory to ConfigRepository, because if we do the above things, it's really not a factory any more. but, i want to get feedback from committers on the above list first.
Comment #56
catchThat's fine with me. I wasn't comfortable with config events going in at all and there's only a couple of contrib modules that are likely to use them anyway.
Comment #57
Anonymous (not verified) commentedcoolio.
also - i plan to just work around our broken Config storage abstractions in contrib for D8 with Config db and friends...
Comment #58
gábor hojtsy#1966538: Translation is not updated for configuration, when the config changes may be some stuff related, although it does not make drastic changes to the locale event listener, last time I checked.
Comment #59
twistor commentedIf we're going to convert ConfigFactory to ConfigSomething, can we get a ConfigSomethingInterface? AFAIR ConfigFactory has been hardcoding Config(). While I have no immediate plans for something better, I would like that our premises align with our reality.
Generalizing to multiple++
Comment #60
alexpottI've never been entire comfortable with the context solution and anything we can do to improve performance here will be a big bonus.
Lets explore the suggestions in #55
Comment #61
Anonymous (not verified) commentedok, so here's a first pass at making read-time Config events use a 'handle multiple config objects' approach.
many yaks were shaved to bring you this patch.
Comment #62
Anonymous (not verified) commentednom nom nom tags nom nom nom
Comment #64
Anonymous (not verified) commentedmarking as postponed on #2098119: Replace config context system with baked-in locale support and single-event based overrides - no point trying to do this until after that lands.
Comment #65
catchComment #66
kim.pepperUn-postponed!
Comment #67
Anonymous (not verified) commentedi have some old code i'll resurrect for this.
Comment #68
Anonymous (not verified) commentedok, here's an incomplete first cut.
this patch adds a preload event, and adds a subscriber which looks for names to preload from Settings.
we may want to put this one in, then add more core subscribers in follow up patches.
Comment #69
Anonymous (not verified) commentedzero byte patch. drupal.org--
Comment #71
dawehnerThis code is a bit hart to understand. If it is not fired yet, set it to fired. Let's just switch the two lines.
We use "@return $this" now.
It would be cool if we could just inject the settings service instead.
The documentation is a bit inaccurate.
Comment #72
kim.pepperFixes issues in #71
Comment #73
jibranIf we have to reroll again.
Gets
Comment #74
kim.pepperThanks Jibran. I've fixed that and added a unit test for ConfigPreloadSubscriber::onConfigPreloadNamesGetSettingsNames().
Comment #75
dawehnerIt is always good to see a unit test!
Comment #76
Anonymous (not verified) commentedyep, i'm happy with this patch to go in as is.
as a follow up, i've opened #2177601: Determine which config objects core should preload to figure out which core modules should subscribe to this event.
Comment #77
yched commentedDoes this mean that the first call to loadMultiple() will receive more results than the ones it asked for ?
Looks like it might have surprising effects if the code foreaches on the results, you're not really supposed to receive results for keys you never asked ?
Couldn't we sliently add the items to preload to the list but then ditch the entries before returning actual results ?
Comment #78
kim.pepperComment #79
webchick#77 looks like a needs review.
Comment #80
pounardAnother idea maybe a bit too late and maybe a bit more hardcore would have been to dump configuration as generated PHP files containing arrays, such as the container is being dumped. This way it could also serve as a security layer where files could not be changed by a hacker that does not have access to writing to the filesystem, and be protected by paranoid admin with restrive file permissions, and would also go to OPCode cache ensuring both 0 file stat and 0 SQL or cache backend queries. This would vanish any need for preloading anything, would be super simple, altered configuration could be dumped too (considering that alteration is not supposed to be variable) and give a very good performance boost altogether (and maybe tend to a 0-query bootstrap).
Comment #81
Anonymous (not verified) commented#77 - wow, i'm so bad at this game. yep, we totes need to fix that.
#80 - sounds like a cool contrib module.
Comment #82
berdirCross-referencing #2172561: Config overrides may spill over to undesired places, I started looking into this and got distracted by performance issues with the config override stuff in general, posted my findings over there for now as that seems to become a general follow-up issue for that...
Comment #83
Anonymous (not verified) commentedi've created #2177739: Fix inefficient config factory caching to deal with the lulz berdir found.
Comment #84
sunThis mostly looks good, but I noticed some additional issues:
Hm. I'm concerned about the name "preload".
Everywhere else in Drupal, "preload" denotes a callback/hook facility for a specific "load" operation.
→ "preload" is even more confusing here, because we are, in fact, in a loadMultiple() method.
What we're really doing here is to "prime" the config factory cache. It's a cache priming facility.
Could we rename these classes and variables accordingly to avoid confusion? E.g.:
$preloadEventFired → $isCachePrimed + isCachePrimed() method
getPreloadNames() → primeCache()
ConfigPreloadEvent → ConfigCachePrimeEvent
48? Why 48? :)
Shouldn't a base/default event subscriber like this just simply use a priority of 0?
It's the first and only subscriber for this event, no?
All other commented out default settings in settings.php are using a space after the #.
Comment #85
twistor commentedShouldn't this be an array_merge()?
Comment #86
Anonymous (not verified) commentedrerolled after the config caching fix patch landed.
Comment #87
wim leersI've reviewed the code from an understandability POV — I don't know the config system at all. Mostly nitpicks though.
Should have an empty line in between.
Why would you set this to TRUE without actually firing it?
The preload event is fired in
getPreloadNames(). This should be set to TRUE after that method is called. Or maybe it should even be set it inside that method?While reading the patch, I thought this event was triggered *after* preloading had occurred, to indicate to other code that config preloading was done.
But apparently it's quite the opposite: this event is used to *collect* a list of names of config objects to be preloaded!
I think this could be documented more clearly in this class, and in
ConfigPreloadEvent.Trailing newlines.
Shouldn't this be
{@inheritdoc}?s/preload subscriber/preload event subscriber/?
What is "Settings"?
If it's
settings.php, then why is it written with a capital letter?Maybe an
@seeto relevant code would be helpful here?Comment #88
Anonymous (not verified) commentednew patch, i've tried to incorporate feedback from #84 and #87.
Comment #89
wim leersInterdiff?
Comment #90
sunThank you — The naming looks much better now! :)
Is this a list of names to prime, or a list of names that have been primed? Can we clarify the phpDoc?
1. s/Gets/Returns/ ?
2. The @return description appears to be copied from elsewhere?
@return $this
If $names is an indexed array, then we need to use array_merge() here, because += will not add indexes that exist already.
array_merge() should also make the array_unique() obsolete.
Do we really need a separate subscriber object here?
What's wrong with making ConfigFactory subscribe directly?
Fine with this name for now, but we need to review + fix the overall situation of setting names at some point:
#2160705: settings.php setting names are inconsistent (and undocumented)
s/yet/already/ ?
The comment reads fine and is informative, if you'd remove this line. :P
In summary: "Configuration object names to prime in cache."
In description:
- Let's remove "core"
- s/it's/its/
- s/any/the/
Comment #91
neetu morwani commentedLast patch re-rolled. Now the patch applies successfully.
Comment #92
neetu morwani commentedLast patch re-rolled. Now the patch applies successfully.
Comment #93
Anonymous (not verified) commentedupdated patch to address #90.
didn't remove the new subscriber, don't really care either way.
Comment #94
alexpottWe need some tests of the functionality.
Comment #95
Anonymous (not verified) commentedhmm. started writing some tests.
might need unit tests with mocks for parts of this, because it's hard to assert from outside the factory that the desired code path was exercised.
Comment #96
alexpottComment #97
Anonymous (not verified) commentedComment #98
kim.pepperFrom my limited understanding, I think this will require some integration tests. Not sure whether this is a new test class or there is an existing one which we can add to?
In the meantime, I've rerolled and cleaned up some imports and removed an unused global $conf.
Comment #99
berdirThe list of cache gets that I posted in #1194136-52: Re-organise core cache bins could be interesting for this. Note that this is the list after applying the patch there, which renames a lot of bins, but doesn't touch cache_config.
Comment #100
berdirLet's play a game of "Spot the difference" :)
Yeah, this definitely needs tests :p
Comment #101
alexpottUse the ConfigEvents class to make life easier too :)
Comment #102
berdirAfter fixing that, it does work, but there's a problem right now..
The are a few things that are happening during bootstrap that have a huge influence whether and what you want to preload. The most important is the page cache.
If you look at the list from the referenced issue, this is what happens in early bootstrap:
cache_config: system.module*
cache_config: system.performance
=== > CACHE HIT/MISS.
cache_bootstrap: module_implements
cache_config: system.file
cache_config: system.filter
* in DrupalKernel::initializeContainer(), should apparently *not* happen unless module list changed, but that logics seems broken. different issue, we still have the problem even there would only be system.performance
Obviously, if you're going to have a page cache hit, you don't want to load all the stuff that comes below. But the preload kicks in on the first config file being loaded, which right now is system.module. Which is too early to know that.
One idea I have is to special case system.module and system.performance, only trigger preload() after that.
Another possibly crazy idea is to invert the preload pattern, trigger something somewhere that simply calls $cache_factory->loadMultiple() instead of the implicit magic that we have right now. That would also make it equally easy to have an on request event listener that is capable of loading route specific config. Risk is to end up with various pre-loaders that all load a few config files.
Comment #103
catchWe have page_cache_without_database, that should skip all config gets on a cache hit when set. At least provides a workaround for sites that know about it.
The preloaded config is similar to the variables table in 7.x in that it's all or nothing when that's disabled though yeah.
If we were going to special case that system.performance, then it should only happen if the page is eligible to be a cache hit - i.e. no session cookie. Looks like an easy change in
_drupal_bootstrap_page_cache()we just don't do that currently. Although still needs a way to trigger preloading or not.Then we'd only load the config separately for requests that have a chance of a cache hit, and not for authenticated users / users with a session where we know there's no chance of a hit, and they don't want the extra i/o.
Comment #104
catchAlso cross-linking #2177461: Refactor page caching into a service. I haven't reviewed that patch yet but it's obviously relevant to this.
Comment #105
Anonymous (not verified) commentedalexpott suggested creating a test class that extends the factory, and do a phpunit test.
there are examples of this in the cached storage test.
Comment #106
alexpottThe example I was thinking of was ThemeHandlerTest. The CachedStorageTest gives examples of mocking config storage.
Comment #107
kim.pepperOK. Here's a crack at a unit test for loading the primed config names in loadMultiple. It actually picked up a bug in merging the name arrays. How about that??
Also added a constant for the event to ConfigEvents.
Comment #108
Anonymous (not verified) commentedwoo, nice work kim!
i can't really RTBC this, because i wrote too much of the code...
Comment #109
larowlanLooks good, a few questions and some general nitpicks
Appears unused?
Should we reference subscribers here? Seems like tail wagging the dog.
could we have an 'isPriming' property for this use case instead? Just to distinguish between the two states.
%s/factoryt/factory
suggest: Tests loading multiple config objects with primed config names?
Comment #110
kim.pepperThanks for the review @larowlan!
ensuringpreventing a redirect loop. Maybe we can just rename to isCachingPriming to make more sense?Comment #111
kim.pepperRe-roll
Comment #112
moshe weitzman commentedCan we come up with an initial list of names that should be preloaded. It seems silly for this to go in without any usage in core. Code looks good.
Comment #113
wim leersAgreed with everything in #112.
Only the silliest of silly nitpicks to be found:
Extraneous newline.
Missing newline.
Comment #114
catchNot sure why this is an event as opposed to either tagged services or just a single service implementing CacheCollector that could be replaced. Earlier patches were along those lines. Trying to think of a case where you'd need to have more than one active strategy for preloading - it seems like that could result in its own overhead if those in turn are caching lists of cids.
Comment #115
Anonymous (not verified) commentedre #118 - i don't care about events or not. i don't really understand 'more than one strategy' though, because there is only one now.
the intent is to enable easy module interaction. an event allows a simple, well known path for modules to take to alter the list of names we'll preload.
if there's another, better way to do that, i'm fine with using it.
Comment #116
catchFor 'more than one strategy', I mean:
- listener A adds configuration IDs by route
- listener B adds configuration IDs by role
or some other combination that different listeners try to do.
Comment #117
Anonymous (not verified) commenteddiscussed this with catch a bit in IRC.
we should stop any work on this patch until we agree on an approach.
catch would like us to go back to earlier approaches of this patch.
Comment #118
catchNeed to think about this more but beejeebus explained the expectation was each module would provide a static list of configuration objects to pre-load via the event. I'm always very wary of anything opt-in for performance because it's extremely to ignore.
I've been assuming that we'd still try to come up with some kind of strategy like #35-38 - although admittedly that might not work at all, but it doesn't feel very compatible with the events.
Comment #119
berdirHere's another reason why the current approach (preload on first load call) is problematic: It's useless for multilingual sites. All of it would need to be loaded again once the language negotiation happened.
We have a RoutePreloader now which is a request event subscriber, I think this should follow that model. Then it's a separate, optional step and the ConfigFactory doesn't need to be made more complicated due to it?
We will still need a solution for the handful of early bootstrap calls, but that could maybe just be a hardcoded list somewhere?
Comment #120
Anonymous (not verified) commentedok, lets ditch this approach.
Comment #121
berdirAttaching a simple proof of concept when doing it as a separate subscriber. I think that's much easier and decoupled, so that the config factory doesn't need to know about this.
We drifted away into a lot of more or less related discussions when looking at this, posting a few notes of things to do separately or improve here:
- Should we have multiple separate subscribers that load on their own or should we have one request subscriber that invokes the existing config event that we have right now in the previous patches? More complexity but it would allow us to group multiple strategies together as a single load.
- This happens after language negotiation, so we still need a solution for the few calls before there:
Without multilingual:
- system.module: This is a (we think flawed) attempt at trying to support multiple webheads and rebuilds on them, but there are many situations that we don't cover with this, like pushing new versions of modules, so we can just as well remove it
- system.performance: This is supposed to be overridable with settings, but it's broken => needs to be fixed.
- Then we have two config calls to system.filter and system.file.
With multilingual, we get 4 additional calls, and that's two to load the languages (I already have a patch to do it in a single call, will open an issue after this comment.) and we load the language types and language negotation settings. Not sure what to do about the remaining 3 after my issue.
Comment #122
catchDiscussed this in depth with Alex Pott, Wim Leers, beejeebus and others at devdays.
The most difficult thing about getting preloading right is the following:
- When lots of configuration objects are used, you want to preload as many as possible.
- When there are render cache hits, less configuration objects will be needed.
Hence the better our overall, high-level caching, pre-loading can result in a lot of information loaded that's not actually required for the request.
Assuming #1880766: Preload configuration objects works and gets in, the individual configuration loads will result in more or less zero i/o (at least when using read-only PhpStorage, or compared to the db even with preloading). So if that gets in, we can skip preloading altogether and mark this duplicate. Postponing for now though.
Comment #123
pounardThere's another way of improving things which would to make bigger config files and having less files (for example put all of the system module in only one or maybe two files). The file number could be dramatically reduced. In most pages you are going to load almost everything of system module anyway ; I'm quite sure this is true for most modules. Having the file structure exposed at the API level was a very bad idea at the very beggining anyway and that's what is causing you the most trouble today. So just reduce the file number. But that probably belongs to another issue(s).
Comment #124
webchickSorry, which issue is this postponed on? #122 contains a self-reference. :)
Comment #125
twistor commentedI believe it's #2228261: Add a local, PhpStorage-based cache backend
Comment #126
catch@pounard while that might help a bit for static configuration, it would make no difference to configuration entities, which in the end will be the largest number of configuration objects on a site. Entity bundles, fields, instances, display modes, views, image styles etc. can't be put into a single file.
Also even one file per module for static configuration could result in over a hundred database queries where there's 100+ modules enabled.
Comment #127
pounardIndeed.
Comment #128
jibranComment #129
catchAlso #2248767: Use fast, local cache back-end (APCu, if available) for low-write caches (bootstrap, discovery, and config) and #2231595: Add a cache backend that checks an inconsistent cache, then falls back to a consistent cache backend.
Those are pretty far along, so I'm bumping this down to major/active.
Pre-loading could be useful to at least some extent even with those patches in, since with opt-in pre-loading it'd be possible to multiple load on cache misses. But that's much less of an issue with a local cache.
Comment #130
fabianx commentedComment #131
alexpottIs this still something we want to pursue given #2248767: Use fast, local cache back-end (APCu, if available) for low-write caches (bootstrap, discovery, and config)?
Comment #132
catchIt's a duplicate of #2348245: Add a cache collector style backend to reduce the number of calls to cache backends if at all.