Skip to content

Commit bbe90a5

Browse files
committed
Merge branch '6.1.x'
2 parents 4697ae1 + 9b3cb15 commit bbe90a5

File tree

9 files changed

+1623
-49
lines changed

9 files changed

+1623
-49
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.http.support;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Set;
22+
import java.util.function.Function;
23+
24+
import io.netty.handler.codec.http.DefaultHttpHeaders;
25+
import org.apache.hc.client5.http.classic.methods.HttpGet;
26+
import org.eclipse.jetty.http.HttpFields;
27+
import org.openjdk.jmh.annotations.Benchmark;
28+
import org.openjdk.jmh.annotations.BenchmarkMode;
29+
import org.openjdk.jmh.annotations.Level;
30+
import org.openjdk.jmh.annotations.Mode;
31+
import org.openjdk.jmh.annotations.Param;
32+
import org.openjdk.jmh.annotations.Scope;
33+
import org.openjdk.jmh.annotations.Setup;
34+
import org.openjdk.jmh.annotations.State;
35+
import org.openjdk.jmh.infra.Blackhole;
36+
37+
import org.springframework.http.HttpHeaders;
38+
import org.springframework.util.MultiValueMap;
39+
40+
/**
41+
* Benchmark for implementations of MultiValueMap adapters over native HTTP
42+
* headers implementations.
43+
* <p>Run JMH with {@code -p implementation=Netty,Netty5,HttpComponents,Jetty}
44+
* to cover all implementations
45+
* @author Simon Baslé
46+
*/
47+
@BenchmarkMode(Mode.Throughput)
48+
public class HeadersAdapterBenchmark {
49+
50+
@Benchmark
51+
public void iterateEntries(BenchmarkData data, Blackhole bh) {
52+
for (Map.Entry<String, List<String>> entry : data.entriesProvider.apply(data.headers)) {
53+
bh.consume(entry.getKey());
54+
for (String s : entry.getValue()) {
55+
bh.consume(s);
56+
}
57+
}
58+
}
59+
60+
@Benchmark
61+
public void toString(BenchmarkData data, Blackhole bh) {
62+
bh.consume(data.headers.toString());
63+
}
64+
65+
@State(Scope.Benchmark)
66+
public static class BenchmarkData {
67+
68+
@Param({"NONE"})
69+
public String implementation;
70+
71+
@Param({"true"})
72+
public boolean duplicate;
73+
74+
public MultiValueMap<String, String> headers;
75+
public Function<MultiValueMap<String, String>, Set<Map.Entry<String, List<String>>>> entriesProvider;
76+
77+
//Uncomment the following line and comment the similar line for setupImplementationBaseline below
78+
//to benchmark current implementations
79+
@Setup(Level.Trial)
80+
public void initImplementationNew() {
81+
this.entriesProvider = map -> new HttpHeaders(map).headerSet();
82+
83+
this.headers = switch (this.implementation) {
84+
case "Netty" -> new Netty4HeadersAdapter(new DefaultHttpHeaders());
85+
case "HttpComponents" -> new HttpComponentsHeadersAdapter(new HttpGet("https://example.com"));
86+
case "Netty5" -> new Netty5HeadersAdapter(io.netty5.handler.codec.http.headers.HttpHeaders.newHeaders());
87+
case "Jetty" -> new JettyHeadersAdapter(HttpFields.build());
88+
//FIXME tomcat/undertow implementations (in another package)
89+
// case "Tomcat" -> new TomcatHeadersAdapter(new MimeHeaders());
90+
// case "Undertow" -> new UndertowHeadersAdapter(new HeaderMap());
91+
default -> throw new IllegalArgumentException("Unsupported implementation: " + this.implementation);
92+
};
93+
initHeaders();
94+
}
95+
96+
//Uncomment the following line and comment the similar line for setupImplementationNew above
97+
//to benchmark old implementations
98+
// @Setup(Level.Trial)
99+
public void setupImplementationBaseline() {
100+
this.entriesProvider = MultiValueMap::entrySet;
101+
102+
this.headers = switch (this.implementation) {
103+
case "Netty" -> new HeadersAdaptersBaseline.Netty4(new DefaultHttpHeaders());
104+
case "HttpComponents" -> new HeadersAdaptersBaseline.HttpComponents(new HttpGet("https://example.com"));
105+
case "Netty5" -> new HeadersAdaptersBaseline.Netty5(io.netty5.handler.codec.http.headers.HttpHeaders.newHeaders());
106+
case "Jetty" -> new HeadersAdaptersBaseline.Jetty(HttpFields.build());
107+
default -> throw new IllegalArgumentException("Unsupported implementation: " + this.implementation);
108+
};
109+
initHeaders();
110+
}
111+
112+
private void initHeaders() {
113+
this.headers.add("TestHeader", "first");
114+
this.headers.add("SecondHeader", "value");
115+
if (this.duplicate) {
116+
this.headers.add("TestHEADER", "second");
117+
}
118+
else {
119+
this.headers.add("TestHeader", "second");
120+
}
121+
this.headers.add("TestHeader", "third");
122+
}
123+
}
124+
}

0 commit comments

Comments
 (0)