-
Notifications
You must be signed in to change notification settings - Fork 189
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
Fix more deadlocks #226
Fix more deadlocks #226
Conversation
…ocks on the execution from the run
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.
Just making sure I grok the general point here - the deadlock was a result of the methods themselves being synchronized
and so juggling around the synchronization fixes things?
@abayer Yeah, we had methods in CpsFlowExecution that synchronize on first the |
In general it is pretty fruitless to write automated tests for deadlocks. Possible, just not productive. You are not demonstrating that the code is free of deadlocks, only that the behavior of a particular sequence of events has changed for the better. |
@@ -620,47 +620,52 @@ private synchronized String getHeadsAsString() { | |||
* Bypasses {@link #croak(Throwable)} and {@link #onProgramEnd(Outcome)} to guarantee a clean path. | |||
*/ | |||
@GuardedBy("this") | |||
synchronized void createPlaceholderNodes(Throwable failureReason) throws Exception { | |||
this.done = true; |
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.
Unreadable diff. better
end.addAction(new ErrorAction(failureReason)); | ||
head.setNewHead(end); | ||
} catch (Exception ex) { | ||
throw ex; |
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.
Uh, what is this try
-catch
-throw
accomplishing? Just delete it!
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.
Main reason is to separate out the synchronization components, but also try to ensure the run save happens.
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.
Wait, no. I'm going to blame jet lag and lack of sleep for this. You're right, nonsensical.
} | ||
} | ||
try { | ||
saveOwner(); | ||
} catch (Exception ex) { | ||
throw ex; |
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.
ditto, makes little sense
try { | ||
this.execution.saveOwner(); | ||
} catch (Exception ex) { | ||
LOGGER.log(Level.WARNING, "Error saving execution for "+this, ex); |
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.
Useless toString()
. Try
LOGGER.log(Level.WARNING, "Error saving execution for " + execution, ex);
@@ -18,6 +18,7 @@ | |||
import org.codehaus.groovy.control.CompilationUnit; | |||
import org.codehaus.groovy.control.CompilerConfiguration; | |||
import org.codehaus.groovy.control.SourceUnit; | |||
import org.jenkinsci.plugins.workflow.flow.FlowExecution; |
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.
unused import
@@ -1217,7 +1226,7 @@ public boolean isComplete() { | |||
} | |||
|
|||
/** | |||
* Record the end of the build. | |||
* Record the end of the build. Note: we should always follow this with a call to saveOwner to persist the 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.
@link
See deadlock file from JENKINS-51132 comment.
This prevents deadlocks by ensuring we do not lock Execution before Run (usually by separating the synchronization scopes).
Lock order should always be Run -> Execution when locks are nested, or locks should be separated (the approach generally used here).
Why aren't there testcases? I have low confidence in our ability produce a testcase that replicates all these deadlocks.