-
Notifications
You must be signed in to change notification settings - Fork 104
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
Disable the automatic snapshots for TestBug297635 #623
Disable the automatic snapshots for TestBug297635 #623
Conversation
@@ -28,6 +31,7 @@ public class DelayedSnapshotJob extends Job { | |||
private static final String MSG_SNAPSHOT = Messages.resources_snapshot; | |||
private SaveManager saveManager; | |||
private Workspace workspace; | |||
private boolean suspended; |
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.
this must be volatile
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.
You might make this an integer and just increment and decrement it when suspend
or resume
are being called. This would relieve existing client code from checking the isSuspended
state before resuming again. isSuspended
might become obsolete even.
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 made it an AtomicInteger
, thanks for the tips to you both!
@@ -47,6 +51,10 @@ public IStatus run(IProgressMonitor monitor) { | |||
if (!workspace.isOpen()) { | |||
return Status.OK_STATUS; | |||
} | |||
if (suspended) { | |||
System.out.println("Automatic snapshots are suspended... skipping"); //$NON-NLS-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.
and system.out must be removed
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.
Oh, "debug code". Thank you for noticing!
97869ab
to
a6c7df4
Compare
ac37216
to
efa6b8b
Compare
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 have some general remarks to this proposal:
- The
DelayedSnapshotJob
is completely hidden by theSaveManager
. The new API exposes that there is some snapshot job running, such that the user has to know about all potential (side) effects of aresume
andsuspend
operation. Currently, these effects are not documented. - I am not sure whether the changes lead to consistent and expectable behavior w.r.t. snapshots. For example...
- Shouldn't the
resume
also at least schedule the job if a snapshot was requested in between? - Shouldn't the
SaveManager.shutdown
still write a snapshot? It uses the snapshop job to do so, which was okay by now as the job was completely hidden/managed by the class. By now it can be influenced from outside, which has an unintended side effect on the shutdown behavior.
- Shouldn't the
All in all, I am not sure if a single test is worth exposing internals of the SaveManager
with all the efforts for documenting and adapting behavior accordingly. At least, I would expect a consistent, documented behavior of the extended SaveManager
.
Are there further scenarios where disabling the snapshot job would be required, such that these changes are justified by being an enabler for further things?
/** | ||
* Suspend automatic snapshots until {@link #resume()} is called. | ||
* | ||
* @see #resume() | ||
*/ | ||
void suspend() { | ||
suspended.incrementAndGet(); | ||
} | ||
|
||
/** | ||
* Resume automatic snapshots. This method does not schedule this Job. | ||
* | ||
* @see #suspend() | ||
*/ | ||
void resume() { | ||
if (suspended.decrementAndGet() < 0) { | ||
suspended.set(0); | ||
} | ||
} |
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.
The documentation is inconsistent with the behavior. I would actually expect the behavior as specified in the Javadoc and not that resume
has to be called as many times as suspend
has been called to actually resume. If a caller really wants to resume
, then they would call resume
as long as isSuspended
returns true
. And whoever else has suspended the job before will then call resume
without any effect.
I see that this conflicts with your proposal to use an integer instead of a boolean for the suspended state, @szarnekow (#623 (comment)), but I am not sure whether that behavior (even if properly documented) is what you expect from suspend
and resume
methods. The behavior of suspend
/resume
methods in the SaveManager
would then, for example, be different from behavior of suspend
/resume
methods in the JobManager
.
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.
Agreed. Sorry about that, I didn't consider the semantics of JobManager.suspend / resume. I was more thinking about the usage pattern where a boolean was stored to call / not call resume again. I think that's highly confusing and prone to invalid state in case multiple threads use these methods.
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.
Good point, I haven't thought about the behavior of suspend
/ resume
in the JobManager
, only about nesting calls like the ones the prepare...
/begin...
/endOperation
in Workspace
.
public void suspendSnapshotJob() { | ||
snapshotJob.suspend(); | ||
} | ||
|
||
public void resumeSnapshotJob() { | ||
snapshotJob.resume(); | ||
} |
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.
These methods should be documented, in particular when the behavior of the methods in the DelayedSnapshotJob
is supposed to stay as it is now.
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.
These methods might not survive, see my proposal below
Disable the automatic snapshots while running tests in TestBug297635 to avoid random failures. Fixes eclipse-platform#460
efa6b8b
to
1b35a80
Compare
Good point, the current implementation would have taken the snapshot the next time an operation finished and
I wouldn't force that. I think that if it's clear that snapshots are disabled then they will be expected to be disabled all the way, even during shutdown.
This is the only case I found for now but I haven't looked for other possible scenarios. I assume there aren't many though.
I see your point: it might be too risky to allow to allow suspending snapshots without ever making sure the original state of the public void runWithSnapshotsDisabled(Runnable runnable) {
snapshotJob.suspend();
try {
runnable.run();
} finally {
snapshotJob.resume();
snapshotIfNeeded();
}
} This would still expose the fact that there are snapshots and that they can be deactivated but they could only be deactivated in a controlled environment and the caller wouldn't even have the chance to "forget" activating them afterwards. It would also make it clear in the stack-trace that snapshot have been temporarily deactivated, which would help debugging. |
When considering the issue rather locally, I would prefer the solution with a scoped disablement over the
Still, I am still not in favor of providing public API that is currently only justified by fixing tests. So I would ask a different question here: instead of "how can we change the API to make the test run?" I would ask "what is the current design flaw that seems to make it impossible to write a proper test?". From a design perspective, it looks to me like "auto-snapshots" are a kind of trait of the |
I see your point. Do you have any suggestions on how to separate that treat without changing the internal public APIs? I thought of maybe overloading the constructors of
What do you think about using reflection to replace the
Could you please elaborate? |
You will probably need to change the API anyway, but since it's
I don't see why it should be more cumbersome, because you have to check and test every place in the
As I mentioned before, in my opinion the need to provide additional API for the test either reveals a broken test or a design flaw and providing some test-specific injection functionality rather looks like a patch for the symptoms than a solution for the root cause to me. Actually, the original issue is not about providing some API but about a failing test. And looking at the test, it is in a real bad state (validating internal states using reflection). Even if disabling snapshots solves the issue for now, it will fail again when internal implementations change. I think the test could be fixed by rewriting it in a much easier way such that it tests what it is actually supposed to test: #460 (comment) |
Superseded by #737 |
Automatic snapshots might cause
TestBug297635::testBug
to fail if the snapshot is taken right beforeassertStateTreesIsNotNull
. The reason for this is that a by taking a snapshot,org.eclipse.core.internal.resources.SaveManager.forgetSavedTree(String)
will be called and it will delete the state-trees.This PR disables the automatic snapshots while running tests in TestBug297635 to avoid such random failures.
Fixes #460