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>

Reply via email to