19
19
20
20
package org .elasticsearch .persistent ;
21
21
22
- import org .apache .logging .log4j .Logger ;
23
22
import org .elasticsearch .ResourceAlreadyExistsException ;
24
23
import org .elasticsearch .ResourceNotFoundException ;
25
24
import org .elasticsearch .action .ActionListener ;
33
32
import org .elasticsearch .common .Nullable ;
34
33
import org .elasticsearch .common .component .AbstractComponent ;
35
34
import org .elasticsearch .common .settings .Settings ;
36
- import org .elasticsearch .tasks .Task ;
37
35
import org .elasticsearch .persistent .PersistentTasksCustomMetaData .Assignment ;
38
36
import org .elasticsearch .persistent .PersistentTasksCustomMetaData .PersistentTask ;
37
+ import org .elasticsearch .tasks .Task ;
39
38
40
39
import java .util .Objects ;
41
40
@@ -52,29 +51,31 @@ public PersistentTasksClusterService(Settings settings, PersistentTasksExecutorR
52
51
this .clusterService = clusterService ;
53
52
clusterService .addListener (this );
54
53
this .registry = registry ;
55
-
56
54
}
57
55
58
56
/**
59
57
* Creates a new persistent task on master node
60
58
*
61
- * @param action the action name
62
- * @param params params
63
- * @param listener the listener that will be called when task is started
59
+ * @param taskId the task's id
60
+ * @param taskName the task's name
61
+ * @param taskParams the task's parameters
62
+ * @param listener the listener that will be called when task is started
64
63
*/
65
- public <Params extends PersistentTaskParams > void createPersistentTask (String taskId , String action , @ Nullable Params params ,
64
+ public <Params extends PersistentTaskParams > void createPersistentTask (String taskId , String taskName , @ Nullable Params taskParams ,
66
65
ActionListener <PersistentTask <?>> listener ) {
67
66
clusterService .submitStateUpdateTask ("create persistent task" , new ClusterStateUpdateTask () {
68
67
@ Override
69
- public ClusterState execute (ClusterState currentState ) throws Exception {
68
+ public ClusterState execute (ClusterState currentState ) {
70
69
PersistentTasksCustomMetaData .Builder builder = builder (currentState );
71
70
if (builder .hasTask (taskId )) {
72
71
throw new ResourceAlreadyExistsException ("task with id {" + taskId + "} already exist" );
73
72
}
74
- validate (action , currentState , params );
75
- final Assignment assignment ;
76
- assignment = getAssignement (action , currentState , params );
77
- return update (currentState , builder .addTask (taskId , action , params , assignment ));
73
+
74
+ PersistentTasksExecutor <Params > taskExecutor = registry .getPersistentTaskExecutorSafe (taskName );
75
+ taskExecutor .validate (taskParams , currentState );
76
+
77
+ Assignment assignment = createAssignment (taskName , taskParams , currentState );
78
+ return update (currentState , builder .addTask (taskId , taskName , taskParams , assignment ));
78
79
}
79
80
80
81
@ Override
@@ -95,7 +96,6 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
95
96
});
96
97
}
97
98
98
-
99
99
/**
100
100
* Restarts a record about a running persistent task from cluster state
101
101
*
@@ -114,7 +114,7 @@ public void completePersistentTask(String id, long allocationId, Exception failu
114
114
}
115
115
clusterService .submitStateUpdateTask (source , new ClusterStateUpdateTask () {
116
116
@ Override
117
- public ClusterState execute (ClusterState currentState ) throws Exception {
117
+ public ClusterState execute (ClusterState currentState ) {
118
118
PersistentTasksCustomMetaData .Builder tasksInProgress = builder (currentState );
119
119
if (tasksInProgress .hasTask (id , allocationId )) {
120
120
tasksInProgress .removeTask (id );
@@ -185,7 +185,7 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
185
185
public void updatePersistentTaskStatus (String id , long allocationId , Task .Status status , ActionListener <PersistentTask <?>> listener ) {
186
186
clusterService .submitStateUpdateTask ("update task status" , new ClusterStateUpdateTask () {
187
187
@ Override
188
- public ClusterState execute (ClusterState currentState ) throws Exception {
188
+ public ClusterState execute (ClusterState currentState ) {
189
189
PersistentTasksCustomMetaData .Builder tasksInProgress = builder (currentState );
190
190
if (tasksInProgress .hasTask (id , allocationId )) {
191
191
return update (currentState , tasksInProgress .updateTaskStatus (id , status ));
@@ -211,93 +211,85 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
211
211
});
212
212
}
213
213
214
- private <Params extends PersistentTaskParams > Assignment getAssignement (String taskName , ClusterState currentState ,
215
- @ Nullable Params params ) {
216
- PersistentTasksExecutor <Params > persistentTasksExecutor = registry .getPersistentTaskExecutorSafe (taskName );
217
- return persistentTasksExecutor .getAssignment (params , currentState );
218
- }
214
+ /**
215
+ * Creates a new {@link Assignment} for the given persistent task.
216
+ *
217
+ * @param taskName the task's name
218
+ * @param taskParams the task's parameters
219
+ * @param currentState the current {@link ClusterState}
219
220
220
- private <Params extends PersistentTaskParams > void validate (String taskName , ClusterState currentState , @ Nullable Params params ) {
221
+ * @return a new {@link Assignment}
222
+ */
223
+ private <Params extends PersistentTaskParams > Assignment createAssignment (final String taskName ,
224
+ final @ Nullable Params taskParams ,
225
+ final ClusterState currentState ) {
221
226
PersistentTasksExecutor <Params > persistentTasksExecutor = registry .getPersistentTaskExecutorSafe (taskName );
222
- persistentTasksExecutor .validate ( params , currentState );
227
+ return persistentTasksExecutor .getAssignment ( taskParams , currentState );
223
228
}
224
229
225
230
@ Override
226
231
public void clusterChanged (ClusterChangedEvent event ) {
227
232
if (event .localNodeMaster ()) {
228
- logger .trace ("checking task reassignment for cluster state {}" , event .state ().getVersion ());
229
- if (reassignmentRequired (event , this ::getAssignement )) {
230
- logger .trace ("task reassignment is needed" );
231
- reassignTasks ();
232
- } else {
233
- logger .trace ("task reassignment is not needed" );
233
+ if (shouldReassignPersistentTasks (event )) {
234
+ logger .trace ("checking task reassignment for cluster state {}" , event .state ().getVersion ());
235
+ clusterService .submitStateUpdateTask ("reassign persistent tasks" , new ClusterStateUpdateTask () {
236
+ @ Override
237
+ public ClusterState execute (ClusterState currentState ) {
238
+ return reassignTasks (currentState );
239
+ }
240
+
241
+ @ Override
242
+ public void onFailure (String source , Exception e ) {
243
+ logger .warn ("failed to reassign persistent tasks" , e );
244
+ }
245
+ });
234
246
}
235
247
}
236
248
}
237
249
238
- interface ExecutorNodeDecider {
239
- <Params extends PersistentTaskParams > Assignment getAssignment (String action , ClusterState currentState , Params params );
240
- }
250
+ /**
251
+ * Returns true if the cluster state change(s) require to reassign some persistent tasks. It can happen in the following
252
+ * situations: a node left or is added, the routing table changed, the master node changed or the persistent tasks changed.
253
+ */
254
+ boolean shouldReassignPersistentTasks (final ClusterChangedEvent event ) {
255
+ final PersistentTasksCustomMetaData tasks = event .state ().getMetaData ().custom (PersistentTasksCustomMetaData .TYPE );
256
+ if (tasks == null ) {
257
+ return false ;
258
+ }
241
259
242
- static boolean reassignmentRequired (ClusterChangedEvent event , ExecutorNodeDecider decider ) {
243
- PersistentTasksCustomMetaData tasks = event .state ().getMetaData ().custom (PersistentTasksCustomMetaData .TYPE );
244
- PersistentTasksCustomMetaData prevTasks = event .previousState ().getMetaData ().custom (PersistentTasksCustomMetaData .TYPE );
245
- if (tasks != null && (Objects .equals (tasks , prevTasks ) == false ||
246
- event .nodesChanged () ||
247
- event .routingTableChanged () ||
248
- event .previousState ().nodes ().isLocalNodeElectedMaster () == false )) {
249
- // We need to check if removed nodes were running any of the tasks and reassign them
250
- boolean reassignmentRequired = false ;
251
- for (PersistentTask <?> taskInProgress : tasks .tasks ()) {
252
- if (taskInProgress .needsReassignment (event .state ().nodes ())) {
253
- // there is an unassigned task or task with a disappeared node - we need to try assigning it
254
- if (Objects .equals (taskInProgress .getAssignment (),
255
- decider .getAssignment (taskInProgress .getTaskName (), event .state (), taskInProgress .getParams ())) == false ) {
256
- // it looks like a assignment for at least one task is possible - let's trigger reassignment
257
- reassignmentRequired = true ;
258
- break ;
259
- }
260
+ boolean masterChanged = event .previousState ().nodes ().isLocalNodeElectedMaster () == false ;
260
261
262
+ if (persistentTasksChanged (event ) || event .nodesChanged () || event .routingTableChanged () || masterChanged ) {
263
+ for (PersistentTask <?> task : tasks .tasks ()) {
264
+ if (needsReassignment (task .getAssignment (), event .state ().nodes ())) {
265
+ Assignment assignment = createAssignment (task .getTaskName (), task .getParams (), event .state ());
266
+ if (Objects .equals (assignment , task .getAssignment ()) == false ) {
267
+ return true ;
268
+ }
261
269
}
262
270
}
263
- return reassignmentRequired ;
264
271
}
265
272
return false ;
266
273
}
267
274
268
275
/**
269
- * Evaluates the cluster state and tries to assign tasks to nodes
276
+ * Evaluates the cluster state and tries to assign tasks to nodes.
277
+ *
278
+ * @param currentState the cluster state to analyze
279
+ * @return an updated version of the cluster state
270
280
*/
271
- public void reassignTasks () {
272
- clusterService .submitStateUpdateTask ("reassign persistent tasks" , new ClusterStateUpdateTask () {
273
- @ Override
274
- public ClusterState execute (ClusterState currentState ) throws Exception {
275
- return reassignTasks (currentState , logger , PersistentTasksClusterService .this ::getAssignement );
276
- }
277
-
278
- @ Override
279
- public void onFailure (String source , Exception e ) {
280
- logger .warn ("Unsuccessful persistent task reassignment" , e );
281
- }
282
-
283
- @ Override
284
- public void clusterStateProcessed (String source , ClusterState oldState , ClusterState newState ) {
285
-
286
- }
287
- });
288
- }
289
-
290
- static ClusterState reassignTasks (ClusterState currentState , Logger logger , ExecutorNodeDecider decider ) {
291
- PersistentTasksCustomMetaData tasks = currentState .getMetaData ().custom (PersistentTasksCustomMetaData .TYPE );
281
+ ClusterState reassignTasks (final ClusterState currentState ) {
292
282
ClusterState clusterState = currentState ;
293
- DiscoveryNodes nodes = currentState .nodes ();
283
+
284
+ final PersistentTasksCustomMetaData tasks = currentState .getMetaData ().custom (PersistentTasksCustomMetaData .TYPE );
294
285
if (tasks != null ) {
295
286
logger .trace ("reassigning {} persistent tasks" , tasks .tasks ().size ());
287
+ final DiscoveryNodes nodes = currentState .nodes ();
288
+
296
289
// We need to check if removed nodes were running any of the tasks and reassign them
297
290
for (PersistentTask <?> task : tasks .tasks ()) {
298
- if (task .needsReassignment (nodes )) {
299
- // there is an unassigned task - we need to try assigning it
300
- Assignment assignment = decider .getAssignment (task .getTaskName (), clusterState , task .getParams ());
291
+ if (needsReassignment (task .getAssignment (), nodes )) {
292
+ Assignment assignment = createAssignment (task .getTaskName (), task .getParams (), clusterState );
301
293
if (Objects .equals (assignment , task .getAssignment ()) == false ) {
302
294
logger .trace ("reassigning task {} from node {} to node {}" , task .getId (),
303
295
task .getAssignment ().getExecutorNode (), assignment .getExecutorNode ());
@@ -313,6 +305,17 @@ static ClusterState reassignTasks(ClusterState currentState, Logger logger, Exec
313
305
return clusterState ;
314
306
}
315
307
308
+ /** Returns true if the persistent tasks are not equal between the previous and the current cluster state **/
309
+ static boolean persistentTasksChanged (final ClusterChangedEvent event ) {
310
+ String type = PersistentTasksCustomMetaData .TYPE ;
311
+ return Objects .equals (event .state ().metaData ().custom (type ), event .previousState ().metaData ().custom (type )) == false ;
312
+ }
313
+
314
+ /** Returns true if the task is not assigned or is assigned to a non-existing node */
315
+ static boolean needsReassignment (final Assignment assignment , final DiscoveryNodes nodes ) {
316
+ return (assignment .isAssigned () == false || nodes .nodeExists (assignment .getExecutorNode ()) == false );
317
+ }
318
+
316
319
private static PersistentTasksCustomMetaData .Builder builder (ClusterState currentState ) {
317
320
return PersistentTasksCustomMetaData .builder (currentState .getMetaData ().custom (PersistentTasksCustomMetaData .TYPE ));
318
321
}
0 commit comments