You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by vl...@apache.org on 2023/05/12 04:23:34 UTC

[jmeter] 01/02: fix: disable FunctionProperty caching

This is an automated email from the ASF dual-hosted git repository.

vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git

commit d0bdbafd7bbedb5e9fc32855740b52cda4282638
Author: Vladimir Sitnikov <si...@gmail.com>
AuthorDate: Thu Mar 2 11:14:47 2023 +0300

    fix: disable FunctionProperty caching
    
    Previously it cached the values based on iteration number only
    which triggered wrong results on concurrent executions.
    
    The previous behavior can be temporary restored with
    function.cache.per.iteration=true property.
---
 bin/jmeter.properties                                 |  7 +++++++
 .../jmeter/testelement/property/FunctionProperty.java | 19 +++++++++++++++++--
 xdocs/changes.xml                                     |  4 ++++
 xdocs/usermanual/properties_reference.xml             |  9 +++++++++
 4 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/bin/jmeter.properties b/bin/jmeter.properties
index 69b77d46bd..410ae16819 100644
--- a/bin/jmeter.properties
+++ b/bin/jmeter.properties
@@ -1055,6 +1055,13 @@ csvdataset.file.encoding_list=UTF-8|UTF-16|ISO-8859-15|US-ASCII
 # ORO PatternCacheLRU size
 #oro.patterncache.size=1000
 
+# Cache function execution during test execution
+# By default, JMeter caches function properties, however, it might cause unexpected results
+# when the component is shared across threads and the expression depends on the thread variables.
+# The caching behaviour would likely change in the upcoming versions
+# Deprecation notice: the setting will likely disappear, so if you need it, consider raising an issue with the use-case.
+#function.cache.per.iteration=false
+
 #TestBeanGui
 #
 #propertyEditorSearchPath=null
diff --git a/src/core/src/main/java/org/apache/jmeter/testelement/property/FunctionProperty.java b/src/core/src/main/java/org/apache/jmeter/testelement/property/FunctionProperty.java
index a4adf02774..238ec0184f 100644
--- a/src/core/src/main/java/org/apache/jmeter/testelement/property/FunctionProperty.java
+++ b/src/core/src/main/java/org/apache/jmeter/testelement/property/FunctionProperty.java
@@ -21,19 +21,28 @@ import org.apache.jmeter.engine.util.CompoundVariable;
 import org.apache.jmeter.testelement.TestElement;
 import org.apache.jmeter.threads.JMeterContext;
 import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jmeter.util.JMeterUtils;
 
 /**
  * Class that implements the Function property
  */
 public class FunctionProperty extends AbstractProperty {
     private static final long serialVersionUID = 233L;
+    private static final boolean FUNCTION_CACHE_PER_ITERATION =
+            JMeterUtils.getPropDefault("function.cache.per.iteration", false);
 
     private transient CompoundVariable function;
 
     private int testIteration = -1;
 
+    /**
+     * The cache will be removed in the subsequent releases.
+     * For now, it is kept for backward compatibility.
+     */
     private String cacheValue;
 
+    private String overrideValue;
+
     public FunctionProperty(String name, CompoundVariable func) {
         super(name);
         function = func;
@@ -48,7 +57,7 @@ public class FunctionProperty extends AbstractProperty {
         if (v instanceof CompoundVariable && !isRunningVersion()) {
             function = (CompoundVariable) v;
         } else {
-            cacheValue = v.toString();
+            overrideValue = v.toString();
         }
     }
 
@@ -87,7 +96,11 @@ public class FunctionProperty extends AbstractProperty {
             log.debug("Not running version, return raw function string");
             return function.getRawParameters();
         }
-        if(!ctx.isSamplingStarted()) {
+        String overrideValue = this.overrideValue;
+        if (overrideValue != null) {
+            return overrideValue;
+        }
+        if (!FUNCTION_CACHE_PER_ITERATION || !ctx.isSamplingStarted()) {
             return function.execute();
         }
         log.debug("Running version, executing function");
@@ -115,6 +128,7 @@ public class FunctionProperty extends AbstractProperty {
     public FunctionProperty clone() {
         FunctionProperty prop = (FunctionProperty) super.clone();
         prop.cacheValue = cacheValue;
+        prop.overrideValue = overrideValue;
         prop.testIteration = testIteration;
         prop.function = function;
         return prop;
@@ -126,5 +140,6 @@ public class FunctionProperty extends AbstractProperty {
     @Override
     public void recoverRunningVersion(TestElement owner) {
         cacheValue = null;
+        overrideValue = null;
     }
 }
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index f212ecfbf5..449fa8f481 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -104,6 +104,10 @@ Summary
   <li><pr>5899</pr>Speed up CPU-bound tests by skipping <code>recoverRunningVersion</code> for elements that are shared between threads (the ones that implement <code>NoThreadClone</code>)</li>
   <li><pr>5914</pr>Use <code>Locale.ROOT</code> instead of default locale for <code>toUpperCase</code>, and <code>toLowerCase</code> to avoid surprises with dotless I in <code>tr_TR</code> locale</li>
   <li><pr>5885</pr>Use Java's <code>ServiceLoader</code> for loading plugins instead of classpath scanning. It enables faster startup</li>
+  <li><pr>5788</pr><code>FunctionProperty</code> no longer caches the value.
+    Previously it cached the values based on iteration number only which triggered wrong results on concurrent executions.
+    The previous behavior can be temporary restored with <code>function.cache.per.iteration</code> property.
+  </li>
 </ul>
 
 <ch_section>Non-functional changes</ch_section>
diff --git a/xdocs/usermanual/properties_reference.xml b/xdocs/usermanual/properties_reference.xml
index 68441b1bb8..cb32afcefa 100644
--- a/xdocs/usermanual/properties_reference.xml
+++ b/xdocs/usermanual/properties_reference.xml
@@ -1339,6 +1339,15 @@ JMETER-SERVER</source>
     ORO PatternCacheLRU size.<br/>
     Defaults to: <code>1000</code>
 </property>
+<property name="function.cache.per.iteration">
+    <p>Cache function execution during test execution.</p>
+    <p>By default, JMeter caches function properties during a test iteration, however,
+    it might cause unexpected results when a component is shared across threads and the expression depends on
+    the thread variables.</p>
+    <note>The property will likely be removed in an upcoming version, so if you need it consider raising
+     an issue with your use-case.</note>
+    Defaults to: <code>false</code>
+</property>
 <property name="propertyEditorSearchPath">
     TestBeanGui<br/>
     Defaults to: <code>null</code>