Skip to content

Commit

Permalink
Save memory when test plan contains lots of HTTP Header Manager eleme…
Browse files Browse the repository at this point in the history
…nts by sharing the managers across threads
  • Loading branch information
vlsi committed May 12, 2023
1 parent 2176b33 commit ad0e8e9
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 1 deletion.
9 changes: 9 additions & 0 deletions bin/jmeter.properties
Expand Up @@ -488,6 +488,15 @@ remote_hosts=127.0.0.1
# RETURN_CUSTOM_STATUS.code=
# RETURN_CUSTOM_STATUS.message=

#---------------------------------------------------------------------------
# HTTP Header Manager configuration
#---------------------------------------------------------------------------
# Save memory by sharing HTTP Header Manager across threads.
# The drawback is that HTTP Header Manager's can't be modified in the runtime
# as all the threads would notice the change.
# If you need dynamic headers, consider using ${..} functions or variables
#http.header_manager.is_shareable=true

#---------------------------------------------------------------------------
# Results file configuration
#---------------------------------------------------------------------------
Expand Down
Expand Up @@ -29,18 +29,20 @@
import java.util.List;

import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.engine.util.NoThreadClone;
import org.apache.jmeter.gui.Replaceable;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JOrphanUtils;

/**
* This class provides an interface to headers file to pass HTTP headers along
* with a request.
*
*/
public class HeaderManager extends ConfigTestElement implements Serializable, Replaceable {
public class HeaderManager extends ConfigTestElement implements Serializable, Replaceable, NoThreadClone {

private static final long serialVersionUID = 240L;

Expand All @@ -57,9 +59,24 @@ public HeaderManager() {
setProperty(new CollectionProperty(HEADERS, new ArrayList<>()));
}

@Override
public boolean isShareable() {
return JMeterUtils.getPropDefault("http.header_manager.is_shareable", true); // $NON-NLS-1$
}

private void assertMutable() {
if (isRunningVersion()) {
throw new IllegalStateException(
"Cannot modify HeaderManager " + getName() + " while test is running. " +
"If you need dynamic headers, prefer using ${...} functions in variables if you need dynamic headers."
);
}
}

/** {@inheritDoc} */
@Override
public void clear() {
assertMutable();
super.clear();
setProperty(new CollectionProperty(HEADERS, new ArrayList<>()));
}
Expand Down Expand Up @@ -160,13 +177,15 @@ public void addFile(String headerFile) throws IOException {
* @param h {@link Header} to add
*/
public void add(Header h) {
assertMutable();
getHeaders().addItem(h);
}

/**
* Add an empty header.
*/
public void add() {
assertMutable();
getHeaders().addItem(new Header());
}

Expand All @@ -176,6 +195,7 @@ public void add() {
* @param index index from the header to remove
*/
public void remove(int index) {
assertMutable();
getHeaders().remove(index);
}

Expand Down Expand Up @@ -224,6 +244,7 @@ public Header getFirstHeaderNamed(final String name) {
* @param name header name
*/
public void removeHeaderNamed(String name) {
assertMutable();
List<Integer> removeIndices = new ArrayList<>();
for (int i = getHeaders().size() - 1; i >= 0; i--) {
Header header = (Header) getHeaders().get(i).getObjectValue();
Expand Down Expand Up @@ -304,6 +325,7 @@ public HeaderManager merge(TestElement element) {

@Override
public int replace(String regex, String replaceBy, boolean caseSensitive) throws Exception {
assertMutable();
final CollectionProperty hdrs = getHeaders();
int totalReplaced = 0;
for (int i = 0; i < hdrs.size(); i++) {
Expand Down
1 change: 1 addition & 0 deletions xdocs/changes.xml
Expand Up @@ -75,6 +75,7 @@ Summary
<h3>HTTP Samplers and Test Script Recorder</h3>
<ul>
<li><pr>5911</pr> Use Caffeine for caching HTTP headers instead of commons-collections4 LRUMap</li>
<li><pr>727</pr> Save memory when test plan contains lots of HTTP Header Manager elements by sharing the managers across threads (add NoThreadClone to HeaderManager)</li>
</ul>

<h3>Other samplers</h3>
Expand Down
17 changes: 17 additions & 0 deletions xdocs/usermanual/properties_reference.xml
Expand Up @@ -602,6 +602,23 @@ JMETER-SERVER</source>
</property>
</properties>
</section>

<section name="&sect-num;.14 HTTP Header Manager configuration" anchor="http_header_manager">
<properties>
<property name="http.header_manager.is_shareable">
By default, HTTP Header Manager elements are shared between threads. It enables to save memory by not
cloning the elements for each thread, however, the drawback is that HTTP Header Manager's can't be
modified in the runtime.<br/>
However, HTTP Header Managers still support <code>${...}</code> functions and variables, so it is still
possible to have dynamic headers.
<br/>
Defaults to:
<code>true</code>
</property>
</properties>
</section>


<section name="&sect-num;.15 Results file configuration" anchor="results_file_config">
<properties>
<property name="jmeter.save.saveservice.output_format">
Expand Down

0 comments on commit ad0e8e9

Please sign in to comment.