Skip to content

Commit 6bec876

Browse files
tlrxdnhatn
authored andcommitted
Improve Close Index Response (#39687)
This changes the `CloseIndexResponse` so that it reports closing result for each index. Shard failures or exception are also reported per index, and the global acknowledgment flag is computed from the index results only. The response looks like: ``` { "acknowledged" : true, "shards_acknowledged" : true, "indices" : { "docs" : { "closed" : true } } } ``` The response reports shard failures like: ``` { "acknowledged" : false, "shards_acknowledged" : false, "indices" : { "docs-1" : { "closed" : true }, "docs-2" : { "closed" : false, "shards" : { "1" : { "failures" : [ { "shard" : 1, "index" : "docs-2", "status" : "BAD_REQUEST", "reason" : { "type" : "index_closed_exception", "reason" : "closed", "index_uuid" : "JFmQwr_aSPiZbkAH_KEF7A", "index" : "docs-2" } } ] } } }, "docs-3" : { "closed" : true } } } ``` Co-authored-by: Tanguy Leroux <[email protected]>
1 parent 63eccb1 commit 6bec876

File tree

10 files changed

+575
-72
lines changed

10 files changed

+575
-72
lines changed

rest-api-spec/src/main/resources/rest-api-spec/test/indices.open/10_basic.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,40 @@
8282
- is_true: acknowledged
8383
- match: { acknowledged: true }
8484
- match: { shards_acknowledged: true }
85+
---
86+
"Close index response with result per index":
87+
- skip:
88+
version: " - 7.99.99"
89+
reason: "close index response reports result per index starting version 8.0.0"
90+
91+
- do:
92+
indices.create:
93+
index: index_1
94+
body:
95+
settings:
96+
number_of_replicas: 0
97+
98+
- do:
99+
indices.create:
100+
index: index_2
101+
body:
102+
settings:
103+
number_of_replicas: 0
104+
105+
- do:
106+
indices.create:
107+
index: index_3
108+
body:
109+
settings:
110+
number_of_replicas: 0
111+
112+
- do:
113+
indices.close:
114+
index: "index_*"
115+
116+
- match: { acknowledged: true }
117+
- match: { shards_acknowledged: true }
118+
- match: { indices.index_1.closed: true }
119+
- match: { indices.index_2.closed: true }
120+
- match: { indices.index_3.closed: true }
121+

server/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexResponse.java

Lines changed: 246 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,40 @@
1818
*/
1919
package org.elasticsearch.action.admin.indices.close;
2020

21+
import org.elasticsearch.ElasticsearchException;
2122
import org.elasticsearch.Version;
23+
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
2224
import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
25+
import org.elasticsearch.common.Nullable;
26+
import org.elasticsearch.common.Strings;
2327
import org.elasticsearch.common.io.stream.StreamInput;
2428
import org.elasticsearch.common.io.stream.StreamOutput;
29+
import org.elasticsearch.common.io.stream.Writeable;
30+
import org.elasticsearch.common.xcontent.ToXContentFragment;
31+
import org.elasticsearch.common.xcontent.XContentBuilder;
32+
import org.elasticsearch.index.Index;
2533

2634
import java.io.IOException;
35+
import java.util.List;
36+
import java.util.Objects;
37+
38+
import static java.util.Collections.emptyList;
39+
import static java.util.Collections.unmodifiableList;
2740

2841
public class CloseIndexResponse extends ShardsAcknowledgedResponse {
2942

43+
private List<IndexResult> indices;
44+
3045
CloseIndexResponse() {
3146
}
3247

33-
public CloseIndexResponse(final boolean acknowledged, final boolean shardsAcknowledged) {
48+
public CloseIndexResponse(final boolean acknowledged, final boolean shardsAcknowledged, final List<IndexResult> indices) {
3449
super(acknowledged, shardsAcknowledged);
50+
this.indices = unmodifiableList(Objects.requireNonNull(indices));
51+
}
52+
53+
public List<IndexResult> getIndices() {
54+
return indices;
3555
}
3656

3757
@Override
@@ -40,6 +60,11 @@ public void readFrom(StreamInput in) throws IOException {
4060
if (in.getVersion().onOrAfter(Version.V_7_2_0)) {
4161
readShardsAcknowledged(in);
4262
}
63+
if (in.getVersion().onOrAfter(Version.V_7_3_0)) {
64+
indices = unmodifiableList(in.readList(IndexResult::new));
65+
} else {
66+
indices = unmodifiableList(emptyList());
67+
}
4368
}
4469

4570
@Override
@@ -48,5 +73,225 @@ public void writeTo(StreamOutput out) throws IOException {
4873
if (out.getVersion().onOrAfter(Version.V_7_2_0)) {
4974
writeShardsAcknowledged(out);
5075
}
76+
if (out.getVersion().onOrAfter(Version.V_7_3_0)) {
77+
out.writeList(indices);
78+
}
79+
}
80+
81+
protected void addCustomFields(final XContentBuilder builder, final Params params) throws IOException {
82+
super.addCustomFields(builder, params);
83+
builder.startObject("indices");
84+
for (IndexResult index : indices) {
85+
index.toXContent(builder, params);
86+
}
87+
builder.endObject();
88+
}
89+
90+
@Override
91+
public String toString() {
92+
return Strings.toString(this);
93+
}
94+
95+
public static class IndexResult implements Writeable, ToXContentFragment {
96+
97+
private final Index index;
98+
private final @Nullable Exception exception;
99+
private final @Nullable ShardResult[] shards;
100+
101+
public IndexResult(final Index index) {
102+
this(index, null, null);
103+
}
104+
105+
public IndexResult(final Index index, final Exception failure) {
106+
this(index, Objects.requireNonNull(failure), null);
107+
}
108+
109+
public IndexResult(final Index index, final ShardResult[] shards) {
110+
this(index, null, Objects.requireNonNull(shards));
111+
}
112+
113+
private IndexResult(final Index index, @Nullable final Exception exception, @Nullable final ShardResult[] shards) {
114+
this.index = Objects.requireNonNull(index);
115+
this.exception = exception;
116+
this.shards = shards;
117+
}
118+
119+
IndexResult(final StreamInput in) throws IOException {
120+
this.index = new Index(in);
121+
this.exception = in.readException();
122+
this.shards = in.readOptionalArray(ShardResult::new, ShardResult[]::new);
123+
}
124+
125+
@Override
126+
public void writeTo(final StreamOutput out) throws IOException {
127+
index.writeTo(out);
128+
out.writeException(exception);
129+
out.writeOptionalArray(shards);
130+
}
131+
132+
public Index getIndex() {
133+
return index;
134+
}
135+
136+
public Exception getException() {
137+
return exception;
138+
}
139+
140+
public ShardResult[] getShards() {
141+
return shards;
142+
}
143+
144+
public boolean hasFailures() {
145+
if (exception != null) {
146+
return true;
147+
}
148+
if (shards != null) {
149+
for (ShardResult shard : shards) {
150+
if (shard.hasFailures()) {
151+
return true;
152+
}
153+
}
154+
}
155+
return false;
156+
}
157+
158+
@Override
159+
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
160+
builder.startObject(index.getName());
161+
{
162+
if (hasFailures()) {
163+
builder.field("closed", false);
164+
if (exception != null) {
165+
builder.startObject("exception");
166+
ElasticsearchException.generateFailureXContent(builder, params, exception, true);
167+
builder.endObject();
168+
} else {
169+
builder.startObject("failedShards");
170+
for (ShardResult shard : shards) {
171+
if (shard.hasFailures()) {
172+
shard.toXContent(builder, params);
173+
}
174+
}
175+
builder.endObject();
176+
}
177+
} else {
178+
builder.field("closed", true);
179+
}
180+
}
181+
return builder.endObject();
182+
}
183+
184+
@Override
185+
public String toString() {
186+
return Strings.toString(this);
187+
}
188+
}
189+
190+
public static class ShardResult implements Writeable, ToXContentFragment {
191+
192+
private final int id;
193+
private final ShardResult.Failure[] failures;
194+
195+
public ShardResult(final int id, final Failure[] failures) {
196+
this.id = id;
197+
this.failures = failures;
198+
}
199+
200+
ShardResult(final StreamInput in) throws IOException {
201+
this.id = in.readVInt();
202+
this.failures = in.readOptionalArray(Failure::readFailure, ShardResult.Failure[]::new);
203+
}
204+
205+
@Override
206+
public void writeTo(final StreamOutput out) throws IOException {
207+
out.writeVInt(id);
208+
out.writeOptionalArray(failures);
209+
}
210+
211+
public boolean hasFailures() {
212+
return failures != null && failures.length > 0;
213+
}
214+
215+
public int getId() {
216+
return id;
217+
}
218+
219+
public Failure[] getFailures() {
220+
return failures;
221+
}
222+
223+
@Override
224+
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
225+
builder.startObject(String.valueOf(id));
226+
{
227+
builder.startArray("failures");
228+
if (failures != null) {
229+
for (Failure failure : failures) {
230+
builder.startObject();
231+
failure.toXContent(builder, params);
232+
builder.endObject();
233+
}
234+
}
235+
builder.endArray();
236+
}
237+
return builder.endObject();
238+
}
239+
240+
@Override
241+
public String toString() {
242+
return Strings.toString(this);
243+
}
244+
245+
public static class Failure extends DefaultShardOperationFailedException implements Writeable {
246+
247+
private @Nullable String nodeId;
248+
249+
private Failure() {
250+
}
251+
252+
public Failure(final String index, final int shardId, final Throwable reason) {
253+
this(index, shardId, reason, null);
254+
}
255+
256+
public Failure(final String index, final int shardId, final Throwable reason, final String nodeId) {
257+
super(index, shardId, reason);
258+
this.nodeId = nodeId;
259+
}
260+
261+
public String getNodeId() {
262+
return nodeId;
263+
}
264+
265+
@Override
266+
public void readFrom(final StreamInput in) throws IOException {
267+
super.readFrom(in);
268+
nodeId = in.readOptionalString();
269+
}
270+
271+
@Override
272+
public void writeTo(final StreamOutput out) throws IOException {
273+
super.writeTo(out);
274+
out.writeOptionalString(nodeId);
275+
}
276+
277+
@Override
278+
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
279+
if (nodeId != null) {
280+
builder.field("node", nodeId);
281+
}
282+
return super.toXContent(builder, params);
283+
}
284+
285+
@Override
286+
public String toString() {
287+
return Strings.toString(this);
288+
}
289+
290+
static Failure readFailure(final StreamInput in) throws IOException {
291+
final Failure failure = new Failure();
292+
failure.readFrom(in);
293+
return failure;
294+
}
295+
}
51296
}
52297
}

server/src/main/java/org/elasticsearch/action/admin/indices/close/TransportCloseIndexAction.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import org.elasticsearch.threadpool.ThreadPool;
4141
import org.elasticsearch.transport.TransportService;
4242

43+
import java.util.Collections;
44+
4345
/**
4446
* Close index action
4547
*/
@@ -109,7 +111,7 @@ protected void masterOperation(final Task task,
109111
final ActionListener<CloseIndexResponse> listener) throws Exception {
110112
final Index[] concreteIndices = indexNameExpressionResolver.concreteIndices(state, request);
111113
if (concreteIndices == null || concreteIndices.length == 0) {
112-
listener.onResponse(new CloseIndexResponse(true, false));
114+
listener.onResponse(new CloseIndexResponse(true, false, Collections.emptyList()));
113115
return;
114116
}
115117

0 commit comments

Comments
 (0)