23
23
import org .elasticsearch .Version ;
24
24
import org .elasticsearch .cluster .ClusterState ;
25
25
import org .elasticsearch .cluster .metadata .MetaData ;
26
+ import org .elasticsearch .cluster .routing .allocation .RoutingAllocation ;
26
27
import org .elasticsearch .cluster .routing .allocation .decider .Decision ;
27
28
import org .elasticsearch .common .Nullable ;
28
29
import org .elasticsearch .common .io .stream .StreamInput ;
39
40
import java .io .IOException ;
40
41
import java .time .Instant ;
41
42
import java .time .ZoneOffset ;
43
+ import java .util .Collections ;
44
+ import java .util .List ;
42
45
import java .util .Locale ;
43
46
import java .util .Objects ;
47
+ import java .util .Set ;
44
48
45
49
/**
46
50
* Holds additional information as to why the shard is in unassigned state.
@@ -214,6 +218,7 @@ public String value() {
214
218
private final String message ;
215
219
private final Exception failure ;
216
220
private final int failedAllocations ;
221
+ private final Set <String > failedNodeIds ;
217
222
private final AllocationStatus lastAllocationStatus ; // result of the last allocation attempt for this shard
218
223
219
224
/**
@@ -224,7 +229,7 @@ public String value() {
224
229
**/
225
230
public UnassignedInfo (Reason reason , String message ) {
226
231
this (reason , message , null , reason == Reason .ALLOCATION_FAILED ? 1 : 0 , System .nanoTime (), System .currentTimeMillis (), false ,
227
- AllocationStatus .NO_ATTEMPT );
232
+ AllocationStatus .NO_ATTEMPT , Collections . emptySet () );
228
233
}
229
234
230
235
/**
@@ -235,9 +240,11 @@ public UnassignedInfo(Reason reason, String message) {
235
240
* @param unassignedTimeMillis the time of unassignment used to display to in our reporting.
236
241
* @param delayed if allocation of this shard is delayed due to INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING.
237
242
* @param lastAllocationStatus the result of the last allocation attempt for this shard
243
+ * @param failedNodeIds a set of nodeIds that failed to complete allocations for this shard
238
244
*/
239
245
public UnassignedInfo (Reason reason , @ Nullable String message , @ Nullable Exception failure , int failedAllocations ,
240
- long unassignedTimeNanos , long unassignedTimeMillis , boolean delayed , AllocationStatus lastAllocationStatus ) {
246
+ long unassignedTimeNanos , long unassignedTimeMillis , boolean delayed , AllocationStatus lastAllocationStatus ,
247
+ Set <String > failedNodeIds ) {
241
248
this .reason = Objects .requireNonNull (reason );
242
249
this .unassignedTimeMillis = unassignedTimeMillis ;
243
250
this .unassignedTimeNanos = unassignedTimeNanos ;
@@ -246,6 +253,7 @@ public UnassignedInfo(Reason reason, @Nullable String message, @Nullable Excepti
246
253
this .failure = failure ;
247
254
this .failedAllocations = failedAllocations ;
248
255
this .lastAllocationStatus = Objects .requireNonNull (lastAllocationStatus );
256
+ this .failedNodeIds = Collections .unmodifiableSet (failedNodeIds );
249
257
assert (failedAllocations > 0 ) == (reason == Reason .ALLOCATION_FAILED ) :
250
258
"failedAllocations: " + failedAllocations + " for reason " + reason ;
251
259
assert !(message == null && failure != null ) : "provide a message if a failure exception is provided" ;
@@ -263,6 +271,11 @@ public UnassignedInfo(StreamInput in) throws IOException {
263
271
this .failure = in .readException ();
264
272
this .failedAllocations = in .readVInt ();
265
273
this .lastAllocationStatus = AllocationStatus .readFrom (in );
274
+ if (in .getVersion ().onOrAfter (Version .V_7_5_0 )) {
275
+ this .failedNodeIds = Collections .unmodifiableSet (in .readSet (StreamInput ::readString ));
276
+ } else {
277
+ this .failedNodeIds = Collections .emptySet ();
278
+ }
266
279
}
267
280
268
281
public void writeTo (StreamOutput out ) throws IOException {
@@ -280,6 +293,9 @@ public void writeTo(StreamOutput out) throws IOException {
280
293
out .writeException (failure );
281
294
out .writeVInt (failedAllocations );
282
295
lastAllocationStatus .writeTo (out );
296
+ if (out .getVersion ().onOrAfter (Version .V_7_5_0 )) {
297
+ out .writeCollection (failedNodeIds , StreamOutput ::writeString );
298
+ }
283
299
}
284
300
285
301
/**
@@ -354,6 +370,19 @@ public AllocationStatus getLastAllocationStatus() {
354
370
return lastAllocationStatus ;
355
371
}
356
372
373
+ /**
374
+ * A set of nodeIds that failed to complete allocations for this shard. {@link org.elasticsearch.gateway.ReplicaShardAllocator}
375
+ * uses this set to avoid repeatedly canceling ongoing recoveries for copies on those nodes although they can perform noop recoveries.
376
+ * This set will be discarded when a shard moves to started. And if a shard is failed while started (i.e., from started to unassigned),
377
+ * the currently assigned node won't be added to this set.
378
+ *
379
+ * @see org.elasticsearch.gateway.ReplicaShardAllocator#processExistingRecoveries(RoutingAllocation)
380
+ * @see org.elasticsearch.cluster.routing.allocation.AllocationService#applyFailedShards(ClusterState, List, List)
381
+ */
382
+ public Set <String > getFailedNodeIds () {
383
+ return failedNodeIds ;
384
+ }
385
+
357
386
/**
358
387
* Calculates the delay left based on current time (in nanoseconds) and the delay defined by the index settings.
359
388
* Only relevant if shard is effectively delayed (see {@link #isDelayed()})
@@ -410,6 +439,9 @@ public String shortSummary() {
410
439
if (failedAllocations > 0 ) {
411
440
sb .append (", failed_attempts[" ).append (failedAllocations ).append ("]" );
412
441
}
442
+ if (failedNodeIds .isEmpty () == false ) {
443
+ sb .append (", failed_nodes[" ).append (failedNodeIds ).append ("]" );
444
+ }
413
445
sb .append (", delayed=" ).append (delayed );
414
446
String details = getDetails ();
415
447
@@ -433,6 +465,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
433
465
if (failedAllocations > 0 ) {
434
466
builder .field ("failed_attempts" , failedAllocations );
435
467
}
468
+ if (failedNodeIds .isEmpty () == false ) {
469
+ builder .field ("failed_nodes" , failedNodeIds );
470
+ }
436
471
builder .field ("delayed" , delayed );
437
472
String details = getDetails ();
438
473
if (details != null ) {
@@ -466,13 +501,16 @@ public boolean equals(Object o) {
466
501
if (reason != that .reason ) {
467
502
return false ;
468
503
}
469
- if (message != null ? ! message .equals (that . message ) : that .message != null ) {
504
+ if (Objects .equals (message , that .message ) == false ) {
470
505
return false ;
471
506
}
472
507
if (lastAllocationStatus != that .lastAllocationStatus ) {
473
508
return false ;
474
509
}
475
- return !(failure != null ? !failure .equals (that .failure ) : that .failure != null );
510
+ if (Objects .equals (failure , that .failure ) == false ) {
511
+ return false ;
512
+ }
513
+ return failedNodeIds .equals (that .failedNodeIds );
476
514
}
477
515
478
516
@ Override
@@ -484,6 +522,7 @@ public int hashCode() {
484
522
result = 31 * result + (message != null ? message .hashCode () : 0 );
485
523
result = 31 * result + (failure != null ? failure .hashCode () : 0 );
486
524
result = 31 * result + lastAllocationStatus .hashCode ();
525
+ result = 31 * result + failedNodeIds .hashCode ();
487
526
return result ;
488
527
}
489
528
0 commit comments