10
10
package org .elasticsearch .cluster .routing .allocation ;
11
11
12
12
import org .elasticsearch .cluster .routing .ShardRouting ;
13
+ import org .elasticsearch .cluster .routing .ShardRoutingState ;
13
14
import org .elasticsearch .cluster .routing .allocation .decider .MaxRetryAllocationDecider ;
14
15
import org .elasticsearch .common .settings .Settings ;
16
+ import org .elasticsearch .index .Index ;
15
17
import org .elasticsearch .index .shard .IndexEventListener ;
16
18
import org .elasticsearch .plugins .Plugin ;
17
19
import org .elasticsearch .test .ESIntegTestCase ;
20
22
import org .elasticsearch .test .MockIndexEventListener ;
21
23
22
24
import java .util .List ;
25
+ import java .util .concurrent .atomic .AtomicBoolean ;
26
+
27
+ import static org .elasticsearch .cluster .metadata .IndexMetadata .INDEX_ROUTING_EXCLUDE_GROUP_PREFIX ;
28
+ import static org .hamcrest .CoreMatchers .equalTo ;
29
+ import static org .hamcrest .CoreMatchers .not ;
30
+ import static org .hamcrest .CoreMatchers .notNullValue ;
23
31
24
32
@ ClusterScope (scope = Scope .TEST , numDataNodes = 0 )
25
33
public class AllocationFailuresResetIT extends ESIntegTestCase {
@@ -72,7 +80,7 @@ private void awaitShardAllocSucceed() throws Exception {
72
80
});
73
81
}
74
82
75
- public void testResetFailuresOnNodeJoin () throws Exception {
83
+ public void testResetAllocationFailuresOnNodeJoin () throws Exception {
76
84
var node1 = internalCluster ().startNode ();
77
85
injectAllocationFailures (node1 );
78
86
prepareCreate (INDEX , indexSettings (1 , 0 )).execute ();
@@ -82,4 +90,44 @@ public void testResetFailuresOnNodeJoin() throws Exception {
82
90
awaitShardAllocSucceed ();
83
91
}
84
92
93
+ public void testResetRelocationFailuresOnNodeJoin () throws Exception {
94
+ String node1 = internalCluster ().startNode ();
95
+ createIndex (INDEX , 1 , 0 );
96
+ ensureGreen (INDEX );
97
+ final var failRelocation = new AtomicBoolean (true );
98
+ String node2 = internalCluster ().startNode ();
99
+ internalCluster ().getInstance (MockIndexEventListener .TestEventListener .class , node2 ).setNewDelegate (new IndexEventListener () {
100
+ @ Override
101
+ public void beforeIndexCreated (Index index , Settings indexSettings ) {
102
+ if (failRelocation .get ()) {
103
+ throw new RuntimeException ("FAIL" );
104
+ }
105
+ }
106
+ });
107
+ updateIndexSettings (Settings .builder ().put (INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + "._name" , node1 ), INDEX );
108
+ ensureGreen (INDEX );
109
+ // await all relocation attempts are exhausted
110
+ var maxAttempts = MaxRetryAllocationDecider .SETTING_ALLOCATION_MAX_RETRY .get (Settings .EMPTY );
111
+ assertBusy (() -> {
112
+ var state = clusterAdmin ().prepareState (TEST_REQUEST_TIMEOUT ).get ().getState ();
113
+ var shard = state .routingTable ().index (INDEX ).shard (SHARD ).primaryShard ();
114
+ assertThat (shard , notNullValue ());
115
+ assertThat (shard .relocationFailureInfo ().failedRelocations (), equalTo (maxAttempts ));
116
+ });
117
+ // ensure the shard remain started
118
+ var state = clusterAdmin ().prepareState (TEST_REQUEST_TIMEOUT ).get ().getState ();
119
+ var shard = state .routingTable ().index (INDEX ).shard (SHARD ).primaryShard ();
120
+ assertThat (shard , notNullValue ());
121
+ assertThat (shard .state (), equalTo (ShardRoutingState .STARTED ));
122
+ assertThat (state .nodes ().get (shard .currentNodeId ()).getName (), equalTo (node1 ));
123
+ failRelocation .set (false );
124
+ // A new node joining should reset the counter and allow more relocation retries
125
+ internalCluster ().startNode ();
126
+ assertBusy (() -> {
127
+ var stateAfterNodeJoin = internalCluster ().clusterService ().state ();
128
+ var relocatedShard = stateAfterNodeJoin .routingTable ().index (INDEX ).shard (SHARD ).primaryShard ();
129
+ assertThat (relocatedShard , notNullValue ());
130
+ assertThat (stateAfterNodeJoin .nodes ().get (relocatedShard .currentNodeId ()).getName (), not (equalTo (node1 )));
131
+ });
132
+ }
85
133
}
0 commit comments