1010
1111import org .elasticsearch .cluster .AbstractDiffable ;
1212import org .elasticsearch .cluster .Diffable ;
13- import org .elasticsearch .common .xcontent .ParseField ;
1413import org .elasticsearch .common .io .stream .StreamInput ;
1514import org .elasticsearch .common .io .stream .StreamOutput ;
1615import org .elasticsearch .common .xcontent .ConstructingObjectParser ;
16+ import org .elasticsearch .common .xcontent .ObjectParser ;
17+ import org .elasticsearch .common .xcontent .ParseField ;
1718import org .elasticsearch .common .xcontent .ToXContentObject ;
1819import org .elasticsearch .common .xcontent .XContentBuilder ;
1920import org .elasticsearch .common .xcontent .XContentParser ;
21+ import org .elasticsearch .core .Nullable ;
22+ import org .elasticsearch .core .TimeValue ;
2023
2124import java .io .IOException ;
2225import java .util .Locale ;
@@ -35,14 +38,16 @@ public class SingleNodeShutdownMetadata extends AbstractDiffable<SingleNodeShutd
3538 public static final ParseField REASON_FIELD = new ParseField ("reason" );
3639 public static final String STARTED_AT_READABLE_FIELD = "shutdown_started" ;
3740 public static final ParseField STARTED_AT_MILLIS_FIELD = new ParseField (STARTED_AT_READABLE_FIELD + "millis" );
41+ public static final ParseField ALLOCATION_DELAY_FIELD = new ParseField ("allocation_delay" );
3842
3943 public static final ConstructingObjectParser <SingleNodeShutdownMetadata , Void > PARSER = new ConstructingObjectParser <>(
4044 "node_shutdown_info" ,
4145 a -> new SingleNodeShutdownMetadata (
4246 (String ) a [0 ],
4347 Type .valueOf ((String ) a [1 ]),
4448 (String ) a [2 ],
45- (long ) a [3 ]
49+ (long ) a [3 ],
50+ (TimeValue ) a [4 ]
4651 )
4752 );
4853
@@ -51,16 +56,24 @@ public class SingleNodeShutdownMetadata extends AbstractDiffable<SingleNodeShutd
5156 PARSER .declareString (ConstructingObjectParser .constructorArg (), TYPE_FIELD );
5257 PARSER .declareString (ConstructingObjectParser .constructorArg (), REASON_FIELD );
5358 PARSER .declareLong (ConstructingObjectParser .constructorArg (), STARTED_AT_MILLIS_FIELD );
59+ PARSER .declareField (
60+ ConstructingObjectParser .optionalConstructorArg (),
61+ (p , c ) -> TimeValue .parseTimeValue (p .textOrNull (), ALLOCATION_DELAY_FIELD .getPreferredName ()), ALLOCATION_DELAY_FIELD ,
62+ ObjectParser .ValueType .STRING_OR_NULL
63+ );
5464 }
5565
5666 public static SingleNodeShutdownMetadata parse (XContentParser parser ) {
5767 return PARSER .apply (parser , null );
5868 }
5969
70+ public static final TimeValue DEFAULT_RESTART_SHARD_ALLOCATION_DELAY = TimeValue .timeValueMinutes (5 );
71+
6072 private final String nodeId ;
6173 private final Type type ;
6274 private final String reason ;
6375 private final long startedAtMillis ;
76+ @ Nullable private final TimeValue allocationDelay ;
6477
6578 /**
6679 * @param nodeId The node ID that this shutdown metadata refers to.
@@ -72,19 +85,25 @@ private SingleNodeShutdownMetadata(
7285 String nodeId ,
7386 Type type ,
7487 String reason ,
75- long startedAtMillis
88+ long startedAtMillis ,
89+ @ Nullable TimeValue allocationDelay
7690 ) {
7791 this .nodeId = Objects .requireNonNull (nodeId , "node ID must not be null" );
7892 this .type = Objects .requireNonNull (type , "shutdown type must not be null" );
7993 this .reason = Objects .requireNonNull (reason , "shutdown reason must not be null" );
8094 this .startedAtMillis = startedAtMillis ;
95+ if (allocationDelay != null && Type .RESTART .equals (type ) == false ) {
96+ throw new IllegalArgumentException ("shard allocation delay is only valid for RESTART-type shutdowns" );
97+ }
98+ this .allocationDelay = allocationDelay ;
8199 }
82100
83101 public SingleNodeShutdownMetadata (StreamInput in ) throws IOException {
84102 this .nodeId = in .readString ();
85103 this .type = in .readEnum (Type .class );
86104 this .reason = in .readString ();
87105 this .startedAtMillis = in .readVLong ();
106+ this .allocationDelay = in .readOptionalTimeValue ();
88107 }
89108
90109 /**
@@ -115,12 +134,27 @@ public long getStartedAtMillis() {
115134 return startedAtMillis ;
116135 }
117136
137+ /**
138+ * @return The amount of time shard reallocation should be delayed for shards on this node, so that they will not be automatically
139+ * reassigned while the node is restarting. Will be {@code null} for non-restart shutdowns.
140+ */
141+ @ Nullable
142+ public TimeValue getAllocationDelay () {
143+ if (allocationDelay != null ) {
144+ return allocationDelay ;
145+ } else if (Type .RESTART .equals (type )) {
146+ return DEFAULT_RESTART_SHARD_ALLOCATION_DELAY ;
147+ }
148+ return null ;
149+ }
150+
118151 @ Override
119152 public void writeTo (StreamOutput out ) throws IOException {
120153 out .writeString (nodeId );
121154 out .writeEnum (type );
122155 out .writeString (reason );
123156 out .writeVLong (startedAtMillis );
157+ out .writeOptionalTimeValue (allocationDelay );
124158 }
125159
126160 @ Override
@@ -131,6 +165,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
131165 builder .field (TYPE_FIELD .getPreferredName (), type );
132166 builder .field (REASON_FIELD .getPreferredName (), reason );
133167 builder .timeField (STARTED_AT_MILLIS_FIELD .getPreferredName (), STARTED_AT_READABLE_FIELD , startedAtMillis );
168+ if (allocationDelay != null ) {
169+ builder .field (ALLOCATION_DELAY_FIELD .getPreferredName (), allocationDelay .getStringRep ());
170+ }
134171 }
135172 builder .endObject ();
136173
@@ -145,7 +182,8 @@ public boolean equals(Object o) {
145182 return getStartedAtMillis () == that .getStartedAtMillis ()
146183 && getNodeId ().equals (that .getNodeId ())
147184 && getType () == that .getType ()
148- && getReason ().equals (that .getReason ());
185+ && getReason ().equals (that .getReason ())
186+ && Objects .equals (allocationDelay , that .allocationDelay );
149187 }
150188
151189 @ Override
@@ -154,7 +192,8 @@ public int hashCode() {
154192 getNodeId (),
155193 getType (),
156194 getReason (),
157- getStartedAtMillis ()
195+ getStartedAtMillis (),
196+ allocationDelay
158197 );
159198 }
160199
@@ -178,6 +217,7 @@ public static class Builder {
178217 private Type type ;
179218 private String reason ;
180219 private long startedAtMillis = -1 ;
220+ private TimeValue allocationDelay ;
181221
182222 private Builder () {}
183223
@@ -217,15 +257,25 @@ public Builder setStartedAtMillis(long startedAtMillis) {
217257 return this ;
218258 }
219259
260+ /**
261+ * @param allocationDelay The amount of time shard reallocation should be delayed while this node is offline.
262+ * @return This builder.
263+ */
264+ public Builder setAllocationDelay (TimeValue allocationDelay ) {
265+ this .allocationDelay = allocationDelay ;
266+ return this ;
267+ }
268+
220269 public SingleNodeShutdownMetadata build () {
221270 if (startedAtMillis == -1 ) {
222271 throw new IllegalArgumentException ("start timestamp must be set" );
223272 }
273+
224274 return new SingleNodeShutdownMetadata (
225275 nodeId ,
226276 type ,
227277 reason ,
228- startedAtMillis
278+ startedAtMillis , allocationDelay
229279 );
230280 }
231281 }
0 commit comments