Skip to content
Permalink
Browse files

Merge pull request #57 from adelcast/dev/adelcast/issue_jenkins-42720

LockableResourcesManager: make queueContext & unqueueContext thread safe
  • Loading branch information...
abayer committed Sep 18, 2017
2 parents 3099e8b + fef087c commit 3f03365a2ce028fc2936fa58a5340e3f4fd37292
@@ -10,6 +10,7 @@

import edu.umd.cs.findbugs.annotations.CheckForNull;
import hudson.Extension;
import hudson.BulkChange;
import hudson.model.AbstractBuild;
import hudson.model.Run;

@@ -609,7 +610,7 @@ public boolean configure(StaplerRequest req, JSONObject json)
* Adds the given context and the required resources to the queue if
* this context is not yet queued.
*/
public void queueContext(StepContext context, LockableResourcesStruct requiredResources, String resourceDescription) {
public synchronized void queueContext(StepContext context, LockableResourcesStruct requiredResources, String resourceDescription) {
for (QueuedContextStruct entry : this.queuedContexts) {
if (entry.getContext() == context) {
return;
@@ -620,7 +621,7 @@ public void queueContext(StepContext context, LockableResourcesStruct requiredRe
save();
}

public boolean unqueueContext(StepContext context) {
public synchronized boolean unqueueContext(StepContext context) {
for (Iterator<QueuedContextStruct> iter = this.queuedContexts.listIterator(); iter.hasNext(); ) {
if (iter.next().getContext() == context) {
iter.remove();
@@ -636,6 +637,17 @@ public static LockableResourcesManager get() {
.getDescriptorOrDie(LockableResourcesManager.class);
}

public synchronized void save() {
if(BulkChange.contains(this))
return;

try {
getConfigFile().write(this);
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to save " + getConfigFile(),e);
}
}

private static final Logger LOGGER = Logger.getLogger(LockableResourcesManager.class.getName());

}
@@ -3,6 +3,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;

import hudson.Functions;
@@ -20,6 +21,7 @@
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import org.jvnet.hudson.test.TestBuilder;
import org.jvnet.hudson.test.recipes.WithPlugin;

import hudson.Launcher;
import hudson.model.AbstractBuild;
@@ -718,4 +720,41 @@ private void waitAndClear(int semaphoreIndex, List<WorkflowRun> nextRuns) throws
waitAndClear(semaphoreIndex + 1, remainingRuns);
}
}

@Test
@WithPlugin("jobConfigHistory.hpi")
public void lockWithLabelConcurrent() {
story.addStep(new Statement() {
@Override
public void evaluate() throws Throwable {
LockableResourcesManager.get().createResourceWithLabel("resource1", "label1");
final WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"import java.util.Random; \n" +
"Random random = new Random(0);\n" +
"lock(label: 'label1') {\n" +
" echo 'Resource locked'\n" +
" sleep random.nextInt(10)*100\n" +
"}\n" +
"echo 'Finish'"
));
final CyclicBarrier barrier = new CyclicBarrier(51);
for (int i = 0; i < 50; i++) {
Thread thread = new Thread() {
public void run() {
try {
barrier.await();
WorkflowRun b1 = p.scheduleBuild2(0).waitForStart();
} catch (Exception e) {
System.err.println("Failed to start pipeline job");
}
}
};
thread.start();
}
barrier.await();
story.j.waitUntilNoActivity();
}
});
}
}
Binary file not shown.

0 comments on commit 3f03365

Please sign in to comment.
You can’t perform that action at this time.