diff --git a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/ExecutionCounter.java b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/ExecutionCounter.java index 1314498211b..7eedebbf1d9 100644 --- a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/ExecutionCounter.java +++ b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/ExecutionCounter.java @@ -19,15 +19,19 @@ package com.cloud.network.nicira; -import java.util.concurrent.atomic.AtomicInteger; - public class ExecutionCounter { private final int executionLimit; - private final AtomicInteger executionCount = new AtomicInteger(0); + private final ThreadLocal executionCount; public ExecutionCounter(final int executionLimit) { this.executionLimit = executionLimit; + executionCount = new ThreadLocal() { + @Override + protected Integer initialValue() { + return new Integer(0); + } + }; } public ExecutionCounter resetExecutionCounter() { @@ -40,7 +44,7 @@ public class ExecutionCounter { } public ExecutionCounter incrementExecutionCounter() { - executionCount.incrementAndGet(); + executionCount.set(executionCount.get() + 1); return this; } diff --git a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/ExecutionCounterTest.java b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/ExecutionCounterTest.java index 18797dfc544..b14694dc098 100644 --- a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/ExecutionCounterTest.java +++ b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/ExecutionCounterTest.java @@ -22,6 +22,11 @@ package com.cloud.network.nicira; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + import org.junit.Test; public class ExecutionCounterTest { @@ -52,4 +57,46 @@ public class ExecutionCounterTest { assertThat(executionCounter.hasReachedExecutionLimit(), equalTo(true)); } + + @Test + public void testConcurrentUpdatesToCounter() throws Exception { + final ExecutionCounter executionCounter = new ExecutionCounter(0); + final ExecutorService executorService = Executors.newFixedThreadPool(3); + final AtomicInteger counterTask1 = new AtomicInteger(-1); + final AtomicInteger counterTask2 = new AtomicInteger(-1); + final AtomicInteger counterTask3 = new AtomicInteger(-1); + + final Runnable task1 = new Runnable() { + @Override + public void run() { + executionCounter.incrementExecutionCounter().incrementExecutionCounter(); + executionCounter.incrementExecutionCounter().incrementExecutionCounter(); + counterTask1.set(executionCounter.getValue()); + } + }; + final Runnable task2 = new Runnable() { + @Override + public void run() { + executionCounter.incrementExecutionCounter().incrementExecutionCounter(); + counterTask2.set(executionCounter.getValue()); + } + }; + final Runnable task3 = new Runnable() { + @Override + public void run() { + counterTask3.set(executionCounter.getValue()); + } + }; + + executorService.execute(task1); + executorService.execute(task2); + executorService.execute(task3); + + executorService.shutdown(); + executorService.awaitTermination(5L, TimeUnit.SECONDS); + + assertThat(counterTask1.get(), equalTo(4)); + assertThat(counterTask2.get(), equalTo(2)); + assertThat(counterTask3.get(), equalTo(0)); + } }