No Code Attached Yet
avatar richard67
richard67
24 Jan 2022

Steps to reproduce the issue

Update a current 3.10-dev installation which has Zend Opcache enabled and working to the latest 4.1 nightly by using the custom update URL https://update.joomla.org/core/nightlies/next_minor_list.xml or the previously downloaded update package https://developer.joomla.org/nightlies/Joomla_4.1.0-dev-Development-Update_Package.zip .

Expected result

Works without any glitch.

Actual result

When the files have been updated but (I think) before the database updates, a blank page is shown with an error message in the title (full error message see tool tip):

j4 1-test-pr-36585_after-update-from-3 10-without-patch_1

Tool tip a bit bigger:

j4 1-test-pr-36585_after-update-from-3 10-without-patch_2

When reloading the page, the update resumes and finishes as usual:

j4 1-test-pr-36585_after-update-from-3 10-ok

This does not happen when updating from 3.10 to 4.0 or from 4.0 to 4.1, as far as I know. Not sure now. I never observed it before with 4.0, but that might just have been luck.

System information (as much as possible)

Current 3.10-dev branch, clean installation, PHP 7.4 with opcache enabled, MySQL 8.0.27, Apache on Linux server, updating to latest Joomla 4.1 nightly.

avatar richard67 richard67 - open - 24 Jan 2022
avatar joomla-cms-bot joomla-cms-bot - change - 24 Jan 2022
Labels Added: No Code Attached Yet
avatar joomla-cms-bot joomla-cms-bot - labeled - 24 Jan 2022
avatar richard67 richard67 - change - 24 Jan 2022
The description was changed
avatar richard67 richard67 - edited - 24 Jan 2022
avatar dgrammatiko
dgrammatiko - comment - 24 Jan 2022

Tthe problem probably is related to the alias of the namespavced class, in 3.10 the driver is JDatabaseDriverMysqli

		$db = isset($config['dbo']) ? $config['dbo'] : \JFactory::getDbo();

In 4.1 it's \Joomla\Database\Mysqli\MysqliDriver

$db = $config['dbo'] ?? Factory::getDbo();

My hunch is that the alias is not yet established...

avatar richard67
richard67 - comment - 24 Jan 2022

@dgrammatiko I think your hunch is right, and it could be a similar if not the same reason why we have to mock some methods from the filesystem class like File or Folder in the "administrator/components/com_joomlaupdate/finalisation.php" file.

I remember having debugged that once and found that sometimes it needs these mocks and sometimes not, on the same environment with the same starting conditions, and I have never found any reason for that.

Maybe @nikosdion has investigated that in past and an idea when and why it needs these mocks and if that could be the same here, autoloader not ready or something like that, depending on timings maybe?

avatar richard67 richard67 - change - 24 Jan 2022
The description was changed
avatar richard67 richard67 - edited - 24 Jan 2022
avatar richard67 richard67 - change - 24 Jan 2022
The description was changed
avatar richard67 richard67 - edited - 24 Jan 2022
avatar dgrammatiko
dgrammatiko - comment - 24 Jan 2022

The File and Folder mocked classes in the update.php should be fine as that file is an entry point (an application) that doesn't extend any of the known applications (CLI, Administrator, Site, etc). The finalization though should (?) be called from the AdministratorApplication thus all the JLoader classes should be there (?). Anyway, @nikosdion probably got all the answers here

avatar richard67
richard67 - comment - 24 Jan 2022

The File and Folder mocked classes in the update.php should be fine as that file is an entry point (an application) that doesn't extend any of the known applications (CLI, Administrator, Site, etc).

Hmm, right ... I always forget that but should know it.

avatar richard67
richard67 - comment - 24 Jan 2022

As soon as anybody else beside me can reproduce this so we can be sure it's not an error in my environment, we should make it a release blocker ... but not before.

avatar richard67 richard67 - change - 24 Jan 2022
The description was changed
avatar richard67 richard67 - edited - 24 Jan 2022
avatar dgrammatiko
dgrammatiko - comment - 24 Jan 2022

My tests were inconclusive here, although I manage to get an error (I forgot to enable debug so it might be this or some random glitch)

Screenshot 2022-01-25 at 00 44 21

avatar richard67
richard67 - comment - 25 Jan 2022

When you reload that page, does the update resume and finish?

avatar dgrammatiko
dgrammatiko - comment - 25 Jan 2022

yes, I could successfully update with ctrl+F5
BTW this was on NginX + PHP 8.0.8 + MySQL 5.7.34

avatar richard67 richard67 - change - 25 Jan 2022
The description was changed
avatar richard67 richard67 - edited - 25 Jan 2022
avatar nikosdion
nikosdion - comment - 25 Jan 2022

How is finalisation.php used

The finalization though should (?) be called from the AdministratorApplication thus all the JLoader classes should be there (?).

No. The finalisation.php file is loaded from extract.php right after the extraction is over, outside Joomla's execution. It's at the very end of the file, under the finalizeUpdate case. It is CRITICALLY IMPORTANT to keep it that way. Joomla may move its core files around. If we don't remove the old files (and clean up the OPcache) the next Joomla pageload will load a mix of old and new files and result in a broken site.

AJAX error

My tests were inconclusive here, although I manage to get an error (I forgot to enable debug so it might be this or some random glitch)

That's an issue with your server. You are using Windows, right? The most common mistake causing that is using the Thread Safe PHP binary with PHP FPM. See https://www.dionysopoulos.me/improve-php-performance-on-windows.html under “PHP versions, bits and thread safety”. Using the wrong thread safety works fairly well until you start having request concurrency or a cadence of request to trigger whatever issue is caused by recycling the PHP threads in PHP-FPM.

Back to the original issue

The first time we try to load the DB driver post-update is in JoomlaInstallerScript::update(). However, this is only called through JoomlaUpdate's UpdateModel (Joomla\Component\Joomlaupdate\Administrator\Model\UpdateModel) in the finaliseUpgrade method, called after including the administrator/components/com_admin/script.php file.

At this point we have finished extracting the update ZIP archive and executed the filesystem cleanup in finalisation.php. Therefore the next Joomla pageload, the one which calls Joomla Update's update.finalise task, will work correctly. In @richard67 's case it did not.

Since the first time it failed saying it cannot find the class and the second time it worked it appears to be an OPcache issue and the affected file whose cache is not cleared is libraries/classmap.php.

Indeed, since you are updating from Joomla 3.10, we do NOT reset the OPcache for each file we are writing to disk. We call opcache_reset which is supposed to clear the entire OPcache upon the script exiting. However, I am not entirely convinced that this is instantaneous and I don't read enough C code to check the PHP source. If it does take some time and the time between calling it in the post-extraction finalisation.php and calling the update.finalise task which loads Joomla again is not enough for the OPcache to actually clear you would indeed get the problem you mentioned.

In Joomla 4's extract.php we address that by clearing the OPcache for each and every extracted .php file.

For Joomla 3.10 the only thing we could do is add an arbitrary time delay, maybe something like 2–5 seconds, before we redirect to the update.finalise task. This means changing media/com_joomlaupdate/js/update.js in Joomla 3.10 line 238 so that finalizeUpdate() is not called immediately but after a short delay.

I am now going to make myself a really big, very caffeinated coffee. Diving into the internals of two versions of Joomla Update first thing in the morning was a bit too hardcore even for me ?

avatar richard67
richard67 - comment - 25 Jan 2022

Un doppio doppio doppio espresso, per favore ? I' will check later to be sure, but I think on my testing environment opcache was not enabled.

avatar richard67
richard67 - comment - 25 Jan 2022

Hmm, I've just checked and it seems it's exactly what @nikosdion supposed. I still had opcache on with SHM caching from some past test long ago so I have forgotten about it in the mean time. Will switch off and test again later.

avatar richard67
richard67 - comment - 25 Jan 2022

Confirmed. It does not happen when opcache is disabled. Will update title and description.

avatar richard67 richard67 - change - 25 Jan 2022
Title
[4.1] Update from 3.10 to 4.1 fails with blank page but can be resumed by page reload
[4.1] Update from 3.10 to 4.1 fails with blank page but can be resumed by page reload when opcache is used
avatar richard67 richard67 - edited - 25 Jan 2022
avatar richard67 richard67 - change - 25 Jan 2022
The description was changed
avatar richard67 richard67 - edited - 25 Jan 2022
avatar nikosdion
nikosdion - comment - 25 Jan 2022

If you can consistently reproduce this with OPcache do the change in update.js and give it another go. I have a feeling that would work.

avatar richard67
richard67 - comment - 25 Jan 2022

@dgrammatiko Can you check if you have opcache enabled on your environment?

avatar richard67
richard67 - comment - 25 Jan 2022

If it turns out to be opcache and page reload helps, we should add something to the 4.x FAQ that when updating from 3.10 and that happens, one should just reload the page to get the update finished.

avatar nikosdion
nikosdion - comment - 25 Jan 2022

As a hunch, I'd set opcache.revalidate_freq in php.ini to something quite longer than 2 seconds. Possibly 120 seconds (ideally, set this to 2x the time it takes for the Joomla 3.10 to 4.x update to download and run on your machine). This would prevent OPcache from figuring out by itself that the file has changed.

avatar zero-24
zero-24 - comment - 25 Jan 2022

For Joomla 3.10 the only thing we could do is add an arbitrary time delay, maybe something like 2–5 seconds, before we redirect to the update.finalise task. This means changing media/com_joomlaupdate/js/update.js in Joomla 3.10 line 238 so that finalizeUpdate() is not called immediately but after a short delay.

I'm happy to accept such a workaround when that works but I dont have a server with such configuration. @richard67 can you give it a try and send a PR?

avatar richard67
richard67 - comment - 25 Jan 2022

I'm happy to accept such a workaround when that works but I dont have a server with such configuration. @richard67 can you give it a try and send a PR?

Will do later today, and if @dgrammatiko can reproduce too that it only happens with opcache, we would have one tester and one author (the one or the other way).

avatar dgrammatiko
dgrammatiko - comment - 25 Jan 2022

@richard67 OPCache was/is enabled with these settings (MAMP default)
Screenshot 2022-01-25 at 11 41 40

avatar richard67
richard67 - comment - 25 Jan 2022

@richard67 OPCache was/is enabled with these settings (MAMP default) Screenshot 2022-01-25 at 11 41 40

@dgrammatiko Can you confirm that it works fine when opcache is disabled?

avatar richard67
richard67 - comment - 25 Jan 2022

@dgrammatiko Could you do the PR for 3.10-dev? My knowledge on JS, especially asynchronous execution, is too little.

avatar dgrammatiko
dgrammatiko - comment - 25 Jan 2022

@richard67 #36841 (but I haven't tested it)

avatar richard67
richard67 - comment - 25 Jan 2022

@richard67 #36841 (but I haven't tested it)

I will test later today.

avatar richard67 richard67 - change - 25 Jan 2022
Status New Closed
Closed_Date 0000-00-00 00:00:00 2022-01-25 12:03:03
Closed_By richard67
avatar richard67 richard67 - close - 25 Jan 2022
avatar richard67
richard67 - comment - 25 Jan 2022

Closing as having a pull request. It's for 3.10-dev as the investigations above have shown the problem has to be handled there.

Add a Comment

Login with GitHub to post a comment