Bug 576506 - [win32] 2021-09 cannot be upgraded to 2021-12
Summary: [win32] 2021-09 cannot be upgraded to 2021-12
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: p2 (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: P2 Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: regression
: 577701 577762 (view as bug list)
Depends on:
Blocks:
 
Reported: 2021-10-07 17:29 EDT by Jonah Graham CLA
Modified: 2022-01-27 11:20 EST (History)
10 users (show)

See Also:


Attachments
log file (15.58 KB, application/octet-stream)
2021-10-07 17:29 EDT, Jonah Graham CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jonah Graham CLA 2021-10-07 17:29:46 EDT
Created attachment 287277 [details]
log file

As part of the EPP release process I verify that the previous release can upgrade to the latest milestone/rc being published.

At the moment, on Windows at least, 2021-09 will not upgrade to 2021-12 M1 because of a problem updated eclipse.exe:

!MESSAGE Backup of file E:\tmp\eclipse-cpp-2021-09-R-win32-x86_64\eclipse\eclipse.exe failed.
!STACK 0
java.io.IOException: Can not remove : E:\tmp\eclipse-cpp-2021-09-R-win32-x86_64\eclipse\eclipse.exe

See attached log for more details, I did the upgrade twice in that instance.

I went back to verify I could upgrade 2021-06 to 2021-09 and that worked fine. Once it was upgraded to 2021-09 I tried to upgrade the same install to 2021-12 M1 and that failed with the same messages.
Comment 1 Jonah Graham CLA 2021-10-07 22:04:26 EDT
AFAICT the issue appears to be the contents of the released 2021-09 since 2021-06 can upgrade directly to 2021-12.
Comment 2 Alexander Kurtakov CLA 2021-10-08 01:18:34 EDT
Sravan, any idea what might be going on here?
Comment 3 Alexander Kurtakov CLA 2021-10-08 01:19:21 EDT
Jonah, just to clarify so update works on linux/mac but not on windows?
Comment 4 Ed Merks CLA 2021-10-08 01:43:03 EDT
I'm pretty sure this is related Bug 537757 where I pointed out that I didn't think what was changed will work on Windows:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=537757#c17

I definitely had to make changes yet again because the installer could not self-update on Windows after those changes...
Comment 5 Niraj Modi CLA 2021-10-08 03:29:13 EDT
(In reply to Jonah Graham from comment #1)
> AFAICT the issue appears to be the contents of the released 2021-09 since
> 2021-06 can upgrade directly to 2021-12.

Just to confirm, I could update Eclipse IBuild from 2021-09 to 2021-12 on Win10.
Tested below upgrade path for Eclipse IBuild:
I20210906-0500 to I20210920-1800
Comment 6 Ed Merks CLA 2021-10-08 03:47:40 EDT
I have a feeling it depends on whether the temp storage and the installation are on the same drive.  In Jonah's case he has the installation on E: and the temporary storage in C:\Users\DITTO-~1\AppData\Local\Temp so I wonder if that case has been tested?
Comment 7 Ed Merks CLA 2021-10-08 04:15:11 EDT
On my new Windows 10 machine, I tried updating the 4.21 SDK to 4.22 from my D: drive and while it didn't fail, it had this in the log:

!ENTRY org.eclipse.equinox.p2.touchpoint.natives 4 0 2021-10-08 10:03:18.136
!MESSAGE org.eclipse.equinox.internal.p2.touchpoint.natives.actions.UnzipAction error unzipping zipfile: D:\eclipse-test\eclipse\p2\org.eclipse.equinox.p2.core\cache\binary\org.eclipse.sdk.ide.executable.win32.win32.x86_64_4.22.0.I20211007-1800destination: D:\eclipse-test\eclipse

It did not update the eclipse.exe and the eclipsec.exe disappeared.
Comment 8 Ed Merks CLA 2021-10-08 04:42:15 EDT
I can confirm the behavior is different if the installation and temp dir are on the same drive.  In that case the error log has this:

!ENTRY org.eclipse.equinox.p2.touchpoint.natives 2 0 2021-10-08 10:22:51.634
!MESSAGE Could not remove temporary backup directory (it is safe to manually delete it and its contents): C:\Users\merks\AppData\Local\Temp\SDKProfile_9635f300-10b2-4cc0-9596-204665b7954b

Both the eclipse.exe and the eclipsec.exe have been properly updated, so it's just a bit of dangling garbage in the temp folder that's a tiny problem.

If I recall correctly, on Windows you cannot move a file from one drive (device) to another, but rather only elsewhere on the same device.  Also, you cannot delete the *.exe of a running application, though I think you can move the *.exe or maybe even rename it.  But the entire implementation has been reworked to use nio, so I'd need to understand all the details of the new implementation.  I did suggest at the time of those changes that this was a concern...
Comment 9 Niraj Modi CLA 2021-10-08 04:44:51 EDT
(In reply to Ed Merks from comment #8)
> I can confirm the behavior is different if the installation and temp dir are
> on the same drive.  In that case the error log has this:
> 
> !ENTRY org.eclipse.equinox.p2.touchpoint.natives 2 0 2021-10-08 10:22:51.634
> !MESSAGE Could not remove temporary backup directory (it is safe to manually
> delete it and its contents):
> C:\Users\merks\AppData\Local\Temp\SDKProfile_9635f300-10b2-4cc0-9596-
> 204665b7954b
> 
> Both the eclipse.exe and the eclipsec.exe have been properly updated, so
> it's just a bit of dangling garbage in the temp folder that's a tiny problem.

Yes, for me it's on the same C drive, notice similar entry in my .log file:
!ENTRY org.eclipse.equinox.p2.touchpoint.natives 2 0 2021-10-08 12:44:58.511
!MESSAGE Could not remove temporary backup directory (it is safe to manually delete it and its contents): C:\Users\NIRAJM~1\AppData\Local\Temp\SDKProfile_54cabcb2-6780-4f06-a475-16e8029d09ed
Comment 10 Ed Merks CLA 2021-10-14 02:10:19 EDT
I just ran into this on a real installation that I could not update.  As a workaround, I added this the eclipse.ini to point at a folder that I created on the same drive as my installation:

-Djava.io.tmpdir=D:\temp


There were a bunch of entries like this:

!ENTRY org.eclipse.equinox.p2.touchpoint.natives 4 0 2021-10-14 07:10:46.218
!MESSAGE Restore failed: java.io.IOException: Directory C:\Users\merks\AppData\Local\Temp\D__Users_merks_oomph-1.23_eclipse_ca43e668-a4db-4ea2-8564-be60e1388d4e\D\Users\merks\oomph-1.23 not empty: ... Manual restore of backup needed for: C:\Users\merks\AppData\Local\Temp\D__Users_merks_oomph-1.23_eclipse_ca43e668-a4db-4ea2-8564-be60e1388d4e\D\Users\merks\oomph-1.23

Then this:

!ENTRY org.eclipse.equinox.p2.engine 4 4 2021-10-14 07:10:46.220
!MESSAGE An error occurred while committing the engine session for profile: D__Users_merks_oomph-1.23_eclipse.
!SUBENTRY 1 org.eclipse.equinox.p2.touchpoint.natives 4 0 2021-10-14 07:10:46.220
!MESSAGE Restore of backup failed - see log for details. Backup directory name: D__Users_merks_oomph-1.23_eclipse_ca43e668-a4db-4ea2-8564-be60e1388d4e.
!STACK 0
java.io.IOException: Errors while restoring - see earlier logged errors
	at org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.restore(SimpleBackupStore.java:471)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.LazyBackupStore.restore(LazyBackupStore.java:58)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.NativeTouchpoint.rollback(NativeTouchpoint.java:234)
	at org.eclipse.equinox.internal.p2.engine.EngineSession.rollback(EngineSession.java:199)
	at org.eclipse.equinox.internal.p2.engine.Engine.perform(Engine.java:89)
	at org.eclipse.equinox.internal.p2.engine.Engine.perform(Engine.java:48)
	at org.eclipse.equinox.internal.provisional.p2.director.PlanExecutionHelper.executePlan(PlanExecutionHelper.java:46)
	at org.eclipse.oomph.p2.internal.core.ProfileTransactionImpl$3.commit(ProfileTransactionImpl.java:549)
	at org.eclipse.oomph.p2.internal.core.ProfileTransactionImpl.commit(ProfileTransactionImpl.java:345)
	at org.eclipse.oomph.setup.p2.impl.P2TaskImpl.perform(P2TaskImpl.java:904)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.doPerformNeededSetupTasks(SetupTaskPerformer.java:3851)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.access$1(SetupTaskPerformer.java:3794)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer$WorkspaceUtil$1.run(SetupTaskPerformer.java:5178)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2313)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2338)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer$WorkspaceUtil.performNeededSetupTasks(SetupTaskPerformer.java:5172)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer$WorkspaceUtil.access$0(SetupTaskPerformer.java:5170)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.performNeededSetupTasks(SetupTaskPerformer.java:3785)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.performTriggeredSetupTasks(SetupTaskPerformer.java:3760)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.perform(SetupTaskPerformer.java:3638)
	at org.eclipse.oomph.setup.ui.wizards.ProgressPage$9.run(ProgressPage.java:595)
	at org.eclipse.oomph.setup.ui.wizards.ProgressPage$11$1.run(ProgressPage.java:722)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)


And finally

!ENTRY org.eclipse.equinox.p2.engine 2 4 2021-10-14 07:10:46.234
!MESSAGE An error occurred while uninstalling
!SUBENTRY 1 org.eclipse.equinox.p2.engine 4 0 2021-10-14 07:10:46.234
!MESSAGE session context was:(profile=D__Users_merks_oomph-1.23_eclipse, phase=org.eclipse.equinox.internal.p2.engine.phases.Uninstall, operand=[R]org.eclipse.platform.ide.executable.win32.win32.x86_64 4.21.0.I20210906-0500 --> null, action=org.eclipse.equinox.internal.p2.touchpoint.natives.actions.CleanupzipAction).
!SUBENTRY 1 org.eclipse.equinox.p2.touchpoint.natives 4 0 2021-10-14 07:10:46.234
!MESSAGE Backup of file D:\Users\merks\oomph-1.23\eclipse\eclipse.exe failed.
!STACK 0
java.io.IOException: Can not remove : D:\Users\merks\oomph-1.23\eclipse\eclipse.exe
	at org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.moveToBackup(SimpleBackupStore.java:575)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.backup(SimpleBackupStore.java:243)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.LazyBackupStore.backup(LazyBackupStore.java:38)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.actions.CleanupzipAction.cleanupzip(CleanupzipAction.java:90)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.actions.CleanupzipAction.execute(CleanupzipAction.java:34)
	at org.eclipse.equinox.internal.p2.engine.ParameterizedProvisioningAction.execute(ParameterizedProvisioningAction.java:42)
	at org.eclipse.equinox.internal.p2.engine.Phase.mainPerform(Phase.java:186)
	at org.eclipse.equinox.internal.p2.engine.Phase.perform(Phase.java:99)
	at org.eclipse.equinox.internal.p2.engine.PhaseSet.perform(PhaseSet.java:50)
	at org.eclipse.equinox.internal.p2.engine.Engine.perform(Engine.java:80)
	at org.eclipse.equinox.internal.p2.engine.Engine.perform(Engine.java:48)
	at org.eclipse.equinox.internal.provisional.p2.director.PlanExecutionHelper.executePlan(PlanExecutionHelper.java:46)
	at org.eclipse.oomph.p2.internal.core.ProfileTransactionImpl$3.commit(ProfileTransactionImpl.java:549)
	at org.eclipse.oomph.p2.internal.core.ProfileTransactionImpl.commit(ProfileTransactionImpl.java:345)
	at org.eclipse.oomph.setup.p2.impl.P2TaskImpl.perform(P2TaskImpl.java:904)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.doPerformNeededSetupTasks(SetupTaskPerformer.java:3851)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.access$1(SetupTaskPerformer.java:3794)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer$WorkspaceUtil$1.run(SetupTaskPerformer.java:5178)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2313)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2338)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer$WorkspaceUtil.performNeededSetupTasks(SetupTaskPerformer.java:5172)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer$WorkspaceUtil.access$0(SetupTaskPerformer.java:5170)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.performNeededSetupTasks(SetupTaskPerformer.java:3785)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.performTriggeredSetupTasks(SetupTaskPerformer.java:3760)
	at org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.perform(SetupTaskPerformer.java:3638)
	at org.eclipse.oomph.setup.ui.wizards.ProgressPage$9.run(ProgressPage.java:595)
	at org.eclipse.oomph.setup.ui.wizards.ProgressPage$11$1.run(ProgressPage.java:722)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Caused by: java.nio.file.AccessDeniedException: D:\Users\merks\oomph-1.23\eclipse\eclipse.exe
	at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:89)
	at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
	at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
	at java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:274)
	at java.base/sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:105)
	at java.base/java.nio.file.Files.delete(Files.java:1141)
	at org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.moveToBackup(SimpleBackupStore.java:573)
	... 27 more
Comment 11 Ed Merks CLA 2021-10-14 02:30:13 EDT
Here's a program that demonstrates the flawed assumption in org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.move(Path, Path)


package org.example.test;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class TestFiles {
	public static void main(String[] args) throws Exception {
		Path exe = Paths.get("D:/Users/merks/oomph-1.23/eclipse/eclipsec.exe");
		Path exeInTemp = Files.createTempFile("foo", "bar.exe");
		Files.copy(exe, exeInTemp, StandardCopyOption.REPLACE_EXISTING);
		System.err.println("Launching " + exeInTemp);
		new ProcessBuilder(exeInTemp.toString()).start();

		Path targetExe = Paths.get("D:/temp/").resolve(exeInTemp.getFileName());
		System.err.println("Moving " + exeInTemp + " to " + targetExe);
		boolean old = false;
		if (old) {
			if (exeInTemp.toFile().renameTo(targetExe.toFile())) {
				System.err.println("Rename failed");
			} else {
				System.err.println("Rename succeeded");
			}
		} else {
			Files.move(exeInTemp, targetExe);
		}

		if (Files.exists(exeInTemp)) {
			System.err.println("Not removed " + exeInTemp);
		}
	}
}


The point here is that a launched executable's file cannot be moved successfully.  You can comment out the start() call to see how it behaves differently. 

If I recall correctly, formerly renameTo was called and the return code was checked.  Set old to true to simulate that above.  But now Files.move is called and that does not throw an exception because it successfully copies the file.   But it does not remove the orignal.  Therefore this logic in org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.moveToBackup(Path, Path) never kicks in:

		try {
			move(path, buPath);
		} catch (IOException e) {
			// TODO Log exception?
			if (!isEclipseExe(path)) {
				throw e;
			}

			Path inPlaceBuPath = toInPlaceBackupPath(path);
			move(path, inPlaceBuPath);
			buInPlace.add(inPlaceBuPath);
		}


This is absolutely needed to actually make it possible to copy the new executable artifact to the old location.

I'm not sure the best way to fix this.  One could test in SimpleBackupStore.move(Path, Path) that the original path still exists and throw an exception.  But I'm not sure that's ideal for all the other calls to that method.  After all, a copy is created at the target.  So likely it's better if we do it like this:

		move(path, buPath);
		if (isEclipseExe(path) && Files.isRegularFile(path)) {
			Path inPlaceBuPath = toInPlaceBackupPath(path);
			move(path, inPlaceBuPath);
			buInPlace.add(inPlaceBuPath);
		}

I.e., only test that the file was not removed as part of the move for the case of the executable.  And even then, we only need to do this check on Windows...

What do you think?
Comment 12 Andrey Loskutov CLA 2021-10-14 05:09:04 EDT
(In reply to Ed Merks from comment #11)
> Here's a program that demonstrates the flawed assumption in
> org.eclipse.equinox.internal.p2.touchpoint.natives.SimpleBackupStore.
> move(Path, Path)
> [...]
> What do you think?

Ed, please provide gerrit, it is easier to discuss code changes there.

@Todor: this is a regression from bug 537757, patch https://git.eclipse.org/r/c/equinox/rt.equinox.p2/+/182585.

Could you please check the Ed's proposal to fix the regression (see comment 11)?
Comment 13 Eclipse Genie CLA 2021-10-14 06:30:07 EDT
New Gerrit change created: https://git.eclipse.org/r/c/equinox/rt.equinox.p2/+/186477
Comment 15 Ed Merks CLA 2021-10-18 05:58:10 EDT
Given the lack of feedback I'll assume this implementation is best.  it's hard to test in real live because of course we need an installation with this installed, and we then need a situation where the eclipse.exe needs updating...
Comment 16 Ed Merks CLA 2021-12-09 11:18:31 EST
*** Bug 577701 has been marked as a duplicate of this bug. ***
Comment 17 Rolf Theunissen CLA 2021-12-13 03:26:14 EST
*** Bug 577762 has been marked as a duplicate of this bug. ***