Skip to content

Commit 8e2aab6

Browse files
authored
Merge branch 'main' into allocation/consolidate_heap_usage_collector_methods
2 parents 8497f20 + 1e1b40d commit 8e2aab6

519 files changed

Lines changed: 21526 additions & 3013 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

benchmarks/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ dependencies {
109109
nativeLib(project(':libs:native'))
110110
implementation project(':modules:bitmap')
111111
implementation("org.roaringbitmap:RoaringBitmap:1.6.15")
112+
// Shared benchmark helpers (Utils, ExtraParam) plus the log4j LoggerFactory bootstrap
113+
// and the BenchmarkConfigurationFactory that strips %node_name / %cluster_name from
114+
// any .properties log4j config on the classpath. See benchmarks/common/build.gradle.
115+
implementation project(':benchmarks:common')
112116
api "org.openjdk.jmh:jmh-core:$versions.jmh"
113117
annotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:$versions.jmh"
114118
annotationProcessor project(':benchmarks:processor')

benchmarks/common/build.gradle

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
// Shared helpers for JMH microbenchmarks. Kept intentionally server-free: benchmarked
11+
// modules may reach into :server for the code under test, but this common jar must not,
12+
// so it stays a clean foundation for future per-module `jmh` sourcesets that don't touch
13+
// server.
14+
apply plugin: org.elasticsearch.gradle.internal.ElasticsearchJavaBasePlugin
15+
apply plugin: 'java-library'
16+
17+
dependencies {
18+
api project(':libs:logging')
19+
api "org.openjdk.jmh:jmh-core:${versions.jmh}"
20+
21+
// ComponentMetadataRulesPlugin strips transitives across the board, so log4j-api must
22+
// be declared explicitly even though log4j-core depends on it. Mirrors server/build.gradle.
23+
implementation "org.apache.logging.log4j:log4j-api:${versions.log4j}"
24+
implementation "org.apache.logging.log4j:log4j-core:${versions.log4j}"
25+
26+
// Activates log4j-core's PluginProcessor so this jar ships a
27+
// META-INF/.../Log4j2Plugins.dat entry for BenchmarkConfigurationFactory. Without this
28+
// the @Plugin annotation is silently ignored at runtime and log4j falls back to its
29+
// default PropertiesConfigurationFactory (@Order 8), which would leave %node_name /
30+
// %cluster_name in patterns and re-introduce the initialization ordering trap that the
31+
// factory is here to prevent. Both jars are needed on the processor path since
32+
// PluginProcessor references classes from log4j-api.
33+
annotationProcessor "org.apache.logging.log4j:log4j-api:${versions.log4j}"
34+
annotationProcessor "org.apache.logging.log4j:log4j-core:${versions.log4j}"
35+
}
36+
37+
// log4j-core registers both PluginProcessor and GraalVmProcessor via
38+
// META-INF/services/javax.annotation.processing.Processor; we only want the former.
39+
// Mirrors server/build.gradle.
40+
tasks.named('compileJava').configure {
41+
options.compilerArgs.addAll('-processor', 'org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor')
42+
}

benchmarks/src/main/java/org/elasticsearch/benchmark/ExtraParam.java renamed to benchmarks/common/src/main/java/org/elasticsearch/benchmark/ExtraParam.java

File renamed without changes.

benchmarks/src/main/java/org/elasticsearch/benchmark/Utils.java renamed to benchmarks/common/src/main/java/org/elasticsearch/benchmark/Utils.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,29 @@
99

1010
package org.elasticsearch.benchmark;
1111

12-
import org.elasticsearch.common.logging.LogConfigurator;
13-
import org.elasticsearch.common.logging.NodeNamePatternConverter;
1412
import org.openjdk.jmh.annotations.Param;
1513

1614
import java.lang.reflect.Field;
1715
import java.util.ArrayList;
1816
import java.util.Collections;
1917
import java.util.List;
2018

19+
/**
20+
* Reflection helpers for JMH benchmarks. The logging bootstrap lives separately in
21+
* {@link org.elasticsearch.benchmark.internal.BenchmarkLogging} so that benchmarks
22+
* that only need parameter enumeration do not force-load the logging machinery.
23+
*/
2124
public final class Utils {
2225

2326
private Utils() {
2427
// utility class
2528
}
2629

27-
static {
28-
LogConfigurator.setClusterName("elasticsearch-benchmark");
29-
LogConfigurator.setNodeName("test");
30-
}
31-
32-
public static void configureBenchmarkLogging() {
33-
NodeNamePatternConverter.setGlobalNodeName("benchmark");
34-
LogConfigurator.configureESLogging();
35-
}
36-
30+
/**
31+
* Reflectively read every value declared by {@code @Param} (and, if present,
32+
* {@code @ExtraParam}) on the given field of {@code clazz}. Used by benchmark
33+
* correctness tests to iterate the same parameter combinations JMH would run.
34+
*/
3735
public static List<String> possibleValues(Class<?> clazz, String field) {
3836
List<String> result = new ArrayList<>();
3937
try {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.benchmark.internal;
11+
12+
import org.apache.logging.log4j.core.LoggerContext;
13+
import org.apache.logging.log4j.core.config.ConfigurationException;
14+
import org.apache.logging.log4j.core.config.ConfigurationFactory;
15+
import org.apache.logging.log4j.core.config.ConfigurationSource;
16+
import org.apache.logging.log4j.core.config.Order;
17+
import org.apache.logging.log4j.core.config.plugins.Plugin;
18+
import org.apache.logging.log4j.core.config.properties.PropertiesConfiguration;
19+
import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder;
20+
import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationFactory;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.util.Properties;
25+
import java.util.regex.Pattern;
26+
27+
/**
28+
* Log4j {@code ConfigurationFactory} that strips {@code %node_name} / {@code %cluster_name}
29+
* (and their {@code ES}-prefixed aliases) out of {@code .properties} log4j configs at load
30+
* time, before log4j hands them to its pattern parser.
31+
*
32+
* <p>Auto-discovered by log4j via the plugin cache: the {@link Plugin @Plugin} annotation
33+
* causes log4j-core's {@code PluginProcessor} (an annotation processor) to add this class
34+
* to the {@code META-INF/.../Log4j2Plugins.dat} entry inside the shipped jar, which log4j
35+
* merges with every other classpath jar's plugin cache at {@code LoggerContext} startup.
36+
* With {@link Order @Order(10)} we outrank the built-in {@code PropertiesConfigurationFactory}
37+
* ({@code @Order(8)}) so we get first pick for {@code .properties} sources — verified via
38+
* {@code OrderComparator}: "larger value means higher priority".
39+
*
40+
* <p>Why strip: benchmarked code that touches log4j at class-init time (Lucene codecs,
41+
* ES internal helpers reached via SPI, …) triggers a {@code LoggerContext} that reads the
42+
* first {@code log4j2*.properties} it finds on the classpath. Historically those patterns
43+
* contain {@code [%node_name]}, whose converter ({@code NodeNamePatternConverter} in
44+
* {@code :server}) requires a {@code SetOnce} to have been populated before pattern parsing
45+
* — a fragile ordering constraint the benchmark suite has repeatedly stumbled over.
46+
* Stripping the tokens sidesteps the ordering entirely and removes the runtime dependency
47+
* on the {@code :server} pattern converters for any classpath they end up on.
48+
*
49+
* <p>Only {@code .properties} configs are intercepted. If a future dep introduces an XML,
50+
* YAML, or JSON log4j config on the benchmarks classpath, add a sibling factory for that
51+
* source type — the built-ins live in {@code org.apache.logging.log4j.core.config.xml} etc.
52+
*/
53+
@Plugin(name = "BenchmarkConfigurationFactory", category = ConfigurationFactory.CATEGORY)
54+
@Order(10)
55+
public final class BenchmarkConfigurationFactory extends PropertiesConfigurationFactory {
56+
57+
// Matches %node_name, %ESnode_name, %cluster_name, %EScluster_name — optionally wrapped
58+
// in [] with surrounding whitespace. Covers every @ConverterKeys value of
59+
// NodeNamePatternConverter ({"ESnode_name", "node_name"}) and
60+
// ClusterNamePatternConverter ({"EScluster_name", "cluster_name"}) in :server.
61+
private static final Pattern STRIP = Pattern.compile("\\s*\\[?\\s*%(?:ES)?(?:node_name|cluster_name)\\s*\\]?\\s*");
62+
63+
@Override
64+
public PropertiesConfiguration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
65+
Properties props = new Properties();
66+
try (InputStream in = source.getInputStream()) {
67+
props.load(in);
68+
} catch (IOException e) {
69+
throw new ConfigurationException("Unable to load " + source, e);
70+
}
71+
for (String name : props.stringPropertyNames()) {
72+
if (name.endsWith(".pattern") == false) {
73+
continue;
74+
}
75+
String value = props.getProperty(name);
76+
if (value == null) {
77+
continue;
78+
}
79+
String stripped = STRIP.matcher(value).replaceAll(" ").trim();
80+
if (stripped.equals(value) == false) {
81+
props.setProperty(name, stripped);
82+
}
83+
}
84+
return new PropertiesConfigurationBuilder().setConfigurationSource(source)
85+
.setRootProperties(props)
86+
.setLoggerContext(loggerContext)
87+
.build();
88+
}
89+
}

0 commit comments

Comments
 (0)