Skip to content

Commit 3353bda

Browse files
committed
Merge branch '6.x' into ccr-6.x
* 6.x: [DOCS] s/Spitting/Splitting in split index docs inner_hits: Return an empty _source for nested inner hit when filtering on a field that doesn't exist. percolator: Avoid TooManyClauses exception if number of terms / ranges is exactly equal to 1024 Dedup translog operations by reading in reverse (#27268) Ensure logging is configured for CLI commands Ensure `doc_stats` are changing even if refresh is disabled (#27505) Fix classes that can exit Revert "Adjust CombinedDeletionPolicy for multiple commits (#27456)" Transpose expected and actual, and remove duplicate info from message.
2 parents 7f4ca39 + 1f9d1b1 commit 3353bda

File tree

36 files changed

+917
-258
lines changed

36 files changed

+917
-258
lines changed

core/cli/src/main/java/org/elasticsearch/cli/Command.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public abstract class Command implements Closeable {
3838
/** A description of the command, used in the help output. */
3939
protected final String description;
4040

41+
private final Runnable beforeMain;
42+
4143
/** The option parser for this command. */
4244
protected final OptionParser parser = new OptionParser();
4345

@@ -46,8 +48,15 @@ public abstract class Command implements Closeable {
4648
private final OptionSpec<Void> verboseOption =
4749
parser.acceptsAll(Arrays.asList("v", "verbose"), "show verbose output").availableUnless(silentOption);
4850

49-
public Command(String description) {
51+
/**
52+
* Construct the command with the specified command description and runnable to execute before main is invoked.
53+
*
54+
* @param description the command description
55+
* @param beforeMain the before-main runnable
56+
*/
57+
public Command(final String description, final Runnable beforeMain) {
5058
this.description = description;
59+
this.beforeMain = beforeMain;
5160
}
5261

5362
private Thread shutdownHookThread;
@@ -75,7 +84,7 @@ public final int main(String[] args, Terminal terminal) throws Exception {
7584
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
7685
}
7786

78-
beforeExecute();
87+
beforeMain.run();
7988

8089
try {
8190
mainWithoutErrorHandling(args, terminal);
@@ -93,12 +102,6 @@ public final int main(String[] args, Terminal terminal) throws Exception {
93102
return ExitCodes.OK;
94103
}
95104

96-
/**
97-
* Setup method to be executed before parsing or execution of the command being run. Any exceptions thrown by the
98-
* method will not be cleanly caught by the parser.
99-
*/
100-
protected void beforeExecute() {}
101-
102105
/**
103106
* Executes the command, but all errors are thrown.
104107
*/

core/cli/src/main/java/org/elasticsearch/cli/MultiCommand.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@ public class MultiCommand extends Command {
3535

3636
private final NonOptionArgumentSpec<String> arguments = parser.nonOptions("command");
3737

38-
public MultiCommand(String description) {
39-
super(description);
38+
/**
39+
* Construct the multi-command with the specified command description and runnable to execute before main is invoked.
40+
*
41+
* @param description the multi-command description
42+
* @param beforeMain the before-main runnable
43+
*/
44+
public MultiCommand(final String description, final Runnable beforeMain) {
45+
super(description, beforeMain);
4046
parser.posixlyCorrect(true);
4147
}
4248

core/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class Elasticsearch extends EnvironmentAwareCommand {
5151

5252
// visible for testing
5353
Elasticsearch() {
54-
super("starts elasticsearch");
54+
super("starts elasticsearch", () -> {}); // we configure logging later so we override the base class from configuring logging
5555
versionOption = parser.acceptsAll(Arrays.asList("V", "version"),
5656
"Prints elasticsearch version information and exits");
5757
daemonizeOption = parser.acceptsAll(Arrays.asList("d", "daemonize"),
@@ -92,15 +92,6 @@ static int main(final String[] args, final Elasticsearch elasticsearch, final Te
9292
return elasticsearch.main(args, terminal);
9393
}
9494

95-
@Override
96-
protected boolean shouldConfigureLoggingWithoutConfig() {
97-
/*
98-
* If we allow logging to be configured without a config before we are ready to read the log4j2.properties file, then we will fail
99-
* to detect uses of logging before it is properly configured.
100-
*/
101-
return false;
102-
}
103-
10495
@Override
10596
protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException {
10697
if (options.nonOptionArguments().isEmpty() == false) {

core/src/main/java/org/elasticsearch/bootstrap/ElasticsearchUncaughtExceptionHandler.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,37 +65,43 @@ public void uncaughtException(Thread t, Throwable e) {
6565
}
6666
}
6767

68-
// visible for testing
6968
static boolean isFatalUncaught(Throwable e) {
7069
return e instanceof Error;
7170
}
7271

73-
// visible for testing
7472
void onFatalUncaught(final String threadName, final Throwable t) {
7573
final Logger logger = Loggers.getLogger(ElasticsearchUncaughtExceptionHandler.class, loggingPrefixSupplier.get());
7674
logger.error(
7775
(org.apache.logging.log4j.util.Supplier<?>)
7876
() -> new ParameterizedMessage("fatal error in thread [{}], exiting", threadName), t);
7977
}
8078

81-
// visible for testing
8279
void onNonFatalUncaught(final String threadName, final Throwable t) {
8380
final Logger logger = Loggers.getLogger(ElasticsearchUncaughtExceptionHandler.class, loggingPrefixSupplier.get());
8481
logger.warn((org.apache.logging.log4j.util.Supplier<?>)
8582
() -> new ParameterizedMessage("uncaught exception in thread [{}]", threadName), t);
8683
}
8784

88-
// visible for testing
8985
void halt(int status) {
90-
AccessController.doPrivileged(new PrivilegedAction<Void>() {
91-
@SuppressForbidden(reason = "halt")
92-
@Override
93-
public Void run() {
94-
// we halt to prevent shutdown hooks from running
95-
Runtime.getRuntime().halt(status);
96-
return null;
97-
}
98-
});
86+
AccessController.doPrivileged(new PrivilegedHaltAction(status));
87+
}
88+
89+
static class PrivilegedHaltAction implements PrivilegedAction<Void> {
90+
91+
private final int status;
92+
93+
private PrivilegedHaltAction(final int status) {
94+
this.status = status;
95+
}
96+
97+
@SuppressForbidden(reason = "halt")
98+
@Override
99+
public Void run() {
100+
// we halt to prevent shutdown hooks from running
101+
Runtime.getRuntime().halt(status);
102+
return null;
103+
}
104+
99105
}
100106

101107
}

core/src/main/java/org/elasticsearch/bootstrap/Security.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ static void configure(Environment environment, boolean filterBadDefaults) throws
119119
Policy.setPolicy(new ESPolicy(createPermissions(environment), getPluginPermissions(environment), filterBadDefaults));
120120

121121
// enable security manager
122-
final String[] classesThatCanExit = new String[]{ElasticsearchUncaughtExceptionHandler.class.getName(), Command.class.getName()};
122+
final String[] classesThatCanExit =
123+
new String[]{
124+
// SecureSM matches class names as regular expressions so we escape the $ that arises from the nested class name
125+
ElasticsearchUncaughtExceptionHandler.PrivilegedHaltAction.class.getName().replace("$", "\\$"),
126+
Command.class.getName()};
123127
System.setSecurityManager(new SecureSM(classesThatCanExit));
124128

125129
// do some basic tests
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.cli;
21+
22+
import org.apache.logging.log4j.Level;
23+
import org.elasticsearch.common.logging.LogConfigurator;
24+
import org.elasticsearch.common.settings.Settings;
25+
26+
/**
27+
* Holder class for method to configure logging without Elasticsearch configuration files for use in CLI tools that will not read such
28+
* files.
29+
*/
30+
final class CommandLoggingConfigurator {
31+
32+
/**
33+
* Configures logging without Elasticsearch configuration files based on the system property "es.logger.level" only. As such, any
34+
* logging will be written to the console.
35+
*/
36+
static void configureLoggingWithoutConfig() {
37+
// initialize default for es.logger.level because we will not read the log4j2.properties
38+
final String loggerLevel = System.getProperty("es.logger.level", Level.INFO.name());
39+
final Settings settings = Settings.builder().put("logger.level", loggerLevel).build();
40+
LogConfigurator.configureWithoutConfig(settings);
41+
}
42+
43+
}

core/src/main/java/org/elasticsearch/cli/EnvironmentAwareCommand.java

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222
import joptsimple.OptionSet;
2323
import joptsimple.OptionSpec;
2424
import joptsimple.util.KeyValuePair;
25-
import org.apache.logging.log4j.Level;
2625
import org.elasticsearch.common.SuppressForbidden;
27-
import org.elasticsearch.common.logging.LogConfigurator;
2826
import org.elasticsearch.common.settings.Settings;
2927
import org.elasticsearch.env.Environment;
3028
import org.elasticsearch.node.InternalSettingsPreparer;
@@ -40,8 +38,25 @@ public abstract class EnvironmentAwareCommand extends Command {
4038

4139
private final OptionSpec<KeyValuePair> settingOption;
4240

43-
public EnvironmentAwareCommand(String description) {
44-
super(description);
41+
/**
42+
* Construct the command with the specified command description. This command will have logging configured without reading Elasticsearch
43+
* configuration files.
44+
*
45+
* @param description the command description
46+
*/
47+
public EnvironmentAwareCommand(final String description) {
48+
this(description, CommandLoggingConfigurator::configureLoggingWithoutConfig);
49+
}
50+
51+
/**
52+
* Construct the command with the specified command description and runnable to execute before main is invoked. Commands constructed
53+
* with this constructor must take ownership of configuring logging.
54+
*
55+
* @param description the command description
56+
* @param beforeMain the before-main runnable
57+
*/
58+
public EnvironmentAwareCommand(final String description, final Runnable beforeMain) {
59+
super(description, beforeMain);
4560
this.settingOption = parser.accepts("E", "Configure a setting").withRequiredArg().ofType(KeyValuePair.class);
4661
}
4762

@@ -104,26 +119,6 @@ private static void putSystemPropertyIfSettingIsMissing(final Map<String, String
104119
}
105120
}
106121

107-
@Override
108-
protected final void beforeExecute() {
109-
if (shouldConfigureLoggingWithoutConfig()) {
110-
// initialize default for es.logger.level because we will not read the log4j2.properties
111-
final String loggerLevel = System.getProperty("es.logger.level", Level.INFO.name());
112-
final Settings settings = Settings.builder().put("logger.level", loggerLevel).build();
113-
LogConfigurator.configureWithoutConfig(settings);
114-
}
115-
}
116-
117-
/**
118-
* Indicate whether or not logging should be configured without reading a log4j2.properties. Most commands should do this because we do
119-
* not configure logging for CLI tools. Only commands that configure logging on their own should not do this.
120-
*
121-
* @return true if logging should be configured without reading a log4j2.properties file
122-
*/
123-
protected boolean shouldConfigureLoggingWithoutConfig() {
124-
return true;
125-
}
126-
127122
/** Execute the command with the initialized {@link Environment}. */
128123
protected abstract void execute(Terminal terminal, OptionSet options, Environment env) throws Exception;
129124

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.cli;
21+
22+
/**
23+
* A command that is aware of logging. This class should be preferred over the base {@link Command} class for any CLI tools that depend on
24+
* core Elasticsearch as they could directly or indirectly touch classes that touch logging and as such logging needs to be configured.
25+
*/
26+
public abstract class LoggingAwareCommand extends Command {
27+
28+
/**
29+
* Construct the command with the specified command description. This command will have logging configured without reading Elasticsearch
30+
* configuration files.
31+
*
32+
* @param description the command description
33+
*/
34+
public LoggingAwareCommand(final String description) {
35+
super(description, CommandLoggingConfigurator::configureLoggingWithoutConfig);
36+
}
37+
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.cli;
21+
22+
/**
23+
* A multi-command that is aware of logging. This class should be preferred over the base {@link MultiCommand} class for any CLI tools that
24+
* depend on core Elasticsearch as they could directly or indirectly touch classes that touch logging and as such logging needs to be
25+
* configured.
26+
*/
27+
public abstract class LoggingAwareMultiCommand extends MultiCommand {
28+
29+
/**
30+
* Construct the command with the specified command description. This command will have logging configured without reading Elasticsearch
31+
* configuration files.
32+
*
33+
* @param description the command description
34+
*/
35+
public LoggingAwareMultiCommand(final String description) {
36+
super(description, CommandLoggingConfigurator::configureLoggingWithoutConfig);
37+
}
38+
39+
}

core/src/main/java/org/elasticsearch/common/lucene/Lucene.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,19 @@
3030
import org.apache.lucene.document.LatLonDocValuesField;
3131
import org.apache.lucene.index.CorruptIndexException;
3232
import org.apache.lucene.index.DirectoryReader;
33+
import org.apache.lucene.index.FilterLeafReader;
3334
import org.apache.lucene.index.IndexCommit;
3435
import org.apache.lucene.index.IndexFileNames;
3536
import org.apache.lucene.index.IndexFormatTooNewException;
3637
import org.apache.lucene.index.IndexFormatTooOldException;
3738
import org.apache.lucene.index.IndexWriter;
3839
import org.apache.lucene.index.IndexWriterConfig;
40+
import org.apache.lucene.index.LeafReader;
3941
import org.apache.lucene.index.LeafReaderContext;
4042
import org.apache.lucene.index.NoMergePolicy;
4143
import org.apache.lucene.index.SegmentCommitInfo;
4244
import org.apache.lucene.index.SegmentInfos;
45+
import org.apache.lucene.index.SegmentReader;
4346
import org.apache.lucene.search.DocIdSetIterator;
4447
import org.apache.lucene.search.Explanation;
4548
import org.apache.lucene.search.FieldDoc;
@@ -650,6 +653,21 @@ public static Version parseVersionLenient(String toParse, Version defaultValue)
650653
return LenientParser.parse(toParse, defaultValue);
651654
}
652655

656+
/**
657+
* Tries to extract a segment reader from the given index reader.
658+
* If no SegmentReader can be extracted an {@link IllegalStateException} is thrown.
659+
*/
660+
public static SegmentReader segmentReader(LeafReader reader) {
661+
if (reader instanceof SegmentReader) {
662+
return (SegmentReader) reader;
663+
} else if (reader instanceof FilterLeafReader) {
664+
final FilterLeafReader fReader = (FilterLeafReader) reader;
665+
return segmentReader(FilterLeafReader.unwrap(fReader));
666+
}
667+
// hard fail - we can't get a SegmentReader
668+
throw new IllegalStateException("Can not extract segment reader from given index reader [" + reader + "]");
669+
}
670+
653671
@SuppressForbidden(reason = "Version#parseLeniently() used in a central place")
654672
private static final class LenientParser {
655673
public static Version parse(String toParse, Version defaultValue) {

0 commit comments

Comments
 (0)