Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 270195 - [reconciler] Problem removing IUs being depended on from software installed by the UI
Summary: [reconciler] Problem removing IUs being depended on from software installed b...
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: p2 (show other bugs)
Version: 3.5   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.6 RC3   Edit
Assignee: DJ Houghton CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 194665
Blocks: 313795
  Show dependency tree
 
Reported: 2009-03-26 19:57 EDT by John Arthorne CLA
Modified: 2010-05-25 16:49 EDT (History)
5 users (show)

See Also:
john.arthorne: review+
simon_kaegi: review+
irbull: review+
pascal: review+


Attachments
repo (2.23 KB, application/octet-stream)
2009-05-07 11:36 EDT, DJ Houghton CLA
no flags Details
partial patch (12.65 KB, patch)
2010-05-04 11:13 EDT, DJ Houghton CLA
no flags Details | Diff
New patch (14.92 KB, patch)
2010-05-10 19:32 EDT, Pascal Rapicault CLA
no flags Details | Diff
patch (18.98 KB, patch)
2010-05-13 15:33 EDT, DJ Houghton CLA
no flags Details | Diff
patch (19.79 KB, patch)
2010-05-13 18:30 EDT, DJ Houghton CLA
no flags Details | Diff
Another version of the patch (20.83 KB, patch)
2010-05-17 22:40 EDT, Pascal Rapicault CLA
no flags Details | Diff
patch (21.65 KB, patch)
2010-05-18 14:35 EDT, DJ Houghton CLA
no flags Details | Diff
patch (22.32 KB, patch)
2010-05-19 16:17 EDT, DJ Houghton CLA
no flags Details | Diff
patch (23.53 KB, patch)
2010-05-19 17:43 EDT, DJ Houghton CLA
no flags Details | Diff
patch (23.63 KB, patch)
2010-05-20 10:18 EDT, DJ Houghton CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description John Arthorne CLA 2009-03-26 19:57:19 EDT
3.5 M6

Martin had a case where a bundle from dropins remained installed into the profile even after being deleted from disk. This resulted in a broken installation. I think the case is:

1) Install bundle a version 1.0 via dropins
2) Install bundle b requiring 'a' [1.0,2.0) via normal install
3) Shutdown, replace a 1.0 in dropins with a 2.0 (actually changed value of .link file to point to newer version)
4) Restart. 'a' 1.0 is still in the profile (presumably because it's required by bundle 'b', however it no longer exists on disk)
Comment 1 DJ Houghton CLA 2009-03-27 09:04:19 EDT
Sounds similar to bug 269297.
Comment 2 DJ Houghton CLA 2009-03-27 14:30:04 EDT
Actually this sounds like another bug that Pascal and I were talking about a while back. (sorry can't find the link)

Pascal, do you remember? It was the one where we were taking the IUs already installed in the profile into consideration and that was causing us problems.
Comment 3 Pascal Rapicault CLA 2009-03-28 13:16:26 EDT
Don't remember if we have a bug for this precise issue, but DJ's description is right on. 
Comment 4 John Arthorne CLA 2009-03-29 23:33:11 EDT
It's completely natural behaviour for the planner to decide to keep the bundle around because it is needed by another installed IU. It seems like we need some way to force the IU to be removed. Maybe it is still available in a repository at that point, but shouldn't be?
Comment 5 DJ Houghton CLA 2009-05-07 11:36:33 EDT
Created attachment 134799 [details]
repo

Here is a repository which contains bundles which exhibit the problem.

- put "a 1.0" in your dropins
- startup
- install "b 1.0" via the UI
- shutdown
- delete "a 1.0" from dropins
- add "a 2.0" to the dropins
- startup

John and I talked about this a bit and it seems like we need some sort of "force uninstall" mode. In this case it would uninstall the bundle which no longer exists as well as anything else which depends on it.

Something to consider post-3.5.
Comment 6 Simon Kaegi CLA 2009-05-07 14:05:52 EDT
Interesting. To clarify a bit (maybe just for me) this is a force uninstall at the planner level.
Comment 7 John Arthorne CLA 2009-05-08 11:35:29 EDT
Yes, essentially we invoke the planner with "please uninstall X", but the planner comes back with an empty plan because someone else needs X. We need a planner request more like "thou shalt uninstall X".
Comment 8 DJ Houghton CLA 2010-04-12 16:59:29 EDT
See also: bug 306424 comment 6
Comment 9 DJ Houghton CLA 2010-04-14 10:17:21 EDT
With the fix for bug 308934, the behaviour is now as follows where A depends on B:

- put B in dropins and start Eclipse
- install A via UI
- exit Eclipse
- delete B from dropins
- start Eclipse 
- get the following in the log:

!ENTRY org.eclipse.equinox.p2.director 4 0 2010-04-14 10:11:23.396
!MESSAGE Problems resolving provisioning plan.
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2010-04-14 10:11:23.396
!MESSAGE No solution found because the problem is unsatisfiable.

Also A is now installed but not resolved. (according to the OSGi console)
Comment 10 Martin Oberhuber CLA 2010-04-14 12:03:44 EDT
Yuck. I guess the minimum I'd expect to be logged is information about WHAT specific IU's requirements can not be resolved (A in this case). In the ideal case it would also say that B is missing.
Comment 11 Pascal Rapicault CLA 2010-04-14 13:02:06 EDT
The behaviour exposed in comment #9 is not correct. This will result in completely breaking the installation and possibly causing it to not be fixable. We need to discuss this but I don't think we can ship with this. IMO the consequences of this new problem are far worse than the problem being fixed.
Comment 12 DJ Houghton CLA 2010-04-14 16:42:38 EDT
To summarize: 

In the old case if you manually deleted something from the dropins and you have something installed (via the UI) which depended on it then you would get no notification that what you have installed is broken and its UI pieces would still appear, etc. Then when you tried to click on an icon or something which had behaviour depending on a piece which is now missing, then it wouldn't work.

In the new case if you manually delete something from the dropins and you have something installed via the UI which depends on it then we unresolve the pieces whose dependencies are now broken. Agreed that the message should be made clearer to help the user understand what exactly went wrong.

Pascal, please feel free to elaborate as to what you feel the solution should be.

The only thing that I can think of to make the situation better is that when you install something from the UI and it depends on something which is in the dropins, then we move (copy?) the bundles from the dropins to the plugins so we now manage them and then aren't optional anymore. Although I doubt that users would want us to move their bundles around like that.
Comment 13 Pascal Rapicault CLA 2010-04-14 22:23:51 EDT
> In the new case if you manually delete something from the dropins and you have
> something installed via the UI which depends on it then we unresolve the pieces
> whose dependencies are now broken. Agreed that the message should be made
> clearer to help the user understand what exactly went wrong.
    In the example of A req B with B is in the dropin. Does this mean that the root IU A will be uninstalled as well? 
    - If A is uninstalled then I'm cool. 
    - If A is not uninstalled then other problems can ensue. The biggest would be when the user goes and try to install something else in the UI (unrelated to A and B), no solution gets found because no repository containing B can be found.
Comment 14 Thomas Watson CLA 2010-04-15 09:43:46 EDT
(In reply to comment #13)
>     In the example of A req B with B is in the dropin. Does this mean that the
> root IU A will be uninstalled as well? 
>     - If A is uninstalled then I'm cool. 
>     - If A is not uninstalled then other problems can ensue. The biggest would
> be when the user goes and try to install something else in the UI (unrelated to
> A and B), no solution gets found because no repository containing B can be
> found.

Just to make sure I understand you correctly.  This essentially means nothing can ever be provisioned because we will always have a broken resolution state according to p2.  This is rather drastic.
Comment 15 John Arthorne CLA 2010-04-15 10:50:19 EDT
(In reply to comment #13)
>     In the example of A req B with B is in the dropin. Does this mean that the
> root IU A will be uninstalled as well? 
>     - If A is uninstalled then I'm cool. 
>     - If A is not uninstalled then other problems can ensue. The biggest would
> be when the user goes and try to install something else in the UI (unrelated to
> A and B), no solution gets found because no repository containing B can be
> found.

You're cool ;)
Comment 16 Pascal Rapicault CLA 2010-04-15 13:36:23 EDT
>You're cool ;)
   Unfortunately I'm not. I've tested this on I20100414-1200 with some plug-ins (will attach later) and the behaviour I have observed is rather surprising :)
Steps followed:
- put the ToDropin in the dropins folder, start and notice the presence of the plugin
- go to the UI and install the TestMixedInstall IU, notice that the plugin called ToInstallIn is there and notice the presence of the root.
- delete from the dropins the ToDropin plugin restart

Some of the surprising things:
- go to the installed software page and notice that root IU is still visible. This is misleading since in reality all the plug-ins are gone.
- the install is not broken, this is somewhat a good thing because the user can continue installing things
- the install is not broken, this is somewhat a bad thing because the user can install something that depends on "TestMixedInstall" IU, it will look like if it has worked and it will not have worked.
- the IU for ToDropin is *still* in the profile. This is really not expected

So in short, I think the new behaviour is no better than the previous one, if not worse. As for how to improve the situation. The uninstallation of something that is depended on from a root should cause the root IU to be uninstalled. I have not looked at the code but it feels like the removal is bypassing the planner which is the only way you can end up with such a situation.

So an approach would:
- Notice that a file has been deleted from disk
- Emit a request causing the removal of the IU (PCR#removeIU) but also forces it absence in the final result (PCR#addExtraRequirement(Negation of the IU being removed)). 
- If the resolution fails, it is because the item being removed is being depended on from a root. 
- Then find the root (this should be available in the planner result), emit another request that is the same one from the original plus requesting the forced removal of the root.
- Repeat until the plan comes back without error.

This approach has the advantage that it leaves the installation completely consistent from a dependency standpoint but also from a runtime standpoint.
The only problem now is how to let the user know that some things have been uninstalled because of the removal of things in the dropins. Ideally we could introduce a concept of "root error" but this may be a bit too much for this.

In any event since it has been decided to invest in this, I think it needs to be fully fixed or leave the old behavior. I don't see the point in introducing in introducing an alternatively bogus behavior :)
Comment 17 DJ Houghton CLA 2010-04-23 17:58:34 EDT
Pascal and I talked about this today and have come up with a plan.

1). For the "move" case we will not go through the planner. We will recognize that some IUs need to be moved and then manually create the plan to remove/add them and call the engine directly.

2). To handle the case where we have strict IUs which depend on things we want to remove, we will:
- create a plan with the removed IUs
- include all root IUs as optional
- get the plan back
- for each root, does the plan now remove it?
- if so then add a negation to remove it

We need to watch out for the case where the user has messed things up and all the roots want to be removed. We can't do this.

In the end we probably want 2 calls to the engine (one for move and one for the second part) but we might be able to get away with one.
Comment 18 DJ Houghton CLA 2010-05-04 11:13:14 EDT
Created attachment 166962 [details]
partial patch

Pascal, here is a work-in-progress patch. The code which I need a hand with is in #createAddRemovePlan. I don't have the logic quite right when changing some of the roots from strict to optional, etc.
Comment 19 Pascal Rapicault CLA 2010-05-10 19:32:29 EDT
Created attachment 167844 [details]
New patch

Here is a new patch. I've only focused on the addition/removal case. It is now able to reset the inclusion rules, and warn the user when a strict root is being removed as a result of the reconciliation.
One thing I wonder is if instead of resetting the inclusion rules manually like this new patch does, we would not be better off calling the planner a second time with the set of strict roots that are not modified (for example if we detect that GMF needs to be removed, then explicitly remove it and leave the SDK as strict).

I have also released two new test cases ProfileSynchronizerTest and ProfileSynchronizerTest2 that are not enabled.
Comment 20 Pascal Rapicault CLA 2010-05-12 11:44:44 EDT
I would really like to see this go in RC1 otherwise it will be in 3.6.1.
Comment 21 DJ Houghton CLA 2010-05-12 23:06:36 EDT
Sorry Pascal, I didn't get to review this today. Since the last RC1 build is tomorrow morning it looks like it won't make it. If you don't feel comfortable releasing this into RC2 then we should review the current behaviour in HEAD and ensure that is what we want for 3.6. We may need to back out of other changes as I know you didn't like some of the changes to get the move case detected.
Comment 22 Pascal Rapicault CLA 2010-05-12 23:20:23 EDT
I think we are very close to have something good here. At this point I would rather polish this bug rather than diving in the other things that I did not like.
Let's try to get to this tomorrow and release it in RC2 (or a respin of RC1 if we can manage this).
Comment 23 DJ Houghton CLA 2010-05-13 08:00:38 EDT
Based on the change, I would vote for RC2 over RC1 so we can get more testing on it rather than releasing it on the last day of the RC in the final build.
Comment 24 DJ Houghton CLA 2010-05-13 15:33:08 EDT
Created attachment 168455 [details]
patch

Updated patch. I made a few modifications to get the move case working again, tried to get rid of some of the TODOs, etc. 

Still testing so not ready for release.
Comment 25 DJ Houghton CLA 2010-05-13 18:30:32 EDT
Created attachment 168488 [details]
patch

Here is an updated patch and it is starting to feel good. I've separated the move and add/remove actions into separate "perform" methods to better report to the user when we have a problem creating a plan.

I've done some manual testing but would like more automated tests for this. I've also verified that the scenario in comment #5 now works.
Comment 26 Pascal Rapicault CLA 2010-05-17 22:40:25 EDT
Created attachment 168852 [details]
Another version of the patch

Here is yet another copy of the patch. I was not a big fan of bashing the IU properties to strict on the initial plan, and also not planning with the roots with their real inclusion status. Therefore this change actually look at the result from the first plan (where everything is optional), create a new request and replan with what has been learnt from the first plan (i.e. explicitly removing the strict roots that will be dropped). 
The patch includes a change in the profile change request to fix the behaviour clone (one field was not copied).
Now I really like the patch and I think we are good to release this.
Comment 27 Pascal Rapicault CLA 2010-05-17 22:41:38 EDT
One final observation the following if-block should never ever occur. If it does it means that we have a bug in our code which is why I'm throwing the illegal state exception and writing in sysout.

			if (!plan.getStatus().isOK()) {
				System.out.println("original request"); //$NON-NLS-1$
				System.out.println(request);
				System.out.println("final request"); //$NON-NLS-1$
				System.out.println(finalRequest);
				throw new IllegalStateException("The second plan is not resolvable."); //$NON-NLS-1$
			}
Comment 28 DJ Houghton CLA 2010-05-18 14:12:11 EDT
Pascal does the latest patch leave the root IUs in a state where they are all still marked as optional? I think we are missing code that sets the inclusion rule back to strict for roots which aren't removed by the plan.

This might be easier done by cloning early and then adding the negation and property changes later after we get the initial plan results.
Comment 29 DJ Houghton CLA 2010-05-18 14:35:28 EDT
Created attachment 168993 [details]
patch

Updated version of the patch implementing changes described in the previous comment.
Comment 30 John Arthorne CLA 2010-05-18 16:55:50 EDT
For part 1) in comment #17 I like this fix better than what we have in HEAD today. I would agree to doing that part of the fix.

However I'm worried about part 2), in particular marking strict roots as optional. I see that this will handle the case where the strict root requires something that has been deleted, but I'm worried it will cause strict roots to be uninstalled in other scenarios. From my point of view, uninstalling a strict root should *never* happen unless it is completely impossible for it to remain installed (like its dependencies have been deleted.

For example imagine a case like this:

A is installed strict, depends on C [1.0,1.1)
B is installed optional, depends on C [2.0,3.0)

B, c 1.0 and c 2.0 are in dropins. Normally, the planner will pick (A, C 1.0). However if A is marked optional, it might instead pick (B, C 2.0) since that solution is equally valid. Now we have uninstalled a strict root in order to satisfy an optional root. This is one example, but I'm worried there might be other side-effects like this from marking strict roots as optional here.
Comment 31 John Arthorne CLA 2010-05-18 16:58:55 EDT
My current thinking is that we should either do nothing for 3.6.0, or do only part 1) and defer the rest. From DJ's testing it looks like we will be no worse than the 3.5 behavior if we defer the fix for 2). We would then have more time in 3.7 and possibly 3.6.1. to make a safe fix for case 2 (uninstalling strict roots whose dependencies have been deleted).
Comment 32 Pascal Rapicault CLA 2010-05-19 09:04:03 EDT
(In reply to comment #30)
> For part 1) in comment #17 I like this fix better than what we have in HEAD
> today. I would agree to doing that part of the fix.
  +1

> However I'm worried about part 2), in particular marking strict roots as
> optional. I see that this will handle the case where the strict root requires
> something that has been deleted, but I'm worried it will cause strict roots to
> be uninstalled in other scenarios. From my point of view, uninstalling a strict
> root should *never* happen unless it is completely impossible for it to remain
> installed (like its dependencies have been deleted.
>[...]
  This is a good point. Initially we wanted to look into the results of the planner (in case of error) and this is likely the solution to adopt going forward.
Comment 33 Pascal Rapicault CLA 2010-05-19 09:06:18 EDT
Accidentally moved to 3.6.1. Moving back to rc2 for the move part.
Comment 34 Pascal Rapicault CLA 2010-05-19 09:14:16 EDT
I suggest that we also release the clone() method in ProfileChangeRequest
Comment 35 DJ Houghton CLA 2010-05-19 16:17:36 EDT
Created attachment 169212 [details]
patch

New patch. Same as last one but just disables the "remove strict roots" code. (I left it in the class and disabled it so we wouldn't lose it or worry about having to merge changed code and stale patches later)
Comment 36 John Arthorne CLA 2010-05-19 17:16:05 EDT
Some comments from code review with DJ:

 - Modify debug(request) to also print move info
 - Change in synchronizeCacheExtensions not needed
 - Changed method signature in createProvisioningPlan not needed
 - Make sure debug(request,plan) output still makes sense
Comment 37 DJ Houghton CLA 2010-05-19 17:43:52 EDT
Created attachment 169234 [details]
patch

Updated patch including changes from John's feedback. We still need to test more but I am posting this for others to see.

Note to reviewers: if you delete the #performStrictRootRemoval method (which is disabled) then it makes the patch much simpler to review.
Comment 38 Pascal Rapicault CLA 2010-05-19 22:16:56 EDT
The only comment would be to rename the method performMove to performRemoveForMovedIUs since it only take care of the removal part.
Comment 39 John Arthorne CLA 2010-05-20 08:37:22 EDT
I agree with renaming the method as Pascal suggests. One hopefully final comment, in the synchronize method we have:

	IStatus moveResult = performMove(request, context, monitor);
	if (!moveResult.isOK())
		return moveResult;

Usually with a plan result we do something like if (status.matches(IStatus.ERROR | IStatus.CANCEL)) rather than status.isOk(). I don't know if we have cases of the engine returning INFO or WARNING, but we should probably be consistent here and let the reconcile continue on to the next step unless we get ERROR or CANCEL.
Comment 40 DJ Houghton CLA 2010-05-20 10:18:14 EDT
Created attachment 169348 [details]
patch

Updated patch based on recent comments.
Comment 41 DJ Houghton CLA 2010-05-20 15:10:32 EDT
Opened bug 313795 to track the original issue and we'll use this bug to track the #move issue in part one of comment #17.
Comment 42 John Arthorne CLA 2010-05-20 17:13:02 EDT
I think DJ wants to do some more testing, but +1 for RC3.
Comment 43 Martin Oberhuber CLA 2010-05-21 08:13:50 EDT
Let me state here my original use case (which might be a helpful test case for this once it's done):

1.) Download eclipse-SDK-3.6Mx.zip
2.) Add *.link file pointing to emf-2.5 extension location
3.) In the UI, install something that depends on EMF, e.g. GMF or TM-discovery
4.) Replace the *.link file by a new one pointing to emf-2.6 ext.loc.

Since I expect the EMF "update" to be fully compatible, I expect the whole environment to come up properly again. I'd never expect anything that I installed from the UI to be removed. In the worst case (that I really broke some dependency, which I personally am pretty sure I never did since the "update" should be compatible) I would expect my UI-installed extension to be flagged with an error marker, such that I can "repair" my install by reverting to emf-2.5.

I think my original use case as per comment 0 was not using EMF but the CDT, and a DSDP-TM addon that depends on the CDT. We have since migrated that addon into the CDT, so the original case isn't easily reproducable any more. But I am very sure that I didn't break any version range (as John indicates in comment 0 points 2) and 3) with the [1.0,2.0) version range).

Hope that helps!
Comment 44 Simon Kaegi CLA 2010-05-25 16:18:00 EDT
+1 for doing the "move" part for 3.6 RC3.

It looks to me like our algorithm for part 2 was very close and we might consider doing something in 3.6.1.
Comment 45 DJ Houghton CLA 2010-05-25 16:33:47 EDT
Released to HEAD.
Using bug 313795 to track remaining issues for 3.6.1/3.7 target.
Closing.
Comment 46 Ian Bull CLA 2010-05-25 16:49:45 EDT
I created a patch with just the desired changed (as opposed to the current patch with the force remove operations if'd out). I did this to get a better sense of what this patch covers.  I'm happy with either version, as it doesn't seem dangerous to release a bunch of 'dead code', but again, those are always famous last words :-).

The only comment I had was we do a short-circuit:

if (additions.isEmpty() && removals.isEmpty())
  return Status.OK_STATUS;

If we (for 3.6.1) flip the bit on the force remove, this short-circuit might not be a good idea (I think we compute the additions / removals for the force removal after this check).