Skip to content

Commit ce2b86a

Browse files
committed
Keep failures to resolve indices
1 parent 07be3f2 commit ce2b86a

File tree

5 files changed

+54
-14
lines changed

5 files changed

+54
-14
lines changed

x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/CanMatchIT.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,21 @@ public void testFailOnUnavailableShards() throws Exception {
250250
try (EsqlQueryResponse resp = run("from events,logs | KEEP timestamp,message")) {
251251
assertThat(getValuesList(resp), hasSize(5));
252252
}
253+
253254
internalCluster().stopNode(logsOnlyNode);
254255
ensureClusterSizeConsistency();
255256

256257
// when one shard is unavailable
257-
expectThrows(Exception.class, containsString("no shard copies found"), () -> run("from events,logs | KEEP timestamp,message"));
258-
expectThrows(Exception.class, containsString("no shard copies found"), () -> run("from * | KEEP timestamp,message"));
258+
expectThrows(
259+
Exception.class,
260+
containsString("index [logs] has no active shard copy"),
261+
() -> run("from events,logs | KEEP timestamp,message")
262+
);
263+
expectThrows(
264+
Exception.class,
265+
containsString("index [logs] has no active shard copy"),
266+
() -> run("from * | KEEP timestamp,message")
267+
);
259268
}
260269

261270
public void testSkipOnIndexName() {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/index/IndexResolution.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesFailure;
1010
import org.elasticsearch.core.Nullable;
1111

12-
import java.util.Collections;
1312
import java.util.Map;
1413
import java.util.Objects;
1514
import java.util.Set;
@@ -25,24 +24,26 @@ public final class IndexResolution {
2524
public static IndexResolution valid(
2625
EsIndex index,
2726
Set<String> resolvedIndices,
27+
FieldCapabilitiesFailure localResolutionFailure,
2828
Map<String, FieldCapabilitiesFailure> unavailableClusters
2929
) {
3030
Objects.requireNonNull(index, "index must not be null if it was found");
3131
Objects.requireNonNull(resolvedIndices, "resolvedIndices must not be null");
32+
Objects.requireNonNull(resolvedIndices, "resolutionFailures must not be null");
3233
Objects.requireNonNull(unavailableClusters, "unavailableClusters must not be null");
33-
return new IndexResolution(index, null, resolvedIndices, unavailableClusters);
34+
return new IndexResolution(index, null, resolvedIndices, localResolutionFailure, unavailableClusters);
3435
}
3536

3637
/**
3738
* Use this method only if the set of concrete resolved indices is the same as EsIndex#concreteIndices().
3839
*/
3940
public static IndexResolution valid(EsIndex index) {
40-
return valid(index, index.concreteIndices(), Collections.emptyMap());
41+
return valid(index, index.concreteIndices(), null, Map.of());
4142
}
4243

4344
public static IndexResolution invalid(String invalid) {
4445
Objects.requireNonNull(invalid, "invalid must not be null to signal that the index is invalid");
45-
return new IndexResolution(null, invalid, Collections.emptySet(), Collections.emptyMap());
46+
return new IndexResolution(null, invalid, Set.of(), null, Map.of());
4647
}
4748

4849
public static IndexResolution notFound(String name) {
@@ -56,18 +57,22 @@ public static IndexResolution notFound(String name) {
5657

5758
// all indices found by field-caps
5859
private final Set<String> resolvedIndices;
60+
@Nullable
61+
private final FieldCapabilitiesFailure localResolutionFailure;
5962
// remote clusters included in the user's index expression that could not be connected to
6063
private final Map<String, FieldCapabilitiesFailure> unavailableClusters;
6164

6265
private IndexResolution(
6366
EsIndex index,
6467
@Nullable String invalid,
6568
Set<String> resolvedIndices,
69+
@Nullable FieldCapabilitiesFailure localResolutionFailure,
6670
Map<String, FieldCapabilitiesFailure> unavailableClusters
6771
) {
6872
this.index = index;
6973
this.invalid = invalid;
7074
this.resolvedIndices = resolvedIndices;
75+
this.localResolutionFailure = localResolutionFailure;
7176
this.unavailableClusters = unavailableClusters;
7277
}
7378

@@ -109,6 +114,14 @@ public Set<String> resolvedIndices() {
109114
return resolvedIndices;
110115
}
111116

117+
/**
118+
* @return local cluster index resolution failure if present
119+
*/
120+
@Nullable
121+
public FieldCapabilitiesFailure getLocalResolutionFailure() {
122+
return localResolutionFailure;
123+
}
124+
112125
@Override
113126
public boolean equals(Object obj) {
114127
if (obj == null || obj.getClass() != getClass()) {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,13 @@ private void preAnalyzeIndices(
482482
indexExpressionToResolve,
483483
result.fieldNames,
484484
requestFilter,
485-
listener.map(indexResolution -> result.withIndexResolution(indexResolution))
485+
listener.delegateFailure((l, indexResolution) -> {
486+
if (configuration.allowPartialResults() == false && indexResolution.getLocalResolutionFailure() != null) {
487+
l.onFailure(indexResolution.getLocalResolutionFailure().getException());
488+
} else {
489+
l.onResponse(result.withIndexResolution(indexResolution));
490+
}
491+
})
486492
);
487493
}
488494
} else {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package org.elasticsearch.xpack.esql.session;
88

9+
import org.elasticsearch.ExceptionsHelper;
910
import org.elasticsearch.action.ActionListener;
1011
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesFailure;
1112
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesIndexResponse;
@@ -87,7 +88,10 @@ public void resolveAsMergedMapping(
8788
client.execute(
8889
EsqlResolveFieldsAction.TYPE,
8990
createFieldCapsRequest(indexWildcard, fieldNames, requestFilter),
90-
listener.delegateFailureAndWrap((l, response) -> l.onResponse(mergedMappings(indexWildcard, response)))
91+
listener.delegateFailureAndWrap((l, response) -> {
92+
93+
l.onResponse(mergedMappings(indexWildcard, response));
94+
})
9195
);
9296
}
9397

@@ -152,6 +156,14 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
152156
fieldCapsResponse.getFailures()
153157
);
154158

159+
FieldCapabilitiesFailure localResolutionFailure = null;
160+
for (FieldCapabilitiesFailure failure : fieldCapsResponse.getFailures()) {
161+
if (ExceptionsHelper.isRemoteUnavailableException(failure.getException()) == false) {
162+
localResolutionFailure = failure;
163+
break;
164+
}
165+
}
166+
155167
Map<String, IndexMode> concreteIndices = Maps.newMapWithExpectedSize(fieldCapsResponse.getIndexResponses().size());
156168
for (FieldCapabilitiesIndexResponse ir : fieldCapsResponse.getIndexResponses()) {
157169
concreteIndices.put(ir.getIndexName(), ir.getIndexMode());
@@ -163,7 +175,7 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
163175
}
164176
// If all the mappings are empty we return an empty set of resolved indices to line up with QL
165177
var index = new EsIndex(indexPattern, rootFields, allEmpty ? Map.of() : concreteIndices, partiallyUnmappedFields);
166-
return IndexResolution.valid(index, concreteIndices.keySet(), unavailableRemotes);
178+
return IndexResolution.valid(index, concreteIndices.keySet(), localResolutionFailure, unavailableRemotes);
167179
}
168180

169181
private static Map<String, List<IndexFieldCapabilities>> collectFieldCaps(FieldCapabilitiesResponse fieldCapsResponse) {

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
254254
)
255255
);
256256

257-
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Map.of());
257+
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), null, Map.of());
258258

259259
EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
260260

@@ -298,7 +298,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
298298
)
299299
);
300300
Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of();
301-
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
301+
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), null, unavailableClusters);
302302

303303
EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
304304

@@ -340,7 +340,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
340340
// remote1 is unavailable
341341
var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
342342
Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of(REMOTE1_ALIAS, failure);
343-
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
343+
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), null, unavailableClusters);
344344

345345
EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
346346

@@ -383,7 +383,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
383383

384384
var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
385385
Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of(REMOTE1_ALIAS, failure);
386-
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
386+
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), null, unavailableClusters);
387387
VerificationException ve = expectThrows(
388388
VerificationException.class,
389389
() -> EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution)
@@ -417,7 +417,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
417417
// remote1 is unavailable
418418
var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
419419
Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of(REMOTE1_ALIAS, failure);
420-
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
420+
IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), null, unavailableClusters);
421421

422422
EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
423423

0 commit comments

Comments
 (0)