Hello!
In previous versions of drush (I tested on 3.3), the following steps would produce a list of useful information about the code base:
1. Download and unpack a copy of the Drupal source code.
2. Add and configure its settings.php file; make sure to include a valid db_url.
3. From the command line, cd to the site root and run "drush core-status".
The output would include, among other things, information about what version of the Drupal source was in that directory.
Unfortunately, newer versions of drush no longer seem to support this; if you do the above using drush 4.2, it will complain that the "access" table in the database does not exist yet.
I believe this is a bug; it seems like core-status should work regardless of whether or not the database has been completely installed, if only to provide basic information about the codebase version, database connection parameters, and so forth.
Thanks!
Adam
| Comment | File | Size | Author |
|---|---|---|---|
| #27 | drupal-max-validate-1069372-27.patch | 4.3 KB | jazzslider |
| #22 | drush-max-validate.patch | 4.17 KB | greg.1.anderson |
| #21 | full-bootstrap-validation-1069372-21.patch | 1.29 KB | jazzslider |
| #14 | full-bootstrap-validation-1069372-13.patch | 1.94 KB | jazzslider |
| #12 | full-bootstrap-validation-1069372-11.patch | 3.85 KB | jazzslider |
Comments
Comment #1
msonnabaum commentedLooks like having DRUSH_BOOTSTRAP_MAX in the command definition was causing the command to not get run.
Attached patch fixes it by changing it to DRUSH_BOOTSTRAP_DRUPAL_SITE, but maybe another maintainer can chime in and explain why we might need DRUSH_BOOTSTRAP_MAX there?
Comment #2
moshe weitzman commentedWe need MAX so that we can provide information thats only available after a full bootstrap such as 'Drupal bootstrap: successful'.
It is plausible that we bring back this old behavior but it was never really a supported feature.
Comment #3
greg.1.anderson commentedDRUSH_BOOTSTRAP_MAX is also better than DRUSH_BOOTSTRAP_DRUPAL_SITE in that the former will work if there is no site at all, whereas the later will fail and not give any output.
If we support this feature, then we would have to insure that bootstrap max stopped cleanly at bootstrap site if there was a settings.php with a db_url but no installed site.
Comment #4
jazzslider commentedHello!
Drush core-status appears to have been designed to function in a variety of different scenarios; for instance:
1. If you run it from a directory that isn't inside a Drupal installation, it'll give you the drush version and the location of php.ini.
2. If you run it from a directory that just has Drupal source code, but no settings.php file (or a settings.php without a db_url), it'll give you the version number for the Drupal source code, in addition to the drush version and php.ini information.
3. If you run it from a directory that has Drupal source code and a settings.php file that points at a valid, but as-yet-uninstalled database, you get ugly error messages.
4. If you run it from a directory that has a working, fully-installed Drupal instance, it'll give you the Drupal version, the database connection parameters, and everything else it listed in scenarios 1 and 2.
From these examples, it looks like the basic idea behind drush core-status is to provide the user with as much Drupal-related status information about the current working directory as it can find. The only scenario under which it fails to do so is scenario 3, which is what I ran into this morning. Personally, I think if you're going to support scenarios 2 and 4, it only makes sense to support 3 as well.
One other way to look at it: the scenario I've described is the point at which a Drupal site install meets the minimum requirements for successfully running install.php. No site is going to stay in that condition for long, but you could say that about scenario 2 as well, and that's supported just fine.
Just my two cents; I really could use this feature, so I figured I'd do my best to argue for it :)
Thanks!
Adam
Comment #5
greg.1.anderson commentedI don't think there is any question that there is some value here. Solution is in #3; patches welcome.
Comment #6
jazzslider commentedHello!
OK, I'm happy to help however I can. Trick is, I'm not sure I completely trust my understanding of how the bootstrap process works. If someone can help me put the pieces together I'd be happy to submit a patch. Here's a brain dump that covers what I think I understand, and ends with a possible solution I'd be happy to implement if it sounds about right:
When drush is invoked, it compiles a list of available commands from all available hook_drush_command() implementations. When it finds the command definition that matches the command with which it was invoked (say, "core-status"), it checks to see if that command definition requires a certain bootstrap level (specified by the 'bootstrap' parameter). If it finds one, it runs drush_bootstrap_to_phase($command['bootstrap']), ensuring that the Drupal instance is bootstrapped high enough for the command to function. Once that's done, it dispatches the command.
In the case of "core-status", the bootstrap level required is currently DRUSH_BOOTSTRAP_MAX. This is a special-case bootstrap level, which drush_bootstrap_to_phase() handles by passing control over to drush_bootstrap_max(). The latter is designed to "bootstrap to the highest level possible, without triggering any errors". For each possible bootstrap phase, it does two things: (1) validate that this bootstrap phase can be reached by running drush_bootstrap_validate(), and (2) actually bootstrap to that phase by running drush_bootstrap().
So …given the conditions necessary to produce this bug (settings.php is present and contains a valid $db_url, but the database is empty), here's what happens. Our error is occurring during drush_bootstrap_max(), specifically during the call to drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL). Both validation and bootstrap succeed completely for phases 1-4 (_ROOT, _SITE, _CONFIGURATION, and _DATABASE) …it's just that last phase that fails. The problem is that it actually passes validation …that is to say, even though there isn't a database, drush_bootstrap_validate() thinks it's still safe to bootstrap to phase _FULL.
So then, it seems like the best fix for this problem would be to add some validation logic for the _FULL phase. It does not appear that there is currently any validation logic for that phase (there is no _drush_bootstrap_drupal_full_validate() function). I'd be happy to write such a validation function, but the question is, what should it contain? In order to fix this particular bug, the only test we'd absolutely HAVE to implement is "does the 'access' table exist in the database?". However, that doesn't really seem like it guarantees a positive answer to the real question, "is the site installed?"
What do you think?
Thanks!
Adam
Comment #7
greg.1.anderson commentedYour analysis is spot-on, and your question in the last paragraph is the crux of the issue; there isn't necessarily a right answer, because a quick check might not always be accurate, and an accurate check might take longer than we would want for a validation check that is rarely needed.
Try calling 'show tables;', and test to see if the result is > 0. Use the sql query wrapper in sql/sql.drush.inc so that postgres works right. Time how long the bootstrap takes with and without this test. Then we'd have to discuss whether the accuracy : overhead trade-off is worth it.
Thanks for investigating.
Comment #8
jazzslider commentedHello!
The attached patch is a decent starting point. Couple of notes:
* I don't fully understand why, but it seems that _drush_sql_query() utilizes drush_op_system() to execute the query, which results in the query output being thrown away. The patch changes this to drush_shell_exec(), allowing the output to be retrieved later by drush_shell_exec_output().
* I have yet to benchmark the performance difference; I figured I'd get the patch out there first and then come back with some timings later as I have opportunity.
Please review; this does seem to meet my use case, although since it touches such a core aspect of drush's functionality I definitely understand if it needs additional review.
Thanks!
Adam
Comment #9
jazzslider commentedHello!
OK, and now for some quick benchmark results. My methodology here is simple: inside drupal_bootstrap_max(), I inserted code that calls microtime() once before the call to drupal_bootstrap_validate() and once after, both only if the $phase_index is DRUSH_BOOTSTRAP_DRUPAL_FULL. The difference is then output directly to the console.
Without my modifications, the results of five consecutive runs were as follows:
* 0.00001499 µs (originally output as 1.4999999999987E-5 µs …correct me if I've converted this wrong)
* 0.00001400 µs
* 0.00001799 µs
* 0.00001499 µs
* 0.00001999 µs
* Average: 0.00001639 µs
After applying my patch, the results of five consecutive runs were as follows:
* 0.014139 µs
* 0.014775 µs
* 0.01417 µs
* 0.013974 µs
* 0.016126 µs
* Average: 0.0146368 µs
The difference is significant if you think of it in terms of percentage increase (almost 900%!), but we're talking a fraction of a microsecond here, so the actual increase is pretty negligible (.00000000001639 seconds total increase).
Personally I think the ability to use drush core-status in this situation is worth the extra fraction of a microsecond it takes to count the tables in the db. However, there's still the question of unintended consequences. Note that my patch does include a change to how drush_sql_query executes its commands; if someone more familiar with the codebase can tell me if that change is a good idea or not, that's really the only remaining question I can see needing answering here.
Thanks!
Adam
Comment #10
greg.1.anderson commentedYour units look wrong; maybe that's 0.0146368 s, not µs? In any event, I think the time is probably okay, although it would be interesting to know what the difference in time is for the whole bootstrap max function. Clearly changing a call that does nothing to a call that does something is going to have a large relative increase in execution time.
Regarding #8, drush_op_system prints its results to stdout, whereas drush_shell_exec does not. If you switch _drush_sql_query from one to the other, you would have to change everyone who calls _drush_sql_query to get and print the output. Something like the pattern below would probably be better:
(fake unworking code):
Then make the existing _drush_sql_query into _drush_sql_query_execute. Instead of that, maybe _drush_sql_query_execute should return drush_shell_exec_output, or FALSE on error?
Comment #11
jazzslider commentedAh, you're right about the unit. I always get that confused when using microtime(); the function name kind of implies that it's returning microseconds …but it's actually just returning seconds with microsecond precision. Sorry about that.
Meanwhile, I'll see what I can do about the sql_query call.
Thanks!
Adam
Comment #12
jazzslider commentedHello!
OK, here's a new patch implementing your suggestions from #10. Please let me know what you think!
Thanks,
Adam
Comment #13
greg.1.anderson commentedn.b. the result code from drush_op_system != the return code from drush_shell_exec. However, from reviewing your code, it looks like the new code is correct, and the old code was wrong, so maybe you just fixed a bug. Could you double-check the return code for me? I'll test this later; code looks good.
Comment #14
jazzslider commentedAh, I didn't see that. This new patch should resolve that; it tests the return value of drush_shell_exec for TRUE (success), instead of 0 (which would be the success value for drush_op_system).
Thanks!
Adam
Comment #15
greg.1.anderson commentedThis works for me, and I think it's RTBC. Since this affects the bootstrap, though, I'd like at least one other maintainer to concur that this change is okay.
Comment #16
msonnabaum commentedLooks good to me too.
Committed to 5.x and 4.x.
Comment #17
moshe weitzman commentedThis looks like a proper fix for the feature request. But I am not so sure we are doing the right thing here. D7 at least can be tuned that it does very few or even none DB queries for a full bootstrap. Consider its swappable cache, session, field storage, etc. So this patch adds a mandatory query for FULL. Not sure how fast this query is for all DB sizes and platforms.
This patch can stay in for now, while we think about it.
Comment #18
greg.1.anderson commentedWhat if we added a new function to each bootstrap phase, max_validate_xxx()? This function would only be called during bootstrap_max, not during a normal bootstrap. This way, we could have a slightly slower but more accurate bootstrap for
drush statusand other commands that wanted to do an as-far-as-possible bootstrap, but stay light for commands that must get all the way to a certain bootstrap phase or fail.Comment #19
moshe weitzman commentedGood idea. That makes me wonder if all our current validation is in the category of max_validate_xxx() and thus only needs to run when we are in a MAX bootstrap.
Comment #20
greg.1.anderson commentedOh, I haven't looked, but if I had to guess I would say that some would be max_ and some wouldn't. In theory, anything in validate that is a simple test (not an initialization) is unnecessary, but some of those tests probably prevent hard-to-diagnose error messages, and therefore would still be valuable.
Comment #21
jazzslider commentedHello!
Something else just occurred to me: the actual installation process has its own means of determining the installation status. Apparently, it uses a value in the variable table called "install_task" …if it's "done", it doesn't continue with the installation.
Two things, then:
1. Checking for "install_task" = "done" would probably be just as quick as, if not quicker than, the test I implemented in #14. It also wouldn't require use of the drush_sql_query wrapper, since the syntax of the necessary query would be standard SQL.
2. Personally, I think it would also be very useful to output the value of "install_task" in the table produced by drush core-status. Otherwise, core-status's output is identical for both installed and non-installed sites.
I've attached a new patch that implements #1. #2 seems a bit more complicated; doesn't make much sense just to run a query directly in _core_site_status_table(), but I'm not entirely sure I understand the context system used to get all the values currently listed there. Presumably we could add another context value, say, DRUSH_DRUPAL_SITE_INSTALL_TASK, or some such? I'm just not sure how or where to do that, or if it's actually a good idea.
Thanks!
Adam
Comment #22
greg.1.anderson commented@jazzslider: As long as you're working on optimizing this patch, could you try out the attached further optimization? :)
Side note: I tried to replace the direct SQL call with a call to variable_get, but that didn't seem to work. I did not investigate why; too early in the bootstrap, I guess.
Comment #23
jazzslider commentedHello!
I tried out your patch from #22, and it seems to work perfectly for me.
Thanks!
Adam
Comment #24
greg.1.anderson commentedComment #25
jazzslider commentedHello!
Whoops, I think I spoke too soon about that install_task thing …it would seem that Drupal 5 doesn't track installation progress that way. Would it be worth re-implementing the original test for when core-status runs against a D5 site?
I do think that when install_task is available, that's a better, more accurate test of the state of the site …but if it's not available in all versions, it may be necessary to have a fallback method (like the 'show tables;' approach from #14). I'd be happy to write a new patch at some point today.
Thanks!
Adam
Comment #26
moshe weitzman commentedWe are going to drop support for Drupal5 in Drush5. I think this patch can just return TRUE for Drupal5 sites. Also, we should drupal_bootstrap($phase) such that variable_get() works. $phase will vary by Drupal version ... I need to more closely review this still.
Comment #27
jazzslider commentedHello!
The attached patch is identical to #22 except that it now returns TRUE for Drupal 5 sites, as moshe suggested in #26.
@moshe, I've done some brainstorming on your other question: what bootstrap phase would we need to get to in order for variable_get() to work?
The problem is, by the time we run _full_validate(), that question becomes moot. We know we're already bootstrapped to DRUPAL_DATABASE because otherwise we wouldn't be trying to validate the next phase higher. We also know we can't attempt to bootstrap to DRUPAL_FULL yet, because the point of _full_validate() is to determine if that's even possible. Based on this logic, it kind of seems like we're stuck at DRUPAL_DATABASE …and if DRUPAL_DATABASE isn't enough to run variable_get(), then we're going to have to rely on a direct query; is there another option?
The only problem I can see with using a direct query is if we're operating on a site that somehow doesn't store its variables in the database …i.e., they've got some module installed that overrides the default backend for performance reasons (does memcached do this?). If that's the case, I'm not sure what options there are …but if variable_get() doesn't work, we're kind of stuck, aren't we?
Just some thoughts …again, my familiarity with this code base only goes back to the beginning of this ticket, so if I'm missing something, just let me know.
Thanks!
Adam
Comment #28
greg.1.anderson commentedWe could always just go back to the test to insure that there are some tables in the database, and take it on faith that Drupal is initialized correctly if the db is not empty. This, while not perfect, would still be something of an improvement.
I don't have any better answers to your other questions yet; maybe moshe will have some thoughts.
Comment #29
moshe weitzman commentedI meant $phase in the sense of Drupal, not Drush. This is pretty confusing stuff if you are not a bootstrap guru for both drupal and drush. And if you are, you are probably a drush maintainer :). Anyway, some pseudo code:
Comment #30
greg.1.anderson commentedYes, I'm with you now. The think I was concerned about was that we could not do #29, because we are trying to do a variable_get to determine if it is okay to bootstrap Drupal. If it is not okay to bootstrap Drupal, then the calls in #29 will probably fail.
However, it is okay for the bootstrap to fail in the _validate phase. I sort of think that if we just went ahead and did #29 during $max_validate, then we could just return TRUE if it worked, and FALSE if it did not; the call to variable_get being by that time superfluous.
Comment #31
moshe weitzman commentedI like #30 proposal. But still, I'm still on the fence about whether this complexity addition is worth it for the feature it provides here.
Comment #32
greg.1.anderson commentedYes; since the full_validate function would bootstrap Drupal conditionally, based on the value of $max_validate, then the regular bootstrap_full function would have to be aware of how far Drupal had already been bootstrapped. I'm not sure it's worth it.
Comment #33
catchMoshe pointed me here, I haven't looked at the latest patch, but the one that was committed is going to cause issues, and I don't see the latest patch removing the problematic part of it.
This is from my localhost but will be just as applicable to a real server:
SHOW OPEN TABLES shows you what's currently in the table cache, if it's in use, or locked.
In that table, there are 219 rows, the rest were from the mysql table itself iirc.
Then I switched to my Drupal 7 sandbox db.
Ran show tables.
Then, I ran SHOW OPEN TABLES again:
So now all my D7 tables that hadn't been used since MySQL last started, were added to the table cache.
Reasons this is bad:
- Many sites have database tables that never normally get used - disabled modules, core features like actions or IP blocking that aren't in use, all the cache_* tables if using memcache or similar.
- Many Drupal sites have > 150 database tables.
- On multisite or shared hosting you'll have many different sites in the same db.
- The default value for the table cache is often around 1,000 and it's not often raised over 3,000.
- That means running SHOW TABLES every drush command is going to pollute the table cache, and cause items to be evicted from there that otherwise wouldn't be.
Something like SELECT 1 FROM system is a bit less robust, but would work on any Drupal version since at least 4.7 or earlier, and not mess up the table cache. Ought to be possible to wrap that in a try/catch? Or wrap the actual commands that need a full bootstrap in a try catch? Or if not, maybe query information_schema instead? But IMO this should be rolled back for now.
Comment #34
msonnabaum commentedThe current commit also has the annoying side effect of printing the output of 'SHOW TABLES' when the --debug flag is used.
I've rolled this back in 4.x until we have a better solution since I don't want it to be a release blocker for 4.3. I'll leave it to Moshe & Greg to decide what to do with master in the meantime.
Comment #35
moshe weitzman commentedOn my request, mark rolled back the prior commit on master branch as well. I'm sympathetic to the use case here, but we haven't found an elegant enough approach IMO.
Special apologies to jazzslider who has worked hard here and learned a lot about drush in the meanwhile. I look forward to future patches and reviews from you. You will have better luck next time, I'm sure.
Comment #36
jazzslider commentedHello!
@catch: the patch I submitted in #27 wouldn't have the problem you described, since it no longer relies on SHOW TABLES; instead, it queries the variables table for a particular value that's always present on installed sites from Drupal 6 onward. As far as the table cache is concerned, it would have the same impact as the alternative query you suggested. It would also avoid the problem @msonnabaum mentioned in #34, as it's no longer using the drush sql query wrapper that outputs query results to stdout. I believe it also circumvents the potential performance problems @moshe brought up in #17, due to the max_validate modifications introduced by @greg in #22.
I agree that the committed patch wasn't the right approach …but #27 takes quite a different tack, and IMO should be considered on its own merits before we close this down completely.
Thanks!
Adam
Comment #37
greg.1.anderson commentedDoes #27 work in --simulate mode? -s killed the bootstrap with the previous patch.