Skip to content

Commit 587034d

Browse files
authored
Add set_priority action to ILM (#37397)
This commit adds a set_priority action to the hot, warm, and cold phases for an ILM policy. This action sets the `index.priority` on the managed index to allow different priorities between the hot, warm, and cold recoveries. This commit also includes the HLRC and documentation changes. closes #36905
1 parent 20ed3dd commit 587034d

File tree

21 files changed

+547
-34
lines changed

21 files changed

+547
-34
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleNamedXContentProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ public List<NamedXContentRegistry.Entry> getNamedXContentParsers() {
5353
ShrinkAction::parse),
5454
new NamedXContentRegistry.Entry(LifecycleAction.class,
5555
new ParseField(FreezeAction.NAME),
56-
FreezeAction::parse)
56+
FreezeAction::parse),
57+
new NamedXContentRegistry.Entry(LifecycleAction.class,
58+
new ParseField(SetPriorityAction.NAME),
59+
SetPriorityAction::parse)
5760
);
5861
}
5962
}

client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicy.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@ public class LifecyclePolicy implements ToXContentObject {
5757
throw new IllegalArgumentException("ordered " + PHASES_FIELD.getPreferredName() + " are not supported");
5858
}, PHASES_FIELD);
5959

60-
ALLOWED_ACTIONS.put("hot", Sets.newHashSet(RolloverAction.NAME));
61-
ALLOWED_ACTIONS.put("warm", Sets.newHashSet(AllocateAction.NAME, ForceMergeAction.NAME, ReadOnlyAction.NAME, ShrinkAction.NAME));
62-
ALLOWED_ACTIONS.put("cold", Sets.newHashSet(AllocateAction.NAME, FreezeAction.NAME));
60+
ALLOWED_ACTIONS.put("hot", Sets.newHashSet(SetPriorityAction.NAME, RolloverAction.NAME));
61+
ALLOWED_ACTIONS.put("warm", Sets.newHashSet(SetPriorityAction.NAME, AllocateAction.NAME, ForceMergeAction.NAME,
62+
ReadOnlyAction.NAME, ShrinkAction.NAME));
63+
ALLOWED_ACTIONS.put("cold", Sets.newHashSet(SetPriorityAction.NAME, AllocateAction.NAME, FreezeAction.NAME));
6364
ALLOWED_ACTIONS.put("delete", Sets.newHashSet(DeleteAction.NAME));
6465
}
6566

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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+
package org.elasticsearch.client.indexlifecycle;
20+
21+
import org.elasticsearch.common.Nullable;
22+
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.Strings;
24+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
25+
import org.elasticsearch.common.xcontent.ObjectParser;
26+
import org.elasticsearch.common.xcontent.ToXContent;
27+
import org.elasticsearch.common.xcontent.ToXContentObject;
28+
import org.elasticsearch.common.xcontent.XContentBuilder;
29+
import org.elasticsearch.common.xcontent.XContentParser;
30+
31+
import java.io.IOException;
32+
33+
/**
34+
* A {@link LifecycleAction} which sets the index's priority. The higher the priority, the faster the recovery.
35+
*/
36+
public class SetPriorityAction implements LifecycleAction, ToXContentObject {
37+
public static final String NAME = "set_priority";
38+
private static final ParseField RECOVERY_PRIORITY_FIELD = new ParseField("priority");
39+
40+
@SuppressWarnings("unchecked")
41+
private static final ConstructingObjectParser<SetPriorityAction, Void> PARSER = new ConstructingObjectParser<>(NAME, true,
42+
a -> new SetPriorityAction((Integer) a[0]));
43+
44+
//package private for testing
45+
final Integer recoveryPriority;
46+
47+
static {
48+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
49+
(p) -> p.currentToken() == XContentParser.Token.VALUE_NULL ? null : p.intValue()
50+
, RECOVERY_PRIORITY_FIELD, ObjectParser.ValueType.INT_OR_NULL);
51+
}
52+
53+
public static SetPriorityAction parse(XContentParser parser) {
54+
return PARSER.apply(parser, null);
55+
}
56+
57+
public SetPriorityAction(@Nullable Integer recoveryPriority) {
58+
if (recoveryPriority != null && recoveryPriority <= 0) {
59+
throw new IllegalArgumentException("[" + RECOVERY_PRIORITY_FIELD.getPreferredName() + "] must be 0 or greater");
60+
}
61+
this.recoveryPriority = recoveryPriority;
62+
}
63+
64+
@Override
65+
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
66+
builder.startObject();
67+
builder.field(RECOVERY_PRIORITY_FIELD.getPreferredName(), recoveryPriority);
68+
builder.endObject();
69+
return builder;
70+
}
71+
72+
@Override
73+
public boolean equals(Object o) {
74+
if (this == o) return true;
75+
if (o == null || getClass() != o.getClass()) return false;
76+
77+
SetPriorityAction that = (SetPriorityAction) o;
78+
79+
return recoveryPriority != null ? recoveryPriority.equals(that.recoveryPriority) : that.recoveryPriority == null;
80+
}
81+
82+
@Override
83+
public int hashCode() {
84+
return recoveryPriority != null ? recoveryPriority.hashCode() : 0;
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return Strings.toString(this);
90+
}
91+
92+
@Override
93+
public String getName() {
94+
return NAME;
95+
}
96+
}

client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.elasticsearch.client.indexlifecycle.LifecycleAction;
5555
import org.elasticsearch.client.indexlifecycle.ReadOnlyAction;
5656
import org.elasticsearch.client.indexlifecycle.RolloverAction;
57+
import org.elasticsearch.client.indexlifecycle.SetPriorityAction;
5758
import org.elasticsearch.client.indexlifecycle.ShrinkAction;
5859
import org.elasticsearch.cluster.ClusterName;
5960
import org.elasticsearch.common.CheckedFunction;
@@ -644,7 +645,7 @@ public void testDefaultNamedXContents() {
644645

645646
public void testProvidedNamedXContents() {
646647
List<NamedXContentRegistry.Entry> namedXContents = RestHighLevelClient.getProvidedNamedXContents();
647-
assertEquals(18, namedXContents.size());
648+
assertEquals(19, namedXContents.size());
648649
Map<Class<?>, Integer> categories = new HashMap<>();
649650
List<String> names = new ArrayList<>();
650651
for (NamedXContentRegistry.Entry namedXContent : namedXContents) {
@@ -668,14 +669,15 @@ public void testProvidedNamedXContents() {
668669
assertTrue(names.contains(MeanReciprocalRank.NAME));
669670
assertTrue(names.contains(DiscountedCumulativeGain.NAME));
670671
assertTrue(names.contains(ExpectedReciprocalRank.NAME));
671-
assertEquals(Integer.valueOf(7), categories.get(LifecycleAction.class));
672+
assertEquals(Integer.valueOf(8), categories.get(LifecycleAction.class));
672673
assertTrue(names.contains(AllocateAction.NAME));
673674
assertTrue(names.contains(DeleteAction.NAME));
674675
assertTrue(names.contains(ForceMergeAction.NAME));
675676
assertTrue(names.contains(ReadOnlyAction.NAME));
676677
assertTrue(names.contains(RolloverAction.NAME));
677678
assertTrue(names.contains(ShrinkAction.NAME));
678679
assertTrue(names.contains(FreezeAction.NAME));
680+
assertTrue(names.contains(SetPriorityAction.NAME));
679681
}
680682

681683
public void testApiNamingConventions() throws Exception {

client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/GetLifecyclePolicyResponseTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ protected NamedXContentRegistry xContentRegistry() {
6767
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse),
6868
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse),
6969
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse),
70-
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(FreezeAction.NAME), FreezeAction::parse)
70+
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(FreezeAction.NAME), FreezeAction::parse),
71+
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(SetPriorityAction.NAME), SetPriorityAction::parse)
7172
));
7273
return new NamedXContentRegistry(entries);
7374
}

client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicyMetadataTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ protected NamedXContentRegistry xContentRegistry() {
6363
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse),
6464
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse),
6565
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse),
66-
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(FreezeAction.NAME), FreezeAction::parse)
66+
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(FreezeAction.NAME), FreezeAction::parse),
67+
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(SetPriorityAction.NAME), SetPriorityAction::parse)
6768
));
6869
return new NamedXContentRegistry(entries);
6970
}

client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/LifecyclePolicyTests.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@
3939
import static org.hamcrest.Matchers.equalTo;
4040

4141
public class LifecyclePolicyTests extends AbstractXContentTestCase<LifecyclePolicy> {
42-
private static final Set<String> VALID_HOT_ACTIONS = Sets.newHashSet(RolloverAction.NAME);
43-
private static final Set<String> VALID_WARM_ACTIONS = Sets.newHashSet(AllocateAction.NAME, ForceMergeAction.NAME,
44-
ReadOnlyAction.NAME, ShrinkAction.NAME);
45-
private static final Set<String> VALID_COLD_ACTIONS = Sets.newHashSet(AllocateAction.NAME, FreezeAction.NAME);
42+
private static final Set<String> VALID_HOT_ACTIONS = Sets.newHashSet(SetPriorityAction.NAME, RolloverAction.NAME);
43+
private static final Set<String> VALID_WARM_ACTIONS = Sets.newHashSet(SetPriorityAction.NAME, AllocateAction.NAME,
44+
ForceMergeAction.NAME, ReadOnlyAction.NAME, ShrinkAction.NAME);
45+
private static final Set<String> VALID_COLD_ACTIONS = Sets.newHashSet(SetPriorityAction.NAME, AllocateAction.NAME, FreezeAction.NAME);
4646
private static final Set<String> VALID_DELETE_ACTIONS = Sets.newHashSet(DeleteAction.NAME);
4747

4848
private String lifecycleName;
@@ -67,7 +67,8 @@ protected NamedXContentRegistry xContentRegistry() {
6767
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse),
6868
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse),
6969
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse),
70-
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(FreezeAction.NAME), FreezeAction::parse)
70+
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(FreezeAction.NAME), FreezeAction::parse),
71+
new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(SetPriorityAction.NAME), SetPriorityAction::parse)
7172
));
7273
return new NamedXContentRegistry(entries);
7374
}
@@ -210,6 +211,8 @@ public static LifecyclePolicy createRandomPolicy(String lifecycleName) {
210211
return ShrinkActionTests.randomInstance();
211212
case FreezeAction.NAME:
212213
return new FreezeAction();
214+
case SetPriorityAction.NAME:
215+
return SetPriorityActionTests.randomInstance();
213216
default:
214217
throw new IllegalArgumentException("invalid action [" + action + "]");
215218
}};
@@ -241,6 +244,8 @@ private LifecycleAction getTestAction(String actionName) {
241244
return ShrinkActionTests.randomInstance();
242245
case FreezeAction.NAME:
243246
return new FreezeAction();
247+
case SetPriorityAction.NAME:
248+
return SetPriorityActionTests.randomInstance();
244249
default:
245250
throw new IllegalArgumentException("unsupported phase action [" + actionName + "]");
246251
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
package org.elasticsearch.client.indexlifecycle;
20+
21+
import org.elasticsearch.common.xcontent.XContentParser;
22+
import org.elasticsearch.test.AbstractXContentTestCase;
23+
import org.elasticsearch.test.EqualsHashCodeTestUtils;
24+
25+
import java.io.IOException;
26+
27+
import static org.hamcrest.Matchers.equalTo;
28+
29+
public class SetPriorityActionTests extends AbstractXContentTestCase<SetPriorityAction> {
30+
31+
@Override
32+
protected SetPriorityAction doParseInstance(XContentParser parser) throws IOException {
33+
return SetPriorityAction.parse(parser);
34+
}
35+
36+
@Override
37+
protected SetPriorityAction createTestInstance() {
38+
return randomInstance();
39+
}
40+
41+
static SetPriorityAction randomInstance() {
42+
return new SetPriorityAction(randomIntBetween(1, 100));
43+
}
44+
45+
@Override
46+
protected boolean supportsUnknownFields() {
47+
return false;
48+
}
49+
50+
public void testNonPositivePriority() {
51+
Exception e = expectThrows(Exception.class, () -> new SetPriorityAction(randomIntBetween(-100, 0)));
52+
assertThat(e.getMessage(), equalTo("[priority] must be 0 or greater"));
53+
}
54+
55+
public void testNullPriorityAllowed(){
56+
SetPriorityAction nullPriority = new SetPriorityAction(null);
57+
assertNull(nullPriority.recoveryPriority);
58+
}
59+
60+
public void testEqualsAndHashCode() {
61+
EqualsHashCodeTestUtils.checkEqualsAndHashCode(createTestInstance(), this::copy);
62+
}
63+
64+
SetPriorityAction copy(SetPriorityAction setPriorityAction) {
65+
return new SetPriorityAction(setPriorityAction.recoveryPriority);
66+
}
67+
68+
SetPriorityAction notCopy(SetPriorityAction setPriorityAction) {
69+
return new SetPriorityAction(setPriorityAction.recoveryPriority + 1);
70+
}
71+
}

docs/reference/ilm/policy-definitions.asciidoc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,16 @@ executing.
8585
The below list shows the actions which are available in each phase.
8686

8787
* Hot
88+
- <<ilm-set-priority-action,Set Priority>>
8889
- <<ilm-rollover-action,Rollover>>
8990
* Warm
91+
- <<ilm-set-priority-action,Set Priority>>
9092
- <<ilm-allocate-action,Allocate>>
9193
- <<ilm-readonly-action,Read-Only>>
9294
- <<ilm-forcemerge-action,Force Merge>>
9395
- <<ilm-shrink-action,Shrink>>
9496
* Cold
97+
- <<ilm-set-priority-action,Set Priority>>
9598
- <<ilm-allocate-action,Allocate>>
9699
- <<ilm-freeze-action,Freeze>>
97100
* Delete
@@ -525,6 +528,48 @@ The above example illustrates a policy which attempts to delete an
525528
index one day after the index has been rolled over. It does not
526529
delete the index one day after it has been created.
527530

531+
[[ilm-set-priority-action]]
532+
==== Set Priority
533+
534+
Phases allowed: hot, warm, cold.
535+
536+
This action sets the <<recovery-prioritization, index priority>> on the index as
537+
soon as the policy enters the hot, warm, or cold phase. Indices with a higher
538+
priority will be recovered before indices with lower priorities following a node
539+
restart. Generally, indexes in the hot phase should have the highest value and
540+
indexes in the cold phase should have the lowest values. For example:
541+
100 for the hot phase, 50 for the warm phase, and 0 for the cold phase.
542+
Indicies that don't set this value have an implicit default priority of 1.
543+
544+
[[ilm-set-priority-options]]
545+
.Set Priority Options
546+
[options="header"]
547+
|======
548+
| Name | Required | Default | Description
549+
| `priority` | yes | - | The priority for the index. Must be 0 or greater.
550+
The value may also be set to null to remove the priority.
551+
552+
|======
553+
554+
[source,js]
555+
--------------------------------------------------
556+
PUT _ilm/policy/my_policy
557+
{
558+
"policy": {
559+
"phases": {
560+
"warm": {
561+
"actions": {
562+
"set_priority" : {
563+
"priority": 50
564+
}
565+
}
566+
}
567+
}
568+
}
569+
}
570+
--------------------------------------------------
571+
// CONSOLE
572+
528573
[[ilm-shrink-action]]
529574
==== Shrink
530575

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
5353
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
5454
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleType;
55+
import org.elasticsearch.xpack.core.indexlifecycle.SetPriorityAction;
5556
import org.elasticsearch.xpack.core.indexlifecycle.ReadOnlyAction;
5657
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
5758
import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction;
@@ -427,7 +428,8 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
427428
new NamedWriteableRegistry.Entry(LifecycleAction.class, RolloverAction.NAME, RolloverAction::new),
428429
new NamedWriteableRegistry.Entry(LifecycleAction.class, ShrinkAction.NAME, ShrinkAction::new),
429430
new NamedWriteableRegistry.Entry(LifecycleAction.class, DeleteAction.NAME, DeleteAction::new),
430-
new NamedWriteableRegistry.Entry(LifecycleAction.class, FreezeAction.NAME, FreezeAction::new)
431+
new NamedWriteableRegistry.Entry(LifecycleAction.class, FreezeAction.NAME, FreezeAction::new),
432+
new NamedWriteableRegistry.Entry(LifecycleAction.class, SetPriorityAction.NAME, SetPriorityAction::new)
431433
);
432434
}
433435

0 commit comments

Comments
 (0)