Update 12 Aug 2013: The registry has been removed from Drupal 8 and is less critical. However it is still critical for D7.
catch notes in comment #130 that while we no longer write the info to the {system} table, some alters may affect what does get saved to config. The patch at #134 needs review.
Problem/Motivation
If a file containing a class is moved (either during development or by contrib/core updates), then the registry will be out of date before it is rebuilt.
If the registry is out of date, it is possible (and on some sites, likely) that it will try to request an out of date file during hook_boot(), hook_init() or a hook that is called during page rendering. This often results in a situation where the registry can be built neither via triggering a rebuild from the UI (i.e. saving the modules page), nor from drush cc all - since Drupal will throw fatal errors before getting to that point.
The original proposal (and committed patch) in this issue added a registry_rebuild() to update.php - so that hitting that file would trigger a rebuild in a reduced environment (i.e. not requiring a full bootstrap). However, registry_rebuild() causes two hooks to be invoked - hook_system_info_alter() and hook_registry_files_alter(). If all modules aren't loaded when these hooks are called, then those alter hooks won't be invoked, and this can also leave the registry in an inconsistent state - for example ctools_registry_files_alter().
Proposed resolution
Update 12 Aug 2013: "Throw away the system info cache if not yet at full bootstrap" see comment #130
Add as much as possible of a full bootstrap (making an attempt not to invoke hooks like _boot() and init()) to system_rebuild_module_data() or similar, then re-add registry_rebuild() somewhere to update.php.
If you just need to rebuild a broken registry for now take a look at Registry Rebuild.
Remaining tasks
A better solution to this problem needs to be figured out for Drupal 8.
There is a patch at comment #134
User interface changes
No user facing changes. Inclusion of an easy 'rebuild registry' / 'fix my site' button was discussed but not implemented.
API changes
None
Original report by Frando
The attached patch adds a new file to drupal called recovery.php. This file clears all caches and rebuilds the registry and the menu. Most of this is done already on admin/build/modules, but there are situations where that won't be accessible.
Very simple proof that this is needed: Make sure toolbar.module is activated, then delete modules/toolbar/toolbar.module and bam, your site is unusable. Visit recovery.php and it will work again. Now, of course you say why should you delete such a file, but especially during development you can break the registry a lot of times, e.g. when moving code around. There is no good way to fix this without such a script (as, with a broken registry, you usually cannot boot up to DRUPAL_BOOTSTRAP_FULL and therefore neither visit admin/build/modules nor get to the "clear all caches" button). This is why recovery.php first boots up to DRUPAL_BOOTSTRAP_DATABASE, loads needed includes and then performs a registry_rebuild() before finishing the bootstrap and clearing the other caches and doing a menu rebuild.
Some credit goes to chx for the initial idea and the initial (but not working) code at http://drupalbin.com/9754.
Comment | File | Size | Author |
---|---|---|---|
#173 | 534594-173-D7-system-info-cache_0.patch | 1.03 KB | mgifford |
#170 | 534594-170-D7-system-info-cache.patch | 1.04 KB | mgifford |
#165 | 534594-165-D7-system-info-cache.patch | 1.07 KB | mgifford |
#159 | 534594-159-D7-system-info-cache.patch | 1.07 KB | mgifford |
#153 | 534594-153-system-info-cache.patch | 1.28 KB | Anonymous (not verified) |
Comments
Comment #1
CorniI CreditAttribution: CorniI commentedgreat, subscribing :)
Comment #2
chx CreditAttribution: chx commentedHm, this might want to go into update.php? Esp since that has access control and I feel like some access control would be great for this...
Comment #3
Frando CreditAttribution: Frando commentedYeah, access control is likely needed, otherwise we'd make any drupal site more or less a free for all victim to DoS attacks I fear as menu_rebuild is really expensive. So yes, merging with update.php sounds good (or at least sharing some code). I'm really low on free time currently and am so at least for the next week, so not sure when I'll come around to do that. If anyone wants to go for it, go for it.
Comment #4
coltraneSetting to CNW then. I agree access control is needed.
Comment #5
catchAdded the registry_rebuild() to update.php. Not sure where it's best to put the menu_rebuild() and drupal_flush_all_caches(), but this works for the registry recovery anyway
Comment #6
moshe weitzman CreditAttribution: moshe weitzman commentedPretty quickly, visiting update.php is going to be as slow as modules page. I think we should add a recovery button to the current first page of update.php. that submit handler can flush caches and rebuild menu.
Comment #7
catchI think it's fine for update.php to be slow, not averse to a 'fix my site' button either though.
Comment #8
coltraneI don't like running the update process to rebuild the registry so I favor Moshe's idea of a submit handler on a button. But update.php having the use of a "recovery" or rebuild is misleading.
Comment #9
catchWell, update.php needs to handle rebuilding the registry anyway, because a module adding or removing a hook implementation can hose your site completely.
Comment #10
coltraneSure, so to clarify the point of this issue is the ability for someone to just run registry_rebuild() because something got hosed. update.php does that, I'm just stating that I think update.php has been and should stay about updating modules and something new created for this issue. But, I understand not duplicating code and not adding another top-level file so perhaps Moshe's idea is the route to go.
Comment #11
Frando CreditAttribution: Frando commentedI actually still quite like the idea of a seperate recovery script. Or a button/link on update.php that calls the code in the OP. Registry rebuilding is use case #1, but it'll be also very handy during development to simply have that "one click to rebuild 'em all".
Comment #12
cburschkaWhat's the status of this?
The suggestions seem to be
recovery.php
that will rebuild all registries and flush all caches.update.php
.update.php
is called.Number 3 has the drawback of being hard to find and incurring a performance cost. Number 2 may also be hard to find, while number 1 introduces a new top-level file when we already have three (authorize.php).
Comment #13
pwolanin CreditAttribution: pwolanin commentedWe still also really need a "fix my site" button (and may also a function that can be called by drush and the like)
Comment #14
pwolanin CreditAttribution: pwolanin commentedThis is really impeding development for D7.
Comment #15
catchComment #16
catchJust got bitten by this #1134798: EntityCacheTaxonomyTermController not found.
Comment #17
Dries CreditAttribution: Dries commentedCommitted to 7.x and 8.x. Thanks!
Comment #18
David_Rothstein CreditAttribution: David_Rothstein commentedStill needs to go in D7.
Comment #19
catch#5: registry_rebuild.patch queued for re-testing.
Comment #21
catchI pulled 7.x and this made it in, not sure why David thought this hadn't been applied - maybe git log isn't handling commits to both branches so well?
Unfortunately the comment in the patch dates back to when we had the function registry, now we don't.
Comment #22
Anonymous (not verified) CreditAttribution: Anonymous commentedi think we need to roll this back.
registry_rebuild() in update.php happens before a full bootstrap, so modules that rely on a fully bootstrapped drupal to properly implement hook_registry_files_alter() don't put all the resources they need into the registry.
symptom is issues like #1170312: After updating to Drupal 7.2 Fatal error: Class 'ctools_export_ui' not found.
Comment #23
catchReasons not to commit patches from 'code needs review' part 293.
Comment #24
webchickOk, committed the rollback to 8.x and 7.x. This broke (as in fatal error, destroy-your-site kind of broke) sites with CTools module, at least.
Comment #25
catchDiscussed this with beejeebus, merlinofchaos and webchick in irc and this whole issue is even more of a snake pit than we thought.
http://api.drupal.org/api/drupal/includes--bootstrap.inc/function/regist...
registry_rebuild() depends on system module.
system_rebuild_module_data() invokes hook_system_info_alter() - but there is no guarantee that all modules are loaded when that hook runs.
_registry_update() invokes hook_registry_files_alter(), but again there is no guarantee that all modules are loaded when that runs.
This patch added a call to registry_rebuild() before a full bootstrap.
ctools implements hook_registry_files_alter(), and the classes it is registering are used all over the place.
Boom!
At least for Drupal 7, I think we need to do something like the following. For Drupal 8 this will require dismantling most of system module and having a module system that doesn't depend on itself and a class autoloader that either doesn't depend on the module system or doesn't pretend to be useful for anything other than classes in modules.
But for now:
1. registry_rebuild() should add a full bootstrap right inside, possible we should even move it to system.module or common.inc to enforce this slightly more.
2. No class that can ever be used before full bootstrap can use the registry for autoload, that includes core classes, otherwise we can never, ever move them safely.
3. No hook_boot() implementation can rely on the registry for autoload, that's the same as #2, hmm.
Another possibility is to add bootstrap_alter(), make both hook_registry_files_alter() and hook_system_info_alter() bootstrap hooks, and then registry_rebuild() might work at a lower bootstrap level, but that won't remove the recursive dependency, it'll just be adding a (quite ugly) bandaid to it.
None of these solutions are good so it is a case of which makes us throw up least.
Modules that own classes that want to move them, will have to add registry_rebuild() in a hook_update_N() until this is sorted out, this worked for #1134798: EntityCacheTaxonomyTermController not found.
Comment #26
catchRe-titling slightly.
Comment #27
Anonymous (not verified) CreditAttribution: Anonymous commentedi think we need to do 1. from #25, and lots of doco.
really want to kill the concept of a registry for D8, and make it more of a classical class autoloader.
Comment #28
catchNot enough docs but I wonder if this is enough to make it work.
Comment #29
sunIMHO we'll only introduce more weird and unexpected behaviors by automatically loading all modules here.
Instead, the calling code should have to ensure that the environment for executing a command is properly setup before executing the command.
In turn, I'd rather like to see a
module_load_all(NULL)
condition here (or at the beginning of registry_rebuild()) that merely checks whether all modules have been loaded, but doesn't autoload them. In case they were not, we throw an exception or do whatever else that halts processing and ensures the command is not executed and the caller gets to know of the bogus invocation attempt.Powered by Dreditor.
Comment #30
catchI'm not sure that will work for system_rebuild_module_data(), but there's an easy way to find out.
However throwing the error doesn't deal with the original point of this issue, is that moving classes around completely hoses installs, maybe my hook_update_N() (and a handbook page with instructions on how to hack index.php) is enough though? Then docs, then checking we don't use autoload for anything in /includes.
Comment #31
Anonymous (not verified) CreditAttribution: Anonymous commentedcatch, i don't think there's a clean way to handle the 'class moved' case, if that class is required for a full bootstrap. the only way to make this better involves API changes that i don't think we can get in for D7.
that really sucks, but it is what it is. i think we just need to enforce the dependency on a full bootstrap in registry rebuilds, and make it clear in code comments and elsewhere why.
we could also add something like this to ease the dev pain:
Comment #32
catch@sun, this is broken beyond repair in D7 so we need something to fix it now, not how we'd like it to eventually work (which is going to require very large API changes), I'm marking back to CNR to give some other people the chance to review that approach.
Comment #33
Fabianx CreditAttribution: Fabianx commentedSubscribe
Comment #34
catchRe-setting.
Comment #35
catch@justinrandell - for cases that can't be fixed with loading all modules, then that seems like all we can do for classes that are needed prior to full bootstrap in Drupal 7.
Comment #36
Anonymous (not verified) CreditAttribution: Anonymous commented@catch - ok, want me to add that to the patch, or start another issue?
Comment #37
catchThis is an issue where things are broken either way, so if we can handle both kinds of broken in this issue as much as is possible that sounds good to me!
For testing this, if we go with the module_load_all() and/or force a bootstrap, we could do the following:
Two testing modules, one implements hook_boot() and calls registry_rebuild().
The other implements hook_system_info_alter() and hook_registry_files_alter() - just does drupal_set_message('something'); in each.
Then enable both modules from the test, hit a page, check for existence of both of the messages, ensure they don't show up when the hook_boot() module is disabled, that'd be it.
If we can hit update.php from simpletest (can't remember if we can or not) we could add the same check for that, minus the hook_boot() module.
If instead we went for the module_load_all(NULL) check that sun suggested, we'd be enforcing that every one of these functions can only be called after a full bootstrap:
http://api.drupal.org/api/drupal/modules--system--system.module/function...
That's a lot of functions, like I said just uploading the patch that does that should tell whether that's possible or not.
Comment #38
sunAs an example. I don't think that update.php allows to invoke registry_rebuild() - only system.module is loaded.
Comment #40
yareckon CreditAttribution: yareckon commentedsub.
Comment #41
catchChanging the title.
Comment #42
catchThis is why #38 breaks:
So I'm re-uploading #28 with an extra comment. Still needs a test but running by the test bot.
If we want the install system to not depend on system module, and I think we do, then we can work on that as part of the overall effort at #679112: Time for system.module and most of includes to commit seppuku, but that is not a critical Drupal 7 issue.
Will add tests later this evening or tomorrow if it's doable.
Comment #43
catchWith tests.
Comment #44
aspilicious CreditAttribution: aspilicious commentedTrailing whitespace.
Nice test :)
Powered by Dreditor.
Comment #45
catchFixed the whitespace.
Comment #46
aspilicious CreditAttribution: aspilicious commentedThis problem got me yesterday...
Fixed it my self, else I could test this.
Comment #47
catchrfay posted http://drupal.org/project/registry_rebuild
However we still need registry_rebuild() / _system_rebuild_module_data() to either handle loading all modules or not allow itself to run even if we were to completely give up on fixing this problem in core for D7.
Comment #48
pwolanin CreditAttribution: pwolanin commentedlooks reasonable, but need to review further.
Comment #49
catchJust spent over an hour discussing this with chx and beejeebus in irc, chx may have come up with a way around this that kills at least some of the circular dependencies:
- Add a variant of system_rebuild_module_data() that doesn't invoke any hooks (i.e. hook_system_info_alter()) - but just finds module files etc.
- Deprecate files[] completely.
- Remove hook_registry_files_alter()
- registry_rebuild() scans all modules for .module and .inc files, and adds them to the registry regardless of whether the module is enabled or disabled.
- the registry no longer differentiates between enabled or disabled modules - classes are added regardless.
- registry rebuilds will be more expensive, but we can likely avoid doing so as often as we currently do, so there might be a performance trade-off but it won't be a straight hit, and it'll only really be on rebuilds (the table size is not going to grow so much that runtime registry queries get noticeably slower, they'll all indexed, and registry rebuilds shouldn't block processes from executing hopefully).
Comment #50
sunLibraries API needs this alter hook to register additional PHP libraries in */libraries directories.
Comment #51
neclimdulI'll regret this later but... sub.
Comment #52
catch@sun: so if we wanted to account for that and still remove the hook, we'd need to scan the libraries directory if it exists and also scan .php files?
Comment #53
sunThat's a tough question and I'm not familiar enough with fundamental principles of PHP OO auto-loading. Libraries need to be considered as external code; "PHP soup" if you will. They may contain code that's incompatible or shouldn't be used. Modules that use a certain library may only need a subset of what the library provides. (custom integration example) Lastly, note that libraries may exist in
/libraries
(distros),/profiles/*/libraries
(installation profiles), and/sites/*/libraries
(sites). Overrides are supposed to behave like module and theme overrides, but I guess/hope the current registry file parsing implements that already. In the end, we could simply try to hard-code the additional libraries paths to scan, even though it feels slightly sub-optimal to me.Comment #54
catchOK, I'm moving this back to CNR. I wasn't aware that libraries module was using this hook, and that's a different use-case to the ctools one (which is just trying to avoid putting things in files[]), so we need more discussion.
We could force libraries module to implement it's own autoloader, but I imagine you wouldn't be overly keen on that.
Comment #55
pwolanin CreditAttribution: pwolanin commentedI think that's going to break too much. If simpletest cannot use autoloading, let's just rework it, and not break the rest of core for that edge case.
Comment #56
pwolanin CreditAttribution: pwolanin commentedcross posted - back to CNR
Comment #57
neclimdulI think I agree with pwolanin though I'm not sure what his comment was responding too. We should make the registry behave as sanely as possible. The alter hook isn't being abused by ctools/libraries but the simpletest exceptions seem to be complicating things. We should optimise for core and the rest of contrib and solve simpletest separately.
Comment #58
basicmagic.net CreditAttribution: basicmagic.net commentedsubscribe
Comment #59
omercioglu CreditAttribution: omercioglu commentedsub
Comment #60
rfayIronically, I didn't even know that this issue existed and was involved with the problems that caused the creation of Registry Rebuild. I thought it was just an entity/rules thing coming around to bite us. Thanks to all for your work on this.
I'm interested that the rollback happened about June 1, but I got bit only about June 20. And it seemed like there were piles of people affected in that timeframe. Could be that it came with the Entity/Rules/Commerce updates that forced the old version of this, and that I hadn't updated. Could be I guess.
Comment #61
catchSo entity/rules/commerce may have been hitting the original bug this issue was intended to help with - which is that if you move/rename a class, you can end up in an unrecoverable position.
The patch that got committed to 7.2 and was rolled back, would have fixed this except for hook_registry_files_alter(), which ctools was using to register classes on behalf of other modules, and the fact this hook wasn't run from the registry_rebuild() on update.php meant that this also left people in an unrecoverable position.
I haven't checked the code of the registry_rebuild() project, but it sounds like the two rebuilds approach may cover both of these cases, I assumed you'd seen this issue when I saw that project, otherwise I'd have pinged you about it..
The current patch here does two things:
1. Enforces that hook_system_info_alter() and hook_registry_files_alter() actually get invoked when their parent functions are called, currently they are some of the time, but other times not - by forcing a module_load_all(). This was a new discovery that was only tracked down by Justin after 7.2 had hosed some sites. An earlier patch by sun caused them to throw an exception if they were called during early bootstrap, but core itself does this deep in the installer so IMO it's not happening for D7.
2. Adds the registry_rebuild() back to update.php again in the hope that D7 itself can provide roughly the same functionality as registry_rebuild project does when you hit update.php (which you should after updating modules). Randy if you're able to review that based on having done a similar thing in registry_rebuild that'd be really handy.
Comment #62
catch#45 is still valid, but if we wanted to just ensure the ctools issue can't happen again, here's a minimal patch that enforces modules are loaded when invoking hook_system_info_files_alter() and hook_registry_files_alter().
Comment #64
moshe weitzman CreditAttribution: moshe weitzman commentedI really think it is a bad pattern for random parts of the codebase to do the job of the bootstrap. not a fan of that module_invoke_all().
Comment #65
catch@moshe. It's a bad pattern for functions available (and currently required) at any bootstrap level to be dependent on all modules being loaded. The patch names describe my feelings about the issue, perhaps you could suggest an alternative? Note that sun's patch to throw the exception would require refactoring large parts of the installer and modules system to break all these circular dependencies. That is something that desperately needs to happen in D8 but won't get backported.
Comment #66
moshe weitzman CreditAttribution: moshe weitzman commentedAs long as we fix it with the exception in D8 then I'm OK with hackola for D7 (i.e. module_invoke_all).
Comment #67
carlos8f CreditAttribution: carlos8f commentedsubscribing
Comment #68
pwolanin CreditAttribution: pwolanin commentedI think we should go forward with #45, as long as that avoids the ctools breakage.
However, here's a re-roll of the last patch without the test part which is not relevant.
Comment #70
xjmTagging issues not yet using summary template.
Comment #71
mrf CreditAttribution: mrf commentedremoving issue summary initiative tag
Comment #71.0
mrf CreditAttribution: mrf commentedAdding issue summary as part of http://groups.drupal.org/node/167534
Comment #72
catchSince there's no good solution for this in D7 (although I would still go for #45) and http://drupal.org/project/registry_rebuild exists, I'm demoting this to major.
Comment #73
q0rban CreditAttribution: q0rban commentedSubscribe
Comment #74
fagosubscribing
Comment #75
wojtha CreditAttribution: wojtha commentedI'm not sure whats the motivation of the #68 patch, but it doesn't fix the issue in the D7. After moving the modules from /modules to /modules/contrib the site hangs and there is no standard way how to rebuild the registry cache (admin/modules, update.php, drush cc - none of them works).
Comment #76
catch@wojtha - you'd need the patch from #45 and visit update.php to actually repair a broken registry.
This issue now incorporates two bugs:
1. Can't rebuild a broken registry.
2. registry_rebuild() can easily create an incomplete registry if called before all modules are loaded.
Moving back to needs review since we have patches that try to fix both of those and mainly need to decide on whether we're fixing either.
Comment #77
wojtha CreditAttribution: wojtha commentedI though the #68 by pwolanin was the same as the #45, just with the tests stripped. Now I see that pwolanin forgot to add registry_rebuild() in the update.php ... I'll try again.
Comment #78
catch#1327958: D8 upgrade path before /core move is completely hosed leaves unrecoverable, so I'm bumping this back to critical.
Comment #79
xjmAttached just rerolls #68 for core/. Can someone clarify what is missing from this patch? I compared it with #45 and did not see anything that was removed other than tests.
Comment #80
catchIt's the update.php hunk that's different:
Dave Reid reminded me about #1049284: Running update.php to flush caches no longer works unless there are updates pending, we could leave the registry building to that issue possibly (at least, for that issue to get fixed we need to correctly rebuild the registry on update.php as well as flushing other caches and registries).
Comment #81
xjmDoing a full cache clear for #1049284: Running update.php to flush caches no longer works unless there are updates pending early enough for this issue makes update.php blow up in entertaining ways. So, I think the solution is separate. Attached is #79 with the registry rebuild from #80 added back in.
Comment #83
xjmSo, for the record, #81 will break update.php with both hunks, but not with just the one or the other.
Comment #84
xjmDrupal.org hates me and I've tried to post this like 80 times. Anyway. Drupal is not sufficiently bootstrapped by this point in update.php for
module_load_all()
. I haven't yet determined how it was bootstrapped enough back in June in #28. Also, catch's patch names resonate. Also too,Edit: And gettin' our bad selves bootstrapped might also let us move up the general cache clear action in #1049284: Running update.php to flush caches no longer works unless there are updates pending for consistency and general not-clearing-cached-stuff-piecemeal-in-5-places-in-update.php.
Comment #85
Anonymous (not verified) CreditAttribution: Anonymous commentedoooook. here's a test that fails. i'm kinda not sure 100% what we want to do here.
Comment #86
Anonymous (not verified) CreditAttribution: Anonymous commentedoooook. here's another go, this time the test actually does something to try and pass.
Comment #87
xjmThis is the difference between 85 and 86, for reference.
Comment #88
xjmDoes the
registry_rebuild()
need to happen beforeupdate_check_requirements()
to resolve this issue? If not, we can move the registry rebuild a little later, when we're flushing a couple other caches, and avoid the need to manually bootstrap insideregistry_rebuild()
. Attached patch does that.We still need a failing test for the bug that broke ctools as well as what's described in #75. Honestly I am not positive these patches even resolve it. Hopefully we can extend @beejeebus's test case for that.
Comment #89
xjmMoving
registry_rebuild()
to system.module also seems plausible to me... here's what that would look like. No idea if this will blow stuff up, but hey, the upgrade tests pass.Comment #90
xjmOkay, also. This comment doesn't even seem to be correct anymore. module_load_all() doesn't get you around needing a full bootstrap, because it itself goes boom without a full bootstrap. What has changed since June on this point?
Comment #91
catchWhy does module_load_all() go boom without a full bootstrap? It should work as long as module.inc is loaded no?
Comment #92
Anonymous (not verified) CreditAttribution: Anonymous commentedre #83 - this is some of the most awesomest non-orthogonal drupal code ever.
why does it only die if you have both hunks?
a) because the fatal is in _system_rebuild_module_data(), and we need the registry_rebuild() hunk for that
b) because the fatal needs a real, honest-to-goodness rebuild with all modules, and we need module_load_all() for that
well. actually, field_ui. coz when feild_ui is enabled, *field* module calls into path.inc code in its implementation of hook_system_info_alter(). and path.inc isn't loaded before a full bootstrap.
if you didn't have field_ui enabled, you wouldn't even see this WSOD. obviously, right?
Comment #93
xjmI think this is well-earned.
Comment #94
catchSo the code in field_system_info_alter() was added in #943772: field_delete_field() and others fail for inactive fields which I RTBC'ed, and itself fixed a critical.
We could try to do that without calling l() or t(), but this boils down to hook_system_info_alter() also needing everything available.
Discussed a bit with beejeebus in irc. If we do a full bootstrap (i.e. call hook_boot() or hook_init()) then we risk calling code that relies on the registry (which might be broken), so Drupal can fatal before we try to fix it. However a middle-ground is for probably _system_rebuild_module_data() to do a mini-full-bootstrap - i.e. include as much code as possible but don't invoke any hooks. This is going to look extremely ugly, but that's what we're dealing with.
Comment #95
sunLatest discussion on this issue makes it appear very similar to #996236: drupal_flush_all_caches() does not clear entity info cache, in which we're trying to solve the info/cache/registry/rebuild interdependency nightmare. There's at least one working patch already, which only has one remaining issue with the installer. I'd strongly suggest to solve that challenge in aforementioned issue.
And, given that #1049284: Running update.php to flush caches no longer works unless there are updates pending already deals with the invocation from update.php, I'm actually no longer sure what exactly this issue is about. The issue summary doesn't clarify either - can we clarify and update that?
Comment #95.0
sunUpdated issue summary. Fixed broken link and updated API changes to none.
Comment #96
catchI've updated the summary.
Comment #97
chx CreditAttribution: chx commentedComment #99
xjmLooks like #98 was against D7. Here's a D8 reroll. I checked the
DRUPAL_ROOT
but I think they are correct as-is since it is defined inupdate.php
bygetcwd()
(andupdate.php
itself is insidecore/
). If I'm wrong, testbot will tell us. :)Comment #101
xjmOkay I was wrong. Adding
core/
; will post reroll shortly.Comment #103
xjmComment #104
David_Rothstein CreditAttribution: David_Rothstein commentedShould this function be in includes/update.inc rather than update.php? That way it would be available to Drush also.
Comment #106
Anonymous (not verified) CreditAttribution: Anonymous commentedmkay. so it took way too long to figure out that those notices happen because it's not safe to rebuild the registry if maintenance mode is defined.
updated patch just checks that, tests pass locally, uploading to see what the bot thinks. haven't addressed #104.
Comment #107
Anonymous (not verified) CreditAttribution: Anonymous commentedchx pointed out that we can ditch the reference in
foreach ($modules as &$module) {
in subsequent rerolls.Comment #108
Anonymous (not verified) CreditAttribution: Anonymous commentedupdated patch to incorporate #104, first stab at a real docblock for the function.
Comment #109
aspilicious CreditAttribution: aspilicious commentedso what happens if you put your site in maintenance mode before you update?
The update destroys the registry and now registry_rebuild() won't be called because we are in maintenance mode...
And we can't disable maintenance mode because the site is broken.
Comment #110
xjmMaybe we need to use drupal_maintenance_theme()?
Comment #111
Anonymous (not verified) CreditAttribution: Anonymous commentedeverything works fine for me in manual testing of the 'turn on maintenance mode before update.php case'. the registry that is rebuilt via update.php is not so broken that its impossible to switch the site back on.
working on a test though.
Comment #112
Anonymous (not verified) CreditAttribution: Anonymous commentedok, here's a first cut at a test, lets see what the bot thinks.
Comment #113
Anonymous (not verified) CreditAttribution: Anonymous commentedxjm pointed out we can't rely on fatal error information being output to the screen, and suggested some code post the fatal that won't run.
implemented that with the attached patch.
Comment #114
xjmThe test looks good to me. Attached includes a bit of minor comment cleanup from #113, and I've uploaded the tests separately to expose the fails.
Comment #115
David_Rothstein CreditAttribution: David_Rothstein commentedLooking at update_rebuild_registry() it seems to duplicate a LOT of code from the first part of _registry_update()... I'm not sure if it's worth the effort to make them share some of the code, but at the very least I feel like we need to explain what the differences are. Otherwise it's very hard to tell what this code is doing. It seems like the main differences are that it's a "hard rebuild" (forces all database entries in the registry to be wiped and regenerated), and that it skips stuff like hook_register_files_alter(). So basically, the bare minimum rebuild to get the site up and running. And that explains why it needs to set the 'registry_rebuild' variable at the end, so you can get a "real" rebuild on the next page load.
But the code comments currently don't tell me any of that, so I was left wondering if that was actually the case and which of the differences are critical or not.
For example, there are a bunch of other smaller differences: It uses RecursiveDirectoryIterator rather than file_scan_directory(), it uses drupal_parse_info_file() rather than relying on the data in the {system} table (is that because the data in the {system} table might be out of date?), etc. I'm not sure if those are just unintentional differences or if they actually matter because we're early in the bootstrap on a potentially broken site.
Beyond the missing info, this looks really good though. It's the kind of patch where if it works we shouldn't ask too many questions - I just want to make sure we capture what we do know as code comments :)
A minor issue is that the test is missing a comma after
'group' => 'System'
.Comment #116
Anonymous (not verified) CreditAttribution: Anonymous commentedthanks for the review. attached patch:
- adds more inline comments to explain why we're doing things the way we are
- takes out the .info parsing
- adds the comma to the test :-)
Comment #117
David_Rothstein CreditAttribution: David_Rothstein commentedNice, that looks a lot better to me.
My only remaining comment is that it would be a good idea to add a
@see _registry_update()
to the PHPDoc at the top of the function, as well as one additional sentence there - maybe something like:"Since this function does not result in a fully-built registry (only the minimum needed for Drupal to bootstrap), it also sets a variable which will trigger a complete rebuild during the next full bootstrap after it runs."
That way anyone reading the PHPDoc gets the essential information about this function without having to read through the more detailed comments in the code.
Comment #118
Anonymous (not verified) CreditAttribution: Anonymous commentedthanks again, i like that phpdoc suggestion.
attached patch incorporates #117.
Comment #119
David_Rothstein CreditAttribution: David_Rothstein commentedI was going to RTBC this patch, but then played around with it for a while and came up with a number of questions:
So maybe something similar is required here.
variable_set('registry_rebuild', TRUE)
line should go inside the database transaction, rather than after it? We probably want to ensure that no one acts on the rebuild request before the transaction is committed.wouldn't that also force each file to be rescanned, without having to destroy the tables beforehand?
Additionally, perhaps the call to
cache('bootstrap')->set('lookup_cache', array())
should happen at the end of the rebuild process initiated by update_rebuild_registry(), rather than the beginning. On a healthy site, that allows other requests to keep using the cache even while the major surgery is going on. That would seem to be more in line with how a normal rebuild works also, where the cache isn't rewritten until the end of the page request.FYI, @aspilicious's concern in #109 is a bit related to my last point above, and I was worried about it too. But then I realized that when your site is in maintenance mode, the MAINTENANCE_MODE variable is not actually defined. (Go figure.) So that part is actually OK; even sites in maintenance mode will still get the full registry rebuild once someone tries to hit the main site. The only concern is over update.php itself, as I described above.
Anyway, sorry for all the questions, but given this issue's history we probably need to be pretty careful with this patch.
Comment #120
Anonymous (not verified) CreditAttribution: Anonymous commentedthanks for the careful review, as usual.
i think some of what you point out raises again the question of whether we should have an explicit 'rebuild' idea, rather than just 'if you hit update.php, we rebuild'.
1. yep, definitely needs fixing
2. yes.
3. yes, i think that's a good idea.
4. i think that will be alright, but we need to make sure that what is rebuilt isn't still hosed, so there's an attraction to blowing it all away. as for the WSODs, should be fine on systems that support transactions - no other mysql threads will see the truncated tables until the transaction is committed.
5. hmm, i'll dig into this idea a bit.
i agree its worth 'overdoing' this patch, because while we can possibly kill the registry in D8, we're stuck with it in D7 forever.
Comment #121
David_Rothstein CreditAttribution: David_Rothstein commentedHave to say the same thought crossed my mind also. But from a user experience standpoint, it's so much better if this just works on its own. I would say that if all the issues I raised can be fixed (including #5) we are probably OK leaving it as an automatic step in update.php.
Right, I forgot to mention that the concern in #4 is only for databases that don't support transactions, which does lessen it a bit.
Comment #122
sunRight on spot: #1404198: Separate database cache clearing from static cache clearing and data structure rebuilding
Comment #123
tim.plunkettIn light of #1541674: Remove the registry is this still relevant in D8?
Comment #124
BerdirNo, it won't be relevant anymore I think. Not sure if we want to wait with moving back to 7.x until the remove registry patch is actually commited.
Comment #125
tim.plunkettIf anyone thinks its best to postpone it, feel free, but I think this is fine.
Comment #126
catchI'd be so happy to move this back to Drupal 7, but system_rebuild_module_data() is still going to suffer from the same problem even when the registry is removed. That's less critical than the registry but it could still leave sites in an inconsistent state.
Comment #127
catchThe registry is gone now, so we need to figure out what to do here.
system_rebuild_module_data() still needs all modules loaded because it fires hook_system_info_alter(), but I'm not aware of any fatal errors caused by this in either 7.x or 8.x so that's really more of a major bug. However the fix is going to be similar to one of the patches already posted here, so we should probably keep things together in one issue, and the 7.x patch will just need to ensure the registry is taken care of as well.
Comment #128
sunsystem_rebuild_module_data() is called in a controlled fashion though. It is only invoked from callers that operate in a DRUPAL_BOOTSTRAP_FULL environment, AFAICS. I don't see what would need to be fixed there.
That said, that's (vastly) less of a case for system_rebuild_theme_data(), which apparently depends on loaded modules + hook_system_info_alter(), too, but I'm already trying hard to fix that nightmare over in #1067408: Themes do not have an installation status
I'd recommend to move this issue to 7.x.
Comment #129
Damien Tournoud CreditAttribution: Damien Tournoud commentedMajor based on #127.
I wonder if we should just make hook_system_info_alter() a bootstrap hook.
Comment #130
catchThis is major for 8.x now, but it's still critical for 7.x unfortunately.
Whether we can completely fix it or not for 7.x it'll need to be tracked as such (although I still think my earlier patches on this issue were fine for a 7.x fix and just need proper review).
I considered splitting this into 8.x and 7.x issues but the alter hook is still fired in the same place under the same conditions so that'd just mean less context and more issues at the moment.
With 8.x, we no longer write the info to the {system} table. So while some alters might affect the stuff that gets saved to config, we could at least just throw away the system info cache if we're not at full bootstrap.
Untested patch for that.
Comment #131
YesCT CreditAttribution: YesCT commented#130: system_info.patch queued for re-testing.
Comment #133
star-szrRerolled for #1831702: CacheArray Implements / Overrides documentation fix.
Comment #134
star-szrOops, patch.
Comment #135
kerasai CreditAttribution: kerasai commented#134: 534594-133.patch queued for re-testing.
Comment #135.0
kerasai CreditAttribution: kerasai commentedUpdated issue summary.
Comment #135.1
kattekrab CreditAttribution: kattekrab commentedadded link to patch to the issue summary.
Comment #136
kattekrab CreditAttribution: kattekrab commentedAs discussed above, this is no longer relevant to Drupal 8, but is still a problem for D7. Updated the issue summary, and setting back to D7.
Comment #137
catchNo this is still an 8.x bug per #130.
Comment #138
kattekrab CreditAttribution: kattekrab commentedOops. Sorry!
Comment #138.0
kattekrab CreditAttribution: kattekrab commentedadded "Update 12 Aug 2013: The registry has been removed from Drupal 8 so this issue is no longer valid. Setting back to D7."
Comment #138.1
kattekrab CreditAttribution: kattekrab commenteda weak tidy up
Comment #139
kattekrab CreditAttribution: kattekrab commented#134: 534594-133.patch queued for re-testing.
Comment #141
star-szrTagging for reroll.
Comment #142
star-szrOh, hang on. The patch does still apply :)
Comment #143
catchThis likely shouldn't do anything in resolveCacheMiss(), but instead avoid writing to cache if !$this->persistable in destruct().
Comment #144
catchHmm actually patch ought to work, sending for re-test.
Comment #145
catch#134: 534594-133.patch queued for re-testing.
Comment #146
catch#134 looks good to me, previous test failure was a bot with no space. Marking RTBC.
Comment #147
alexpottLet's see if we can write a test for this using an event that fires pre bootstrap finishing.
Comment #148
catchSo the test would be have an event listener that tries to get system info
- ensure the cache entry is empty
- request a page.
- make sure it's still empty
To go further, could also check that the cache entry is valid when the event listener doesn't run.
Comment #149
chx CreditAttribution: chx commentedComment #150
Anonymous (not verified) CreditAttribution: Anonymous commentedi think we should put the check on bootstrap phase in resolveCacheMiss().
we don't care about the bootstrap phase on __construct(), we care about it on a cache miss, which may be much later.
optionally, we could keep track of whether the system info we primed is untrusted, and if we get another cache miss after a full bootstrap, clear out the static cache in system_rebuild_module_data() and get it again. not sure how important this bit is though, so i'd be ok with just fixing when we first check for full bootstrap.
Comment #151
Anonymous (not verified) CreditAttribution: Anonymous commentedhere's a patch for the first bit of #150.
Comment #152
alexpottNo need for this now
Comment #153
Anonymous (not verified) CreditAttribution: Anonymous commentedah, good point.
Comment #154
catchThat's nicer.
Comment #155
catchWhoops, still no tests...
Comment #155.0
catch-
Comment #156
star-szrCNW for tests.
Comment #157
catchAll bootstrap hooks have gone. And there are either few or none pre-module events (see https://api.drupal.org/api/drupal/core!includes!bootstrap.inc/function/d...)
So... I think this is a 7.x issue only now, moving there.
Comment #158
catchComment #159
mgiffordThis looks like it will work...
Comment #160
mgiffordNope.
Comment #162
neclimdulDidn't really review logic but functinoality: There is a } out of place in your class. Also, the $data in resolveCacheMiss doesn't resolve to anything.
Comment #163
mgiffordI was looking for the out of place } but still haven't found it. Where is it.
Also not sure where that $data should come from. Mostly I was trying to just backport what others had done.
Comment #164
Fabianx CreditAttribution: Fabianx commentedThis should be:
While it is great to cache this, I think this function should take a parameter so that the drupal_bootstrap_full can actually set that the schema cache now can be persisted.
Also shouldn't this fully go to DrupalCacheArray directly so that all cache arrays only persist if they are used within DRUPAL_BOOTSTRAP_FULL?
Comment #165
mgiffordI've re-rolled the patch based on your first comment.
The second though seems like your suggesting to go further than we did in D8, right?
In which case that should be a new D8 issue that we could bring back.
Comment #167
Fabianx CreditAttribution: Fabianx commentedThe first line will also need to be removed.
Comment #168
mgiffordWhat first line?
protected $persistable;
or$this->persist($offset);
@Fabianx more clarification please.
Comment #169
Fabianx CreditAttribution: Fabianx commented$this->persist($offset); needs to be removed else you do set it then set it again in the if, but you want to only do it in the if case not in the other case.
Comment #170
mgiffordOk, thanks for the clarification.
Comment #171
mgiffordComment #173
mgiffordThis might not fail so badly.
Comment #175
kattekrab CreditAttribution: kattekrab commented@mgifford that patch didn't pass Mike - maybe needs a reroll by now too.
Comment #178
mgiffordThe code applies too, but now getting this error:
( ! ) Fatal error: Call to undefined method SchemaCache::persistable() in /DRUPAL7/includes/bootstrap.inc on line 2993
It definitely needs to be rerolled..
Comment #179
Fabianx CreditAttribution: Fabianx commentedI am splitting of the latest patch into a new sub-issue:
#2450533: SchemaCache is prone to persistent cache corruption / drupal_get_complete_schema() is not robust against recursion
Because this one is for more services in Drupal 7, than just the schema cache ...
Comment #180
Fabianx CreditAttribution: Fabianx commentedMaking this one a meta.
Comment #185
vijaycs85Comment #186
grahamvalue CreditAttribution: grahamvalue commentedGot here from #3028130: Class [warning] RulesPluginFeaturesIntegrationInterface does not exist and could not be loaded faces.inc:233.
Updating to rules-7.x-2.12 just caused several sites to crash.
It's understandable that there are technical reasons why rebuilding the registry cannot be done as part of the update process.
But isn't there some way that module maintainers can warn site maintainers that updating a certain module will require a registry rebuild, failing which their sites will crash?
Comment #188
stephencamilo CreditAttribution: stephencamilo as a volunteer commentedComment #189
drumm(disregard, bumping to fix issue indexing)