This is an automated email from the ASF dual-hosted git repository.
fschumacher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git
The following commit(s) were added to refs/heads/master by this push:
new f6aa6fa Use AtomicInteger for __counter instead of synchronization on
our own
f6aa6fa is described below
commit f6aa6fac2a3ec2c576e16b0f121cf9f83d8bc2af
Author: Felix Schumacher <[email protected]>
AuthorDate: Sat Aug 17 15:43:16 2019 +0200
Use AtomicInteger for __counter instead of synchronization on our own
This simplifies the code a bit and makes the intent it a bit clearer
---
.../apache/jmeter/functions/IterationCounter.java | 26 ++-------
.../jmeter/functions/IterationCounterSpec.groovy | 65 ++++++++++++++++++++++
xdocs/changes.xml | 1 +
3 files changed, 71 insertions(+), 21 deletions(-)
diff --git
a/src/functions/src/main/java/org/apache/jmeter/functions/IterationCounter.java
b/src/functions/src/main/java/org/apache/jmeter/functions/IterationCounter.java
index 7b90388..88e396a 100644
---
a/src/functions/src/main/java/org/apache/jmeter/functions/IterationCounter.java
+++
b/src/functions/src/main/java/org/apache/jmeter/functions/IterationCounter.java
@@ -21,6 +21,7 @@ package org.apache.jmeter.functions;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.samplers.SampleResult;
@@ -39,28 +40,17 @@ public class IterationCounter extends AbstractFunction {
private static final String KEY = "__counter"; //$NON-NLS-1$
- private ThreadLocal<Integer> perThreadInt;
-
private Object[] variables;
- private int globalCounter;//MAXINT = 2,147,483,647
+ private AtomicInteger globalCounter = new AtomicInteger();
- private void init(){ // WARNING: called from ctor so must not be
overridden (i.e. must be private or final)
- synchronized(this){
- globalCounter=0;
- }
- perThreadInt = ThreadLocal.withInitial(() -> Integer.valueOf(0));
- }
+ private ThreadLocal<AtomicInteger> perThreadInt =
ThreadLocal.withInitial(AtomicInteger::new);
static {
desc.add(JMeterUtils.getResString("iteration_counter_arg_1"));
//$NON-NLS-1$
desc.add(JMeterUtils.getResString("function_name_paropt"));
//$NON-NLS-1$
}
- public IterationCounter() {
- init();
- }
-
/** {@inheritDoc} */
@Override
public String execute(SampleResult previousResult, Sampler currentSampler)
@@ -78,15 +68,9 @@ public class IterationCounter extends AbstractFunction {
String counterString = ""; //$NON-NLS-1$
if (perThread) {
- int threadCounter;
- threadCounter = perThreadInt.get().intValue() + 1;
- perThreadInt.set(Integer.valueOf(threadCounter));
- counterString = String.valueOf(threadCounter);
+ counterString = String.valueOf(perThreadInt.get().addAndGet(1));
} else {
- synchronized (this) {
- globalCounter++;
- counterString = String.valueOf(globalCounter);
- }
+ counterString = String.valueOf(globalCounter.addAndGet(1));
}
// vars will be null on Test Plan
diff --git
a/src/functions/src/test/groovy/org/apache/jmeter/functions/IterationCounterSpec.groovy
b/src/functions/src/test/groovy/org/apache/jmeter/functions/IterationCounterSpec.groovy
new file mode 100644
index 0000000..d974d22
--- /dev/null
+++
b/src/functions/src/test/groovy/org/apache/jmeter/functions/IterationCounterSpec.groovy
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jmeter.functions;
+
+import java.util.concurrent.CountDownLatch
+
+import org.apache.jmeter.engine.util.CompoundVariable
+import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jmeter.threads.JMeterVariables
+
+import spock.lang.Specification
+import spock.lang.Unroll
+
+@Unroll
+class IterationCounterSpec extends Specification {
+
+ def "Counter per thread counts for each thread"() {
+ given:
+ def context = JMeterContextService.getContext()
+ context.setVariables(new JMeterVariables())
+ def counter = new IterationCounter()
+ counter.setParameters(Arrays.asList(new CompoundVariable("true"),
new CompoundVariable("var")))
+ when:
+ Thread.start({ (1..10).each { counter.execute(null, null) }
}).join()
+ (1..10).each { counter.execute(null, null) }
+ then:
+ context.getVariables().get("var") == "10"
+ }
+
+ def "global Counter counts for all threads"() {
+ given:
+ def context = JMeterContextService.getContext()
+ context.setVariables(new JMeterVariables())
+ def counter = new IterationCounter()
+ counter.setParameters(Arrays.asList(new CompoundVariable("false"),
new CompoundVariable("var")))
+ def nrOfThreads = 100
+ def latch = new CountDownLatch(nrOfThreads)
+ when:
+ (1..nrOfThreads).each {
+ Thread.start({
+ (1..1000).each { counter.execute(null, null) }
+ latch.countDown()
+ })
+ }
+ latch.await()
+ counter.execute(null, null)
+ then:
+ context.getVariables().get("var") == "100001"
+ }
+}
\ No newline at end of file
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index a94edca..cb6713c 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -113,6 +113,7 @@ to view the last release notes of version 5.1.1.
<h3>Functions</h3>
<ul>
<li><bug>63219</bug>New function <code>__StringToFile</code> to save/append
a string into a file. Contributed by Ubik Load Pack (support at
ubikloadpack.com)</li>
+ <li>Use <code>AtomicInteger</code> for <code>__counter</code> instead of
synchronization on our own</li>
</ul>
<h3>I18N</h3>