-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ProfileChangeOperation: fix progressmonitor usage #335 #336
Conversation
07048c5
to
a13a0eb
Compare
a13a0eb
to
a1592a0
Compare
return; | ||
} | ||
IStatus status = transfer(targetDescriptor, sourceDescriptor, monitor); | ||
SubMonitor subMon = SubMonitor.convert(monitor,NLS.bind(Messages.downloading, getArtifactKey().getId()),1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Converting the monitor into a SubMonitor
with work one does not look necessary here and it can just be passed directly.
Furthermore I think it is not necessary to add the try-catch-block to ensure done is called in any ways.
Just calling done below is sufficient and if the method throws the method returns any way and a caller that catches an exception either calls done on the passed monitor or (should) call split which also cleans up children.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Furthermore I think it is not necessary to add the try-catch-block to ensure done is called in any ways
Correct, IProgressmonitor states:
CALLER/CALLEE RESPONSIBILITIES:
Methods that receive an IProgressMonitor ("callees") must either obey the following conventions or include JavaDoc explaining how it differs from these rules. The called method:
Will call beginTask on the argument 0 or 1 times, at its option.
Will not promise to invoke done() on the monitor.
Will not call setCanceled on the monitor.
May rely on the monitor not being null.
May rely on the monitor ignoring the string passed to beginTask.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Furthermore I think it is not necessary to add the try-catch-block to ensure done is called in any ways
Correct, IProgressmonitor states:
CALLER/CALLEE RESPONSIBILITIES:
Methods that receive an IProgressMonitor ("callees") must either obey the following conventions or include JavaDoc explaining how it differs from these rules. The called method:
Will call beginTask on the argument 0 or 1 times, at its option.
Will not promise to invoke done() on the monitor.
Will not call setCanceled on the monitor.
May rely on the monitor not being null.
May rely on the monitor ignoring the string passed to beginTask.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
furthermore I think it is not necessary to add the try-catch-block to ensure done is called in any ways.
Yep, see javadoc of IProgressMonitor ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By passing a submonitor with progress one and unconditional calling done() the progress is unconditional increased which ensures to use up all the reserved progress. That is technically not necessary but ensures a user readable progress from 0 to 100% . This commit fixes the error and proofs that with junit test. This pattern is easy to understand and not error prone. I am not interested in further "optimizations" that "may" work under special conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wanted to note that when one splits a monitor previous aquired "splits" will be completed automatically, so if the toplevel is calling done()
and the other code is always using split()
progress si still reported correctly in every case.
This is to ease fulfill the contract responsibility of IProgressMonitor
for the called method:
- Will call beginTask on the argument 0 or 1 times, at its option.
- Will not promise to invoke done() on the monitor.
- Will not call setCanceled on the monitor.
- May rely on the monitor not being null.
- May rely on the monitor ignoring the string passed to beginTask.
so calling done is of course allowed, but not required by a method receiving a monitor.
if (steps.isEmpty()) { | ||
LogHelper.log(new Status(IStatus.WARNING, Activator.ID, | ||
NLS.bind(Messages.noDigestAlgorithmToVerifyDownload, artifactDescriptor.getArtifactKey()))); | ||
monitor = IProgressMonitor.nullSafe(monitor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SubMonitor.convert
can handle null monitors and can't we just call done on the sub-monitor?
Again I think the try-catch is not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all my concerns are expressed by the junit result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But asserting in AbstractProvisioningUITest that for example ProvisioningSession.performProvisioningPlan()
consumes all work of the monitor is not right.
From the Java-doc of IProgressMonitor:
https://github.com/eclipse-equinox/equinox/blob/8beb9ce0b1dea1176b06ad7300f2663ff6db4eff/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/IProgressMonitor.java#L57
CALLER/CALLEE RESPONSIBILITIES:
Methods that receive an {@link IProgressMonitor} ("callees") must either obey the following conventions or include these rules. The called method:
[...]
- Will not promise to invoke {@link #done()} on the monitor.
[...]
The caller:
[...]
Will not rely on the callee to invoke {@link #done()} on the monitor. It must either select an implementation of {@link IProgressMonitor} that does not require {@link #done()} to be called, for example {@link SubMonitor}, or it must invoke {@link #done()} itself after the method returns.
And the only real caller of ProvisioningSession.performProvisioningPlan()
in ProfileModificationJob.runModal() even explicitly calls done, although even that would actually not be necessary since the caller of that method respectively the creator of a progress-monitor is responsible to call done.
So asserting that in the tests is too strict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Jörg for this PR.
In general in most places SubMonitor.convert()
can be used directly and calling IProgressMonitor.nullSafe()
seems not necessary.
Furthermore as already written in the detailed comments, a try-catch-block is often not necessary because in case of an exception the method terminates immediatly and progress-reporting usually stops anyways.
Besides the already covered locations it looks like MirrorRequest.transfer()
also seem not to handle its monitor correctly, just like SimpleArtifactRepository.getArtifact()
and getRawArtifact()
.
Mind to submit as-is if nobody works on further improvements? |
I can take care of this later/in the next days. |
4962ea4
to
d97e3cd
Compare
@jukzi as discussed I now corrected/simplified the usage of the SubMonitor. In some places I used newChild() instead of split() since split throws |
d97e3cd
to
25832ef
Compare
@HannesWell the tests fail now - which shows the problem |
As said above it is not a problem. A callee does need not call done on the received monitor as the doc states. Did you encounter any creator of a Monitor that did not call done? If yes that should be fixed instead of requiring the calles to call done. Of course they should consume some amounts of work, but the last bit can be left out. Therefore the SubMonitor.split/newChild() pattern was introduced, which actually makes it relatively simple to use monitors right. |
A receiver of the monitor might or might not call any method on the monitor... The good thing about submonitor is that one can reuse unused progress if desired. |
25832ef
to
58d2455
Compare
passing a monitor to two callees requires it to be splitted. eclipse-equinox#335 Also fixed forgotten monitor.done() in performProvisioningPlan and improved tests.
72e668f
to
a24950d
Compare
I know changed the two methods that the test complains about (although I still have the opinion that they are too strict) to call done at the end of the method, but not in a finally block. This way all the callers that make false assumptions should be happy too. This way we can have at least the more important changes to avoid multiple monitor usages. |
passing a monitor to two callees requires it to be splitted.
#335
Also fixed forgotten monitor.done() in performProvisioningPlan and improved tests.