Skip to content

Commit f20aaf5

Browse files
rjernstalbertzaharovits
authored andcommitted
Remove non-state transforms (#110646)
Reserved cluster state is build from handlers that modify cluster state. In the past there was one "non-state" handler that stored it's state outside cluster state. However, with that use case now gone, non-state transforms are no longer needed. This commit removes support for non-state transforms.
1 parent 9b0a097 commit f20aaf5

File tree

6 files changed

+45
-238
lines changed

6 files changed

+45
-238
lines changed

server/src/main/java/org/elasticsearch/reservedstate/TransformState.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,13 @@
88

99
package org.elasticsearch.reservedstate;
1010

11-
import org.elasticsearch.action.ActionListener;
1211
import org.elasticsearch.cluster.ClusterState;
1312

1413
import java.util.Set;
15-
import java.util.function.Consumer;
1614

1715
/**
1816
* A {@link ClusterState} wrapper used by the ReservedClusterStateService to pass the
1917
* current state as well as previous keys set by an {@link ReservedClusterStateHandler} to each transform
2018
* step of the cluster state update.
21-
*
22-
* Each {@link ReservedClusterStateHandler} can also provide a non cluster state transform consumer that should run after
23-
* the cluster state is fully validated. This allows for handlers to perform extra steps, like clearing caches or saving
24-
* other state outside the cluster state. The consumer, if provided, must return a {@link NonStateTransformResult} with
25-
* the keys that will be saved as reserved in the cluster state.
2619
*/
27-
public record TransformState(ClusterState state, Set<String> keys, Consumer<ActionListener<NonStateTransformResult>> nonStateTransform) {
28-
public TransformState(ClusterState state, Set<String> keys) {
29-
this(state, keys, null);
30-
}
31-
}
20+
public record TransformState(ClusterState state, Set<String> keys) {}

server/src/main/java/org/elasticsearch/reservedstate/service/ReservedClusterStateService.java

Lines changed: 36 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import org.elasticsearch.Version;
1414
import org.elasticsearch.action.ActionListener;
1515
import org.elasticsearch.action.ActionResponse;
16-
import org.elasticsearch.action.support.RefCountingListener;
1716
import org.elasticsearch.cluster.ClusterState;
1817
import org.elasticsearch.cluster.metadata.ReservedStateErrorMetadata;
1918
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
@@ -22,16 +21,13 @@
2221
import org.elasticsearch.cluster.service.MasterServiceTaskQueue;
2322
import org.elasticsearch.common.Priority;
2423
import org.elasticsearch.core.Tuple;
25-
import org.elasticsearch.reservedstate.NonStateTransformResult;
2624
import org.elasticsearch.reservedstate.ReservedClusterStateHandler;
2725
import org.elasticsearch.reservedstate.TransformState;
2826
import org.elasticsearch.xcontent.ConstructingObjectParser;
2927
import org.elasticsearch.xcontent.ParseField;
3028
import org.elasticsearch.xcontent.XContentParser;
3129

3230
import java.util.ArrayList;
33-
import java.util.Collection;
34-
import java.util.Collections;
3531
import java.util.HashMap;
3632
import java.util.LinkedHashSet;
3733
import java.util.List;
@@ -156,7 +152,6 @@ public void initEmpty(String namespace, ActionListener<ActionResponse.Empty> lis
156152
new ReservedStateUpdateTask(
157153
namespace,
158154
emptyState,
159-
List.of(),
160155
Map.of(),
161156
List.of(),
162157
// error state should not be possible since there is no metadata being parsed or processed
@@ -210,65 +205,44 @@ public void process(String namespace, ReservedStateChunk reservedStateChunk, Con
210205
return;
211206
}
212207

213-
// We trial run all handler validations to ensure that we can process all of the cluster state error free. During
214-
// the trial run we collect 'consumers' (functions) for any non cluster state transforms that need to run.
215-
var trialRunResult = trialRun(namespace, state, reservedStateChunk, orderedHandlers);
208+
// We trial run all handler validations to ensure that we can process all of the cluster state error free.
209+
var trialRunErrors = trialRun(namespace, state, reservedStateChunk, orderedHandlers);
216210
// this is not using the modified trial state above, but that doesn't matter, we're just setting errors here
217-
var error = checkAndReportError(namespace, trialRunResult.errors, reservedStateVersion);
211+
var error = checkAndReportError(namespace, trialRunErrors, reservedStateVersion);
218212

219213
if (error != null) {
220214
errorListener.accept(error);
221215
return;
222216
}
223-
224-
// Since we have validated that the cluster state update can be correctly performed in the trial run, we now
225-
// execute the non cluster state transforms. These are assumed to be async and we continue with the cluster state update
226-
// after all have completed. This part of reserved cluster state update is non-atomic, some or all of the non-state
227-
// transformations can succeed, and we can fail to eventually write the reserved cluster state.
228-
executeNonStateTransformationSteps(trialRunResult.nonStateTransforms, new ActionListener<>() {
229-
@Override
230-
public void onResponse(Collection<NonStateTransformResult> nonStateTransformResults) {
231-
// Once all of the non-state transformation results complete, we can proceed to
232-
// do the final save of the cluster state. The non-state transformation reserved keys are applied
233-
// to the reserved state after all other key handlers.
234-
updateTaskQueue.submitTask(
235-
"reserved cluster state [" + namespace + "]",
236-
new ReservedStateUpdateTask(
237-
namespace,
238-
reservedStateChunk,
239-
nonStateTransformResults,
240-
handlers,
241-
orderedHandlers,
242-
ReservedClusterStateService.this::updateErrorState,
243-
new ActionListener<>() {
244-
@Override
245-
public void onResponse(ActionResponse.Empty empty) {
246-
logger.info("Successfully applied new reserved cluster state for namespace [{}]", namespace);
247-
errorListener.accept(null);
248-
}
249-
250-
@Override
251-
public void onFailure(Exception e) {
252-
// Don't spam the logs on repeated errors
253-
if (isNewError(existingMetadata, reservedStateVersion.version())) {
254-
logger.debug("Failed to apply reserved cluster state", e);
255-
errorListener.accept(e);
256-
} else {
257-
errorListener.accept(null);
258-
}
259-
}
217+
updateTaskQueue.submitTask(
218+
"reserved cluster state [" + namespace + "]",
219+
new ReservedStateUpdateTask(
220+
namespace,
221+
reservedStateChunk,
222+
handlers,
223+
orderedHandlers,
224+
ReservedClusterStateService.this::updateErrorState,
225+
new ActionListener<>() {
226+
@Override
227+
public void onResponse(ActionResponse.Empty empty) {
228+
logger.info("Successfully applied new reserved cluster state for namespace [{}]", namespace);
229+
errorListener.accept(null);
230+
}
231+
232+
@Override
233+
public void onFailure(Exception e) {
234+
// Don't spam the logs on repeated errors
235+
if (isNewError(existingMetadata, reservedStateVersion.version())) {
236+
logger.debug("Failed to apply reserved cluster state", e);
237+
errorListener.accept(e);
238+
} else {
239+
errorListener.accept(null);
260240
}
261-
),
262-
null
263-
);
264-
}
265-
266-
@Override
267-
public void onFailure(Exception e) {
268-
// If we encounter an error while runnin the non-state transforms, we avoid saving any cluster state.
269-
errorListener.accept(checkAndReportError(namespace, List.of(stackTrace(e)), reservedStateVersion));
270-
}
271-
});
241+
}
242+
}
243+
),
244+
null
245+
);
272246
}
273247

274248
// package private for testing
@@ -324,14 +298,13 @@ public void onFailure(Exception e) {
324298
/**
325299
* Goes through all of the handlers, runs the validation and the transform part of the cluster state.
326300
* <p>
327-
* While running the handlers we also collect any non cluster state transformation consumer actions that
328-
* need to be performed asynchronously before we attempt to save the cluster state. The trial run does not
329-
* result in an update of the cluster state, it's only purpose is to verify if we can correctly perform a
330-
* cluster state update with the given reserved state chunk.
301+
* The trial run does not result in an update of the cluster state, it's only purpose is to verify
302+
* if we can correctly perform a cluster state update with the given reserved state chunk.
331303
*
332304
* Package private for testing
305+
* @return Any errors that occured
333306
*/
334-
TrialRunResult trialRun(
307+
List<String> trialRun(
335308
String namespace,
336309
ClusterState currentState,
337310
ReservedStateChunk stateChunk,
@@ -341,7 +314,6 @@ TrialRunResult trialRun(
341314
Map<String, Object> reservedState = stateChunk.state();
342315

343316
List<String> errors = new ArrayList<>();
344-
List<Consumer<ActionListener<NonStateTransformResult>>> nonStateTransforms = new ArrayList<>();
345317

346318
ClusterState state = currentState;
347319

@@ -351,39 +323,12 @@ TrialRunResult trialRun(
351323
Set<String> existingKeys = keysForHandler(existingMetadata, handlerName);
352324
TransformState transformState = handler.transform(reservedState.get(handlerName), new TransformState(state, existingKeys));
353325
state = transformState.state();
354-
if (transformState.nonStateTransform() != null) {
355-
nonStateTransforms.add(transformState.nonStateTransform());
356-
}
357326
} catch (Exception e) {
358327
errors.add(format("Error processing %s state change: %s", handler.name(), stackTrace(e)));
359328
}
360329
}
361330

362-
return new TrialRunResult(nonStateTransforms, errors);
363-
}
364-
365-
/**
366-
* Runs the non cluster state transformations asynchronously, collecting the {@link NonStateTransformResult} objects.
367-
* <p>
368-
* Once all non cluster state transformations have completed, we submit the cluster state update task, which
369-
* updates all of the handler state, including the keys produced by the non cluster state transforms. The new reserved
370-
* state version isn't written to the cluster state until the cluster state task runs.
371-
*
372-
* Package private for testing
373-
*/
374-
static void executeNonStateTransformationSteps(
375-
List<Consumer<ActionListener<NonStateTransformResult>>> nonStateTransforms,
376-
ActionListener<Collection<NonStateTransformResult>> listener
377-
) {
378-
final List<NonStateTransformResult> result = Collections.synchronizedList(new ArrayList<>(nonStateTransforms.size()));
379-
try (var listeners = new RefCountingListener(listener.map(ignored -> result))) {
380-
for (var transform : nonStateTransforms) {
381-
// non cluster state transforms don't modify the cluster state, they however are given a chance to return a more
382-
// up-to-date version of the modified keys we should save in the reserved state. These calls are
383-
// async and report back when they are done through the postTasksListener.
384-
transform.accept(listeners.acquire(result::add));
385-
}
386-
}
331+
return errors;
387332
}
388333

389334
/**
@@ -449,9 +394,4 @@ private void addStateHandler(String key, Set<String> keys, LinkedHashSet<String>
449394
public void installStateHandler(ReservedClusterStateHandler<?> handler) {
450395
this.handlers.put(handler.name(), handler);
451396
}
452-
453-
/**
454-
* Helper record class to combine the result of a trial run, non cluster state actions and any errors
455-
*/
456-
record TrialRunResult(List<Consumer<ActionListener<NonStateTransformResult>>> nonStateTransforms, List<String> errors) {}
457397
}

server/src/main/java/org/elasticsearch/reservedstate/service/ReservedStateUpdateTask.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.elasticsearch.cluster.metadata.ReservedStateHandlerMetadata;
2121
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
2222
import org.elasticsearch.gateway.GatewayService;
23-
import org.elasticsearch.reservedstate.NonStateTransformResult;
2423
import org.elasticsearch.reservedstate.ReservedClusterStateHandler;
2524
import org.elasticsearch.reservedstate.TransformState;
2625

@@ -51,20 +50,17 @@ public class ReservedStateUpdateTask implements ClusterStateTaskListener {
5150
private final Collection<String> orderedHandlers;
5251
private final Consumer<ErrorState> errorReporter;
5352
private final ActionListener<ActionResponse.Empty> listener;
54-
private final Collection<NonStateTransformResult> nonStateTransformResults;
5553

5654
public ReservedStateUpdateTask(
5755
String namespace,
5856
ReservedStateChunk stateChunk,
59-
Collection<NonStateTransformResult> nonStateTransformResults,
6057
Map<String, ReservedClusterStateHandler<?>> handlers,
6158
Collection<String> orderedHandlers,
6259
Consumer<ErrorState> errorReporter,
6360
ActionListener<ActionResponse.Empty> listener
6461
) {
6562
this.namespace = namespace;
6663
this.stateChunk = stateChunk;
67-
this.nonStateTransformResults = nonStateTransformResults;
6864
this.handlers = handlers;
6965
this.orderedHandlers = orderedHandlers;
7066
this.errorReporter = errorReporter;
@@ -115,12 +111,6 @@ protected ClusterState execute(final ClusterState currentState) {
115111

116112
checkAndThrowOnError(errors, reservedStateVersion);
117113

118-
// Once we have set all of the handler state from the cluster state update tasks, we add the reserved keys
119-
// from the non cluster state transforms.
120-
for (var transform : nonStateTransformResults) {
121-
reservedMetadataBuilder.putHandler(new ReservedStateHandlerMetadata(transform.handlerName(), transform.updatedKeys()));
122-
}
123-
124114
// Remove the last error if we had previously encountered any in prior processing of reserved state
125115
reservedMetadataBuilder.errorMetadata(null);
126116

0 commit comments

Comments
 (0)